From c07adb807c41a1545a9a0f5bbf40080d86946538 Mon Sep 17 00:00:00 2001
From: Sebastien Douheret <sebastien.douheret@iot.bzh>
Date: Tue, 16 May 2017 22:51:32 +0200
Subject: Auto start Syncthing and Syncthing-inotify.

Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
---
 lib/xdsconfig/config.go       | 180 +++---------------------------------------
 lib/xdsconfig/fileconfig.go   |  14 ++--
 lib/xdsconfig/folderconfig.go |  26 +++---
 3 files changed, 34 insertions(+), 186 deletions(-)

(limited to 'lib/xdsconfig')

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
-- 
cgit