diff options
author | Sebastien Douheret <sebastien.douheret@iot.bzh> | 2017-08-10 12:19:34 +0200 |
---|---|---|
committer | Sebastien Douheret <sebastien.douheret@iot.bzh> | 2017-08-16 14:27:28 +0200 |
commit | dd6f08b10b1597f44e3dc25509ac9a45336b0914 (patch) | |
tree | 3dcb835306bc3adbae7c27d94fc8a51de8d6f09a /lib/syncthing | |
parent | 0262f5bef6ff67e77b844a04733c57740fba9f00 (diff) |
Add folder interface and support native pathmap folder type.
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'lib/syncthing')
-rw-r--r-- | lib/syncthing/folder-st.go | 97 | ||||
-rw-r--r-- | lib/syncthing/st.go | 50 | ||||
-rw-r--r-- | lib/syncthing/stfolder.go | 123 |
3 files changed, 216 insertions, 54 deletions
diff --git a/lib/syncthing/folder-st.go b/lib/syncthing/folder-st.go new file mode 100644 index 0000000..ffcd284 --- /dev/null +++ b/lib/syncthing/folder-st.go @@ -0,0 +1,97 @@ +package st + +import ( + "fmt" + "path/filepath" + + "github.com/iotbzh/xds-server/lib/folder" + "github.com/iotbzh/xds-server/lib/xdsconfig" + "github.com/syncthing/syncthing/lib/config" +) + +// IFOLDER interface implementation for syncthing + +// STFolder . +type STFolder struct { + globalConfig *xdsconfig.Config + st *SyncThing + fConfig folder.FolderConfig + stfConfig config.FolderConfiguration +} + +// NewFolderST Create a new instance of STFolder +func (s *SyncThing) NewFolderST(gc *xdsconfig.Config) *STFolder { + return &STFolder{ + globalConfig: gc, + st: s, + } +} + +// Add a new folder +func (f *STFolder) Add(cfg folder.FolderConfig) (*folder.FolderConfig, error) { + + // Sanity check + if cfg.DataCloudSync.SyncThingID == "" { + return nil, fmt.Errorf("device id not set (SyncThingID field)") + } + + // rootPath should not be empty + if cfg.RootPath == "" { + cfg.RootPath = f.globalConfig.FileConf.ShareRootDir + } + + f.fConfig = cfg + + f.fConfig.DataCloudSync.BuilderSThgID = f.st.MyID // FIXME - should be removed after local ST config rework + + // Update Syncthing folder + // (expect if status is ErrorConfig) + // TODO: add cache to avoid multiple requests on startup + if f.fConfig.Status != folder.StatusErrorConfig { + id, err := f.st.FolderChange(f.fConfig) + if err != nil { + return nil, err + } + + f.stfConfig, err = f.st.FolderConfigGet(id) + if err != nil { + f.fConfig.Status = folder.StatusErrorConfig + return nil, err + } + + f.fConfig.Status = folder.StatusEnable + } + + return &f.fConfig, nil +} + +// GetConfig Get public part of folder config +func (f *STFolder) GetConfig() folder.FolderConfig { + return f.fConfig +} + +// GetFullPath returns the full path +func (f *STFolder) GetFullPath(dir string) string { + if &dir == nil { + dir = "" + } + if filepath.IsAbs(dir) { + return filepath.Join(f.fConfig.RootPath, dir) + } + return filepath.Join(f.fConfig.RootPath, f.fConfig.ClientPath, dir) +} + +// Remove a folder +func (f *STFolder) Remove() error { + return f.st.FolderDelete(f.stfConfig.ID) +} + +// Sync Force folder files synchronization +func (f *STFolder) Sync() error { + return f.st.FolderScan(f.stfConfig.ID, "") +} + +// IsInSync Check if folder files are in-sync +func (f *STFolder) IsInSync() (bool, error) { + return f.st.IsFolderInSync(f.stfConfig.ID) +} diff --git a/lib/syncthing/st.go b/lib/syncthing/st.go index 3380cda..9bdb48f 100644 --- a/lib/syncthing/st.go +++ b/lib/syncthing/st.go @@ -32,6 +32,7 @@ type SyncThing struct { Home string STCmd *exec.Cmd STICmd *exec.Cmd + MyID string // Private fields binDir string @@ -211,13 +212,13 @@ func (s *SyncThing) Start() (*exec.Cmd, error) { env := []string{ "STNODEFAULTFOLDER=1", "STNOUPGRADE=1", - "STNORESTART=1", + "STNORESTART=1", // FIXME SEB remove ? } 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 { @@ -314,7 +315,9 @@ func (s *SyncThing) Connect() error { s.client.SetLogger(s.log) - return nil + s.MyID, err = s.IDGet() + + return err } // IDGet returns the Syncthing ID of Syncthing instance running locally @@ -360,44 +363,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, "") -} diff --git a/lib/syncthing/stfolder.go b/lib/syncthing/stfolder.go index 661e19d..bbdcc43 100644 --- a/lib/syncthing/stfolder.go +++ b/lib/syncthing/stfolder.go @@ -1,34 +1,77 @@ package st import ( + "encoding/json" + "fmt" "path/filepath" "strings" - "github.com/iotbzh/xds-server/lib/xdsconfig" + "github.com/iotbzh/xds-server/lib/folder" "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/protocol" ) +// FolderLoadFromStConfig Load/Retrieve folder config from syncthing database +func (s *SyncThing) FolderLoadFromStConfig(f *[]folder.FolderConfig) error { + + defaultSdk := "" // cannot know which was the default sdk + + stCfg, err := s.ConfigGet() + if err != nil { + return err + } + if len(stCfg.Devices) < 1 { + return fmt.Errorf("Cannot load syncthing config: no device defined") + } + devID := stCfg.Devices[0].DeviceID.String() + if devID == s.MyID { + if len(stCfg.Devices) < 2 { + return fmt.Errorf("Cannot load syncthing config: no valid device found") + } + devID = stCfg.Devices[1].DeviceID.String() + } + + for _, stFld := range stCfg.Folders { + cliPath := strings.TrimPrefix(stFld.RawPath, s.conf.FileConf.ShareRootDir) + if cliPath == "" { + cliPath = stFld.RawPath + } + *f = append(*f, folder.FolderConfig{ + ID: stFld.ID, + Label: stFld.Label, + ClientPath: strings.TrimRight(cliPath, "/"), + Type: folder.TypeCloudSync, + Status: folder.StatusDisable, + DefaultSdk: defaultSdk, + RootPath: s.conf.FileConf.ShareRootDir, + DataCloudSync: folder.CloudSyncConfig{SyncThingID: devID}, + }) + } + + return nil +} + // FolderChange is called when configuration has changed -func (s *SyncThing) FolderChange(f xdsconfig.FolderConfig) error { +func (s *SyncThing) FolderChange(f folder.FolderConfig) (string, error) { // Get current config stCfg, err := s.ConfigGet() if err != nil { s.log.Errorln(err) - return err + return "", err } + stClientID := f.DataCloudSync.SyncThingID // Add new Device if needed var devID protocol.DeviceID - if err := devID.UnmarshalText([]byte(f.SyncThingID)); err != nil { - s.log.Errorf("not a valid device id (err %v)\n", err) - return err + if err := devID.UnmarshalText([]byte(stClientID)); err != nil { + s.log.Errorf("not a valid device id (err %v)", err) + return "", err } newDevice := config.DeviceConfiguration{ DeviceID: devID, - Name: f.SyncThingID, + Name: stClientID, Addresses: []string{"dynamic"}, } @@ -49,13 +92,13 @@ func (s *SyncThing) FolderChange(f xdsconfig.FolderConfig) error { label = strings.Split(id, "/")[0] } if id = f.ID; id == "" { - id = f.SyncThingID[0:15] + "_" + label + id = stClientID[0:15] + "_" + label } folder := config.FolderConfiguration{ ID: id, Label: label, - RawPath: filepath.Join(s.conf.FileConf.ShareRootDir, f.RelativePath), + RawPath: filepath.Join(s.conf.FileConf.ShareRootDir, f.ClientPath), } if s.conf.FileConf.SThgConf.RescanIntervalS > 0 { @@ -85,7 +128,7 @@ func (s *SyncThing) FolderChange(f xdsconfig.FolderConfig) error { s.log.Errorln(err) } - return nil + return id, nil } // FolderDelete is called to delete a folder config @@ -110,3 +153,63 @@ func (s *SyncThing) FolderDelete(id string) error { return nil } + +// FolderConfigGet Returns the configuration of a specific folder +func (s *SyncThing) FolderConfigGet(folderID string) (config.FolderConfiguration, error) { + fc := config.FolderConfiguration{} + if folderID == "" { + return fc, fmt.Errorf("folderID not set") + } + cfg, err := s.ConfigGet() + if err != nil { + return fc, err + } + for _, f := range cfg.Folders { + if f.ID == folderID { + fc = f + return fc, nil + } + } + return fc, fmt.Errorf("id not found") +} + +// 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, "") +} |