X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=lib%2Fagent%2Fxdsserver.go;h=e2c38c1bbecbf1780cdbb0dec5984a2160464ba5;hb=4e9af3723740f16f3843a68508b6e933ea871b98;hp=c900c9e946bf80192b7197339e70c722b2bbbb01;hpb=4695555e178bcabe54c5bf82117c9c4cef5440b5;p=src%2Fxds%2Fxds-agent.git diff --git a/lib/agent/xdsserver.go b/lib/agent/xdsserver.go index c900c9e..e2c38c1 100644 --- a/lib/agent/xdsserver.go +++ b/lib/agent/xdsserver.go @@ -11,6 +11,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/iotbzh/xds-agent/lib/apiv1" "github.com/iotbzh/xds-agent/lib/xdsconfig" common "github.com/iotbzh/xds-common/golib" uuid "github.com/satori/go.uuid" @@ -63,9 +64,12 @@ type XdsBuilderConfig struct { type XdsFolderType string const ( - XdsTypePathMap = "PathMap" + // XdsTypePathMap Path Mapping folder type + XdsTypePathMap = "PathMap" + // XdsTypeCloudSync Cloud synchronization (AKA syncthing) folder type XdsTypeCloudSync = "CloudSync" - XdsTypeCifsSmb = "CIFS" + // XdsTypeCifsSmb CIFS (AKA samba) folder type + XdsTypeCifsSmb = "CIFS" ) // XdsFolderConfig XdsServer folder config @@ -77,6 +81,8 @@ type XdsFolderConfig struct { Status string `json:"status"` IsInSync bool `json:"isInSync"` DefaultSdk string `json:"defaultSdk"` + ClientData string `json:"clientData"` // free form field that can used by client + // Specific data depending on which Type is used DataPathMap XdsPathMapConfig `json:"dataPathMap,omitempty"` DataCloudSync XdsCloudSyncConfig `json:"dataCloudSync,omitempty"` @@ -84,7 +90,9 @@ type XdsFolderConfig struct { // XdsPathMapConfig Path mapping specific data type XdsPathMapConfig struct { - ServerPath string `json:"serverPath"` + ServerPath string `json:"serverPath"` + CheckFile string `json:"checkFile"` + CheckContent string `json:"checkContent"` } // XdsCloudSyncConfig CloudSync (AKA Syncthing) specific data @@ -109,11 +117,15 @@ type XdsEventFolderChange struct { Folder XdsFolderConfig `json:"folder"` } +// EventCB Event emitter callback +type EventCB func(privData interface{}, evtData interface{}) error + // caller Used to chain event listeners type caller struct { - id uuid.UUID - EventName string - Func func(interface{}) + id uuid.UUID + EventName string + Func EventCB + PrivateData interface{} } const _IDTempoPrefix = "tempo-" @@ -201,37 +213,36 @@ func (xs *XdsServer) SendCommand(cmd string, body []byte) (*http.Response, error // GetVersion Send Get request to retrieve XDS Server version func (xs *XdsServer) GetVersion(res interface{}) error { - return xs._HTTPGet("/version", &res) + return xs.client.Get("/version", &res) } // GetFolders Send GET request to get current folder configuration -func (xs *XdsServer) GetFolders(prjs *[]XdsFolderConfig) error { - return xs._HTTPGet("/folders", prjs) +func (xs *XdsServer) GetFolders(folders *[]XdsFolderConfig) error { + return xs.client.Get("/folders", folders) } // FolderAdd Send POST request to add a folder -func (xs *XdsServer) FolderAdd(prj *XdsFolderConfig, res interface{}) error { - response, err := xs._HTTPPost("/folder", prj) +func (xs *XdsServer) FolderAdd(fld *XdsFolderConfig, res interface{}) error { + err := xs.client.Post("/folders", fld, res) if err != nil { - return err + return fmt.Errorf("FolderAdd error: %s", err.Error()) } - if response.StatusCode != 200 { - return fmt.Errorf("FolderAdd error status=%s", response.Status) - } - // Result is a XdsFolderConfig that is equivalent to ProjectConfig - err = json.Unmarshal(xs.client.ResponseToBArray(response), res) - return err } // FolderDelete Send DELETE request to delete a folder func (xs *XdsServer) FolderDelete(id string) error { - return xs.client.HTTPDelete("/folder/" + id) + return xs.client.HTTPDelete("/folders/" + id) } // FolderSync Send POST request to force synchronization of a folder func (xs *XdsServer) FolderSync(id string) error { - return xs.client.HTTPPost("/folder/sync/"+id, "") + return xs.client.HTTPPost("/folders/sync/"+id, "") +} + +// FolderUpdate Send PUT request to update a folder +func (xs *XdsServer) FolderUpdate(fld *XdsFolderConfig, resFld *XdsFolderConfig) error { + return xs.client.Put("/folders/"+fld.ID, fld, resFld) } // SetAPIRouterGroup . @@ -248,7 +259,13 @@ func (xs *XdsServer) PassthroughGet(url string) { xs.apiRouter.GET(url, func(c *gin.Context) { var data interface{} - if err := xs._HTTPGet(url, &data); err != nil { + // Take care of param (eg. id in /projects/:id) + nURL := url + if strings.Contains(url, ":") { + nURL = strings.TrimPrefix(c.Request.URL.Path, xs.APIURL) + } + // Send Get request + if err := xs.client.Get(nURL, &data); err != nil { if strings.Contains(err.Error(), "connection refused") { xs.Connected = false xs._NotifyState() @@ -276,11 +293,25 @@ func (xs *XdsServer) PassthroughPost(url string) { return } - response, err := xs._HTTPPost(url, bodyReq[:n]) + // Take care of param (eg. id in /projects/:id) + nURL := url + if strings.Contains(url, ":") { + nURL = strings.TrimPrefix(c.Request.URL.Path, xs.APIURL) + } + + // Send Post request + body, err := json.Marshal(bodyReq[:n]) + if err != nil { + common.APIError(c, err.Error()) + return + } + + response, err := xs.client.HTTPPostWithRes(nURL, string(body)) if err != nil { common.APIError(c, err.Error()) return } + bodyRes, err := ioutil.ReadAll(response.Body) if err != nil { common.APIError(c, "Cannot read response body") @@ -292,16 +323,17 @@ func (xs *XdsServer) PassthroughPost(url string) { // EventRegister Post a request to register to an XdsServer event func (xs *XdsServer) EventRegister(evName string, id string) error { - var err error - _, err = xs._HTTPPost("/events/register", XdsEventRegisterArgs{ - Name: evName, - ProjectID: id, - }) - return err + return xs.client.Post( + "/events/register", + XdsEventRegisterArgs{ + Name: evName, + ProjectID: id, + }, + nil) } // EventOn Register a callback on events reception -func (xs *XdsServer) EventOn(evName string, f func(interface{})) (uuid.UUID, error) { +func (xs *XdsServer) EventOn(evName string, privData interface{}, f EventCB) (uuid.UUID, error) { if xs.ioSock == nil { return uuid.Nil, fmt.Errorf("Io.Socket not initialized") } @@ -315,17 +347,28 @@ func (xs *XdsServer) EventOn(evName string, f func(interface{})) (uuid.UUID, err // FIXME: use generic type: data interface{} instead of data XdsEventFolderChange var err error - if evName == "event:FolderStateChanged" { + if evName == "event:folder-state-change" { err = xs.ioSock.On(evn, func(data XdsEventFolderChange) error { xs.sockEventsLock.Lock() - defer xs.sockEventsLock.Unlock() - for _, c := range xs.sockEvents[evn] { - c.Func(data) + sEvts := make([]*caller, len(xs.sockEvents[evn])) + copy(sEvts, xs.sockEvents[evn]) + xs.sockEventsLock.Unlock() + for _, c := range sEvts { + c.Func(c.PrivateData, data) } return nil }) } else { - err = xs.ioSock.On(evn, f) + err = xs.ioSock.On(evn, func(data interface{}) error { + xs.sockEventsLock.Lock() + sEvts := make([]*caller, len(xs.sockEvents[evn])) + copy(sEvts, xs.sockEvents[evn]) + xs.sockEventsLock.Unlock() + for _, c := range sEvts { + c.Func(c.PrivateData, data) + } + return nil + }) } if err != nil { return uuid.Nil, err @@ -333,9 +376,10 @@ func (xs *XdsServer) EventOn(evName string, f func(interface{})) (uuid.UUID, err } c := &caller{ - id: uuid.NewV1(), - EventName: evName, - Func: f, + id: uuid.NewV1(), + EventName: evName, + Func: f, + PrivateData: privData, } xs.sockEvents[evName] = append(xs.sockEvents[evName], c) @@ -364,11 +408,12 @@ func (xs *XdsServer) EventOff(evName string, id uuid.UUID) error { } // ProjectToFolder Convert Project structure to Folder structure -func (xs *XdsServer) ProjectToFolder(pPrj ProjectConfig) *XdsFolderConfig { +func (xs *XdsServer) ProjectToFolder(pPrj apiv1.ProjectConfig) *XdsFolderConfig { stID := "" if pPrj.Type == XdsTypeCloudSync { stID, _ = xs.SThg.IDGet() } + // TODO: limit ClientData size and gzip it (see https://golang.org/pkg/compress/gzip/) fPrj := XdsFolderConfig{ ID: pPrj.ID, Label: pPrj.Label, @@ -377,6 +422,7 @@ func (xs *XdsServer) ProjectToFolder(pPrj ProjectConfig) *XdsFolderConfig { Status: pPrj.Status, IsInSync: pPrj.IsInSync, DefaultSdk: pPrj.DefaultSdk, + ClientData: pPrj.ClientData, DataPathMap: XdsPathMapConfig{ ServerPath: pPrj.ServerPath, }, @@ -393,7 +439,7 @@ func (xs *XdsServer) ProjectToFolder(pPrj ProjectConfig) *XdsFolderConfig { } // FolderToProject Convert Folder structure to Project structure -func (xs *XdsServer) FolderToProject(fPrj XdsFolderConfig) ProjectConfig { +func (xs *XdsServer) FolderToProject(fPrj XdsFolderConfig) apiv1.ProjectConfig { inSync := fPrj.IsInSync sts := fPrj.Status @@ -402,30 +448,31 @@ func (xs *XdsServer) FolderToProject(fPrj XdsFolderConfig) ProjectConfig { sts = fPrj.DataCloudSync.STSvrStatus switch fPrj.DataCloudSync.STLocStatus { - case StatusErrorConfig, StatusDisable, StatusPause: + case apiv1.StatusErrorConfig, apiv1.StatusDisable, apiv1.StatusPause: sts = fPrj.DataCloudSync.STLocStatus break - case StatusSyncing: - if sts != StatusErrorConfig && sts != StatusDisable && sts != StatusPause { - sts = StatusSyncing + case apiv1.StatusSyncing: + if sts != apiv1.StatusErrorConfig && sts != apiv1.StatusDisable && sts != apiv1.StatusPause { + sts = apiv1.StatusSyncing } break - case StatusEnable: + case apiv1.StatusEnable: // keep STSvrStatus break } } - pPrj := ProjectConfig{ + pPrj := apiv1.ProjectConfig{ ID: fPrj.ID, ServerID: xs.ID, Label: fPrj.Label, ClientPath: fPrj.ClientPath, ServerPath: fPrj.DataPathMap.ServerPath, - Type: ProjectType(fPrj.Type), + Type: apiv1.ProjectType(fPrj.Type), Status: sts, IsInSync: inSync, DefaultSdk: fPrj.DefaultSdk, + ClientData: fPrj.ClientData, } return pPrj } @@ -463,24 +510,6 @@ func (xs *XdsServer) _CreateConnectHTTP() error { return nil } -// _HTTPGet . -func (xs *XdsServer) _HTTPGet(url string, data interface{}) error { - var dd []byte - if err := xs.client.HTTPGet(url, &dd); err != nil { - return err - } - return json.Unmarshal(dd, &data) -} - -// _HTTPPost . -func (xs *XdsServer) _HTTPPost(url string, data interface{}) (*http.Response, error) { - body, err := json.Marshal(data) - if err != nil { - return nil, err - } - return xs.client.HTTPPostWithRes(url, string(body)) -} - // Re-established connection func (xs *XdsServer) _reconnect() error { err := xs._connect(true) @@ -495,7 +524,7 @@ func (xs *XdsServer) _reconnect() error { func (xs *XdsServer) _connect(reConn bool) error { xdsCfg := XdsServerConfig{} - if err := xs._HTTPGet("/config", &xdsCfg); err != nil { + if err := xs.client.Get("/config", &xdsCfg); err != nil { xs.Connected = false if !reConn { xs._NotifyState() @@ -589,7 +618,7 @@ func (xs *XdsServer) _SocketConnect() error { // Send event to notify changes func (xs *XdsServer) _NotifyState() { - evSts := ServerCfg{ + evSts := apiv1.ServerCfg{ ID: xs.ID, URL: xs.BaseURL, APIURL: xs.APIURL, @@ -597,7 +626,7 @@ func (xs *XdsServer) _NotifyState() { ConnRetry: xs.ConnRetry, Connected: xs.Connected, } - if err := xs.events.Emit(EVTServerConfig, evSts); err != nil { + if err := xs.events.Emit(apiv1.EVTServerConfig, evSts, ""); err != nil { xs.Log.Warningf("Cannot notify XdsServer state change: %v", err) } }