From bab7c8ebbff24ab50326ead5693cfcabcc87ca0a Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Wed, 21 Dec 2016 18:41:25 +0000 Subject: [PATCH] all: Add folder pause, make pauses permanent (fixes #3407, fixes #215, fixes #3001) GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3520 --- cmd/syncthing/gui.go | 74 +++--- cmd/syncthing/main.go | 28 +- cmd/syncthing/mocked_config_test.go | 4 + cmd/syncthing/verboseservice.go | 12 + gui/default/index.html | 17 +- gui/default/syncthing/core/eventService.js | 2 + .../syncthing/core/syncthingController.js | 38 ++- lib/config/deviceconfiguration.go | 1 + lib/config/folderconfiguration.go | 1 + lib/config/wrapper.go | 12 + lib/connections/service.go | 3 +- lib/connections/structs.go | 1 - lib/db/structs.pb.go | 58 ++-- lib/discover/local.pb.go | 33 ++- lib/events/events.go | 6 + lib/model/model.go | 209 +++++++++------ lib/model/model_test.go | 91 +++++++ lib/protocol/bep.pb.go | 248 ++++++++++-------- lib/protocol/bep.proto | 1 + lib/protocol/deviceid_test.pb.go | 16 +- 20 files changed, 548 insertions(+), 307 deletions(-) diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index c6d4a8172..7fb701c59 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -82,8 +82,6 @@ type modelIntf interface { Availability(folder, file string, version protocol.Vector, block protocol.BlockInfo) []model.Availability GetIgnores(folder string) ([]string, []string, error) SetIgnores(folder string, content []string) error - PauseDevice(device protocol.DeviceID) - ResumeDevice(device protocol.DeviceID) DelayScan(folder string, next time.Duration) ScanFolder(folder string) error ScanFolders() map[string]error @@ -105,6 +103,7 @@ type configIntf interface { Subscribe(c config.Committer) Folders() map[string]config.FolderConfiguration Devices() map[protocol.DeviceID]config.DeviceConfiguration + SetDevice(config.DeviceConfiguration) error Save() error ListenAddresses() []string RequiresRestart() bool @@ -258,21 +257,21 @@ func (s *apiService) Serve() { // 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) // - postRestMux.HandleFunc("/rest/system/error", s.postSystemError) // - 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] + 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) // + postRestMux.HandleFunc("/rest/system/error", s.postSystemError) // + 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.makeDevicePauseHandler(true)) // device + postRestMux.HandleFunc("/rest/system/resume", s.makeDevicePauseHandler(false)) // device + postRestMux.HandleFunc("/rest/system/debug", s.postSystemDebug) // [enable] [disable] // Debug endpoints, not for general use debugMux := http.NewServeMux() @@ -1103,30 +1102,27 @@ func (s *apiService) postSystemUpgrade(w http.ResponseWriter, r *http.Request) { } } -func (s *apiService) postSystemPause(w http.ResponseWriter, r *http.Request) { - var qs = r.URL.Query() - var deviceStr = qs.Get("device") +func (s *apiService) makeDevicePauseHandler(paused bool) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var qs = r.URL.Query() + var deviceStr = qs.Get("device") - device, err := protocol.DeviceIDFromString(deviceStr) - if err != nil { - http.Error(w, err.Error(), 500) - return + device, err := protocol.DeviceIDFromString(deviceStr) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + + cfg, ok := s.cfg.Devices()[device] + if !ok { + http.Error(w, "not found", http.StatusNotFound) + } + + cfg.Paused = paused + if err := s.cfg.SetDevice(cfg); err != nil { + http.Error(w, err.Error(), 500) + } } - - s.model.PauseDevice(device) -} - -func (s *apiService) postSystemResume(w http.ResponseWriter, r *http.Request) { - var qs = r.URL.Query() - var deviceStr = qs.Get("device") - - device, err := protocol.DeviceIDFromString(deviceStr) - if err != nil { - http.Error(w, err.Error(), 500) - return - } - - s.model.ResumeDevice(device) } func (s *apiService) postDBScan(w http.ResponseWriter, r *http.Request) { diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 57d1cb50c..ba25c30f4 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -212,6 +212,7 @@ type RuntimeOptions struct { auditEnabled bool verbose bool paused bool + unpaused bool guiAddress string guiAPIKey string generateDir string @@ -267,7 +268,8 @@ func parseCommandLineOptions() RuntimeOptions { flag.StringVar(&options.upgradeTo, "upgrade-to", options.upgradeTo, "Force upgrade directly from specified URL") flag.BoolVar(&options.auditEnabled, "audit", false, "Write events to audit file") flag.BoolVar(&options.verbose, "verbose", false, "Print verbose log output") - flag.BoolVar(&options.paused, "paused", false, "Start with all devices paused") + flag.BoolVar(&options.paused, "paused", false, "Start with all devices and folders paused") + flag.BoolVar(&options.unpaused, "unpaused", false, "Start with all devices and folders unpaused") flag.StringVar(&options.logFile, "logfile", options.logFile, "Log file name (use \"-\" for stdout)") if runtime.GOOS == "windows" { // Allow user to hide the console window @@ -701,14 +703,17 @@ func syncthingMain(runtimeOptions RuntimeOptions) { m.StartDeadlockDetector(20 * time.Minute) } - if runtimeOptions.paused { - for device := range cfg.Devices() { - m.PauseDevice(device) - } + if runtimeOptions.unpaused { + setPauseState(cfg, false) + } else if runtimeOptions.paused { + setPauseState(cfg, true) } // Add and start folders for _, folderCfg := range cfg.Folders() { + if folderCfg.Paused { + continue + } m.AddFolder(folderCfg) m.StartFolder(folderCfg.ID) } @@ -1203,3 +1208,16 @@ func showPaths() { fmt.Printf("GUI override directory:\n\t%s\n\n", locations[locGUIAssets]) fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations[locDefFolder]) } + +func setPauseState(cfg *config.Wrapper, paused bool) { + raw := cfg.RawCopy() + for i := range raw.Devices { + raw.Devices[i].Paused = paused + } + for i := range raw.Folders { + raw.Folders[i].Paused = paused + } + if err := cfg.Replace(raw); err != nil { + l.Fatalln("Cannot adjust paused state:", err) + } +} diff --git a/cmd/syncthing/mocked_config_test.go b/cmd/syncthing/mocked_config_test.go index ed320d0a7..0ebdf9cf1 100644 --- a/cmd/syncthing/mocked_config_test.go +++ b/cmd/syncthing/mocked_config_test.go @@ -45,6 +45,10 @@ func (c *mockedConfig) Devices() map[protocol.DeviceID]config.DeviceConfiguratio return nil } +func (c *mockedConfig) SetDevice(config.DeviceConfiguration) error { + return nil +} + func (c *mockedConfig) Save() error { return nil } diff --git a/cmd/syncthing/verboseservice.go b/cmd/syncthing/verboseservice.go index 9d3aff5d5..c47e54b78 100644 --- a/cmd/syncthing/verboseservice.go +++ b/cmd/syncthing/verboseservice.go @@ -166,6 +166,18 @@ func (s *verboseService) formatEvent(ev events.Event) string { device := data["device"] return fmt.Sprintf("Device %v was resumed", device) + case events.FolderPaused: + data := ev.Data.(map[string]string) + id := data["id"] + label := data["label"] + return fmt.Sprintf("Folder %v (%v) was paused", id, label) + + case events.FolderResumed: + data := ev.Data.(map[string]string) + id := data["id"] + label := data["label"] + return fmt.Sprintf("Folder %v (%v) was resumed", id, label) + case events.ListenAddressesChanged: data := ev.Data.(map[string]interface{}) address := data["address"] diff --git a/gui/default/index.html b/gui/default/index.html index eeb28e752..55e4c0b90 100644 --- a/gui/default/index.html +++ b/gui/default/index.html @@ -271,6 +271,7 @@
+ @@ -307,11 +308,11 @@ {{folder.path}} - +  Error {{model[folder.id].invalid || model[folder.id].error}} - +  Global State @@ -321,7 +322,7 @@ - +  Local State @@ -417,6 +418,12 @@  Override Changes + + @@ -601,10 +608,10 @@