diff options
Diffstat (limited to 'lib/apiv1/make.go')
-rw-r--r-- | lib/apiv1/make.go | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/lib/apiv1/make.go b/lib/apiv1/make.go new file mode 100644 index 0000000..eac6210 --- /dev/null +++ b/lib/apiv1/make.go @@ -0,0 +1,151 @@ +package apiv1 + +import ( + "net/http" + + "time" + + "strconv" + + "github.com/gin-gonic/gin" + "github.com/iotbzh/xds-server/lib/common" +) + +// MakeArgs is the parameters (json format) of /make command +type MakeArgs struct { + ID string `json:"id"` + RPath string `json:"rpath"` // relative path into project + Args string `json:"args"` + 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"` +} + +// Event name send in WS +const MakeOutEvent = "make:output" +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 + id := c.Param("id") + if id == "" { + id = args.ID + } + if id == "" { + common.APIError(c, "Invalid id") + return + } + + prj := s.cfg.GetFolderFromID(id) + if prj == nil { + common.APIError(c, "Unknown id") + return + } + + execTmo := args.CmdTimeout + if execTmo == 0 { + // TODO get default timeout from config.json file + execTmo = 24 * 60 * 60 // 1 day + } + + cmd := "cd " + prj.GetFullPath(args.RPath) + " && make" + if args.Args != "" { + cmd += " " + args.Args + } + + // Define callback for output + var oCB common.EmitOutputCB + oCB = func(sid string, id int, stdout, stderr string) { + // 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:%d", MakeOutEvent, sid, id) + return + } + s.log.Debugf("%s emitted - WS sid %s - id:%d", MakeOutEvent, sid, id) + + // FIXME replace by .BroadcastTo a room + err := (*so).Emit(MakeOutEvent, MakeOutMsg{ + CmdID: strconv.Itoa(id), + 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, id int, code int, err error) { + s.log.Debugf("Command [Cmd ID %d] exited: code %d, error: %v", id, 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:%d", MakeExitEvent, id) + return + } + + // FIXME replace by .BroadcastTo a room + e := (*so).Emit(MakeExitEvent, MakeExitMsg{ + CmdID: strconv.Itoa(id), + Timestamp: time.Now().String(), + Code: code, + Error: err, + }) + if e != nil { + s.log.Errorf("WS Emit : %v", e) + } + } + + cmdID := makeCommandID + makeCommandID++ + + s.log.Debugf("Execute [Cmd ID %d]: %v", cmdID, cmd) + err := common.ExecPipeWs(cmd, sop, sess.ID, cmdID, execTmo, s.log, oCB, eCB) + if err != nil { + common.APIError(c, err.Error()) + return + } + + c.JSON(http.StatusOK, + gin.H{ + "status": "OK", + "cmdID": cmdID, + }) +} |