diff options
author | Sebastien Douheret <sebastien.douheret@iot.bzh> | 2017-05-16 22:51:32 +0200 |
---|---|---|
committer | Sebastien Douheret <sebastien.douheret@iot.bzh> | 2017-05-17 14:04:32 +0200 |
commit | c07adb807c41a1545a9a0f5bbf40080d86946538 (patch) | |
tree | 21e00efbcd03360416698663a1ea89536717ae86 /lib | |
parent | 8983eebdbe74489d62eae4097580fc430d75bd07 (diff) |
Auto start Syncthing and Syncthing-inotify.
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/apiv1/apiv1.go | 7 | ||||
-rw-r--r-- | lib/apiv1/config.go | 2 | ||||
-rw-r--r-- | lib/apiv1/exec.go | 2 | ||||
-rw-r--r-- | lib/apiv1/folders.go | 4 | ||||
-rw-r--r-- | lib/apiv1/make.go | 2 | ||||
-rw-r--r-- | lib/model/folder.go | 99 | ||||
-rw-r--r-- | lib/session/session.go | 2 | ||||
-rw-r--r-- | lib/syncthing/st.go | 204 | ||||
-rw-r--r-- | lib/webserver/server.go (renamed from lib/xdsserver/server.go) | 13 | ||||
-rw-r--r-- | lib/xdsconfig/config.go | 180 | ||||
-rw-r--r-- | lib/xdsconfig/fileconfig.go | 14 | ||||
-rw-r--r-- | lib/xdsconfig/folderconfig.go | 26 |
12 files changed, 342 insertions, 213 deletions
diff --git a/lib/apiv1/apiv1.go b/lib/apiv1/apiv1.go index 56c7503..c94849d 100644 --- a/lib/apiv1/apiv1.go +++ b/lib/apiv1/apiv1.go @@ -4,6 +4,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/gin-gonic/gin" + "github.com/iotbzh/xds-server/lib/model" "github.com/iotbzh/xds-server/lib/session" "github.com/iotbzh/xds-server/lib/xdsconfig" ) @@ -13,17 +14,19 @@ type APIService struct { router *gin.Engine apiRouter *gin.RouterGroup sessions *session.Sessions - cfg xdsconfig.Config + cfg *xdsconfig.Config + mfolder *model.Folder log *logrus.Logger } // New creates a new instance of API service -func New(sess *session.Sessions, cfg xdsconfig.Config, r *gin.Engine) *APIService { +func New(sess *session.Sessions, cfg *xdsconfig.Config, mfolder *model.Folder, r *gin.Engine) *APIService { s := &APIService{ router: r, sessions: sess, apiRouter: r.Group("/api/v1"), cfg: cfg, + mfolder: mfolder, log: cfg.Log, } diff --git a/lib/apiv1/config.go b/lib/apiv1/config.go index a2817a0..326b6fa 100644 --- a/lib/apiv1/config.go +++ b/lib/apiv1/config.go @@ -36,7 +36,7 @@ func (s *APIService) setConfig(c *gin.Context) { s.log.Debugln("SET config: ", cfgArg) - if err := s.cfg.UpdateAll(cfgArg); err != nil { + if err := s.mfolder.UpdateAll(cfgArg); err != nil { common.APIError(c, err.Error()) return } diff --git a/lib/apiv1/exec.go b/lib/apiv1/exec.go index b0bfd41..18fdc7e 100644 --- a/lib/apiv1/exec.go +++ b/lib/apiv1/exec.go @@ -75,7 +75,7 @@ func (s *APIService) execCmd(c *gin.Context) { return } - prj := s.cfg.GetFolderFromID(id) + prj := s.mfolder.GetFolderFromID(id) if prj == nil { common.APIError(c, "Unknown id") return diff --git a/lib/apiv1/folders.go b/lib/apiv1/folders.go index b1864a2..b4d2ac0 100644 --- a/lib/apiv1/folders.go +++ b/lib/apiv1/folders.go @@ -44,7 +44,7 @@ func (s *APIService) addFolder(c *gin.Context) { s.log.Debugln("Add folder config: ", cfgArg) - newFld, err := s.cfg.UpdateFolder(cfgArg) + newFld, err := s.mfolder.UpdateFolder(cfgArg) if err != nil { common.APIError(c, err.Error()) return @@ -68,7 +68,7 @@ func (s *APIService) delFolder(c *gin.Context) { var delEntry xdsconfig.FolderConfig var err error - if delEntry, err = s.cfg.DeleteFolder(id); err != nil { + if delEntry, err = s.mfolder.DeleteFolder(id); err != nil { common.APIError(c, err.Error()) return } diff --git a/lib/apiv1/make.go b/lib/apiv1/make.go index 9596e13..0f7561f 100644 --- a/lib/apiv1/make.go +++ b/lib/apiv1/make.go @@ -72,7 +72,7 @@ func (s *APIService) buildMake(c *gin.Context) { return } - prj := s.cfg.GetFolderFromID(id) + prj := s.mfolder.GetFolderFromID(id) if prj == nil { common.APIError(c, "Unknown id") return diff --git a/lib/model/folder.go b/lib/model/folder.go new file mode 100644 index 0000000..6687b68 --- /dev/null +++ b/lib/model/folder.go @@ -0,0 +1,99 @@ +package model + +import ( + "fmt" + + "github.com/iotbzh/xds-server/lib/syncthing" + "github.com/iotbzh/xds-server/lib/xdsconfig" +) + +// Folder Represent a an XDS folder +type Folder struct { + Conf *xdsconfig.Config + SThg *st.SyncThing +} + +// NewFolder Create a new instance of Model Folder +func NewFolder(cfg *xdsconfig.Config, st *st.SyncThing) *Folder { + return &Folder{ + Conf: cfg, + SThg: st, + } +} + +// GetFolderFromID retrieves the Folder config from id +func (c *Folder) GetFolderFromID(id string) *xdsconfig.FolderConfig { + if idx := c.Conf.Folders.GetIdx(id); idx != -1 { + return &c.Conf.Folders[idx] + } + return nil +} + +// UpdateAll updates all the current configuration +func (c *Folder) UpdateAll(newCfg xdsconfig.Config) error { + return fmt.Errorf("Not Supported") + /* + if err := VerifyConfig(newCfg); err != nil { + return err + } + + // TODO: c.Builder = c.Builder.Update(newCfg.Builder) + c.Folders = c.Folders.Update(newCfg.Folders) + + // FIXME To be tested & improved error handling + for _, f := range c.Folders { + if err := c.SThg.FolderChange(st.FolderChangeArg{ + ID: f.ID, + Label: f.Label, + RelativePath: f.RelativePath, + SyncThingID: f.SyncThingID, + ShareRootDir: c.ShareRootDir, + }); err != nil { + return err + } + } + + return nil + */ +} + +// UpdateFolder updates a specific folder into the current configuration +func (c *Folder) UpdateFolder(newFolder xdsconfig.FolderConfig) (xdsconfig.FolderConfig, error) { + // rootPath should not be empty + if newFolder.RootPath == "" { + newFolder.RootPath = c.Conf.ShareRootDir + } + + // Sanity check of folder settings + if err := newFolder.Verify(); err != nil { + return xdsconfig.FolderConfig{}, err + } + + c.Conf.Folders = c.Conf.Folders.Update(xdsconfig.FoldersConfig{newFolder}) + + err := c.SThg.FolderChange(st.FolderChangeArg{ + ID: newFolder.ID, + Label: newFolder.Label, + RelativePath: newFolder.RelativePath, + SyncThingID: newFolder.SyncThingID, + ShareRootDir: c.Conf.ShareRootDir, + }) + newFolder.BuilderSThgID = c.Conf.Builder.SyncThingID // FIXME - should be removed after local ST config rework + newFolder.Status = xdsconfig.FolderStatusEnable + + return newFolder, err +} + +// DeleteFolder deletes a specific folder +func (c *Folder) DeleteFolder(id string) (xdsconfig.FolderConfig, error) { + var fld xdsconfig.FolderConfig + var err error + + if err = c.SThg.FolderDelete(id); err != nil { + return fld, err + } + + c.Conf.Folders, fld, err = c.Conf.Folders.Delete(id) + + return fld, err +} diff --git a/lib/session/session.go b/lib/session/session.go index 35dfdc6..d4e1ad3 100644 --- a/lib/session/session.go +++ b/lib/session/session.go @@ -205,8 +205,8 @@ func (s *Sessions) monitorSessMap() { s.log.Debugln("Stop monitorSessMap") return case <-time.After(sessionMonitorTime * time.Second): - s.log.Debugf("Sessions Map size: %d", len(s.sessMap)) if dbgFullTrace { + s.log.Debugf("Sessions Map size: %d", len(s.sessMap)) s.log.Debugf("Sessions Map : %v", s.sessMap) } diff --git a/lib/syncthing/st.go b/lib/syncthing/st.go index 7d07b70..15cab0d 100644 --- a/lib/syncthing/st.go +++ b/lib/syncthing/st.go @@ -2,26 +2,207 @@ package st import ( "encoding/json" + "os" + "os/exec" + "path" + "path/filepath" + "syscall" + "time" "strings" "fmt" + "io" + "github.com/Sirupsen/logrus" "github.com/iotbzh/xds-server/lib/common" + "github.com/iotbzh/xds-server/lib/xdsconfig" "github.com/syncthing/syncthing/lib/config" ) // SyncThing . type SyncThing struct { BaseURL string - client *common.HTTPClient - log *logrus.Logger + APIKey string + Home string + STCmd *exec.Cmd + + // Private fields + binDir string + logsDir string + exitSTChan chan ExitChan + client *common.HTTPClient + log *logrus.Logger +} + +// ExitChan Channel used for process exit +type ExitChan struct { + status int + err error } // NewSyncThing creates a new instance of Syncthing -func NewSyncThing(url string, apikey string, log *logrus.Logger) *SyncThing { - cl, err := common.HTTPNewClient(url, +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 { + url = stCfg.GuiAddress + apiKey = stCfg.GuiAPIKey + home = stCfg.Home + binDir = stCfg.BinDir + } + + if url == "" { + url = "http://localhost:8384" + } + 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" + } + } + + s := SyncThing{ + BaseURL: url, + APIKey: apiKey, + Home: home, + binDir: binDir, + logsDir: conf.FileConf.LogsDir, + log: log, + } + + return &s +} + +// Start Starts syncthing process +func (s *SyncThing) startProc(exeName string, args []string, env []string, eChan *chan ExitChan) (*exec.Cmd, error) { + + // Kill existing process (useful for debug ;-) ) + if os.Getenv("DEBUG_MODE") != "" { + exec.Command("bash", "-c", "pkill -9 "+exeName).Output() + } + + path, err := exec.LookPath(path.Join(s.binDir, exeName)) + if err != nil { + return nil, fmt.Errorf("Cannot find %s executable in %s", exeName, s.binDir) + } + cmd := exec.Command(path, args...) + cmd.Env = os.Environ() + for _, ev := range env { + cmd.Env = append(cmd.Env, ev) + } + + // open log file + var outfile *os.File + logFilename := filepath.Join(s.logsDir, exeName+".log") + if s.logsDir != "" { + outfile, err := os.Create(logFilename) + if err != nil { + return nil, fmt.Errorf("Cannot create log file %s", logFilename) + } + + cmdOut, err := cmd.StdoutPipe() + if err != nil { + return nil, fmt.Errorf("Pipe stdout error for : %s", err) + } + + go io.Copy(outfile, cmdOut) + } + + err = cmd.Start() + if err != nil { + return nil, err + } + + *eChan = make(chan ExitChan, 1) + go func(c *exec.Cmd, oF *os.File) { + status := 0 + sts, err := c.Process.Wait() + if !sts.Success() { + s := sts.Sys().(syscall.WaitStatus) + status = s.ExitStatus() + } + if oF != nil { + oF.Close() + } + s.log.Debugf("%s exited with status %d, err %v", exeName, status, err) + + *eChan <- ExitChan{status, err} + }(cmd, outfile) + + return cmd, nil +} + +// Start Starts syncthing process +func (s *SyncThing) Start() (*exec.Cmd, error) { + var err error + + s.log.Infof(" ST home=%s", s.Home) + s.log.Infof(" ST url=%s", s.BaseURL) + + args := []string{ + "--home=" + s.Home, + "-no-browser", + "--gui-address=" + s.BaseURL, + } + + if s.APIKey != "" { + args = append(args, "-gui-apikey=\""+s.APIKey+"\"") + s.log.Infof(" ST apikey=%s", s.APIKey) + } + if s.log.Level == logrus.DebugLevel { + args = append(args, "-verbose") + } + + env := []string{ + "STNODEFAULTFOLDER=1", + } + + s.STCmd, err = s.startProc("syncthing", args, env, &s.exitSTChan) + + return s.STCmd, 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()) + + select { + case <-exit: + case <-time.After(time.Second): + // A bigger bonk on the head. + if err := proc.Signal(os.Kill); err != nil { + s.log.Infof("Proc term %s error: %s", pname, err.Error()) + } + <-exit + } + } + s.log.Infof("%s stopped (PID %d)", pname, proc.Pid) +} + +// Stop Stops syncthing process +func (s *SyncThing) Stop() { + if s.STCmd == nil { + return + } + s.stopProc("syncthing", s.STCmd.Process, s.exitSTChan) + s.STCmd = nil +} + +// Connect Establish HTTP connection with Syncthing +func (s *SyncThing) Connect() error { + var err error + s.client, err = common.HTTPNewClient(s.BaseURL, common.HTTPClientConfig{ URLPrefix: "/rest", HeaderClientKeyName: "X-Syncthing-ID", @@ -29,19 +210,14 @@ func NewSyncThing(url string, apikey string, log *logrus.Logger) *SyncThing { if err != nil { msg := ": " + err.Error() if strings.Contains(err.Error(), "connection refused") { - msg = fmt.Sprintf("(url: %s)", url) + msg = fmt.Sprintf("(url: %s)", s.BaseURL) } - log.Debugf("ERROR: cannot connect to Syncthing %s", msg) - return nil + return fmt.Errorf("ERROR: cannot connect to Syncthing %s", msg) } - - s := SyncThing{ - BaseURL: url, - client: cl, - log: log, + if s.client == nil { + return fmt.Errorf("ERROR: cannot connect to Syncthing (null client)") } - - return &s + return nil } // IDGet returns the Syncthing ID of Syncthing instance running locally diff --git a/lib/xdsserver/server.go b/lib/webserver/server.go index 90d0f38..7be157a 100644 --- a/lib/xdsserver/server.go +++ b/lib/webserver/server.go @@ -1,4 +1,4 @@ -package xdsserver +package webserver import ( "net/http" @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/googollee/go-socket.io" "github.com/iotbzh/xds-server/lib/apiv1" + "github.com/iotbzh/xds-server/lib/model" "github.com/iotbzh/xds-server/lib/session" "github.com/iotbzh/xds-server/lib/xdsconfig" ) @@ -21,8 +22,9 @@ type ServerService struct { api *apiv1.APIService sIOServer *socketio.Server webApp *gin.RouterGroup - cfg xdsconfig.Config + cfg *xdsconfig.Config sessions *session.Sessions + mfolder *model.Folder log *logrus.Logger stop chan struct{} // signals intentional stop } @@ -31,7 +33,7 @@ const indexFilename = "index.html" const cookieMaxAge = "3600" // NewServer creates an instance of ServerService -func NewServer(cfg xdsconfig.Config) *ServerService { +func NewServer(cfg *xdsconfig.Config, mfolder *model.Folder, log *logrus.Logger) *ServerService { // Setup logging for gin router if cfg.Log.Level == logrus.DebugLevel { @@ -55,8 +57,9 @@ func NewServer(cfg xdsconfig.Config) *ServerService { sIOServer: nil, webApp: nil, cfg: cfg, - log: cfg.Log, + log: log, sessions: nil, + mfolder: mfolder, stop: make(chan struct{}), } @@ -77,7 +80,7 @@ func (s *ServerService) Serve() error { s.sessions = session.NewClientSessions(s.router, s.log, cookieMaxAge) // Create REST API - s.api = apiv1.New(s.sessions, s.cfg, s.router) + s.api = apiv1.New(s.sessions, s.cfg, s.mfolder, s.router) // Websocket routes s.sIOServer, err = socketio.NewServer(nil) diff --git a/lib/xdsconfig/config.go b/lib/xdsconfig/config.go index 801891b..3f8a91d 100644 --- a/lib/xdsconfig/config.go +++ b/lib/xdsconfig/config.go @@ -2,15 +2,11 @@ package xdsconfig import ( "fmt" - "strings" "os" - "time" - "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" - "github.com/iotbzh/xds-server/lib/syncthing" ) // Config parameters (json format) of /config command @@ -21,14 +17,12 @@ type Config struct { Builder BuilderConfig `json:"builder"` Folders FoldersConfig `json:"folders"` - // Private / un-exported fields - progName string - fileConf FileConfig + // Private (un-exported fields in REST GET /config route) + FileConf FileConfig `json:"-"` WebAppDir string `json:"-"` HTTPPort string `json:"-"` ShareRootDir string `json:"-"` Log *logrus.Logger `json:"-"` - SThg *st.SyncThing `json:"-"` } // Config default values @@ -36,196 +30,48 @@ const ( DefaultAPIVersion = "1" DefaultPort = "8000" DefaultShareDir = "/mnt/share" - DefaultLogLevel = "error" ) // Init loads the configuration on start-up -func Init(ctx *cli.Context) (Config, error) { +func Init(cliCtx *cli.Context, log *logrus.Logger) (*Config, error) { var err error - // Set logger level and formatter - log := ctx.App.Metadata["logger"].(*logrus.Logger) - - logLevel := ctx.GlobalString("log") - if logLevel == "" { - logLevel = DefaultLogLevel - } - if log.Level, err = logrus.ParseLevel(logLevel); err != nil { - fmt.Printf("Invalid log level : \"%v\"\n", logLevel) - os.Exit(1) - } - log.Formatter = &logrus.TextFormatter{} - // Define default configuration c := Config{ - Version: ctx.App.Metadata["version"].(string), + Version: cliCtx.App.Metadata["version"].(string), APIVersion: DefaultAPIVersion, - VersionGitTag: ctx.App.Metadata["git-tag"].(string), + VersionGitTag: cliCtx.App.Metadata["git-tag"].(string), Builder: BuilderConfig{}, Folders: FoldersConfig{}, - progName: ctx.App.Name, WebAppDir: "webapp/dist", HTTPPort: DefaultPort, ShareRootDir: DefaultShareDir, Log: log, - SThg: nil, } // config file settings overwrite default config - err = updateConfigFromFile(&c, ctx.GlobalString("config")) + err = updateConfigFromFile(&c, cliCtx.GlobalString("config")) if err != nil { - return Config{}, err + return nil, err } // Update location of shared dir if needed if !dirExists(c.ShareRootDir) { if err := os.MkdirAll(c.ShareRootDir, 0770); err != nil { - c.Log.Fatalf("No valid shared directory found (err=%v)", err) + return nil, fmt.Errorf("No valid shared directory found: %v", err) } } c.Log.Infoln("Share root directory: ", c.ShareRootDir) - // FIXME - add a builder interface and support other builder type (eg. native) - builderType := "syncthing" - - switch builderType { - case "syncthing": - // Syncthing settings only configurable from config.json file - stGuiAddr := c.fileConf.SThgConf.GuiAddress - stGuiApikey := c.fileConf.SThgConf.GuiAPIKey - if stGuiAddr == "" { - stGuiAddr = "http://localhost:8384" - } - if stGuiAddr[0:7] != "http://" { - stGuiAddr = "http://" + stGuiAddr - } - - // Retry if connection fail - retry := 5 - for retry > 0 { - c.SThg = st.NewSyncThing(stGuiAddr, stGuiApikey, c.Log) - if c.SThg != nil { - break - } - c.Log.Warningf("Establishing connection to Syncthing (retry %d/5)", retry) - time.Sleep(time.Second) - retry-- - } - if c.SThg == nil { - c.Log.Fatalf("ERROR: cannot connect to Syncthing (url: %s)", stGuiAddr) - } - - // Retrieve Syncthing config - id, err := c.SThg.IDGet() - if err != nil { - return Config{}, err - } - - if c.Builder, err = NewBuilderConfig(id); err != nil { - c.Log.Fatalln(err) - } - - // Retrieve initial Syncthing config - stCfg, err := c.SThg.ConfigGet() - if err != nil { - return Config{}, err - } - for _, stFld := range stCfg.Folders { - relativePath := strings.TrimPrefix(stFld.RawPath, c.ShareRootDir) - if relativePath == "" { - relativePath = stFld.RawPath - } - newFld := NewFolderConfig(stFld.ID, stFld.Label, c.ShareRootDir, strings.Trim(relativePath, "/")) - c.Folders = c.Folders.Update(FoldersConfig{newFld}) - } - - default: - log.Fatalln("Unsupported builder type") - } - - return c, nil -} - -// GetFolderFromID retrieves the Folder config from id -func (c *Config) GetFolderFromID(id string) *FolderConfig { - if idx := c.Folders.GetIdx(id); idx != -1 { - return &c.Folders[idx] - } - return nil -} - -// UpdateAll updates all the current configuration -func (c *Config) UpdateAll(newCfg Config) error { - return fmt.Errorf("Not Supported") - /* - if err := VerifyConfig(newCfg); err != nil { - return err + if c.FileConf.LogsDir != "" && !dirExists(c.FileConf.LogsDir) { + if err := os.MkdirAll(c.FileConf.LogsDir, 0770); err != nil { + return nil, fmt.Errorf("Cannot create logs dir: %v", err) } - - // TODO: c.Builder = c.Builder.Update(newCfg.Builder) - c.Folders = c.Folders.Update(newCfg.Folders) - - // SEB A SUP model.NotifyListeners(c, NotifyFoldersChange, FolderConfig{}) - // FIXME To be tested & improved error handling - for _, f := range c.Folders { - if err := c.SThg.FolderChange(st.FolderChangeArg{ - ID: f.ID, - Label: f.Label, - RelativePath: f.RelativePath, - SyncThingID: f.SyncThingID, - ShareRootDir: c.ShareRootDir, - }); err != nil { - return err - } - } - - return nil - */ -} - -// UpdateFolder updates a specific folder into the current configuration -func (c *Config) UpdateFolder(newFolder FolderConfig) (FolderConfig, error) { - // rootPath should not be empty - if newFolder.rootPath == "" { - newFolder.rootPath = c.ShareRootDir - } - - // Sanity check of folder settings - if err := FolderVerify(newFolder); err != nil { - return FolderConfig{}, err } + c.Log.Infoln("Logs directory: ", c.FileConf.LogsDir) - c.Folders = c.Folders.Update(FoldersConfig{newFolder}) - - // SEB A SUP model.NotifyListeners(c, NotifyFolderAdd, newFolder) - err := c.SThg.FolderChange(st.FolderChangeArg{ - ID: newFolder.ID, - Label: newFolder.Label, - RelativePath: newFolder.RelativePath, - SyncThingID: newFolder.SyncThingID, - ShareRootDir: c.ShareRootDir, - }) - - newFolder.BuilderSThgID = c.Builder.SyncThingID // FIXME - should be removed after local ST config rework - newFolder.Status = FolderStatusEnable - - return newFolder, err -} - -// DeleteFolder deletes a specific folder -func (c *Config) DeleteFolder(id string) (FolderConfig, error) { - var fld FolderConfig - var err error - - //SEB A SUP model.NotifyListeners(c, NotifyFolderDelete, fld) - if err = c.SThg.FolderDelete(id); err != nil { - return fld, err - } - - c.Folders, fld, err = c.Folders.Delete(id) - - return fld, err + return &c, nil } func dirExists(path string) bool { diff --git a/lib/xdsconfig/fileconfig.go b/lib/xdsconfig/fileconfig.go index 7370ed0..3daf77c 100644 --- a/lib/xdsconfig/fileconfig.go +++ b/lib/xdsconfig/fileconfig.go @@ -12,23 +12,25 @@ import ( ) type SyncThingConf struct { + BinDir string `json:"binDir"` Home string `json:"home"` GuiAddress string `json:"gui-address"` GuiAPIKey string `json:"gui-apikey"` } type FileConfig struct { - WebAppDir string `json:"webAppDir"` - ShareRootDir string `json:"shareRootDir"` - HTTPPort string `json:"httpPort"` - SThgConf SyncThingConf `json:"syncthing"` + WebAppDir string `json:"webAppDir"` + ShareRootDir string `json:"shareRootDir"` + HTTPPort string `json:"httpPort"` + SThgConf *SyncThingConf `json:"syncthing"` + LogsDir string `json:"logsDir"` } // getConfigFromFile reads configuration from a config file. // Order to determine which config file is used: // 1/ from command line option: "--config myConfig.json" // 2/ $HOME/.xds/config.json file -// 3/ <current_dir>/agent-config.json file +// 3/ <current_dir>/config.json file // 4/ <xds-server executable dir>/config.json file func updateConfigFromFile(c *Config, confFile string) error { @@ -73,7 +75,7 @@ func updateConfigFromFile(c *Config, confFile string) error { if err := json.NewDecoder(fd).Decode(&fCfg); err != nil { return err } - c.fileConf = fCfg + c.FileConf = fCfg // Support environment variables (IOW ${MY_ENV_VAR} syntax) in config.json // TODO: better to use reflect package to iterate on fields and be more generic diff --git a/lib/xdsconfig/folderconfig.go b/lib/xdsconfig/folderconfig.go index f22e76f..e32f46a 100644 --- a/lib/xdsconfig/folderconfig.go +++ b/lib/xdsconfig/folderconfig.go @@ -30,8 +30,8 @@ type FolderConfig struct { BuilderSThgID string `json:"builderSThgID"` Status string `json:"status"` - // Private fields - rootPath string + // Not exported fields + RootPath string `json:"-"` } // NewFolderConfig creates a new folder object @@ -43,7 +43,7 @@ func NewFolderConfig(id, label, rootDir, path string) FolderConfig { Type: FolderTypeCloudSync, SyncThingID: "", Status: FolderStatusDisable, - rootPath: rootDir, + RootPath: rootDir, } } @@ -53,30 +53,30 @@ func (c *FolderConfig) GetFullPath(dir string) string { dir = "" } if filepath.IsAbs(dir) { - return filepath.Join(c.rootPath, dir) + return filepath.Join(c.RootPath, dir) } - return filepath.Join(c.rootPath, c.RelativePath, dir) + return filepath.Join(c.RootPath, c.RelativePath, dir) } -// FolderVerify is called to verify that a configuration is valid -func FolderVerify(fCfg FolderConfig) error { +// Verify is called to verify that a configuration is valid +func (c *FolderConfig) Verify() error { var err error - if fCfg.Type != FolderTypeCloudSync { + if c.Type != FolderTypeCloudSync { err = fmt.Errorf("Unsupported folder type") } - if fCfg.SyncThingID == "" { + if c.SyncThingID == "" { err = fmt.Errorf("device id not set (SyncThingID field)") } - if fCfg.rootPath == "" { - err = fmt.Errorf("rootPath must not be empty") + if c.RootPath == "" { + err = fmt.Errorf("RootPath must not be empty") } if err != nil { - fCfg.Status = FolderStatusErrorConfig - log.Printf("ERROR FolderVerify: %v\n", err) + c.Status = FolderStatusErrorConfig + log.Printf("ERROR Verify: %v\n", err) } return err |