Add folder update support and ClientData field.
[src/xds/xds-server.git] / lib / model / folders.go
index 576c4a2..0e28538 100644 (file)
@@ -10,6 +10,7 @@ import (
        "time"
 
        "github.com/Sirupsen/logrus"
+       "github.com/franciscocpg/reflectme"
        common "github.com/iotbzh/xds-common/golib"
        "github.com/iotbzh/xds-server/lib/folder"
        "github.com/iotbzh/xds-server/lib/syncthing"
@@ -146,6 +147,27 @@ func (f *Folders) SaveConfig() error {
        return foldersConfigWrite(f.fileOnDisk, f.getConfigArrUnsafe())
 }
 
+// ResolveID Complete a Folder ID (helper for user that can use partial ID value)
+func (f *Folders) ResolveID(id string) (string, error) {
+       if id == "" {
+               return "", nil
+       }
+
+       match := []string{}
+       for iid := range f.folders {
+               if strings.HasPrefix(iid, id) {
+                       match = append(match, iid)
+               }
+       }
+
+       if len(match) == 1 {
+               return match[0], nil
+       } else if len(match) == 0 {
+               return id, fmt.Errorf("Unknown id")
+       }
+       return id, fmt.Errorf("Multiple IDs found with provided prefix: " + id)
+}
+
 // Get returns the folder config or nil if not existing
 func (f *Folders) Get(id string) *folder.IFOLDER {
        if id == "" {
@@ -168,8 +190,7 @@ func (f *Folders) GetConfigArr() []folder.FolderConfig {
 
 // getConfigArrUnsafe Same as GetConfigArr without mutex protection
 func (f *Folders) getConfigArrUnsafe() []folder.FolderConfig {
-       var conf []folder.FolderConfig
-
+       conf := []folder.FolderConfig{}
        for _, v := range f.folders {
                conf = append(conf, (*v).GetConfig())
        }
@@ -214,24 +235,23 @@ func (f *Folders) createUpdate(newF folder.FolderConfig, create bool, initial bo
                return nil, fmt.Errorf("Unsupported folder type")
        }
 
+       // Allocate a new UUID
+       if create {
+               newF.ID = fld.NewUID("")
+       }
+       if !create && newF.ID == "" {
+               return nil, fmt.Errorf("Cannot update folder with null ID")
+       }
+
        // Set default value if needed
        if newF.Status == "" {
                newF.Status = folder.StatusDisable
        }
        if newF.Label == "" {
-               newF.Label = filepath.Base(newF.ClientPath) + "_" + newF.ID[0:8]
-       }
-
-       // Allocate a new UUID
-       if create {
-               i := len(newF.Label)
-               if i > 20 {
-                       i = 20
+               newF.Label = filepath.Base(newF.ClientPath)
+               if len(newF.ID) > 8 {
+                       newF.Label += "_" + newF.ID[0:8]
                }
-               newF.ID = fld.NewUID(newF.Label[:i])
-       }
-       if !create && newF.ID == "" {
-               return nil, fmt.Errorf("Cannot update folder with null ID")
        }
 
        // Normalize path (needed for Windows path including bashlashes)
@@ -299,6 +319,54 @@ func (f *Folders) Delete(id string) (folder.FolderConfig, error) {
        return fld, err
 }
 
+// Update Update a specific folder
+func (f *Folders) Update(id string, cfg folder.FolderConfig) (*folder.FolderConfig, error) {
+       fcMutex.Lock()
+       defer fcMutex.Unlock()
+
+       fc, exist := f.folders[id]
+       if !exist {
+               return nil, fmt.Errorf("unknown id")
+       }
+
+       // Copy current in a new object to change nothing in case of an error rises
+       newCfg := folder.FolderConfig{}
+       reflectme.Copy((*fc).GetConfig(), &newCfg)
+
+       // Only update some fields
+       dirty := false
+       for _, fieldName := range folder.FolderConfigUpdatableFields {
+               valNew, err := reflectme.GetField(cfg, fieldName)
+               if err == nil {
+                       valCur, err := reflectme.GetField(newCfg, fieldName)
+                       if err == nil && valNew != valCur {
+                               err = reflectme.SetField(&newCfg, fieldName, valNew)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               dirty = true
+                       }
+               }
+       }
+
+       if !dirty {
+               return &newCfg, nil
+       }
+
+       fld, err := (*fc).Update(newCfg)
+       if err != nil {
+               return fld, err
+       }
+
+       // Save config on disk
+       err = f.SaveConfig()
+
+       // Send event to notified changes
+       // TODO emit folder change event
+
+       return fld, err
+}
+
 // RegisterEventChange requests registration for folder event change
 func (f *Folders) RegisterEventChange(id string, cb *folder.EventCB, data *folder.EventCBData) error {