2 * Copyright (C) 2018 "IoT.bzh"
3 * Author Sebastien Douheret <sebastien@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
24 "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent/lib/xaapiv1"
25 common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
26 "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
27 "github.com/franciscocpg/reflectme"
28 "github.com/gin-gonic/gin"
29 uuid "github.com/satori/go.uuid"
32 // targetsPassthroughInit Declare passthrough routes for targets
33 func (s *APIService) targetsPassthroughInit(svr *XdsServer) error {
34 svr.PassthroughGet("/targets")
35 svr.PassthroughGet("/targets/:id")
36 svr.PassthroughPost("/targets")
37 svr.PassthroughDelete("/targets/:id")
39 svr.PassthroughGet("/targets/:id/terminals")
40 svr.PassthroughGet("/targets/:id/terminals/:tid")
41 svr.PassthroughPost("/targets/:id/terminals")
42 svr.PassthroughPut("/targets/:id/terminals/:tid")
43 svr.PassthroughDelete("/targets/:id/terminals/:tid")
45 svr.apiRouter.POST("/targets/:id/terminals/:tid/open", s.TargetTerminalOpen)
47 svr.PassthroughPost("/targets/:id/terminals/:tid/close")
48 svr.PassthroughPost("/targets/:id/terminals/:tid/resize")
49 svr.PassthroughPost("/targets/:id/terminals/:tid/signal")
50 svr.PassthroughPost("/targets/:id/terminals/:tid/signal/:sig")
55 // GetServerFromTargetID Retrieve XDS Server definition from a target ID
56 func (s *APIService) GetServerFromTargetID(targetID, termID string) (*XdsServer, string, error) {
58 // FIXME add cache (but take care to support partial term ID)
59 for _, svr := range s.xdsServers {
60 term := xsapiv1.TerminalConfig{}
61 if err := svr.CommandTgtTerminalGet(targetID, termID, &term); err == nil {
62 return svr, term.ID, nil
65 return nil, "", fmt.Errorf("Cannot identify XDS Server")
68 // TargetTerminalOpen Open a target terminal/console
69 func (s *APIService) TargetTerminalOpen(c *gin.Context) {
71 // First retrieve Server ID and send command to right server
72 targetID := c.Param("id")
73 svr, termID, err := s.GetServerFromTargetID(targetID, c.Param("tid"))
75 common.APIError(c, err.Error())
79 // Retrieve session info
80 sess := s.sessions.Get(c)
82 common.APIError(c, "Unknown sessions")
87 common.APIError(c, "Websocket not established")
91 // Forward input events from client to XDSServer through WS
92 err = (*sock).On(xsapiv1.TerminalInEvent, func(stdin string) {
93 s.LogSillyf("TARGET TERMINAL EVENT IN (%s) <<%v>>", xsapiv1.TerminalInEvent, stdin)
94 svr.EventEmit(xaapiv1.TerminalInEvent, stdin)
97 msgErr := "Error while registering WS for " + xsapiv1.TerminalInEvent + " event"
98 s.Log.Errorf(msgErr, ", err: %v", err)
99 common.APIError(c, msgErr)
103 // Forward output events from XDSServer to client through WS
104 var outFwdFuncID uuid.UUID
105 outFwdFunc := func(pData interface{}, evData interface{}) error {
106 sid := pData.(string)
107 // IO socket can be nil when disconnected
108 so := s.sessions.IOSocketGet(sid)
110 s.Log.Infof("%s not emitted: WS closed (sid:%s)", xaapiv1.TerminalOutEvent, sid)
114 // Add sessionID to event Data
115 reflectme.SetField(evData, "sessionID", sid)
117 s.LogSillyf("TARGET TERMINAL EVENT OUT (%s) <<%v>>", xaapiv1.TerminalOutEvent, evData)
119 // Forward event to Client/Dashboard
120 (*so).Emit(xaapiv1.TerminalOutEvent, evData)
123 outFwdFuncID, err = svr.EventOn(xsapiv1.TerminalOutEvent, sess.ID, outFwdFunc)
125 common.APIError(c, err.Error())
129 // Handle Exit event separately to cleanup registered listener
130 var exitFuncID uuid.UUID
131 exitFunc := func(privD interface{}, evData interface{}) error {
132 evN := xaapiv1.TerminalExitEvent
134 pData := privD.(map[string]string)
135 sid := pData["sessID"]
137 // Add sessionID to event Data
138 reflectme.SetField(evData, "sessionID", sid)
140 // IO socket can be nil when disconnected
141 so := s.sessions.IOSocketGet(sid)
143 (*so).Emit(evN, evData)
145 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
149 svr.EventOff(xaapiv1.TerminalOutEvent, outFwdFuncID)
150 svr.EventOff(evN, exitFuncID)
155 privData := map[string]string{
158 exitFuncID, err = svr.EventOn(xaapiv1.TerminalExitEvent, privData, exitFunc)
160 common.APIError(c, err.Error())
164 // Forward back command to right server
165 res := xsapiv1.TerminalConfig{}
166 if err := svr.CommandTgtTerminalOpen(targetID, termID, &res); err != nil {
167 common.APIError(c, err.Error())
171 c.JSON(http.StatusOK, res)