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