summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSebastien Douheret <sebastien.douheret@iot.bzh>2017-12-16 00:10:14 +0100
committerSebastien Douheret <sebastien.douheret@iot.bzh>2017-12-16 00:10:14 +0100
commit285332c351777b74abca638b8b2a2cde3c68edc6 (patch)
treece52d6d347f23a944520a6b239f8099de75e1a41 /lib
parent963931e04d44a5b40d38817163f52f56241a9f33 (diff)
Fixed and improved events management.
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'lib')
-rw-r--r--lib/syncthing/stEvent.go51
-rw-r--r--lib/syncthing/stfolder.go10
-rw-r--r--lib/xdsserver/apiv1-events.go100
-rw-r--r--lib/xdsserver/events.go125
-rw-r--r--lib/xdsserver/folder-interface.go23
-rw-r--r--lib/xdsserver/folder-pathmap.go56
-rw-r--r--lib/xdsserver/folder-st-disable.go27
-rw-r--r--lib/xdsserver/folder-st.go110
-rw-r--r--lib/xdsserver/folders.go52
-rw-r--r--lib/xdsserver/xdsserver.go4
-rw-r--r--lib/xsapiv1/events.go35
11 files changed, 338 insertions, 255 deletions
diff --git a/lib/syncthing/stEvent.go b/lib/syncthing/stEvent.go
index 6cb7a31..948f88a 100644
--- a/lib/syncthing/stEvent.go
+++ b/lib/syncthing/stEvent.go
@@ -26,6 +26,8 @@ import (
"time"
"github.com/Sirupsen/logrus"
+ uuid "github.com/satori/go.uuid"
+ "github.com/syncthing/syncthing/lib/sync"
)
// Events .
@@ -37,6 +39,7 @@ type Events struct {
st *SyncThing
log *logrus.Logger
cbArr map[string][]cbMap
+ mutex sync.Mutex
}
type Event struct {
@@ -75,7 +78,7 @@ type STEvent struct {
}
type cbMap struct {
- id int
+ id string
cb EventsCB
filterID string
data *EventsCBData
@@ -91,6 +94,7 @@ func (s *SyncThing) NewEventListener() *Events {
st: s,
log: s.log,
cbArr: make(map[string][]cbMap),
+ mutex: sync.NewMutex(),
}
}
@@ -106,21 +110,24 @@ func (e *Events) Stop() {
}
// Register Add a listener on an event
-func (e *Events) Register(evName string, cb EventsCB, filterID string, data *EventsCBData) (int, error) {
+func (e *Events) Register(evName string, cb EventsCB, filterID string, data *EventsCBData) (string, error) {
if evName == "" || !strings.Contains(EventsAll, evName) {
- return -1, fmt.Errorf("Unknown event name")
+ return "", fmt.Errorf("Unknown event name")
}
if data == nil {
data = &EventsCBData{}
}
+ e.mutex.Lock()
+ defer e.mutex.Unlock()
+
cbList := []cbMap{}
if _, ok := e.cbArr[evName]; ok {
cbList = e.cbArr[evName]
}
- id := len(cbList)
- (*data)["id"] = strconv.Itoa(id)
+ id := uuid.NewV1().String()
+ (*data)["id"] = id
e.cbArr[evName] = append(cbList, cbMap{id: id, cb: cb, filterID: filterID, data: data})
@@ -128,19 +135,23 @@ func (e *Events) Register(evName string, cb EventsCB, filterID string, data *Eve
}
// UnRegister Remove a listener event
-func (e *Events) UnRegister(evName string, id int) error {
- cbKey, ok := e.cbArr[evName]
- if !ok {
- return fmt.Errorf("No event registered to such name")
- }
-
- // FIXME - NOT TESTED
- if id >= len(cbKey) {
- return fmt.Errorf("Invalid id")
- } else if id == len(cbKey) {
- e.cbArr[evName] = cbKey[:id-1]
- } else {
- e.cbArr[evName] = cbKey[id : id+1]
+func (e *Events) UnRegister(id string) error {
+ e.mutex.Lock()
+ defer e.mutex.Unlock()
+
+ for evName, cbKey := range e.cbArr {
+ newCbList := []cbMap{}
+ change := false
+ for _, k := range cbKey {
+ if k.id != id {
+ newCbList = append(newCbList, k)
+ } else {
+ change = true
+ }
+ }
+ if change {
+ e.cbArr[evName] = newCbList
+ }
}
return nil
@@ -207,8 +218,10 @@ func (e *Events) monitorLoop() {
e.log.Warnf("ST EVENT: %d %s\n %v", stEv.GlobalID, stEv.Type, stEv)
}
+ e.mutex.Lock()
cbKey, ok := e.cbArr[stEv.Type]
if !ok {
+ e.mutex.Unlock()
continue
}
@@ -264,6 +277,8 @@ func (e *Events) monitorLoop() {
c.cb(evData, c.data)
}
}
+
+ e.mutex.Unlock()
}
}
}
diff --git a/lib/syncthing/stfolder.go b/lib/syncthing/stfolder.go
index d67b164..1dcbfe1 100644
--- a/lib/syncthing/stfolder.go
+++ b/lib/syncthing/stfolder.go
@@ -70,6 +70,12 @@ func (s *SyncThing) FolderLoadFromStConfig(f *[]xsapiv1.FolderConfig) error {
// FolderChange is called when configuration has changed
func (s *SyncThing) FolderChange(f xsapiv1.FolderConfig) (string, error) {
+ var label, id string
+
+ if id = f.ID; id == "" {
+ s.log.Errorln("Try to create Syncthing folder with null ID: %v", f)
+ return "", fmt.Errorf("Cannot create Syncthing folder (ID must be set")
+ }
// Get current config
stCfg, err := s.ConfigGet()
@@ -104,13 +110,9 @@ func (s *SyncThing) FolderChange(f xsapiv1.FolderConfig) (string, error) {
}
// Add or update Folder settings
- var label, id string
if label = f.Label; label == "" {
label = strings.Split(id, "/")[0]
}
- if id = f.ID; id == "" {
- id = stClientID[0:15] + "_" + label
- }
folder := stconfig.FolderConfiguration{
ID: id,
diff --git a/lib/xdsserver/apiv1-events.go b/lib/xdsserver/apiv1-events.go
index 9f0a774..0942753 100644
--- a/lib/xdsserver/apiv1-events.go
+++ b/lib/xdsserver/apiv1-events.go
@@ -19,8 +19,6 @@ package xdsserver
import (
"net/http"
- "strings"
- "time"
"github.com/gin-gonic/gin"
common "github.com/iotbzh/xds-common/golib"
@@ -29,14 +27,14 @@ import (
// eventsList Registering for events that will be send over a WS
func (s *APIService) eventsList(c *gin.Context) {
-
+ c.JSON(http.StatusOK, s.events.GetList())
}
// eventsRegister Registering for events that will be send over a WS
func (s *APIService) eventsRegister(c *gin.Context) {
var args xsapiv1.EventRegisterArgs
- if c.BindJSON(&args) != nil {
+ if c.BindJSON(&args) != nil || args.Name == "" {
common.APIError(c, "Invalid arguments")
return
}
@@ -47,82 +45,8 @@ func (s *APIService) eventsRegister(c *gin.Context) {
return
}
- evType := strings.TrimPrefix(xsapiv1.EVTFolderStateChange, xsapiv1.EventTypePrefix)
- if args.Name != evType {
- common.APIError(c, "Unsupported event name")
- return
- }
-
- /* XXX - to be removed if no plan to support "generic" event
- var cbFunc st.EventsCB
- cbFunc = func(ev st.Event, data *st.EventsCBData) {
-
- evid, _ := strconv.Atoi((*data)["id"].(string))
- ssid := (*data)["sid"].(string)
- so := s.sessions.IOSocketGet(ssid)
- if so == nil {
- s.log.Infof("Event %s not emitted - sid: %s", ev.Type, ssid)
-
- // Consider that client disconnected, so unregister this event
- s.mfolders.SThg.Events.UnRegister(ev.Type, evid)
- return
- }
-
- msg := EventMsg{
- Time: ev.Time,
- Type: ev.Type,
- Data: ev.Data,
- }
-
- if err := (*so).Emit(EVTAll, msg); err != nil {
- s.log.Errorf("WS Emit Event : %v", err)
- }
-
- if err := (*so).Emit(EventTypePrefix+ev.Type, msg); err != nil {
- s.log.Errorf("WS Emit Event : %v", err)
- }
- }
-
- data := make(st.EventsCBData)
- data["sid"] = sess.ID
-
- id, err := s.mfolders.SThg.Events.Register(args.Name, cbFunc, args.ProjectID, &data)
- */
-
- var cbFunc FolderEventCB
- cbFunc = func(cfg *xsapiv1.FolderConfig, data *FolderEventCBData) {
- ssid := (*data)["sid"].(string)
- so := s.sessions.IOSocketGet(ssid)
- if so == nil {
- //s.log.Infof("Event %s not emitted - sid: %s", ev.Type, ssid)
-
- // Consider that client disconnected, so unregister this event
- // SEB FIXMEs.mfolders.RegisterEventChange(ev.Type)
- return
- }
-
- msg := xsapiv1.EventMsg{
- Time: time.Now().String(),
- Type: evType,
- Folder: *cfg,
- }
-
- s.Log.Debugf("WS Emit %s - Status=%10s, IsInSync=%6v, ID=%s",
- xsapiv1.EventTypePrefix+evType, cfg.Status, cfg.IsInSync, cfg.ID)
-
- if err := (*so).Emit(xsapiv1.EventTypePrefix+evType, msg); err != nil {
- s.Log.Errorf("WS Emit Folder StateChanged event : %v", err)
- }
- }
- data := make(FolderEventCBData)
- data["sid"] = sess.ID
-
- prjID, err := s.mfolders.ResolveID(args.ProjectID)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- if err = s.mfolders.RegisterEventChange(prjID, &cbFunc, &data); err != nil {
+ // Register to all or to a specific events
+ if err := s.events.Register(args.Name, sess.ID); err != nil {
common.APIError(c, err.Error())
return
}
@@ -134,16 +58,22 @@ func (s *APIService) eventsRegister(c *gin.Context) {
func (s *APIService) eventsUnRegister(c *gin.Context) {
var args xsapiv1.EventUnRegisterArgs
- if c.BindJSON(&args) != nil || args.Name == "" || args.ID < 0 {
+ if c.BindJSON(&args) != nil || args.Name == "" {
common.APIError(c, "Invalid arguments")
return
}
- /* TODO
- if err := s.mfolders.SThg.Events.UnRegister(args.Name, args.ID); err != nil {
+
+ sess := s.sessions.Get(c)
+ if sess == nil {
+ common.APIError(c, "Unknown sessions")
+ return
+ }
+
+ // Register to all or to a specific events
+ if err := s.events.UnRegister(args.Name, sess.ID); err != nil {
common.APIError(c, err.Error())
return
}
+
c.JSON(http.StatusOK, gin.H{"status": "OK"})
- */
- common.APIError(c, "Not implemented yet")
}
diff --git a/lib/xdsserver/events.go b/lib/xdsserver/events.go
new file mode 100644
index 0000000..007b89a
--- /dev/null
+++ b/lib/xdsserver/events.go
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 "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 xdsserver
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/iotbzh/xds-server/lib/xsapiv1"
+)
+
+// EventDef Definition on one event
+type EventDef struct {
+ sids map[string]int
+}
+
+// Events Hold registered events per context
+type Events struct {
+ *Context
+ eventsMap map[string]*EventDef
+}
+
+// NewEvents creates an instance of Events
+func NewEvents(ctx *Context) *Events {
+ evMap := make(map[string]*EventDef)
+ for _, ev := range xsapiv1.EVTAllList {
+ evMap[ev] = &EventDef{
+ sids: make(map[string]int),
+ }
+ }
+ return &Events{
+ Context: ctx,
+ eventsMap: evMap,
+ }
+}
+
+// GetList returns the list of all supported events
+func (e *Events) GetList() []string {
+ return xsapiv1.EVTAllList
+}
+
+// Register Used by a client/session to register to a specific (or all) event(s)
+func (e *Events) Register(evName, sessionID string) error {
+ evs := xsapiv1.EVTAllList
+ if evName != xsapiv1.EVTAll {
+ if _, ok := e.eventsMap[evName]; !ok {
+ return fmt.Errorf("Unsupported event type name")
+ }
+ evs = []string{evName}
+ }
+ for _, ev := range evs {
+ e.eventsMap[ev].sids[sessionID]++
+ }
+ return nil
+}
+
+// UnRegister Used by a client/session to un-register event(s)
+func (e *Events) UnRegister(evName, sessionID string) error {
+ evs := xsapiv1.EVTAllList
+ if evName != xsapiv1.EVTAll {
+ if _, ok := e.eventsMap[evName]; !ok {
+ return fmt.Errorf("Unsupported event type name")
+ }
+ evs = []string{evName}
+ }
+ for _, ev := range evs {
+ if _, exist := e.eventsMap[ev].sids[sessionID]; exist {
+ delete(e.eventsMap[ev].sids, sessionID)
+ break
+ }
+ }
+ return nil
+}
+
+// Emit Used to manually emit an event
+func (e *Events) Emit(evName string, data interface{}, fromSid string) error {
+ var firstErr error
+
+ if _, ok := e.eventsMap[evName]; !ok {
+ return fmt.Errorf("Unsupported event type")
+ }
+
+ firstErr = nil
+ evm := e.eventsMap[evName]
+ e.LogSillyf("Emit Event %s: len(sids)=%d, data=%v", evName, len(evm.sids), data)
+ for sid := range evm.sids {
+ so := e.sessions.IOSocketGet(sid)
+ if so == nil {
+ if firstErr == nil {
+ firstErr = fmt.Errorf("IOSocketGet return nil (SID=%v)", sid)
+ }
+ continue
+ }
+ msg := xsapiv1.EventMsg{
+ Time: time.Now().String(),
+ FromSessionID: fromSid,
+ Type: evName,
+ Data: data,
+ }
+ e.Log.Debugf("Emit Event %s: %v", evName, sid)
+ if err := (*so).Emit(evName, msg); err != nil {
+ e.Log.Errorf("WS Emit %v error : %v", evName, err)
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+ }
+
+ return firstErr
+}
diff --git a/lib/xdsserver/folder-interface.go b/lib/xdsserver/folder-interface.go
index 2b836e7..151530c 100644
--- a/lib/xdsserver/folder-interface.go
+++ b/lib/xdsserver/folder-interface.go
@@ -24,16 +24,15 @@ type FolderEventCB func(cfg *xsapiv1.FolderConfig, data *FolderEventCBData)
// IFOLDER Folder interface
type IFOLDER interface {
- NewUID(suffix string) string // Get a new folder UUID
- Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) // Add a new folder
- GetConfig() xsapiv1.FolderConfig // Get folder public configuration
- GetFullPath(dir string) string // Get folder full path
- ConvPathCli2Svr(s string) string // Convert path from Client to Server
- ConvPathSvr2Cli(s string) string // Convert path from Server to Client
- Remove() error // Remove a folder
- Update(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) // Update a new folder
- RegisterEventChange(cb *FolderEventCB, data *FolderEventCBData) error // Request events registration (sent through WS)
- UnRegisterEventChange() error // Un-register events
- Sync() error // Force folder files synchronization
- IsInSync() (bool, error) // Check if folder files are in-sync
+ NewUID(suffix string) string // Get a new folder UUID
+ Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) // Add a new folder
+ Setup(prj xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) // Local setup of the folder
+ GetConfig() xsapiv1.FolderConfig // Get folder public configuration
+ GetFullPath(dir string) string // Get folder full path
+ ConvPathCli2Svr(s string) string // Convert path from Client to Server
+ ConvPathSvr2Cli(s string) string // Convert path from Server to Client
+ Remove() error // Remove a folder
+ Update(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) // Update a new folder
+ Sync() error // Force folder files synchronization
+ IsInSync() (bool, error) // Check if folder files are in-sync
}
diff --git a/lib/xdsserver/folder-pathmap.go b/lib/xdsserver/folder-pathmap.go
index bb33a98..0452b13 100644
--- a/lib/xdsserver/folder-pathmap.go
+++ b/lib/xdsserver/folder-pathmap.go
@@ -34,14 +34,14 @@ import (
// PathMap .
type PathMap struct {
*Context
- config xsapiv1.FolderConfig
+ fConfig xsapiv1.FolderConfig
}
// NewFolderPathMap Create a new instance of PathMap
func NewFolderPathMap(ctx *Context) *PathMap {
f := PathMap{
Context: ctx,
- config: xsapiv1.FolderConfig{
+ fConfig: xsapiv1.FolderConfig{
Status: xsapiv1.StatusDisable,
},
}
@@ -59,6 +59,12 @@ func (f *PathMap) NewUID(suffix string) string {
// Add a new folder
func (f *PathMap) Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
+ return f.Setup(cfg)
+}
+
+// Setup Setup local project config
+func (f *PathMap) Setup(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
+
if cfg.DataPathMap.ServerPath == "" {
return nil, fmt.Errorf("ServerPath must be set")
}
@@ -80,10 +86,10 @@ func (f *PathMap) Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
return nil, fmt.Errorf("ServerPath directory is not accessible: %s", dir)
}
- f.config = cfg
- f.config.RootPath = dir
- f.config.DataPathMap.ServerPath = dir
- f.config.IsInSync = true
+ f.fConfig = cfg
+ f.fConfig.RootPath = dir
+ f.fConfig.DataPathMap.ServerPath = dir
+ f.fConfig.IsInSync = true
// Verify file created by XDS agent when needed
if cfg.DataPathMap.CheckFile != "" {
@@ -116,30 +122,30 @@ func (f *PathMap) Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
}
}
- f.config.Status = xsapiv1.StatusEnable
+ f.fConfig.Status = xsapiv1.StatusEnable
- return &f.config, nil
+ return &f.fConfig, nil
}
// GetConfig Get public part of folder config
func (f *PathMap) GetConfig() xsapiv1.FolderConfig {
- return f.config
+ return f.fConfig
}
// GetFullPath returns the full path of a directory (from server POV)
func (f *PathMap) GetFullPath(dir string) string {
if &dir == nil {
- return f.config.DataPathMap.ServerPath
+ return f.fConfig.DataPathMap.ServerPath
}
- return filepath.Join(f.config.DataPathMap.ServerPath, dir)
+ return filepath.Join(f.fConfig.DataPathMap.ServerPath, dir)
}
// ConvPathCli2Svr Convert path from Client to Server
func (f *PathMap) ConvPathCli2Svr(s string) string {
- if f.config.ClientPath != "" && f.config.DataPathMap.ServerPath != "" {
+ if f.fConfig.ClientPath != "" && f.fConfig.DataPathMap.ServerPath != "" {
return strings.Replace(s,
- f.config.ClientPath,
- f.config.DataPathMap.ServerPath,
+ f.fConfig.ClientPath,
+ f.fConfig.DataPathMap.ServerPath,
-1)
}
return s
@@ -147,10 +153,10 @@ func (f *PathMap) ConvPathCli2Svr(s string) string {
// ConvPathSvr2Cli Convert path from Server to Client
func (f *PathMap) ConvPathSvr2Cli(s string) string {
- if f.config.ClientPath != "" && f.config.DataPathMap.ServerPath != "" {
+ if f.fConfig.ClientPath != "" && f.fConfig.DataPathMap.ServerPath != "" {
return strings.Replace(s,
- f.config.DataPathMap.ServerPath,
- f.config.ClientPath,
+ f.fConfig.DataPathMap.ServerPath,
+ f.fConfig.ClientPath,
-1)
}
return s
@@ -164,21 +170,11 @@ func (f *PathMap) Remove() error {
// Update update some fields of a folder
func (f *PathMap) Update(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
- if f.config.ID != cfg.ID {
+ if f.fConfig.ID != cfg.ID {
return nil, fmt.Errorf("Invalid id")
}
- f.config = cfg
- return &f.config, nil
-}
-
-// RegisterEventChange requests registration for folder change event
-func (f *PathMap) RegisterEventChange(cb *FolderEventCB, data *FolderEventCBData) error {
- return nil
-}
-
-// UnRegisterEventChange remove registered callback
-func (f *PathMap) UnRegisterEventChange() error {
- return nil
+ f.fConfig = cfg
+ return &f.fConfig, nil
}
// Sync Force folder files synchronization
diff --git a/lib/xdsserver/folder-st-disable.go b/lib/xdsserver/folder-st-disable.go
index 4dbe2a9..c52854d 100644
--- a/lib/xdsserver/folder-st-disable.go
+++ b/lib/xdsserver/folder-st-disable.go
@@ -29,7 +29,7 @@ import (
// STFolderDisable .
type STFolderDisable struct {
*Context
- config xsapiv1.FolderConfig
+ fConfig xsapiv1.FolderConfig
}
// NewFolderSTDisable Create a new instance of STFolderDisable
@@ -51,15 +51,20 @@ func (f *STFolderDisable) NewUID(suffix string) string {
// Add a new folder
func (f *STFolderDisable) Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
- f.config = cfg
- f.config.Status = xsapiv1.StatusDisable
- f.config.IsInSync = false
- return &f.config, nil
+ return f.Setup(cfg)
+}
+
+// Setup Setup local project config
+func (f *STFolderDisable) Setup(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
+ f.fConfig = cfg
+ f.fConfig.Status = xsapiv1.StatusDisable
+ f.fConfig.IsInSync = false
+ return &f.fConfig, nil
}
// GetConfig Get public part of folder config
func (f *STFolderDisable) GetConfig() xsapiv1.FolderConfig {
- return f.config
+ return f.fConfig
}
// GetFullPath returns the full path of a directory (from server POV)
@@ -87,16 +92,6 @@ func (f *STFolderDisable) Update(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfi
return nil, nil
}
-// RegisterEventChange requests registration for folder change event
-func (f *STFolderDisable) RegisterEventChange(cb *FolderEventCB, data *FolderEventCBData) error {
- return nil
-}
-
-// UnRegisterEventChange remove registered callback
-func (f *STFolderDisable) UnRegisterEventChange() error {
- return nil
-}
-
// Sync Force folder files synchronization
func (f *STFolderDisable) Sync() error {
return nil
diff --git a/lib/xdsserver/folder-st.go b/lib/xdsserver/folder-st.go
index c8f718a..9cbb570 100644
--- a/lib/xdsserver/folder-st.go
+++ b/lib/xdsserver/folder-st.go
@@ -23,8 +23,8 @@ import (
"path/filepath"
"strings"
- "github.com/iotbzh/xds-server/lib/xsapiv1"
st "github.com/iotbzh/xds-server/lib/syncthing"
+ "github.com/iotbzh/xds-server/lib/xsapiv1"
uuid "github.com/satori/go.uuid"
"github.com/syncthing/syncthing/lib/config"
)
@@ -34,14 +34,14 @@ import (
// STFolder .
type STFolder struct {
*Context
- st *st.SyncThing
- fConfig xsapiv1.FolderConfig
- stfConfig config.FolderConfiguration
- eventIDs []int
- eventChangeCB *FolderEventCB
- eventChangeCBData *FolderEventCBData
+ st *st.SyncThing
+ fConfig xsapiv1.FolderConfig
+ stfConfig config.FolderConfiguration
+ eventIDs []string
}
+var stEventMonitored = []string{st.EventStateChanged, st.EventFolderPaused}
+
// NewFolderST Create a new instance of STFolder
func NewFolderST(ctx *Context, sthg *st.SyncThing) *STFolder {
return &STFolder{
@@ -79,33 +79,42 @@ func (f *STFolder) Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error)
f.fConfig = cfg
// Update Syncthing folder
- // (except if status is ErrorConfig)
- // TODO: add cache to avoid multiple requests on startup
- if f.fConfig.Status != xsapiv1.StatusErrorConfig {
- id, err := f.st.FolderChange(f.fConfig)
- if err != nil {
- return nil, err
- }
+ _, err := f.st.FolderChange(f.fConfig)
+ if err != nil {
+ return nil, err
+ }
- f.stfConfig, err = f.st.FolderConfigGet(id)
+ // Use Setup function to setup remains fields
+ return f.Setup(f.fConfig)
+}
+
+// Setup Setup local project config
+func (f *STFolder) Setup(fld xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
+
+ var err error
+
+ // Update folder Config
+ f.fConfig = fld
+
+ // Retrieve Syncthing folder config
+ f.stfConfig, err = f.st.FolderConfigGet(f.fConfig.ID)
+ if err != nil {
+ f.fConfig.Status = xsapiv1.StatusErrorConfig
+ return nil, err
+ }
+
+ // Register to events to update folder status
+ for _, evName := range stEventMonitored {
+ evID, err := f.st.Events.Register(evName, f.cbEventState, f.fConfig.ID, nil)
if err != nil {
- f.fConfig.Status = xsapiv1.StatusErrorConfig
return nil, err
}
-
- // Register to events to update folder status
- for _, evName := range []string{st.EventStateChanged, st.EventFolderPaused} {
- evID, err := f.st.Events.Register(evName, f.cbEventState, id, nil)
- if err != nil {
- return nil, err
- }
- f.eventIDs = append(f.eventIDs, evID)
- }
-
- f.fConfig.IsInSync = false // will be updated later by events
- f.fConfig.Status = xsapiv1.StatusEnable
+ f.eventIDs = append(f.eventIDs, evID)
}
+ f.fConfig.IsInSync = false // will be updated later by events
+ f.fConfig.Status = xsapiv1.StatusEnable
+
return &f.fConfig, nil
}
@@ -149,15 +158,27 @@ func (f *STFolder) ConvPathSvr2Cli(s string) string {
// Remove a folder
func (f *STFolder) Remove() error {
- err := f.st.FolderDelete(f.stfConfig.ID)
+ var err1 error
+ // Un-register events
+ for _, evID := range f.eventIDs {
+ if err := f.st.Events.UnRegister(evID); err != nil && err1 == nil {
+ // only report 1st error
+ err1 = err
+ }
+ }
+
+ // Delete in Syncthing
+ err2 := f.st.FolderDelete(f.stfConfig.ID)
// Delete folder on server side
- err2 := os.RemoveAll(f.GetFullPath(""))
+ err3 := os.RemoveAll(f.GetFullPath(""))
- if err != nil {
- return err
+ if err1 != nil {
+ return err1
+ } else if err2 != nil {
+ return err2
}
- return err2
+ return err3
}
// Update update some fields of a folder
@@ -169,20 +190,6 @@ func (f *STFolder) Update(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, erro
return &f.fConfig, nil
}
-// RegisterEventChange requests registration for folder event change
-func (f *STFolder) RegisterEventChange(cb *FolderEventCB, data *FolderEventCBData) error {
- f.eventChangeCB = cb
- f.eventChangeCBData = data
- return nil
-}
-
-// UnRegisterEventChange remove registered callback
-func (f *STFolder) UnRegisterEventChange() error {
- f.eventChangeCB = nil
- f.eventChangeCBData = nil
- return nil
-}
-
// Sync Force folder files synchronization
func (f *STFolder) Sync() error {
return f.st.FolderScan(f.stfConfig.ID, "")
@@ -222,9 +229,10 @@ func (f *STFolder) cbEventState(ev st.Event, data *st.EventsCBData) {
f.fConfig.IsInSync = false
}
- if f.eventChangeCB != nil &&
- (prevSync != f.fConfig.IsInSync || prevStatus != f.fConfig.Status) {
- cpConf := f.fConfig
- (*f.eventChangeCB)(&cpConf, f.eventChangeCBData)
+ if prevSync != f.fConfig.IsInSync || prevStatus != f.fConfig.Status {
+ // Emit Folder state change event
+ if err := f.events.Emit(xsapiv1.EVTFolderStateChange, &f.fConfig, ""); err != nil {
+ f.Log.Warningf("Cannot notify folder change: %v", err)
+ }
}
}
diff --git a/lib/xdsserver/folders.go b/lib/xdsserver/folders.go
index 7a45bbd..b0c198a 100644
--- a/lib/xdsserver/folders.go
+++ b/lib/xdsserver/folders.go
@@ -216,6 +216,7 @@ func (f *Folders) Add(newF xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error)
// CreateUpdate creates or update a folder
func (f *Folders) createUpdate(newF xsapiv1.FolderConfig, create bool, initial bool) (*xsapiv1.FolderConfig, error) {
+ var err error
fcMutex.Lock()
defer fcMutex.Unlock()
@@ -269,12 +270,21 @@ func (f *Folders) createUpdate(newF xsapiv1.FolderConfig, create bool, initial b
// Normalize path (needed for Windows path including bashlashes)
newF.ClientPath = common.PathNormalize(newF.ClientPath)
- // Add new folder
- newFolder, err := fld.Add(newF)
- if err != nil {
- newF.Status = xsapiv1.StatusErrorConfig
- log.Printf("ERROR Adding folder: %v\n", err)
- return newFolder, err
+ var newFolder *xsapiv1.FolderConfig
+ if create {
+ // Add folder
+ if newFolder, err = fld.Add(newF); err != nil {
+ newF.Status = xsapiv1.StatusErrorConfig
+ log.Printf("ERROR Adding folder: %v\n", err)
+ return newFolder, err
+ }
+ } else {
+ // Just update project config
+ if newFolder, err = fld.Setup(newF); err != nil {
+ newF.Status = xsapiv1.StatusErrorConfig
+ log.Printf("ERROR Updating folder: %v\n", err)
+ return newFolder, err
+ }
}
// Add to folders list
@@ -287,13 +297,6 @@ func (f *Folders) createUpdate(newF xsapiv1.FolderConfig, create bool, initial b
}
}
- // Register event change callback
- for _, rcb := range f.registerCB {
- if err := fld.RegisterEventChange(rcb.cb, rcb.data); err != nil {
- return newFolder, err
- }
- }
-
// Force sync after creation
// (need to defer to be sure that WS events will arrive after HTTP creation reply)
go func() {
@@ -379,29 +382,6 @@ func (f *Folders) Update(id string, cfg xsapiv1.FolderConfig) (*xsapiv1.FolderCo
return fld, err
}
-// RegisterEventChange requests registration for folder event change
-func (f *Folders) RegisterEventChange(id string, cb *FolderEventCB, data *FolderEventCBData) error {
-
- flds := make(map[string]*IFOLDER)
- if id != "" {
- // Register to a specific folder
- flds[id] = f.Get(id)
- } else {
- // Register to all folders
- flds = f.folders
- f.registerCB = append(f.registerCB, RegisteredCB{cb: cb, data: data})
- }
-
- for _, fld := range flds {
- err := (*fld).RegisterEventChange(cb, data)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
// ForceSync Force the synchronization of a folder
func (f *Folders) ForceSync(id string) error {
fc := f.Get(id)
diff --git a/lib/xdsserver/xdsserver.go b/lib/xdsserver/xdsserver.go
index 64041b9..46e860b 100644
--- a/lib/xdsserver/xdsserver.go
+++ b/lib/xdsserver/xdsserver.go
@@ -51,6 +51,7 @@ type Context struct {
sdks *SDKs
WWWServer *WebServer
sessions *Sessions
+ events *Events
Exit chan os.Signal
}
@@ -128,6 +129,9 @@ func (ctx *Context) Run() (int, error) {
ctx._logPrint("Logging file for HTTP requests: %s\n", logFileHTTPReq)
}
+ // Create events management
+ ctx.events = NewEvents(ctx)
+
// Create syncthing instance when section "syncthing" is present in server-config.json
if ctx.Config.FileConf.SThgConf != nil {
ctx.SThg = st.NewSyncThing(ctx.Config, ctx.Log)
diff --git a/lib/xsapiv1/events.go b/lib/xsapiv1/events.go
index e19eb82..1552579 100644
--- a/lib/xsapiv1/events.go
+++ b/lib/xsapiv1/events.go
@@ -17,6 +17,11 @@
package xsapiv1
+import (
+ "encoding/json"
+ "fmt"
+)
+
// EventRegisterArgs Parameters (json format) of /events/register command
type EventRegisterArgs struct {
Name string `json:"name"`
@@ -31,9 +36,10 @@ type EventUnRegisterArgs struct {
// EventMsg Message send
type EventMsg struct {
- Time string `json:"time"`
- Type string `json:"type"`
- Folder FolderConfig `json:"folder"`
+ Time string `json:"time"`
+ FromSessionID string `json:"sessionID"` // Session ID of client who produce this event
+ Type string `json:"type"`
+ Data interface{} `json:"data"` // Data
}
// EventEvent Event send in WS when an internal event (eg. Syncthing event is received)
@@ -46,3 +52,26 @@ const (
EVTFolderChange = EventTypePrefix + "folder-change" // type EventMsg with Data type xsapiv1.???
EVTFolderStateChange = EventTypePrefix + "folder-state-change" // type EventMsg with Data type xsapiv1.???
)
+
+// EVTAllList List of all supported events
+var EVTAllList = []string{
+ EVTFolderChange,
+ EVTFolderStateChange,
+}
+
+// DecodeFolderConfig Helper to decode Data field type FolderConfig
+func (e *EventMsg) DecodeFolderConfig() (FolderConfig, error) {
+ var err error
+ f := FolderConfig{}
+ switch e.Type {
+ case EVTFolderChange, EVTFolderStateChange:
+ d := []byte{}
+ d, err = json.Marshal(e.Data)
+ if err == nil {
+ err = json.Unmarshal(d, &f)
+ }
+ default:
+ err = fmt.Errorf("Invalid type")
+ }
+ return f, err
+}