6 "github.com/franciscocpg/reflectme"
7 "github.com/gin-gonic/gin"
8 "github.com/iotbzh/xds-agent/lib/xaapiv1"
9 common "github.com/iotbzh/xds-common/golib"
10 "github.com/iotbzh/xds-server/lib/xsapiv1"
11 uuid "github.com/satori/go.uuid"
14 // ExecCmd executes remotely a command
15 func (s *APIService) execCmd(c *gin.Context) {
17 args := xaapiv1.ExecArgs{}
18 if err := c.BindJSON(&args); err != nil {
19 s.Log.Warningf("/exec invalid args, err=%v", err)
20 common.APIError(c, "Invalid arguments")
24 // First get Project ID to retrieve Server ID and send command to right server
29 id, err := s.projects.ResolveID(iid)
31 common.APIError(c, err.Error())
34 prj := s.projects.Get(id)
36 common.APIError(c, "Unknown id")
40 svr := (*prj).GetServer()
42 common.APIError(c, "Cannot identify XDS Server")
46 // Retrieve session info
47 sess := s.sessions.Get(c)
49 common.APIError(c, "Unknown sessions")
54 common.APIError(c, "Websocket not established")
58 // Forward input events from client to XDSServer through WS
59 // TODO use XDSServer events names definition
60 evtInList := []string{
62 xaapiv1.ExecInferiorInEvent,
64 for _, evName := range evtInList {
66 err := (*sock).On(evN, func(stdin string) {
68 s.Log.Debugf("EXEC EVENT IN (%s) <<%v>>", evN, stdin)
70 svr.EventEmit(evN, stdin)
73 msgErr := "Error while registering WS for " + evN + " event"
74 s.Log.Errorf(msgErr, ", err: %v", err)
75 common.APIError(c, msgErr)
80 // Forward output events from XDSServer to client through WS
81 // TODO use XDSServer events names definition
82 var fwdFuncID []uuid.UUID
83 evtOutList := []string{
85 xaapiv1.ExecInferiorOutEvent,
87 for _, evName := range evtOutList {
89 fwdFunc := func(pData interface{}, evData interface{}) error {
91 // IO socket can be nil when disconnected
92 so := s.sessions.IOSocketGet(sid)
94 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
98 // Add sessionID to event Data
99 reflectme.SetField(evData, "sessionID", sid)
102 s.Log.Debugf("EXEC EVENT OUT (%s) <<%v>>", evN, evData)
105 // Forward event to Client/Dashboard
106 (*so).Emit(evN, evData)
109 id, err := svr.EventOn(evN, sess.ID, fwdFunc)
111 common.APIError(c, err.Error())
114 fwdFuncID = append(fwdFuncID, id)
117 // Handle Exit event separately to cleanup registered listener
118 var exitFuncID uuid.UUID
119 exitFunc := func(privD interface{}, evData interface{}) error {
120 evN := xaapiv1.ExecExitEvent
122 pData := privD.(map[string]string)
123 sid := pData["sessID"]
124 prjID := pData["prjID"]
126 // Add sessionID to event Data
127 reflectme.SetField(evData, "sessionID", sid)
129 // IO socket can be nil when disconnected
130 so := s.sessions.IOSocketGet(sid)
132 (*so).Emit(evN, evData)
134 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
137 prj := s.projects.Get(prjID)
139 evD := evData.(map[string]interface{})
140 cmdIDData, cmdIDExist := evD["cmdID"]
141 svr := (*prj).GetServer()
142 if svr != nil && cmdIDExist {
143 svr.CommandDelete(cmdIDData.(string))
145 s.Log.Infof("%s: cannot retrieve server for sid=%s, prjID=%s, evD=%v", evN, sid, prjID, evD)
148 s.Log.Infof("%s: cannot retrieve project for sid=%s, prjID=%s", evN, sid, prjID)
152 for i, evName := range evtOutList {
153 svr.EventOff(evName, fwdFuncID[i])
155 svr.EventOff(evN, exitFuncID)
160 prjCfg := (*prj).GetProject()
161 privData := map[string]string{"sessID": sess.ID, "prjID": prjCfg.ID}
162 exitFuncID, err = svr.EventOn(xaapiv1.ExecExitEvent, privData, exitFunc)
164 common.APIError(c, err.Error())
168 // Forward back command to right server
169 res := xsapiv1.ExecResult{}
170 xsArgs := &xsapiv1.ExecArgs{
179 TTYGdbserverFix: args.TTYGdbserverFix,
180 ExitImmediate: args.ExitImmediate,
181 CmdTimeout: args.CmdTimeout,
183 if err := svr.CommandExec(xsArgs, &res); err != nil {
184 common.APIError(c, err.Error())
188 // Add command to running commands list
189 if err := svr.CommandAdd(res.CmdID, xsArgs); err != nil {
190 common.APIError(c, err.Error())
194 c.JSON(http.StatusOK, xaapiv1.ExecResult{Status: res.Status, CmdID: res.CmdID})
197 // execSignalCmd executes remotely the signal command
198 func (s *APIService) execSignalCmd(c *gin.Context) {
200 args := xaapiv1.ExecSignalArgs{}
201 if err := c.BindJSON(&args); err != nil {
202 s.Log.Warningf("/signal invalid args, err=%v", err)
203 common.APIError(c, "Invalid arguments")
207 // Retrieve on which xds-server the command is running
209 var dataCmd interface{}
210 for _, svr = range s.xdsServers {
211 dataCmd = svr.CommandGet(args.CmdID)
217 common.APIError(c, "Cannot retrieve XDS Server for this cmdID")
221 // Forward back command to right server
222 res := xsapiv1.ExecSigResult{}
223 xsArgs := &xsapiv1.ExecSignalArgs{
227 if err := svr.CommandSignal(xsArgs, &res); err != nil {
228 common.APIError(c, err.Error())
232 c.JSON(http.StatusOK, xaapiv1.ExecSignalResult{Status: res.Status, CmdID: res.CmdID})