func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) RelayClient { closeInvitationsOnFinish := false if invitations == nil { closeInvitationsOnFinish = true invitations = make(chan protocol.SessionInvitation) } return &staticClient{ uri: uri, invitations: invitations, closeInvitationsOnFinish: closeInvitationsOnFinish, config: configForCerts(certs), messageTimeout: time.Minute * 2, connectTimeout: timeout, stop: make(chan struct{}), stopped: make(chan struct{}), mut: sync.NewRWMutex(), connected: false, } }
func newDynamicClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) RelayClient { closeInvitationsOnFinish := false if invitations == nil { closeInvitationsOnFinish = true invitations = make(chan protocol.SessionInvitation) } return &dynamicClient{ pooladdr: uri, certs: certs, invitations: invitations, closeInvitationsOnFinish: closeInvitationsOnFinish, timeout: timeout, mut: sync.NewRWMutex(), } }
func NewService(cfg *config.Wrapper, tlsCfg *tls.Config) *Service { conns := make(chan *tls.Conn) service := &Service{ Supervisor: suture.New("Service", suture.Spec{ Log: func(log string) { l.Debugln(log) }, FailureBackoff: 5 * time.Minute, FailureDecay: float64((10 * time.Minute) / time.Second), FailureThreshold: 5, }), cfg: cfg, tlsCfg: tlsCfg, tokens: make(map[string]suture.ServiceToken), clients: make(map[string]client.RelayClient), mut: sync.NewRWMutex(), invitations: make(chan protocol.SessionInvitation), conns: conns, } rcfg := cfg.Raw() service.CommitConfiguration(rcfg, rcfg) cfg.Subscribe(service) receiver := &invitationReceiver{ tlsCfg: tlsCfg, conns: conns, invitations: service.invitations, stop: make(chan struct{}), } eventBc := &eventBroadcaster{ Service: service, stop: make(chan struct{}), } service.Add(receiver) service.Add(eventBc) return service }
func NewCachingMux() *CachingMux { return &CachingMux{ Supervisor: suture.NewSimple("discover.cachingMux"), mut: sync.NewRWMutex(), } }
func (s *apiService) Serve() { s.listenerMut.Lock() listener := s.listener s.listenerMut.Unlock() if listener == nil { // Not much we can do here other than exit quickly. The supervisor // will log an error at some point. return } // The GET handlers getRestMux := http.NewServeMux() getRestMux.HandleFunc("/rest/db/completion", s.getDBCompletion) // device folder getRestMux.HandleFunc("/rest/db/file", s.getDBFile) // folder file getRestMux.HandleFunc("/rest/db/ignores", s.getDBIgnores) // folder getRestMux.HandleFunc("/rest/db/need", s.getDBNeed) // folder [perpage] [page] getRestMux.HandleFunc("/rest/db/status", s.getDBStatus) // folder getRestMux.HandleFunc("/rest/db/browse", s.getDBBrowse) // folder [prefix] [dirsonly] [levels] getRestMux.HandleFunc("/rest/events", s.getEvents) // since [limit] getRestMux.HandleFunc("/rest/stats/device", s.getDeviceStats) // - getRestMux.HandleFunc("/rest/stats/folder", s.getFolderStats) // - getRestMux.HandleFunc("/rest/svc/deviceid", s.getDeviceID) // id getRestMux.HandleFunc("/rest/svc/lang", s.getLang) // - getRestMux.HandleFunc("/rest/svc/report", s.getReport) // - getRestMux.HandleFunc("/rest/system/browse", s.getSystemBrowse) // current getRestMux.HandleFunc("/rest/system/config", s.getSystemConfig) // - getRestMux.HandleFunc("/rest/system/config/insync", s.getSystemConfigInsync) // - getRestMux.HandleFunc("/rest/system/connections", s.getSystemConnections) // - getRestMux.HandleFunc("/rest/system/discovery", s.getSystemDiscovery) // - getRestMux.HandleFunc("/rest/system/error", s.getSystemError) // - getRestMux.HandleFunc("/rest/system/ping", s.restPing) // - getRestMux.HandleFunc("/rest/system/status", s.getSystemStatus) // - getRestMux.HandleFunc("/rest/system/upgrade", s.getSystemUpgrade) // - getRestMux.HandleFunc("/rest/system/version", s.getSystemVersion) // - getRestMux.HandleFunc("/rest/system/debug", s.getSystemDebug) // - getRestMux.HandleFunc("/rest/system/log", s.getSystemLog) // [since] getRestMux.HandleFunc("/rest/system/log.txt", s.getSystemLogTxt) // [since] // The POST handlers postRestMux := http.NewServeMux() postRestMux.HandleFunc("/rest/db/prio", s.postDBPrio) // folder file [perpage] [page] postRestMux.HandleFunc("/rest/db/ignores", s.postDBIgnores) // folder postRestMux.HandleFunc("/rest/db/override", s.postDBOverride) // folder postRestMux.HandleFunc("/rest/db/scan", s.postDBScan) // folder [sub...] [delay] postRestMux.HandleFunc("/rest/system/config", s.postSystemConfig) // <body> postRestMux.HandleFunc("/rest/system/error", s.postSystemError) // <body> postRestMux.HandleFunc("/rest/system/error/clear", s.postSystemErrorClear) // - postRestMux.HandleFunc("/rest/system/ping", s.restPing) // - postRestMux.HandleFunc("/rest/system/reset", s.postSystemReset) // [folder] postRestMux.HandleFunc("/rest/system/restart", s.postSystemRestart) // - postRestMux.HandleFunc("/rest/system/shutdown", s.postSystemShutdown) // - postRestMux.HandleFunc("/rest/system/upgrade", s.postSystemUpgrade) // - postRestMux.HandleFunc("/rest/system/pause", s.postSystemPause) // device postRestMux.HandleFunc("/rest/system/resume", s.postSystemResume) // device postRestMux.HandleFunc("/rest/system/debug", s.postSystemDebug) // [enable] [disable] // Debug endpoints, not for general use getRestMux.HandleFunc("/rest/debug/peerCompletion", s.getPeerCompletion) getRestMux.HandleFunc("/rest/debug/httpmetrics", s.getSystemHTTPMetrics) // A handler that splits requests between the two above and disables // caching restMux := noCacheMiddleware(metricsMiddleware(getPostHandler(getRestMux, postRestMux))) // The main routing handler mux := http.NewServeMux() mux.Handle("/rest/", restMux) mux.HandleFunc("/qr/", s.getQR) // Serve compiled in assets unless an asset directory was set (for development) assets := &embeddedStatic{ theme: s.cfg.GUI().Theme, lastModified: time.Now(), mut: sync.NewRWMutex(), assetDir: s.assetDir, assets: auto.Assets(), } mux.Handle("/", assets) s.cfg.Subscribe(assets) guiCfg := s.cfg.GUI() // Wrap everything in CSRF protection. The /rest prefix should be // protected, other requests will grant cookies. handler := csrfMiddleware(s.id.String()[:5], "/rest", guiCfg, mux) // Add the CORS handling handler = corsMiddleware(handler) // Add our version and ID as a header to responses handler = withDetailsMiddleware(s.id, handler) // Wrap everything in basic auth, if user/password is set. if len(guiCfg.User) > 0 && len(guiCfg.Password) > 0 { handler = basicAuthAndSessionMiddleware("sessionid-"+s.id.String()[:5], guiCfg, handler) } // Redirect to HTTPS if we are supposed to if guiCfg.UseTLS() { handler = redirectToHTTPSMiddleware(handler) } handler = debugMiddleware(handler) srv := http.Server{ Handler: handler, ReadTimeout: 10 * time.Second, } s.fss = newFolderSummaryService(s.cfg, s.model) defer s.fss.Stop() s.fss.ServeBackground() l.Infoln("API listening on", listener.Addr()) l.Infoln("GUI URL is", guiCfg.URL()) if s.started != nil { // only set when run by the tests close(s.started) } err := srv.Serve(listener) // The return could be due to an intentional close. Wait for the stop // signal before returning. IF there is no stop signal within a second, we // assume it was unintentional and log the error before retrying. select { case <-s.stop: case <-s.configChanged: case <-time.After(time.Second): l.Warnln("API:", err) } }
go restart() } func (s *apiService) postSystemShutdown(w http.ResponseWriter, r *http.Request) { s.flushResponse(`{"ok": "shutting down"}`, w) go shutdown() } func (s *apiService) flushResponse(resp string, w http.ResponseWriter) { w.Write([]byte(resp + "\n")) f := w.(http.Flusher) f.Flush() } var cpuUsagePercent [10]float64 // The last ten seconds var cpuUsageLock = sync.NewRWMutex() func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) { var m runtime.MemStats runtime.ReadMemStats(&m) tilde, _ := osutil.ExpandTilde("~") res := make(map[string]interface{}) res["myID"] = myID.String() res["goroutines"] = runtime.NumGoroutine() res["alloc"] = m.Alloc res["sys"] = m.Sys - m.HeapReleased res["tilde"] = tilde if s.cfg.Options().LocalAnnEnabled || s.cfg.Options().GlobalAnnEnabled { res["discoveryEnabled"] = true discoErrors := make(map[string]string)