Merge branch 'master' into wip
[src/xds/xds-agent.git] / lib / syncthing / st.go
index 6199a8f..031a2ac 100644 (file)
@@ -24,11 +24,14 @@ import (
 
 // SyncThing .
 type SyncThing struct {
-       BaseURL string
-       APIKey  string
-       Home    string
-       STCmd   *exec.Cmd
-       STICmd  *exec.Cmd
+       BaseURL   string
+       APIKey    string
+       Home      string
+       STCmd     *exec.Cmd
+       STICmd    *exec.Cmd
+       MyID      string
+       Connected bool
+       Events    *Events
 
        // Private fields
        binDir      string
@@ -37,6 +40,7 @@ type SyncThing struct {
        exitSTIChan chan ExitChan
        client      *common.HTTPClient
        log         *logrus.Logger
+       conf        *xdsconfig.Config
 }
 
 // ExitChan Channel used for process exit
@@ -45,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
@@ -75,8 +115,12 @@ func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing {
                binDir:  binDir,
                logsDir: conf.FileConf.LogsDir,
                log:     log,
+               conf:    conf,
        }
 
+       // Create Events monitoring
+       s.Events = s.NewEventListener()
+
        return &s
 }
 
@@ -86,8 +130,9 @@ func (s *SyncThing) startProc(exeName string, args []string, env []string, eChan
        var exePath string
 
        // Kill existing process (useful for debug ;-) )
-       if os.Getenv("DEBUG_MODE") != "" {
-               exec.Command("bash", "-c", "pkill -9 "+exeName).Output()
+       if _, dbg := os.LookupEnv("XDS_DEBUG_MODE"); dbg {
+               fmt.Printf("\n!!! DEBUG_MODE set: KILL existing %s process(es) !!!\n", exeName)
+               exec.Command("bash", "-c", "ps -ax |grep "+exeName+" |grep "+s.BaseURL+" |cut  -d' ' -f 1|xargs -I{} kill -9 {}").Output()
        }
 
        // When not set (or set to '.') set bin to path of xds-agent executable
@@ -182,6 +227,8 @@ func (s *SyncThing) Start() (*exec.Cmd, error) {
                "STNOUPGRADE=1",
        }
 
+       /* FIXME - STILL NEEDED ?, if not SUP code
+
        // XXX - temporary hack because -gui-apikey seems to correctly handle by
        // syncthing the early first time
        stConfigFile := filepath.Join(s.Home, "config.xml")
@@ -211,12 +258,12 @@ func (s *SyncThing) Start() (*exec.Cmd, error) {
                        return nil, fmt.Errorf("Cannot write Syncthing config file to set apikey")
                }
        }
-
+       */
        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(stConfigFile); err == nil {
+       if err == nil && 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("<apikey>(.*)</apikey>")
@@ -294,11 +341,17 @@ func (s *SyncThing) StopInotify() {
 // Connect Establish HTTP connection with Syncthing
 func (s *SyncThing) Connect() error {
        var err error
+       s.Connected = false
        s.client, err = common.HTTPNewClient(s.BaseURL,
                common.HTTPClientConfig{
                        URLPrefix:           "/rest",
                        HeaderClientKeyName: "X-Syncthing-ID",
+                       LogOut:              s.conf.LogVerboseOut,
+                       LogPrefix:           "SYNCTHING: ",
+                       LogLevel:            common.HTTPLogLevelWarning,
                })
+       s.client.SetLogLevel(s.log.Level.String())
+
        if err != nil {
                msg := ": " + err.Error()
                if strings.Contains(err.Error(), "connection refused") {
@@ -310,11 +363,17 @@ func (s *SyncThing) Connect() error {
                return fmt.Errorf("ERROR: cannot connect to Syncthing (null client)")
        }
 
-       s.client.SetLogLevel(s.log.Level.String())
-       s.client.LoggerPrefix = "SYNCTHING: "
-       s.client.LoggerOut = s.log.Out
+       s.MyID, err = s.IDGet()
+       if err != nil {
+               return fmt.Errorf("ERROR: cannot retrieve ID")
+       }
+
+       s.Connected = true
 
-       return nil
+       // Start events monitoring
+       err = s.Events.Start()
+
+       return err
 }
 
 // IDGet returns the Syncthing ID of Syncthing instance running locally
@@ -347,3 +406,16 @@ 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
+}