X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=lib%2Fagent%2Fapiv1-exec.go;h=c1992675df7688f7308b55cb9271cd6b4aac133b;hb=02aec942b44eecd2ea9b311bb4ba2d60cce21e9a;hp=83ec7aa008cfea09cc93ff91d50260cbd59bc4d4;hpb=97ca1f277dc8b6973d6fa67add5593a9c395ce60;p=src%2Fxds%2Fxds-agent.git diff --git a/lib/agent/apiv1-exec.go b/lib/agent/apiv1-exec.go index 83ec7aa..c199267 100644 --- a/lib/agent/apiv1-exec.go +++ b/lib/agent/apiv1-exec.go @@ -6,13 +6,13 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/iotbzh/xds-agent/lib/apiv1" common "github.com/iotbzh/xds-common/golib" + uuid "github.com/satori/go.uuid" ) -// Only define useful fields -type ExecArgs struct { - ID string `json:"id" binding:"required"` -} +var execCmdID = 1 +var fwdFuncID []uuid.UUID // ExecCmd executes remotely a command func (s *APIService) execCmd(c *gin.Context) { @@ -24,23 +24,29 @@ func (s *APIService) execSignalCmd(c *gin.Context) { s._execRequest("/signal", c) } -func (s *APIService) _execRequest(url string, c *gin.Context) { +func (s *APIService) _execRequest(cmd string, c *gin.Context) { data, err := c.GetRawData() if err != nil { common.APIError(c, err.Error()) } + args := apiv1.ExecArgs{} + // XXX - we cannot use c.BindJSON, so directly unmarshall it + // (see https://github.com/gin-gonic/gin/issues/1078) + if err := json.Unmarshal(data, &args); err != nil { + common.APIError(c, "Invalid arguments") + return + } + // First get Project ID to retrieve Server ID and send command to right server - id := c.Param("id") - if id == "" { - args := ExecArgs{} - // XXX - we cannot use c.BindJSON, so directly unmarshall it - // (see https://github.com/gin-gonic/gin/issues/1078) - if err := json.Unmarshal(data, &args); err != nil { - common.APIError(c, "Invalid arguments") - return - } - id = args.ID + iid := c.Param("id") + if iid == "" { + iid = args.ID + } + id, err := s.projects.ResolveID(iid) + if err != nil { + common.APIError(c, err.Error()) + return } prj := s.projects.Get(id) if prj == nil { @@ -68,21 +74,67 @@ func (s *APIService) _execRequest(url string, c *gin.Context) { // Forward XDSServer WS events to client WS // TODO removed static event name list and get it from XDSServer - for _, evName := range []string{ - "exec:input", - "exec:output", - "exec:exit", - "exec:inferior-input", - "exec:inferior-output", - } { + evtList := []string{ + apiv1.ExecInEvent, + apiv1.ExecOutEvent, + apiv1.ExecInferiorInEvent, + apiv1.ExecInferiorOutEvent, + } + + for _, evName := range evtList { evN := evName - svr.EventOn(evN, func(evData interface{}) { - (*sock).Emit(evN, evData) - }) + fwdFunc := func(pData interface{}, evData interface{}) error { + sid := pData.(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)", evN, sid) + return nil + } + + // Forward event to Client/Dashboard + (*so).Emit(evN, evData) + return nil + } + id, err := svr.EventOn(evN, sess.ID, fwdFunc) + if err != nil { + common.APIError(c, err.Error()) + return + } + fwdFuncID = append(fwdFuncID, id) + } + + // Handle Exit event separately to cleanup registered listener + var exitFuncID uuid.UUID + exitFunc := func(pData interface{}, evData interface{}) error { + evN := apiv1.ExecExitEvent + sid := pData.(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)", evN, sid) + return nil + } + + (*so).Emit(evN, evData) + + // cleanup listener + for i, evName := range evtList { + svr.EventOff(evName, fwdFuncID[i]) + } + svr.EventOff(evN, exitFuncID) + + return nil + } + exitFuncID, err = svr.EventOn(apiv1.ExecExitEvent, sess.ID, exitFunc) + if err != nil { + common.APIError(c, err.Error()) + return } // Forward back command to right server - response, err := svr.HTTPPostBody(url, string(data)) + response, err := svr.SendCommand(cmd, data) if err != nil { common.APIError(c, err.Error()) return @@ -95,5 +147,4 @@ func (s *APIService) _execRequest(url string, c *gin.Context) { return } c.JSON(http.StatusOK, string(body)) - }