+/*
+ * Copyright (C) 2017-2018 "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 agent
-import "github.com/iotbzh/xds-agent/lib/syncthing"
+import (
+ "encoding/json"
+ "fmt"
-// SEB TODO
+ st "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent.git/lib/syncthing"
+ "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent.git/lib/xaapiv1"
+ "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
+)
// IPROJECT interface implementation for syncthing projects
// STProject .
type STProject struct {
*Context
- server *XdsServer
- folder *FolderConfig
+ server *XdsServer
+ folder *xsapiv1.FolderConfig
+ eventIDs []int
}
// NewProjectST Create a new instance of STProject
p := STProject{
Context: ctx,
server: svr,
- folder: &FolderConfig{},
+ folder: &xsapiv1.FolderConfig{},
}
return &p
}
// Add a new project
-func (p *STProject) Add(cfg ProjectConfig) (*ProjectConfig, error) {
+func (p *STProject) Add(cfg xaapiv1.ProjectConfig) (*xaapiv1.ProjectConfig, error) {
var err error
+ // Add project/folder into XDS Server
err = p.server.FolderAdd(p.server.ProjectToFolder(cfg), p.folder)
if err != nil {
return nil, err
svrPrj := p.GetProject()
// Declare project into local Syncthing
- p.SThg.FolderChange(st.FolderChangeArg{
- ID: cfg.ID,
- Label: cfg.Label,
+ id, err := p.SThg.FolderChange(st.FolderChangeArg{
+ ID: svrPrj.ID,
+ Label: svrPrj.Label,
RelativePath: cfg.ClientPath,
SyncThingID: p.server.ServerConfig.Builder.SyncThingID,
})
+ if err != nil {
+ return nil, err
+ }
- return svrPrj, nil
+ locPrj, err := p.SThg.FolderConfigGet(id)
+ if err != nil {
+ svrPrj.Status = xaapiv1.StatusErrorConfig
+ return nil, err
+ }
+ if svrPrj.ID != locPrj.ID {
+ p.Log.Errorf("Project ID in XDSServer and local ST differ: %s != %s", svrPrj.ID, locPrj.ID)
+ }
+
+ // Use Setup function to setup remains fields
+ return p.Setup(*svrPrj)
}
// Delete a project
func (p *STProject) Delete() error {
- return p.server.FolderDelete(p.folder.ID)
+ errSvr := p.server.FolderDelete(p.folder.ID)
+ errLoc := p.SThg.FolderDelete(p.folder.ID)
+ if errSvr != nil {
+ return errSvr
+ }
+ return errLoc
}
// GetProject Get public part of project config
-func (p *STProject) GetProject() *ProjectConfig {
+func (p *STProject) GetProject() *xaapiv1.ProjectConfig {
prj := p.server.FolderToProject(*p.folder)
prj.ServerID = p.server.ID
return &prj
}
-// SetProject Set project config
-func (p *STProject) SetProject(prj ProjectConfig) *ProjectConfig {
- // SEB TODO
+// Setup Setup local project config
+func (p *STProject) Setup(prj xaapiv1.ProjectConfig) (*xaapiv1.ProjectConfig, error) {
+ // Update folder
p.folder = p.server.ProjectToFolder(prj)
- return p.GetProject()
+ svrPrj := p.GetProject()
+
+ // Register events to update folder status
+ // Register to XDS Server events
+ if _, err := p.server.EventOn(xsapiv1.EVTFolderStateChange, "", p._cbServerFolderChanged); err != nil {
+ p.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTFolderStateChange, err)
+ return svrPrj, err
+ }
+
+ // Register to Local Syncthing events
+ for _, evName := range []string{st.EventStateChanged, st.EventFolderPaused} {
+ evID, err := p.SThg.Events.Register(evName, p._cbLocalSTEvents, svrPrj.ID, nil)
+ if err != nil {
+ return nil, err
+ }
+ p.eventIDs = append(p.eventIDs, evID)
+ }
+
+ return svrPrj, nil
+}
+
+// Update Update some field of a project
+func (p *STProject) Update(prj xaapiv1.ProjectConfig) (*xaapiv1.ProjectConfig, error) {
+
+ if p.folder.ID != prj.ID {
+ return nil, fmt.Errorf("Invalid id")
+ }
+
+ err := p.server.FolderUpdate(p.server.ProjectToFolder(prj), p.folder)
+ if err != nil {
+ return nil, err
+ }
+
+ return p.GetProject(), nil
}
// GetServer Get the XdsServer that holds this project
func (p *STProject) GetServer() *XdsServer {
- // SEB TODO
return p.server
}
-// GetFullPath returns the full path of a directory (from server POV)
-func (p *STProject) GetFullPath(dir string) string {
- /* SEB
- if &dir == nil {
- return p.folder.DataSTProject.ServerPath
- }
- return filepath.Join(p.folder.DataSTProject.ServerPath, dir)
- */
- return "SEB TODO"
-}
-
// Sync Force project files synchronization
func (p *STProject) Sync() error {
- // SEB TODO
- return nil
+ if err := p.server.FolderSync(p.folder.ID); err != nil {
+ return err
+ }
+ return p.SThg.FolderScan(p.folder.ID, "")
}
// IsInSync Check if project files are in-sync
func (p *STProject) IsInSync() (bool, error) {
- // SEB TODO
- return false, nil
+ // Should be up-to-date by callbacks (see below)
+ return p.folder.IsInSync, nil
+}
+
+/**
+** Private functions
+***/
+
+// callback use to update (XDS Server) folder IsInSync status
+
+func (p *STProject) _cbServerFolderChanged(pData interface{}, data interface{}) error {
+ evt := xsapiv1.EventMsg{}
+ d, err := json.Marshal(data)
+ if err != nil {
+ p.Log.Errorf("Cannot marshal XDS Server event folder-change err=%v", err)
+ return err
+ }
+ if err = json.Unmarshal(d, &evt); err != nil {
+ p.Log.Errorf("Cannot unmarshal XDS Server event folder-change err=%v", err)
+ return err
+ }
+
+ fld, err := evt.DecodeFolderConfig()
+ if err != nil {
+ p.Log.Errorf("Cannot decode FolderChanged event: %v", data)
+ }
+
+ // Only process event that concerns this project/folder ID
+ if p.folder.ID != fld.ID {
+ return nil
+ }
+
+ if fld.IsInSync != p.folder.DataCloudSync.STSvrIsInSync ||
+ fld.Status != p.folder.DataCloudSync.STSvrStatus {
+
+ p.folder.DataCloudSync.STSvrIsInSync = fld.IsInSync
+ p.folder.DataCloudSync.STSvrStatus = fld.Status
+
+ if err := p.events.Emit(xaapiv1.EVTProjectChange, p.server.FolderToProject(*p.folder), ""); err != nil {
+ p.Log.Warningf("Cannot notify project change (from server): %v", err)
+ }
+ }
+ return nil
+}
+
+// callback use to update IsInSync status
+func (p *STProject) _cbLocalSTEvents(ev st.Event, data *st.EventsCBData) {
+
+ inSync := p.folder.DataCloudSync.STLocIsInSync
+ sts := p.folder.DataCloudSync.STLocStatus
+ prevSync := inSync
+ prevStatus := sts
+
+ switch ev.Type {
+
+ case st.EventStateChanged:
+ to := ev.Data["to"]
+ switch to {
+ case "scanning", "syncing":
+ sts = xaapiv1.StatusSyncing
+ case "idle":
+ sts = xaapiv1.StatusEnable
+ }
+ inSync = (to == "idle")
+
+ case st.EventFolderPaused:
+ if sts == xaapiv1.StatusEnable {
+ sts = xaapiv1.StatusPause
+ }
+ inSync = false
+ }
+
+ if prevSync != inSync || prevStatus != sts {
+
+ p.folder.DataCloudSync.STLocIsInSync = inSync
+ p.folder.DataCloudSync.STLocStatus = sts
+
+ if err := p.events.Emit(xaapiv1.EVTProjectChange, p.server.FolderToProject(*p.folder), ""); err != nil {
+ p.Log.Warningf("Cannot notify project change (local): %v", err)
+ }
+ }
}