func (pm *PrinterManager) syncPrinters(ignorePrivet bool) error { log.Info("Synchronizing printers, stand by") // Get current snapshot of native printers. nativePrinters, err := pm.native.GetPrinters() if err != nil { return fmt.Errorf("Sync failed while calling GetPrinters(): %s", err) } // Set CapsHash on all printers. for i := range nativePrinters { h := adler32.New() lib.DeepHash(nativePrinters[i].Tags, h) nativePrinters[i].Tags["tagshash"] = fmt.Sprintf("%x", h.Sum(nil)) h = adler32.New() lib.DeepHash(nativePrinters[i].Description, h) nativePrinters[i].CapsHash = fmt.Sprintf("%x", h.Sum(nil)) } // Compare the snapshot to what we know currently. diffs := lib.DiffPrinters(nativePrinters, pm.printers.GetAll()) if diffs == nil { log.Infof("Printers are already in sync; there are %d", len(nativePrinters)) return nil } // Update GCP. ch := make(chan lib.Printer, len(diffs)) for i := range diffs { go pm.applyDiff(&diffs[i], ch, ignorePrivet) } currentPrinters := make([]lib.Printer, 0, len(diffs)) for _ = range diffs { p := <-ch if p.Name != "" { currentPrinters = append(currentPrinters, p) } } // Update what we know. pm.printers.Refresh(currentPrinters) log.Infof("Finished synchronizing %d printers", len(currentPrinters)) return nil }
func newCUPSCore(maxConnections uint, connectTimeout time.Duration) (*cupsCore, error) { host := C.cupsServer() port := C.ippPort() encryption := C.cupsEncryption() timeout := C.int(connectTimeout / time.Millisecond) var e string switch encryption { case C.HTTP_ENCRYPTION_ALWAYS: e = "encrypting ALWAYS" case C.HTTP_ENCRYPTION_IF_REQUESTED: e = "encrypting IF REQUESTED" case C.HTTP_ENCRYPTION_NEVER: e = "encrypting NEVER" case C.HTTP_ENCRYPTION_REQUIRED: e = "encryption REQUIRED" default: encryption = C.HTTP_ENCRYPTION_REQUIRED e = "encrypting REQUIRED" } var hostIsLocal bool if h := C.GoString(host); strings.HasPrefix(h, "/") || h == "localhost" { hostIsLocal = true } cs := lib.NewSemaphore(maxConnections) cp := make(chan *C.http_t) cc := &cupsCore{host, port, encryption, timeout, cs, cp, hostIsLocal} log.Infof("Connecting to CUPS server at %s:%d %s", C.GoString(host), int(port), e) // This connection isn't used, just checks that a connection is possible // before returning from the constructor. http, err := cc.connect() if err != nil { return nil, err } cc.disconnect(http) log.Info("Connected to CUPS server successfully") return cc, nil }
func (service *service) Execute(args []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (bool, uint32) { if service.interactive { if err := log.Start(true); err != nil { fmt.Fprintf(os.Stderr, "Failed to start event log: %s\n", err) return false, 1 } } else { if err := log.Start(false); err != nil { fmt.Fprintf(os.Stderr, "Failed to start event log: %s\n", err) return false, 1 } } defer log.Stop() config, configFilename, err := lib.GetConfig(service.context) if err != nil { fmt.Fprintf(os.Stderr, "Failed to read config file: %s\n", err) return false, 1 } logLevel, ok := log.LevelFromString(config.LogLevel) if !ok { fmt.Fprintf(os.Stderr, "Log level %s is not recognized\n", config.LogLevel) return false, 1 } log.SetLevel(logLevel) if configFilename == "" { log.Info("No config file was found, so using defaults") } else { log.Infof("Using config file %s", configFilename) } completeConfig, _ := json.MarshalIndent(config, "", " ") log.Debugf("Config: %s", string(completeConfig)) log.Info(lib.FullName) if !config.CloudPrintingEnable && !config.LocalPrintingEnable { log.Fatal("Cannot run connector with both local_printing_enable and cloud_printing_enable set to false") return false, 1 } else if config.LocalPrintingEnable { log.Fatal("Local printing has not been implemented in this version of the Windows connector.") return false, 1 } jobs := make(chan *lib.Job, 10) xmppNotifications := make(chan xmpp.PrinterNotification, 5) var g *gcp.GoogleCloudPrint var x *xmpp.XMPP if config.CloudPrintingEnable { xmppPingTimeout, err := time.ParseDuration(config.XMPPPingTimeout) if err != nil { log.Fatalf("Failed to parse xmpp ping timeout: %s", err) return false, 1 } xmppPingInterval, err := time.ParseDuration(config.XMPPPingInterval) if err != nil { log.Fatalf("Failed to parse xmpp ping interval default: %s", err) return false, 1 } g, err = gcp.NewGoogleCloudPrint(config.GCPBaseURL, config.RobotRefreshToken, config.UserRefreshToken, config.ProxyName, config.GCPOAuthClientID, config.GCPOAuthClientSecret, config.GCPOAuthAuthURL, config.GCPOAuthTokenURL, config.GCPMaxConcurrentDownloads, jobs) if err != nil { log.Fatal(err) return false, 1 } x, err = xmpp.NewXMPP(config.XMPPJID, config.ProxyName, config.XMPPServer, config.XMPPPort, xmppPingTimeout, xmppPingInterval, g.GetRobotAccessToken, xmppNotifications) if err != nil { log.Fatal(err) return false, 1 } defer x.Quit() } ws, err := winspool.NewWinSpool(*config.PrefixJobIDToJobTitle, config.DisplayNamePrefix, config.PrinterBlacklist, config.PrinterWhitelist) if err != nil { log.Fatal(err) return false, 1 } nativePrinterPollInterval, err := time.ParseDuration(config.NativePrinterPollInterval) if err != nil { log.Fatalf("Failed to parse printer poll interval: %s", err) return false, 1 } pm, err := manager.NewPrinterManager(ws, g, nil, nativePrinterPollInterval, config.NativeJobQueueSize, *config.CUPSJobFullUsername, config.ShareScope, jobs, xmppNotifications) if err != nil { log.Fatal(err) return false, 1 } defer pm.Quit() if config.CloudPrintingEnable { if config.LocalPrintingEnable { log.Infof("Ready to rock as proxy '%s' and in local mode", config.ProxyName) } else { log.Infof("Ready to rock as proxy '%s'", config.ProxyName) } } else { log.Info("Ready to rock in local-only mode") } s <- runningStatus for { request := <-r switch request.Cmd { case svc.Interrogate: s <- runningStatus case svc.Stop: s <- stoppingStatus log.Info("Shutting down") time.AfterFunc(time.Second*30, func() { log.Fatal("Failed to stop quickly; stopping forcefully") os.Exit(1) }) return false, 0 default: log.Errorf("Received unsupported service command from service control manager: %d", request.Cmd) } } }
func connector(context *cli.Context) int { config, configFilename, err := lib.GetConfig(context) if err != nil { fmt.Fprintf(os.Stderr, "Failed to read config file: %s", err) return 1 } logToJournal := *config.LogToJournal && journal.Enabled() logToConsole := context.Bool("log-to-console") if logToJournal { log.SetJournalEnabled(true) if logToConsole { log.SetWriter(os.Stderr) } else { log.SetWriter(ioutil.Discard) } } else { logFileMaxBytes := config.LogFileMaxMegabytes * 1024 * 1024 var logWriter io.Writer logWriter, err = log.NewLogRoller(config.LogFileName, logFileMaxBytes, config.LogMaxFiles) if err != nil { fmt.Fprintf(os.Stderr, "Failed to start log roller: %s", err) return 1 } if logToConsole { logWriter = io.MultiWriter(logWriter, os.Stderr) } log.SetWriter(logWriter) } logLevel, ok := log.LevelFromString(config.LogLevel) if !ok { fmt.Fprintf(os.Stderr, "Log level %s is not recognized", config.LogLevel) return 1 } log.SetLevel(logLevel) if configFilename == "" { log.Info("No config file was found, so using defaults") } else { log.Infof("Using config file %s", configFilename) } completeConfig, _ := json.MarshalIndent(config, "", " ") log.Debugf("Config: %s", string(completeConfig)) log.Info(lib.FullName) fmt.Println(lib.FullName) if !config.CloudPrintingEnable && !config.LocalPrintingEnable { log.Fatal("Cannot run connector with both local_printing_enable and cloud_printing_enable set to false") return 1 } if _, err := os.Stat(config.MonitorSocketFilename); !os.IsNotExist(err) { if err != nil { log.Fatalf("Failed to stat monitor socket: %s", err) } else { log.Fatalf( "A connector is already running, or the monitoring socket %s wasn't cleaned up properly", config.MonitorSocketFilename) } return 1 } jobs := make(chan *lib.Job, 10) xmppNotifications := make(chan xmpp.PrinterNotification, 5) var g *gcp.GoogleCloudPrint var x *xmpp.XMPP if config.CloudPrintingEnable { xmppPingTimeout, err := time.ParseDuration(config.XMPPPingTimeout) if err != nil { log.Fatalf("Failed to parse xmpp ping timeout: %s", err) return 1 } xmppPingInterval, err := time.ParseDuration(config.XMPPPingInterval) if err != nil { log.Fatalf("Failed to parse xmpp ping interval default: %s", err) return 1 } g, err = gcp.NewGoogleCloudPrint(config.GCPBaseURL, config.RobotRefreshToken, config.UserRefreshToken, config.ProxyName, config.GCPOAuthClientID, config.GCPOAuthClientSecret, config.GCPOAuthAuthURL, config.GCPOAuthTokenURL, config.GCPMaxConcurrentDownloads, jobs) if err != nil { log.Fatal(err) return 1 } x, err = xmpp.NewXMPP(config.XMPPJID, config.ProxyName, config.XMPPServer, config.XMPPPort, xmppPingTimeout, xmppPingInterval, g.GetRobotAccessToken, xmppNotifications) if err != nil { log.Fatal(err) return 1 } defer x.Quit() } cupsConnectTimeout, err := time.ParseDuration(config.CUPSConnectTimeout) if err != nil { log.Fatalf("Failed to parse CUPS connect timeout: %s", err) return 1 } c, err := cups.NewCUPS(*config.CUPSCopyPrinterInfoToDisplayName, *config.PrefixJobIDToJobTitle, config.DisplayNamePrefix, config.CUPSPrinterAttributes, config.CUPSMaxConnections, cupsConnectTimeout, config.PrinterBlacklist, config.PrinterWhitelist, *config.CUPSIgnoreRawPrinters, *config.CUPSIgnoreClassPrinters) if err != nil { log.Fatal(err) return 1 } defer c.Quit() var priv *privet.Privet if config.LocalPrintingEnable { if g == nil { priv, err = privet.NewPrivet(jobs, config.LocalPortLow, config.LocalPortHigh, config.GCPBaseURL, nil) } else { priv, err = privet.NewPrivet(jobs, config.LocalPortLow, config.LocalPortHigh, config.GCPBaseURL, g.ProximityToken) } if err != nil { log.Fatal(err) return 1 } defer priv.Quit() } nativePrinterPollInterval, err := time.ParseDuration(config.NativePrinterPollInterval) if err != nil { log.Fatalf("Failed to parse CUPS printer poll interval: %s", err) return 1 } pm, err := manager.NewPrinterManager(c, g, priv, nativePrinterPollInterval, config.NativeJobQueueSize, *config.CUPSJobFullUsername, config.ShareScope, jobs, xmppNotifications) if err != nil { log.Fatal(err) return 1 } defer pm.Quit() m, err := monitor.NewMonitor(c, g, priv, pm, config.MonitorSocketFilename) if err != nil { log.Fatal(err) return 1 } defer m.Quit() if config.CloudPrintingEnable { if config.LocalPrintingEnable { log.Infof("Ready to rock as proxy '%s' and in local mode", config.ProxyName) fmt.Printf("Ready to rock as proxy '%s' and in local mode\n", config.ProxyName) } else { log.Infof("Ready to rock as proxy '%s'", config.ProxyName) fmt.Printf("Ready to rock as proxy '%s'\n", config.ProxyName) } } else { log.Info("Ready to rock in local-only mode") fmt.Println("Ready to rock in local-only mode") } waitIndefinitely() log.Info("Shutting down") fmt.Println("") fmt.Println("Shutting down") return 0 }