c0d25507aa33ebc3af99ed292076b4708fffa69c
[src/xds/xds-agent.git] / lib / agent / project-st.go
1 package agent
2
3 import (
4         st "github.com/iotbzh/xds-agent/lib/syncthing"
5 )
6
7 // IPROJECT interface implementation for syncthing projects
8
9 // STProject .
10 type STProject struct {
11         *Context
12         server   *XdsServer
13         folder   *XdsFolderConfig
14         eventIDs []int
15 }
16
17 // NewProjectST Create a new instance of STProject
18 func NewProjectST(ctx *Context, svr *XdsServer) *STProject {
19         p := STProject{
20                 Context: ctx,
21                 server:  svr,
22                 folder:  &XdsFolderConfig{},
23         }
24         return &p
25 }
26
27 // Add a new project
28 func (p *STProject) Add(cfg ProjectConfig) (*ProjectConfig, error) {
29         var err error
30
31         // Add project/folder into XDS Server
32         err = p.server.FolderAdd(p.server.ProjectToFolder(cfg), p.folder)
33         if err != nil {
34                 return nil, err
35         }
36         svrPrj := p.GetProject()
37
38         // Declare project into local Syncthing
39         id, err := p.SThg.FolderChange(st.FolderChangeArg{
40                 ID:           svrPrj.ID,
41                 Label:        svrPrj.Label,
42                 RelativePath: cfg.ClientPath,
43                 SyncThingID:  p.server.ServerConfig.Builder.SyncThingID,
44         })
45         if err != nil {
46                 return nil, err
47         }
48
49         locPrj, err := p.SThg.FolderConfigGet(id)
50         if err != nil {
51                 svrPrj.Status = StatusErrorConfig
52                 return nil, err
53         }
54         if svrPrj.ID != locPrj.ID {
55                 p.Log.Errorf("Project ID in XDSServer and local ST differ: %s != %s", svrPrj.ID, locPrj.ID)
56         }
57
58         // Use Update function to setup remains fields
59         return p.UpdateProject(*svrPrj)
60 }
61
62 // Delete a project
63 func (p *STProject) Delete() error {
64         errSvr := p.server.FolderDelete(p.folder.ID)
65         errLoc := p.SThg.FolderDelete(p.folder.ID)
66         if errSvr != nil {
67                 return errSvr
68         }
69         return errLoc
70 }
71
72 // GetProject Get public part of project config
73 func (p *STProject) GetProject() *ProjectConfig {
74         prj := p.server.FolderToProject(*p.folder)
75         prj.ServerID = p.server.ID
76         return &prj
77 }
78
79 // UpdateProject Update project config
80 func (p *STProject) UpdateProject(prj ProjectConfig) (*ProjectConfig, error) {
81         // Update folder
82         p.folder = p.server.ProjectToFolder(prj)
83         svrPrj := p.GetProject()
84
85         // Register events to update folder status
86         // Register to XDS Server events
87         p.server.EventOn("event:FolderStateChanged", p._cbServerFolderChanged)
88         if err := p.server.EventRegister("FolderStateChanged", svrPrj.ID); err != nil {
89                 p.Log.Warningf("XDS Server EventRegister failed: %v", err)
90                 return svrPrj, err
91         }
92
93         // Register to Local Syncthing events
94         for _, evName := range []string{st.EventStateChanged, st.EventFolderPaused} {
95                 evID, err := p.SThg.Events.Register(evName, p._cbLocalSTEvents, svrPrj.ID, nil)
96                 if err != nil {
97                         return nil, err
98                 }
99                 p.eventIDs = append(p.eventIDs, evID)
100         }
101
102         return svrPrj, nil
103 }
104
105 // GetServer Get the XdsServer that holds this project
106 func (p *STProject) GetServer() *XdsServer {
107         return p.server
108 }
109
110 // Sync Force project files synchronization
111 func (p *STProject) Sync() error {
112         if err := p.server.FolderSync(p.folder.ID); err != nil {
113                 return err
114         }
115         return p.SThg.FolderScan(p.folder.ID, "")
116 }
117
118 // IsInSync Check if project files are in-sync
119 func (p *STProject) IsInSync() (bool, error) {
120         // Should be up-to-date by callbacks (see below)
121         return p.folder.IsInSync, nil
122 }
123
124 /**
125 ** Private functions
126 ***/
127
128 // callback use to update (XDS Server) folder IsInSync status
129
130 func (p *STProject) _cbServerFolderChanged(data interface{}) {
131         evt := data.(XdsEventFolderChange)
132
133         // Only process event that concerns this project/folder ID
134         if p.folder.ID != evt.Folder.ID {
135                 return
136         }
137
138         if evt.Folder.IsInSync != p.folder.DataCloudSync.STSvrIsInSync ||
139                 evt.Folder.Status != p.folder.DataCloudSync.STSvrStatus {
140
141                 p.folder.DataCloudSync.STSvrIsInSync = evt.Folder.IsInSync
142                 p.folder.DataCloudSync.STSvrStatus = evt.Folder.Status
143
144                 if err := p.events.Emit(EVTProjectChange, p.server.FolderToProject(*p.folder)); err != nil {
145                         p.Log.Warningf("Cannot notify project change: %v", err)
146                 }
147         }
148 }
149
150 // callback use to update IsInSync status
151 func (p *STProject) _cbLocalSTEvents(ev st.Event, data *st.EventsCBData) {
152
153         inSync := p.folder.DataCloudSync.STLocIsInSync
154         sts := p.folder.DataCloudSync.STLocStatus
155         prevSync := inSync
156         prevStatus := sts
157
158         switch ev.Type {
159
160         case st.EventStateChanged:
161                 to := ev.Data["to"]
162                 switch to {
163                 case "scanning", "syncing":
164                         sts = StatusSyncing
165                 case "idle":
166                         sts = StatusEnable
167                 }
168                 inSync = (to == "idle")
169
170         case st.EventFolderPaused:
171                 if sts == StatusEnable {
172                         sts = StatusPause
173                 }
174                 inSync = false
175         }
176
177         if prevSync != inSync || prevStatus != sts {
178
179                 p.folder.DataCloudSync.STLocIsInSync = inSync
180                 p.folder.DataCloudSync.STLocStatus = sts
181
182                 if err := p.events.Emit(EVTProjectChange, p.server.FolderToProject(*p.folder)); err != nil {
183                         p.Log.Warningf("Cannot notify project change: %v", err)
184                 }
185         }
186 }