aboutsummaryrefslogtreecommitdiffstats
path: root/lib/apiv1
diff options
context:
space:
mode:
authorSebastien Douheret <sebastien.douheret@iot.bzh>2017-11-29 08:54:00 +0100
committerSebastien Douheret <sebastien.douheret@iot.bzh>2017-11-29 11:10:30 +0100
commit2f7828d01f4c4ca2909f95f098627cd5475ed225 (patch)
treeb5e71920b813b95cae3e32044be08b99223348ec /lib/apiv1
parent5caebfb4b7c3b73988f067082b219ce5b7f409ba (diff)
Refit source files to have a public xs-apiv1 lib package.
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'lib/apiv1')
-rw-r--r--lib/apiv1/apiv1.go63
-rw-r--r--lib/apiv1/config.go40
-rw-r--r--lib/apiv1/events.go162
-rw-r--r--lib/apiv1/exec.go416
-rw-r--r--lib/apiv1/folders.go131
-rw-r--r--lib/apiv1/make.go215
-rw-r--r--lib/apiv1/sdks.go29
-rw-r--r--lib/apiv1/version.go26
8 files changed, 0 insertions, 1082 deletions
diff --git a/lib/apiv1/apiv1.go b/lib/apiv1/apiv1.go
deleted file mode 100644
index fffed2d..0000000
--- a/lib/apiv1/apiv1.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package apiv1
-
-import (
- "github.com/Sirupsen/logrus"
- "github.com/gin-gonic/gin"
-
- "github.com/iotbzh/xds-server/lib/crosssdk"
- "github.com/iotbzh/xds-server/lib/model"
- "github.com/iotbzh/xds-server/lib/session"
- "github.com/iotbzh/xds-server/lib/xdsconfig"
-)
-
-// APIService .
-type APIService struct {
- router *gin.Engine
- apiRouter *gin.RouterGroup
- sessions *session.Sessions
- cfg *xdsconfig.Config
- mfolders *model.Folders
- sdks *crosssdk.SDKs
- log *logrus.Logger
-}
-
-// New creates a new instance of API service
-func New(r *gin.Engine, sess *session.Sessions, cfg *xdsconfig.Config, mfolders *model.Folders, sdks *crosssdk.SDKs) *APIService {
- s := &APIService{
- router: r,
- sessions: sess,
- apiRouter: r.Group("/api/v1"),
- cfg: cfg,
- mfolders: mfolders,
- sdks: sdks,
- log: cfg.Log,
- }
-
- s.apiRouter.GET("/version", s.getVersion)
-
- s.apiRouter.GET("/config", s.getConfig)
- s.apiRouter.POST("/config", s.setConfig)
-
- s.apiRouter.GET("/folders", s.getFolders)
- s.apiRouter.GET("/folders/:id", s.getFolder)
- s.apiRouter.PUT("/folders/:id", s.updateFolder)
- s.apiRouter.POST("/folders", s.addFolder)
- s.apiRouter.POST("/folders/sync/:id", s.syncFolder)
- s.apiRouter.DELETE("/folders/:id", s.delFolder)
-
- s.apiRouter.GET("/sdks", s.getSdks)
- s.apiRouter.GET("/sdks/:id", s.getSdk)
-
- s.apiRouter.POST("/make", s.buildMake)
- s.apiRouter.POST("/make/:id", s.buildMake)
-
- s.apiRouter.POST("/exec", s.execCmd)
- s.apiRouter.POST("/exec/:id", s.execCmd)
- s.apiRouter.POST("/signal", s.execSignalCmd)
-
- s.apiRouter.GET("/events", s.eventsList)
- s.apiRouter.POST("/events/register", s.eventsRegister)
- s.apiRouter.POST("/events/unregister", s.eventsUnRegister)
-
- return s
-}
diff --git a/lib/apiv1/config.go b/lib/apiv1/config.go
deleted file mode 100644
index 4b53217..0000000
--- a/lib/apiv1/config.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package apiv1
-
-import (
- "net/http"
- "sync"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
- "github.com/iotbzh/xds-server/lib/xdsconfig"
-)
-
-var confMut sync.Mutex
-
-// GetConfig returns server configuration
-func (s *APIService) getConfig(c *gin.Context) {
- confMut.Lock()
- defer confMut.Unlock()
-
- c.JSON(http.StatusOK, s.cfg)
-}
-
-// SetConfig sets server configuration
-func (s *APIService) setConfig(c *gin.Context) {
- // FIXME - must be tested
- c.JSON(http.StatusNotImplemented, "Not implemented")
-
- var cfgArg xdsconfig.Config
-
- if c.BindJSON(&cfgArg) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- confMut.Lock()
- defer confMut.Unlock()
-
- s.log.Debugln("SET config: ", cfgArg)
-
- common.APIError(c, "Not Supported")
-}
diff --git a/lib/apiv1/events.go b/lib/apiv1/events.go
deleted file mode 100644
index d837571..0000000
--- a/lib/apiv1/events.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package apiv1
-
-import (
- "net/http"
- "strings"
- "time"
-
- "github.com/iotbzh/xds-server/lib/folder"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
-)
-
-// EventArgs is the parameters (json format) of /events/register command
-type EventRegisterArgs struct {
- Name string `json:"name"`
- ProjectID string `json:"filterProjectID"`
-}
-
-type EventUnRegisterArgs struct {
- Name string `json:"name"`
- ID int `json:"id"`
-}
-
-// EventMsg Message send
-type EventMsg struct {
- Time string `json:"time"`
- Type string `json:"type"`
- Folder folder.FolderConfig `json:"folder"`
-}
-
-// EventEvent Event send in WS when an internal event (eg. Syncthing event is received)
-const (
- // EventTypePrefix Used as event prefix
- EventTypePrefix = "event:" // following by event type
-
- // Supported Events type
- EVTAll = EventTypePrefix + "all"
- EVTFolderChange = EventTypePrefix + "folder-change" // type EventMsg with Data type apiv1.???
- EVTFolderStateChange = EventTypePrefix + "folder-state-change" // type EventMsg with Data type apiv1.???
-)
-
-// eventsList Registering for events that will be send over a WS
-func (s *APIService) eventsList(c *gin.Context) {
-
-}
-
-// eventsRegister Registering for events that will be send over a WS
-func (s *APIService) eventsRegister(c *gin.Context) {
- var args EventRegisterArgs
-
- if c.BindJSON(&args) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- sess := s.sessions.Get(c)
- if sess == nil {
- common.APIError(c, "Unknown sessions")
- return
- }
-
- evType := strings.TrimPrefix(EVTFolderStateChange, EventTypePrefix)
- if args.Name != evType {
- common.APIError(c, "Unsupported event name")
- return
- }
-
- /* XXX - to be removed if no plan to support "generic" event
- var cbFunc st.EventsCB
- cbFunc = func(ev st.Event, data *st.EventsCBData) {
-
- evid, _ := strconv.Atoi((*data)["id"].(string))
- ssid := (*data)["sid"].(string)
- so := s.sessions.IOSocketGet(ssid)
- if so == nil {
- s.log.Infof("Event %s not emitted - sid: %s", ev.Type, ssid)
-
- // Consider that client disconnected, so unregister this event
- s.mfolders.SThg.Events.UnRegister(ev.Type, evid)
- return
- }
-
- msg := EventMsg{
- Time: ev.Time,
- Type: ev.Type,
- Data: ev.Data,
- }
-
- if err := (*so).Emit(EVTAll, msg); err != nil {
- s.log.Errorf("WS Emit Event : %v", err)
- }
-
- if err := (*so).Emit(EventTypePrefix+ev.Type, msg); err != nil {
- s.log.Errorf("WS Emit Event : %v", err)
- }
- }
-
- data := make(st.EventsCBData)
- data["sid"] = sess.ID
-
- id, err := s.mfolders.SThg.Events.Register(args.Name, cbFunc, args.ProjectID, &data)
- */
-
- var cbFunc folder.EventCB
- cbFunc = func(cfg *folder.FolderConfig, data *folder.EventCBData) {
- ssid := (*data)["sid"].(string)
- so := s.sessions.IOSocketGet(ssid)
- if so == nil {
- //s.log.Infof("Event %s not emitted - sid: %s", ev.Type, ssid)
-
- // Consider that client disconnected, so unregister this event
- // SEB FIXMEs.mfolders.RegisterEventChange(ev.Type)
- return
- }
-
- msg := EventMsg{
- Time: time.Now().String(),
- Type: evType,
- Folder: *cfg,
- }
-
- s.log.Debugf("WS Emit %s - Status=%10s, IsInSync=%6v, ID=%s",
- EventTypePrefix+evType, cfg.Status, cfg.IsInSync, cfg.ID)
-
- if err := (*so).Emit(EventTypePrefix+evType, msg); err != nil {
- s.log.Errorf("WS Emit Folder StateChanged event : %v", err)
- }
- }
- data := make(folder.EventCBData)
- data["sid"] = sess.ID
-
- prjID, err := s.mfolders.ResolveID(args.ProjectID)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- if err = s.mfolders.RegisterEventChange(prjID, &cbFunc, &data); err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- c.JSON(http.StatusOK, gin.H{"status": "OK"})
-}
-
-// eventsRegister Registering for events that will be send over a WS
-func (s *APIService) eventsUnRegister(c *gin.Context) {
- var args EventUnRegisterArgs
-
- if c.BindJSON(&args) != nil || args.Name == "" || args.ID < 0 {
- common.APIError(c, "Invalid arguments")
- return
- }
- /* TODO
- if err := s.mfolders.SThg.Events.UnRegister(args.Name, args.ID); err != nil {
- common.APIError(c, err.Error())
- return
- }
- c.JSON(http.StatusOK, gin.H{"status": "OK"})
- */
- common.APIError(c, "Not implemented yet")
-}
diff --git a/lib/apiv1/exec.go b/lib/apiv1/exec.go
deleted file mode 100644
index baf431f..0000000
--- a/lib/apiv1/exec.go
+++ /dev/null
@@ -1,416 +0,0 @@
-package apiv1
-
-import (
- "fmt"
- "net/http"
- "os"
- "regexp"
- "strconv"
- "strings"
- "time"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
- "github.com/iotbzh/xds-common/golib/eows"
- "github.com/kr/pty"
-)
-
-type (
- // ExecArgs JSON parameters of /exec command
- ExecArgs struct {
- ID string `json:"id" binding:"required"`
- SdkID string `json:"sdkID"` // sdk ID to use for setting env
- CmdID string `json:"cmdID"` // command unique ID
- Cmd string `json:"cmd" binding:"required"`
- Args []string `json:"args"`
- Env []string `json:"env"`
- RPath string `json:"rpath"` // relative path into project
- TTY bool `json:"tty"` // Use a tty, specific to gdb --tty option
- TTYGdbserverFix bool `json:"ttyGdbserverFix"` // Set to true to activate gdbserver workaround about inferior output
- ExitImmediate bool `json:"exitImmediate"` // when true, exit event sent immediately when command exited (IOW, don't wait file synchronization)
- CmdTimeout int `json:"timeout"` // command completion timeout in Second
- }
-
- // ExecRes JSON result of /exec command
- ExecRes struct {
- Status string `json:"status"` // status OK
- CmdID string `json:"cmdID"` // command unique ID
- }
-
- // ExecSigRes JSON result of /signal command
- ExecSigRes struct {
- Status string `json:"status"` // status OK
- CmdID string `json:"cmdID"` // command unique ID
- }
-
- // ExecInMsg Message used to received input characters (stdin)
- ExecInMsg struct {
- CmdID string `json:"cmdID"`
- Timestamp string `json:"timestamp"`
- Stdin string `json:"stdin"`
- }
-
- // ExecOutMsg Message used to send output characters (stdout+stderr)
- ExecOutMsg struct {
- CmdID string `json:"cmdID"`
- Timestamp string `json:"timestamp"`
- Stdout string `json:"stdout"`
- Stderr string `json:"stderr"`
- }
-
- // ExecExitMsg Message sent when executed command exited
- ExecExitMsg struct {
- CmdID string `json:"cmdID"`
- Timestamp string `json:"timestamp"`
- Code int `json:"code"`
- Error error `json:"error"`
- }
-
- // ExecSignalArgs JSON parameters of /exec/signal command
- ExecSignalArgs struct {
- CmdID string `json:"cmdID" binding:"required"` // command id
- Signal string `json:"signal" binding:"required"` // signal number
- }
-)
-
-const (
- // ExecInEvent Event send in WS when characters are sent (stdin)
- ExecInEvent = "exec:input"
-
- // ExecOutEvent Event send in WS when characters are received (stdout or stderr)
- ExecOutEvent = "exec:output"
-
- // ExecExitEvent Event send in WS when program exited
- ExecExitEvent = "exec:exit"
-
- // ExecInferiorInEvent Event send in WS when characters are sent to an inferior (used by gdb inferior/tty)
- ExecInferiorInEvent = "exec:inferior-input"
-
- // ExecInferiorOutEvent Event send in WS when characters are received by an inferior
- ExecInferiorOutEvent = "exec:inferior-output"
-)
-
-var execCommandID = 1
-
-// ExecCmd executes remotely a command
-func (s *APIService) execCmd(c *gin.Context) {
- var gdbPty, gdbTty *os.File
- var err error
- var args ExecArgs
- if c.BindJSON(&args) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- // TODO: add permission ?
-
- // Retrieve session info
- sess := s.sessions.Get(c)
- if sess == nil {
- common.APIError(c, "Unknown sessions")
- return
- }
- sop := sess.IOSocket
- if sop == nil {
- common.APIError(c, "Websocket not established")
- return
- }
-
- // Allow to pass id in url (/exec/:id) or as JSON argument
- idArg := c.Param("id")
- if idArg == "" {
- idArg = args.ID
- }
- if idArg == "" {
- common.APIError(c, "Invalid id")
- return
- }
- id, err := s.mfolders.ResolveID(idArg)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- f := s.mfolders.Get(id)
- if f == nil {
- common.APIError(c, "Unknown id")
- return
- }
- fld := *f
- prj := fld.GetConfig()
-
- // Build command line
- cmd := []string{}
- // Setup env var regarding Sdk ID (used for example to setup cross toolchain)
- if envCmd := s.sdks.GetEnvCmd(args.SdkID, prj.DefaultSdk); len(envCmd) > 0 {
- cmd = append(cmd, envCmd...)
- cmd = append(cmd, "&&")
- } else {
- // It's an error if no envcmd found while a sdkid has been provided
- if args.SdkID != "" {
- common.APIError(c, "Unknown sdkid")
- return
- }
- }
-
- cmd = append(cmd, "cd", "\""+fld.GetFullPath(args.RPath)+"\"")
- // FIXME - add 'exec' prevents to use syntax:
- // xds-exec -l debug -c xds-config.env -- "cd build && cmake .."
- // but exec is mandatory to allow to pass correctly signals
- // As workaround, exec is set for now on client side (eg. in xds-gdb)
- //cmd = append(cmd, "&&", "exec", args.Cmd)
- cmd = append(cmd, "&&", args.Cmd)
-
- // Process command arguments
- cmdArgs := make([]string, len(args.Args)+1)
-
- // Copy and Translate path from client to server
- for _, aa := range args.Args {
- if strings.Contains(aa, prj.ClientPath) {
- cmdArgs = append(cmdArgs, fld.ConvPathCli2Svr(aa))
- } else {
- cmdArgs = append(cmdArgs, aa)
- }
- }
-
- // Allocate pts if tty if used
- if args.TTY {
- gdbPty, gdbTty, err = pty.Open()
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- s.log.Debugf("Client command tty: %v %v\n", gdbTty.Name(), gdbTty.Name())
- cmdArgs = append(cmdArgs, "--tty="+gdbTty.Name())
- }
-
- // Unique ID for each commands
- if args.CmdID == "" {
- args.CmdID = s.cfg.ServerUID[:18] + "_" + strconv.Itoa(execCommandID)
- execCommandID++
- }
-
- // Create new execution over WS context
- execWS := eows.New(strings.Join(cmd, " "), cmdArgs, sop, sess.ID, args.CmdID)
- execWS.Log = s.log
-
- // Append client project dir to environment
- execWS.Env = append(args.Env, "CLIENT_PROJECT_DIR="+prj.ClientPath)
-
- // Set command execution timeout
- if args.CmdTimeout == 0 {
- // 0 : default timeout
- // TODO get default timeout from config.json file
- execWS.CmdExecTimeout = 24 * 60 * 60 // 1 day
- } else {
- execWS.CmdExecTimeout = args.CmdTimeout
- }
-
- // Define callback for input (stdin)
- execWS.InputEvent = ExecInEvent
- execWS.InputCB = func(e *eows.ExecOverWS, stdin string) (string, error) {
- s.log.Debugf("STDIN <<%v>>", strings.Replace(stdin, "\n", "\\n", -1))
-
- // Handle Ctrl-D
- if len(stdin) == 1 && stdin == "\x04" {
- // Close stdin
- errMsg := fmt.Errorf("close stdin: %v", stdin)
- return "", errMsg
- }
-
- // Set correct path
- data := e.UserData
- prjID := (*data)["ID"].(string)
- f := s.mfolders.Get(prjID)
- if f == nil {
- s.log.Errorf("InputCB: Cannot get folder ID %s", prjID)
- } else {
- // Translate paths from client to server
- stdin = (*f).ConvPathCli2Svr(stdin)
- }
-
- return stdin, nil
- }
-
- // Define callback for output (stdout+stderr)
- execWS.OutputCB = func(e *eows.ExecOverWS, stdout, stderr string) {
- // IO socket can be nil when disconnected
- so := s.sessions.IOSocketGet(e.Sid)
- if so == nil {
- s.log.Infof("%s not emitted: WS closed (sid:%s, msgid:%s)", ExecOutEvent, e.Sid, e.CmdID)
- return
- }
-
- // Retrieve project ID and RootPath
- data := e.UserData
- prjID := (*data)["ID"].(string)
- gdbServerTTY := (*data)["gdbServerTTY"].(string)
-
- f := s.mfolders.Get(prjID)
- if f == nil {
- s.log.Errorf("OutputCB: Cannot get folder ID %s", prjID)
- } else {
- // Translate paths from server to client
- stdout = (*f).ConvPathSvr2Cli(stdout)
- stderr = (*f).ConvPathSvr2Cli(stderr)
- }
-
- s.log.Debugf("%s emitted - WS sid[4:] %s - id:%s - prjID:%s", ExecOutEvent, e.Sid[4:], e.CmdID, prjID)
- if stdout != "" {
- s.log.Debugf("STDOUT <<%v>>", strings.Replace(stdout, "\n", "\\n", -1))
- }
- if stderr != "" {
- s.log.Debugf("STDERR <<%v>>", strings.Replace(stderr, "\n", "\\n", -1))
- }
-
- // FIXME replace by .BroadcastTo a room
- err := (*so).Emit(ExecOutEvent, ExecOutMsg{
- CmdID: e.CmdID,
- Timestamp: time.Now().String(),
- Stdout: stdout,
- Stderr: stderr,
- })
- if err != nil {
- s.log.Errorf("WS Emit : %v", err)
- }
-
- // XXX - Workaround due to gdbserver bug that doesn't redirect
- // inferior output (https://bugs.eclipse.org/bugs/show_bug.cgi?id=437532#c13)
- if gdbServerTTY == "workaround" && len(stdout) > 1 && stdout[0] == '&' {
-
- // Extract and cleanup string like &"bla bla\n"
- re := regexp.MustCompile("&\"(.*)\"")
- rer := re.FindAllStringSubmatch(stdout, -1)
- out := ""
- if rer != nil && len(rer) > 0 {
- for _, o := range rer {
- if len(o) >= 1 {
- out = strings.Replace(o[1], "\\n", "\n", -1)
- out = strings.Replace(out, "\\r", "\r", -1)
- out = strings.Replace(out, "\\t", "\t", -1)
-
- s.log.Debugf("STDOUT INFERIOR: <<%v>>", out)
- err := (*so).Emit(ExecInferiorOutEvent, ExecOutMsg{
- CmdID: e.CmdID,
- Timestamp: time.Now().String(),
- Stdout: out,
- Stderr: "",
- })
- if err != nil {
- s.log.Errorf("WS Emit : %v", err)
- }
- }
- }
- } else {
- s.log.Errorf("INFERIOR out parsing error: stdout=<%v>", stdout)
- }
- }
- }
-
- // Define callback for output
- execWS.ExitCB = func(e *eows.ExecOverWS, code int, err error) {
- s.log.Debugf("Command [Cmd ID %s] exited: code %d, error: %v", e.CmdID, code, err)
-
- // Close client tty
- defer func() {
- if gdbPty != nil {
- gdbPty.Close()
- }
- if gdbTty != nil {
- gdbTty.Close()
- }
- }()
-
- // IO socket can be nil when disconnected
- so := s.sessions.IOSocketGet(e.Sid)
- if so == nil {
- s.log.Infof("%s not emitted - WS closed (id:%s)", ExecExitEvent, e.CmdID)
- return
- }
-
- // Retrieve project ID and RootPath
- data := e.UserData
- prjID := (*data)["ID"].(string)
- exitImm := (*data)["ExitImmediate"].(bool)
-
- // XXX - workaround to be sure that Syncthing detected all changes
- if err := s.mfolders.ForceSync(prjID); err != nil {
- s.log.Errorf("Error while syncing folder %s: %v", prjID, err)
- }
- if !exitImm {
- // Wait end of file sync
- // FIXME pass as argument
- tmo := 60
- for t := tmo; t > 0; t-- {
- s.log.Debugf("Wait file in-sync for %s (%d/%d)", prjID, t, tmo)
- if sync, err := s.mfolders.IsFolderInSync(prjID); sync || err != nil {
- if err != nil {
- s.log.Errorf("ERROR IsFolderInSync (%s): %v", prjID, err)
- }
- break
- }
- time.Sleep(time.Second)
- }
- s.log.Debugf("OK file are synchronized.")
- }
-
- // FIXME replace by .BroadcastTo a room
- errSoEmit := (*so).Emit(ExecExitEvent, ExecExitMsg{
- CmdID: e.CmdID,
- Timestamp: time.Now().String(),
- Code: code,
- Error: err,
- })
- if errSoEmit != nil {
- s.log.Errorf("WS Emit : %v", errSoEmit)
- }
- }
-
- // User data (used within callbacks)
- data := make(map[string]interface{})
- data["ID"] = prj.ID
- data["ExitImmediate"] = args.ExitImmediate
- if args.TTY && args.TTYGdbserverFix {
- data["gdbServerTTY"] = "workaround"
- } else {
- data["gdbServerTTY"] = ""
- }
- execWS.UserData = &data
-
- // Start command execution
- s.log.Infof("Execute [Cmd ID %s]: %v %v", execWS.CmdID, execWS.Cmd, execWS.Args)
-
- err = execWS.Start()
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- c.JSON(http.StatusOK, ExecRes{Status: "OK", CmdID: execWS.CmdID})
-}
-
-// ExecCmd executes remotely a command
-func (s *APIService) execSignalCmd(c *gin.Context) {
- var args ExecSignalArgs
-
- if c.BindJSON(&args) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- s.log.Debugf("Signal %s for command ID %s", args.Signal, args.CmdID)
-
- e := eows.GetEows(args.CmdID)
- if e == nil {
- common.APIError(c, "unknown cmdID")
- return
- }
-
- err := e.Signal(args.Signal)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- c.JSON(http.StatusOK, ExecSigRes{Status: "OK", CmdID: args.CmdID})
-}
diff --git a/lib/apiv1/folders.go b/lib/apiv1/folders.go
deleted file mode 100644
index 073445c..0000000
--- a/lib/apiv1/folders.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package apiv1
-
-import (
- "net/http"
- "os"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
- "github.com/iotbzh/xds-server/lib/folder"
-)
-
-// getFolders returns all folders configuration
-func (s *APIService) getFolders(c *gin.Context) {
- c.JSON(http.StatusOK, s.mfolders.GetConfigArr())
-}
-
-// getFolder returns a specific folder configuration
-func (s *APIService) getFolder(c *gin.Context) {
- id, err := s.mfolders.ResolveID(c.Param("id"))
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- f := s.mfolders.Get(id)
- if f == nil {
- common.APIError(c, "Invalid id")
- return
- }
-
- c.JSON(http.StatusOK, (*f).GetConfig())
-}
-
-// addFolder adds a new folder to server config
-func (s *APIService) addFolder(c *gin.Context) {
- var cfgArg folder.FolderConfig
- if c.BindJSON(&cfgArg) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- s.log.Debugln("Add folder config: ", cfgArg)
-
- newFld, err := s.mfolders.Add(cfgArg)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- // Create xds-project.conf file
- // FIXME: move to folders.createUpdate func (but gin context needed)
- fld := s.mfolders.Get(newFld.ID)
- prjConfFile := (*fld).GetFullPath("xds-project.conf")
- if !common.Exists(prjConfFile) {
- fd, err := os.OpenFile(prjConfFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- fd.WriteString("# XDS project settings\n")
- fd.WriteString("export XDS_SERVER_URL=" + c.Request.Host + "\n")
- fd.WriteString("export XDS_PROJECT_ID=" + newFld.ID + "\n")
- if newFld.DefaultSdk == "" {
- sdks := s.sdks.GetAll()
- newFld.DefaultSdk = sdks[0].ID
- }
- fd.WriteString("export XDS_SDK_ID=" + newFld.DefaultSdk + "\n")
- fd.Close()
- }
-
- c.JSON(http.StatusOK, newFld)
-}
-
-// syncFolder force synchronization of folder files
-func (s *APIService) syncFolder(c *gin.Context) {
- id, err := s.mfolders.ResolveID(c.Param("id"))
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- s.log.Debugln("Sync folder id: ", id)
-
- err = s.mfolders.ForceSync(id)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- c.JSON(http.StatusOK, "")
-}
-
-// delFolder deletes folder from server config
-func (s *APIService) delFolder(c *gin.Context) {
- id, err := s.mfolders.ResolveID(c.Param("id"))
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- s.log.Debugln("Delete folder id ", id)
-
- delEntry, err := s.mfolders.Delete(id)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- c.JSON(http.StatusOK, delEntry)
-}
-
-// updateFolder update some field of a folder
-func (s *APIService) updateFolder(c *gin.Context) {
- id, err := s.mfolders.ResolveID(c.Param("id"))
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- s.log.Debugln("Update folder id ", id)
-
- var cfgArg folder.FolderConfig
- if c.BindJSON(&cfgArg) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- upFld, err := s.mfolders.Update(id, cfgArg)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- c.JSON(http.StatusOK, upFld)
-}
diff --git a/lib/apiv1/make.go b/lib/apiv1/make.go
deleted file mode 100644
index 6e0c7d6..0000000
--- a/lib/apiv1/make.go
+++ /dev/null
@@ -1,215 +0,0 @@
-package apiv1
-
-import (
- "net/http"
- "strings"
-
- "time"
-
- "strconv"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
-)
-
-// MakeArgs is the parameters (json format) of /make command
-type MakeArgs struct {
- ID string `json:"id"`
- SdkID string `json:"sdkID"` // sdk ID to use for setting env
- CmdID string `json:"cmdID"` // command unique ID
- Args []string `json:"args"` // args to pass to make command
- Env []string `json:"env"`
- RPath string `json:"rpath"` // relative path into project
- ExitImmediate bool `json:"exitImmediate"` // when true, exit event sent immediately when command exited (IOW, don't wait file synchronization)
- CmdTimeout int `json:"timeout"` // command completion timeout in Second
-}
-
-// MakeOutMsg Message send on each output (stdout+stderr) of make command
-type MakeOutMsg struct {
- CmdID string `json:"cmdID"`
- Timestamp string `json:"timestamp"`
- Stdout string `json:"stdout"`
- Stderr string `json:"stderr"`
-}
-
-// MakeExitMsg Message send on make command exit
-type MakeExitMsg struct {
- CmdID string `json:"cmdID"`
- Timestamp string `json:"timestamp"`
- Code int `json:"code"`
- Error error `json:"error"`
-}
-
-// MakeOutEvent Event send in WS when characters are received on stdout/stderr
-const MakeOutEvent = "make:output"
-
-// MakeExitEvent Event send in WS when command exited
-const MakeExitEvent = "make:exit"
-
-var makeCommandID = 1
-
-func (s *APIService) buildMake(c *gin.Context) {
- var args MakeArgs
-
- if c.BindJSON(&args) != nil {
- common.APIError(c, "Invalid arguments")
- return
- }
-
- sess := s.sessions.Get(c)
- if sess == nil {
- common.APIError(c, "Unknown sessions")
- return
- }
- sop := sess.IOSocket
- if sop == nil {
- common.APIError(c, "Websocket not established")
- return
- }
-
- // Allow to pass id in url (/make/:id) or as JSON argument
- idArg := c.Param("id")
- if idArg == "" {
- idArg = args.ID
- }
- if idArg == "" {
- common.APIError(c, "Invalid id")
- return
- }
- id, err := s.mfolders.ResolveID(idArg)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- pf := s.mfolders.Get(id)
- if pf == nil {
- common.APIError(c, "Unknown id")
- return
- }
- folder := *pf
- prj := folder.GetConfig()
-
- execTmo := args.CmdTimeout
- if execTmo == 0 {
- // TODO get default timeout from config.json file
- execTmo = 24 * 60 * 60 // 1 day
- }
-
- // TODO merge all code below with exec.go
-
- // Define callback for output
- var oCB common.EmitOutputCB
- oCB = func(sid string, cmdID string, stdout, stderr string, data *map[string]interface{}) {
- // IO socket can be nil when disconnected
- so := s.sessions.IOSocketGet(sid)
- if so == nil {
- s.log.Infof("%s not emitted: WS closed - sid: %s - msg id:%s", MakeOutEvent, sid, cmdID)
- return
- }
-
- // Retrieve project ID and RootPath
- prjID := (*data)["ID"].(string)
- prjRootPath := (*data)["RootPath"].(string)
-
- // Cleanup any references to internal rootpath in stdout & stderr
- stdout = strings.Replace(stdout, prjRootPath, "", -1)
- stderr = strings.Replace(stderr, prjRootPath, "", -1)
-
- s.log.Debugf("%s emitted - WS sid %s - id:%d - prjID:%s", MakeOutEvent, sid, id, prjID)
-
- // FIXME replace by .BroadcastTo a room
- err := (*so).Emit(MakeOutEvent, MakeOutMsg{
- CmdID: cmdID,
- Timestamp: time.Now().String(),
- Stdout: stdout,
- Stderr: stderr,
- })
- if err != nil {
- s.log.Errorf("WS Emit : %v", err)
- }
- }
-
- // Define callback for output
- eCB := func(sid string, cmdID string, code int, err error, data *map[string]interface{}) {
- s.log.Debugf("Command [Cmd ID %s] exited: code %d, error: %v", cmdID, code, err)
-
- // IO socket can be nil when disconnected
- so := s.sessions.IOSocketGet(sid)
- if so == nil {
- s.log.Infof("%s not emitted - WS closed (id:%s", MakeExitEvent, cmdID)
- return
- }
-
- // Retrieve project ID and RootPath
- prjID := (*data)["ID"].(string)
- exitImm := (*data)["ExitImmediate"].(bool)
-
- // XXX - workaround to be sure that Syncthing detected all changes
- if err := s.mfolders.ForceSync(prjID); err != nil {
- s.log.Errorf("Error while syncing folder %s: %v", prjID, err)
- }
- if !exitImm {
- // Wait end of file sync
- // FIXME pass as argument
- tmo := 60
- for t := tmo; t > 0; t-- {
- s.log.Debugf("Wait file insync for %s (%d/%d)", prjID, t, tmo)
- if sync, err := s.mfolders.IsFolderInSync(prjID); sync || err != nil {
- if err != nil {
- s.log.Errorf("ERROR IsFolderInSync (%s): %v", prjID, err)
- }
- break
- }
- time.Sleep(time.Second)
- }
- }
-
- // FIXME replace by .BroadcastTo a room
- e := (*so).Emit(MakeExitEvent, MakeExitMsg{
- CmdID: id,
- Timestamp: time.Now().String(),
- Code: code,
- Error: err,
- })
- if e != nil {
- s.log.Errorf("WS Emit : %v", e)
- }
- }
-
- // Unique ID for each commands
- if args.CmdID == "" {
- args.CmdID = s.cfg.ServerUID[:18] + "_" + strconv.Itoa(makeCommandID)
- makeCommandID++
- }
- cmd := []string{}
-
- // Retrieve env command regarding Sdk ID
- if envCmd := s.sdks.GetEnvCmd(args.SdkID, prj.DefaultSdk); len(envCmd) > 0 {
- cmd = append(cmd, envCmd...)
- cmd = append(cmd, "&&")
- }
-
- cmd = append(cmd, "cd", folder.GetFullPath(args.RPath), "&&", "make")
- if len(args.Args) > 0 {
- cmd = append(cmd, args.Args...)
- }
-
- s.log.Debugf("Execute [Cmd ID %d]: %v", args.CmdID, cmd)
-
- data := make(map[string]interface{})
- data["ID"] = prj.ID
- data["RootPath"] = prj.RootPath
- data["ExitImmediate"] = args.ExitImmediate
-
- err = common.ExecPipeWs(cmd, args.Env, sop, sess.ID, args.CmdID, execTmo, s.log, oCB, eCB, &data)
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
-
- c.JSON(http.StatusOK,
- gin.H{
- "status": "OK",
- "cmdID": args.CmdID,
- })
-}
diff --git a/lib/apiv1/sdks.go b/lib/apiv1/sdks.go
deleted file mode 100644
index f67a0ef..0000000
--- a/lib/apiv1/sdks.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package apiv1
-
-import (
- "net/http"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
-)
-
-// getSdks returns all SDKs configuration
-func (s *APIService) getSdks(c *gin.Context) {
- c.JSON(http.StatusOK, s.sdks.GetAll())
-}
-
-// getSdk returns a specific Sdk configuration
-func (s *APIService) getSdk(c *gin.Context) {
- id, err := s.sdks.ResolveID(c.Param("id"))
- if err != nil {
- common.APIError(c, err.Error())
- return
- }
- sdk := s.sdks.Get(id)
- if sdk.Profile == "" {
- common.APIError(c, "Invalid id")
- return
- }
-
- c.JSON(http.StatusOK, sdk)
-}
diff --git a/lib/apiv1/version.go b/lib/apiv1/version.go
deleted file mode 100644
index 8f928ec..0000000
--- a/lib/apiv1/version.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package apiv1
-
-import (
- "net/http"
-
- "github.com/gin-gonic/gin"
-)
-
-type version struct {
- ID string `json:"id"`
- Version string `json:"version"`
- APIVersion string `json:"apiVersion"`
- VersionGitTag string `json:"gitTag"`
-}
-
-// getInfo : return various information about server
-func (s *APIService) getVersion(c *gin.Context) {
- response := version{
- ID: s.cfg.ServerUID,
- Version: s.cfg.Version,
- APIVersion: s.cfg.APIVersion,
- VersionGitTag: s.cfg.VersionGitTag,
- }
-
- c.JSON(http.StatusOK, response)
-}