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