"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) {
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 {
// 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
return
}
c.JSON(http.StatusOK, string(body))
-
}