X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=lib%2Fsyncthing%2Fst.go;h=3380cda785ce7515f99c901c8f0b38e2802f3410;hb=ab1170e65d6d03dd1eb2542b5fc47694d7785e70;hp=15cab0da1fd770f8c6ee469005d5b3a2cdb96a11;hpb=c07adb807c41a1545a9a0f5bbf40080d86946538;p=src%2Fxds%2Fxds-server.git diff --git a/lib/syncthing/st.go b/lib/syncthing/st.go index 15cab0d..3380cda 100644 --- a/lib/syncthing/st.go +++ b/lib/syncthing/st.go @@ -15,8 +15,12 @@ import ( "io" + "io/ioutil" + + "regexp" + "github.com/Sirupsen/logrus" - "github.com/iotbzh/xds-server/lib/common" + common "github.com/iotbzh/xds-common/golib" "github.com/iotbzh/xds-server/lib/xdsconfig" "github.com/syncthing/syncthing/lib/config" ) @@ -27,13 +31,16 @@ type SyncThing struct { APIKey string Home string STCmd *exec.Cmd + STICmd *exec.Cmd // Private fields - binDir string - logsDir string - exitSTChan chan ExitChan - client *common.HTTPClient - log *logrus.Logger + binDir string + logsDir string + exitSTChan chan ExitChan + exitSTIChan chan ExitChan + conf *xdsconfig.Config + client *common.HTTPClient + log *logrus.Logger } // ExitChan Channel used for process exit @@ -42,6 +49,42 @@ type ExitChan struct { err error } +// ConfigInSync Check whether if Syncthing configuration is in sync +type configInSync struct { + ConfigInSync bool `json:"configInSync"` +} + +// FolderStatus Information about the current status of a folder. +type FolderStatus struct { + GlobalFiles int `json:"globalFiles"` + GlobalDirectories int `json:"globalDirectories"` + GlobalSymlinks int `json:"globalSymlinks"` + GlobalDeleted int `json:"globalDeleted"` + GlobalBytes int64 `json:"globalBytes"` + + LocalFiles int `json:"localFiles"` + LocalDirectories int `json:"localDirectories"` + LocalSymlinks int `json:"localSymlinks"` + LocalDeleted int `json:"localDeleted"` + LocalBytes int64 `json:"localBytes"` + + NeedFiles int `json:"needFiles"` + NeedDirectories int `json:"needDirectories"` + NeedSymlinks int `json:"needSymlinks"` + NeedDeletes int `json:"needDeletes"` + NeedBytes int64 `json:"needBytes"` + + InSyncFiles int `json:"inSyncFiles"` + InSyncBytes int64 `json:"inSyncBytes"` + + State string `json:"state"` + StateChanged time.Time `json:"stateChanged"` + + Sequence int64 `json:"sequence"` + + IgnorePatterns bool `json:"ignorePatterns"` +} + // NewSyncThing creates a new instance of Syncthing func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing { var url, apiKey, home, binDir string @@ -79,6 +122,7 @@ func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing { binDir: binDir, logsDir: conf.FileConf.LogsDir, log: log, + conf: conf, } return &s @@ -166,13 +210,54 @@ func (s *SyncThing) Start() (*exec.Cmd, error) { env := []string{ "STNODEFAULTFOLDER=1", + "STNOUPGRADE=1", + "STNORESTART=1", } s.STCmd, err = s.startProc("syncthing", args, env, &s.exitSTChan) + // Use autogenerated apikey if not set by config.json + if s.APIKey == "" { + if fd, err := os.Open(filepath.Join(s.Home, "config.xml")); err == nil { + defer fd.Close() + if b, err := ioutil.ReadAll(fd); err == nil { + re := regexp.MustCompile("(.*)") + key := re.FindStringSubmatch(string(b)) + if len(key) >= 1 { + s.APIKey = key[1] + } + } + } + } + return s.STCmd, err } +// StartInotify Starts syncthing-inotify process +func (s *SyncThing) StartInotify() (*exec.Cmd, error) { + var err error + exeName := "syncthing-inotify" + + s.log.Infof(" STI url=%s", s.BaseURL) + + args := []string{ + "-target=" + s.BaseURL, + } + if s.APIKey != "" { + args = append(args, "-api="+s.APIKey) + s.log.Infof("%s uses apikey=%s", exeName, s.APIKey) + } + if s.log.Level == logrus.DebugLevel { + args = append(args, "-verbosity=4") + } + + env := []string{} + + s.STICmd, err = s.startProc(exeName, args, env, &s.exitSTIChan) + + return s.STICmd, err +} + func (s *SyncThing) stopProc(pname string, proc *os.Process, exit chan ExitChan) { if err := proc.Signal(os.Interrupt); err != nil { s.log.Infof("Proc interrupt %s error: %s", pname, err.Error()) @@ -199,6 +284,15 @@ func (s *SyncThing) Stop() { s.STCmd = nil } +// StopInotify Stops syncthing process +func (s *SyncThing) StopInotify() { + if s.STICmd == nil { + return + } + s.stopProc("syncthing-inotify", s.STICmd.Process, s.exitSTIChan) + s.STICmd = nil +} + // Connect Establish HTTP connection with Syncthing func (s *SyncThing) Connect() error { var err error @@ -217,6 +311,9 @@ func (s *SyncThing) Connect() error { if s.client == nil { return fmt.Errorf("ERROR: cannot connect to Syncthing (null client)") } + + s.client.SetLogger(s.log) + return nil } @@ -250,3 +347,57 @@ func (s *SyncThing) ConfigSet(cfg config.Configuration) error { } return s.client.HTTPPost("system/config", string(body)) } + +// IsConfigInSync Returns true if configuration is in sync +func (s *SyncThing) IsConfigInSync() (bool, error) { + var data []byte + var d configInSync + if err := s.client.HTTPGet("system/config/insync", &data); err != nil { + return false, err + } + if err := json.Unmarshal(data, &d); err != nil { + return false, err + } + return d.ConfigInSync, nil +} + +// FolderStatus Returns all information about the current +func (s *SyncThing) FolderStatus(folderID string) (*FolderStatus, error) { + var data []byte + var res FolderStatus + if folderID == "" { + return nil, fmt.Errorf("folderID not set") + } + if err := s.client.HTTPGet("db/status?folder="+folderID, &data); err != nil { + return nil, err + } + if err := json.Unmarshal(data, &res); err != nil { + return nil, err + } + return &res, nil +} + +// IsFolderInSync Returns true when folder is in sync +func (s *SyncThing) IsFolderInSync(folderID string) (bool, error) { + // FIXME better to detected FolderCompletion event (/rest/events) + // See https://docs.syncthing.net/dev/events.html + sts, err := s.FolderStatus(folderID) + if err != nil { + return false, err + } + return sts.NeedBytes == 0, nil +} + +// FolderScan Request immediate folder scan. +// Scan all folders if folderID param is empty +func (s *SyncThing) FolderScan(folderID string, subpath string) error { + url := "db/scan" + if folderID != "" { + url += "?folder=" + folderID + + if subpath != "" { + url += "&sub=" + subpath + } + } + return s.client.HTTPPost(url, "") +}