Use go module as dependency tool instead of glide
[src/xds/xds-server.git] / lib / syncthing / st.go
index 3380cda..7ac170b 100644 (file)
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2017-2018 "IoT.bzh"
+ * Author Sebastien Douheret <sebastien@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package st
 
 import (
@@ -19,28 +36,31 @@ import (
 
        "regexp"
 
+       common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
+       "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xdsconfig"
        "github.com/Sirupsen/logrus"
-       common "github.com/iotbzh/xds-common/golib"
-       "github.com/iotbzh/xds-server/lib/xdsconfig"
        "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
        logsDir     string
        exitSTChan  chan ExitChan
        exitSTIChan chan ExitChan
-       conf        *xdsconfig.Config
        client      *common.HTTPClient
        log         *logrus.Logger
+       conf        *xdsconfig.Config
 }
 
 // ExitChan Channel used for process exit
@@ -88,7 +108,6 @@ type FolderStatus struct {
 // 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 {
@@ -99,20 +118,14 @@ func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing {
        }
 
        if url == "" {
-               url = "http://localhost:8384"
+               url = "http://localhost:8385"
        }
        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{
@@ -125,22 +138,43 @@ func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing {
                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()
+               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()
        }
 
-       path, err := exec.LookPath(path.Join(s.binDir, exeName))
+       // 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)
+                       }
+               }
+       }
+
+       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)
@@ -157,7 +191,7 @@ func (s *SyncThing) startProc(exeName string, args []string, env []string, eChan
 
                cmdOut, err := cmd.StdoutPipe()
                if err != nil {
-                       return nil, fmt.Errorf("Pipe stdout error for : %s", err)
+                       return nil, fmt.Errorf("Pipe stdout error for : %v", err)
                }
 
                go io.Copy(outfile, cmdOut)
@@ -211,13 +245,12 @@ 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 == "" {
+       // Use autogenerated apikey if not set by server-config.json
+       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 {
@@ -296,11 +329,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") {
@@ -312,9 +351,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
 
-       return nil
+       // Start events monitoring
+       err = s.Events.Start()
+
+       return err
 }
 
 // IDGet returns the Syncthing ID of Syncthing instance running locally
@@ -360,44 +407,3 @@ func (s *SyncThing) IsConfigInSync() (bool, error) {
        }
        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, "")
-}