X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=lib%2Fsyncthing%2Fst.go;h=031a2ac221487de10f7fa0db1636ec52bfb73998;hb=2d90eac319979dba64371258b30e61e77a15db7d;hp=5976e2f769c25fb273ffec032888f47ab3ddd03e;hpb=a50baa7c309f7eb55fe87c71f4c688ace325b6ac;p=src%2Fxds%2Fxds-agent.git
diff --git a/lib/syncthing/st.go b/lib/syncthing/st.go
index 5976e2f..031a2ac 100644
--- a/lib/syncthing/st.go
+++ b/lib/syncthing/st.go
@@ -17,18 +17,21 @@ import (
"os/exec"
"github.com/Sirupsen/logrus"
- "github.com/iotbzh/xds-agent/lib/common"
"github.com/iotbzh/xds-agent/lib/xdsconfig"
+ common "github.com/iotbzh/xds-common/golib"
"github.com/syncthing/syncthing/lib/config"
)
// 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,10 +49,45 @@ 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
- var err error
stCfg := conf.FileConf.SThgConf
if stCfg != nil {
@@ -59,20 +98,14 @@ func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing {
}
if url == "" {
- url = "http://localhost:8384"
+ url = "http://localhost:8386"
}
if url[0:7] != "http://" {
url = "http://" + url
}
if home == "" {
- home = "/mnt/share"
- }
-
- if binDir == "" {
- if binDir, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
- binDir = "/usr/local/bin"
- }
+ panic("home parameter must be set")
}
s := SyncThing{
@@ -82,24 +115,46 @@ 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
}
// Start Starts syncthing process
func (s *SyncThing) startProc(exeName string, args []string, env []string, eChan *chan ExitChan) (*exec.Cmd, error) {
+ var err error
+ 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
+ bdir := s.binDir
+ if bdir == "" || bdir == "." {
+ exe, _ := os.Executable()
+ if exeAbsPath, err := filepath.Abs(exe); err == nil {
+ if exePath, err := filepath.EvalSymlinks(exeAbsPath); err == nil {
+ bdir = filepath.Dir(exePath)
+ }
+ }
}
- path, err := exec.LookPath(path.Join(s.binDir, exeName))
+ exePath, err = exec.LookPath(path.Join(bdir, exeName))
if err != nil {
- return nil, fmt.Errorf("Cannot find %s executable in %s", exeName, s.binDir)
+ // Let's try in /opt/AGL/bin
+ exePath, err = exec.LookPath(path.Join("opt", "AGL", "bin", exeName))
+ if err != nil {
+ return nil, fmt.Errorf("Cannot find %s executable in %s", exeName, bdir)
+ }
}
- cmd := exec.Command(path, args...)
+ cmd := exec.Command(exePath, args...)
cmd.Env = os.Environ()
for _, ev := range env {
cmd.Env = append(cmd.Env, ev)
@@ -169,12 +224,45 @@ func (s *SyncThing) Start() (*exec.Cmd, error) {
env := []string{
"STNODEFAULTFOLDER=1",
+ "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")
+ if s.APIKey != "" && !common.Exists(stConfigFile) {
+ s.log.Infof("Stop and restart Syncthing (hack for apikey setting)")
+ s.STCmd, err = s.startProc("syncthing", args, env, &s.exitSTChan)
+ tmo := 20
+ for ; tmo > 0; tmo-- {
+ s.log.Debugf("Waiting Syncthing config.xml creation (%v)\n", tmo)
+ time.Sleep(500 * time.Millisecond)
+ if common.Exists(stConfigFile) {
+ break
+ }
+ }
+ if tmo <= 0 {
+ return nil, fmt.Errorf("Cannot start Syncthing for config file creation")
+ }
+ s.Stop()
+ read, err := ioutil.ReadFile(stConfigFile)
+ if err != nil {
+ return nil, fmt.Errorf("Cannot read Syncthing config file for apikey setting")
+ }
+ re := regexp.MustCompile(`.*`)
+ newContents := re.ReplaceAllString(string(read), ""+s.APIKey+"")
+ err = ioutil.WriteFile(stConfigFile, []byte(newContents), 0)
+ if err != nil {
+ 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 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 {
@@ -253,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") {
@@ -269,9 +363,17 @@ func (s *SyncThing) Connect() error {
return fmt.Errorf("ERROR: cannot connect to Syncthing (null client)")
}
- s.client.SetLogger(s.log)
+ s.MyID, err = s.IDGet()
+ if err != nil {
+ return fmt.Errorf("ERROR: cannot retrieve ID")
+ }
+
+ s.Connected = true
+
+ // Start events monitoring
+ err = s.Events.Start()
- return nil
+ return err
}
// IDGet returns the Syncthing ID of Syncthing instance running locally
@@ -304,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
+}