diff --git a/config.yml b/config.yml index 86c75f5..62aa885 100644 --- a/config.yml +++ b/config.yml @@ -8,4 +8,4 @@ mysql: sqlite: file: 'next-terminal.db' server: - addr: 0.0.0.0:8089 \ No newline at end of file + addr: 0.0.0.0:8088 \ No newline at end of file diff --git a/main.go b/main.go index e6ecd4e..7965711 100644 --- a/main.go +++ b/main.go @@ -128,7 +128,7 @@ func Run() error { return err } // 启动定时任务 - //go handle.RunTicker() + go handle.RunTicker() go handle.RunDataFix() return e.Start(global.Config.Server.Addr) diff --git a/pkg/api/routes.go b/pkg/api/routes.go index 64b5eab..057f53c 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -91,6 +91,7 @@ func SetupRoutes() *echo.Echo { sessions.DELETE("/:id/rm", SessionRmEndpoint) sessions.DELETE("/:id", SessionDeleteEndpoint) sessions.GET("/:id/recording", SessionRecordingEndpoint) + sessions.GET("/:id", SessionGetEndpoint) } e.GET("/properties", PropertyGetEndpoint) diff --git a/pkg/api/session.go b/pkg/api/session.go index 4a36e74..6b121e5 100644 --- a/pkg/api/session.go +++ b/pkg/api/session.go @@ -91,7 +91,7 @@ func SessionDiscontentEndpoint(c echo.Context) error { split := strings.Split(sessionIds, ",") for i := range split { - CloseSessionById(split[i], 2001, "管理员强制关闭了此次接入。") + CloseSessionById(split[i], ForcedDisconnect, "管理员强制关闭了此次接入。") } return Success(c, nil) } @@ -105,10 +105,15 @@ func CloseSessionById(sessionId string, code int, reason string) { global.Store.Del(sessionId) + if code == Normal { + return + } session := model.Session{} session.ID = sessionId session.Status = model.Disconnected session.DisconnectedTime = utils.NowJsonTime() + session.Code = code + session.Message = reason model.UpdateSessionById(&session, sessionId) } @@ -318,6 +323,15 @@ func SessionLsEndpoint(c echo.Context) error { return errors.New("获取sftp客户端失败") } + if tun.SftpClient == nil { + sftpClient, err := CreateSftpClient(session.AssetId) + if err != nil { + logrus.Errorf("创建sftp客户端失败:%v", err.Error()) + return err + } + tun.SftpClient = sftpClient + } + fileInfos, err := tun.SftpClient.ReadDir(remoteDir) if err != nil { return err @@ -479,3 +493,12 @@ func SessionRecordingEndpoint(c echo.Context) error { logrus.Debugf("读取录屏文件:%s", recording) return c.File(recording) } + +func SessionGetEndpoint(c echo.Context) error { + sessionId := c.Param("id") + session, err := model.FindSessionById(sessionId) + if err != nil { + return err + } + return Success(c, session) +} diff --git a/pkg/api/tunnel.go b/pkg/api/tunnel.go index cf2e9ca..1ba7440 100644 --- a/pkg/api/tunnel.go +++ b/pkg/api/tunnel.go @@ -11,6 +11,14 @@ import ( "strconv" ) +const ( + Normal int = 0 + NotFoundSession int = 2000 + NewTunnelError int = 2001 + NewSftpClientError int = 2002 + ForcedDisconnect int = 2003 +) + func TunEndpoint(c echo.Context) error { ws, err := UpGrader.Upgrade(c.Response().Writer, c.Request(), nil) @@ -38,12 +46,14 @@ func TunEndpoint(c echo.Context) error { if len(connectionId) > 0 { session, err = model.FindSessionByConnectionId(connectionId) if err != nil { + CloseSessionById(sessionId, NotFoundSession, "会话不存在") return err } configuration.ConnectionID = connectionId } else { session, err = model.FindSessionById(sessionId) if err != nil { + CloseSessionById(sessionId, NotFoundSession, "会话不存在") return err } @@ -95,13 +105,12 @@ func TunEndpoint(c echo.Context) error { configuration.SetParameter(guacd.ColorScheme, propertyMap[guacd.ColorScheme]) break case "vnc": + configuration.SetParameter("username", session.Username) configuration.SetParameter("password", session.Password) - configuration.SetParameter("enable-sftp", "") break case "telnet": configuration.SetParameter("username", session.Username) configuration.SetParameter("password", session.Password) - configuration.SetParameter("enable-sftp", "") break } @@ -115,6 +124,8 @@ func TunEndpoint(c echo.Context) error { tunnel, err := guacd.NewTunnel(addr, configuration) if err != nil { + CloseSessionById(sessionId, NewTunnelError, err.Error()) + logrus.Printf("建立连接失败: %v", err.Error()) return err } @@ -129,35 +140,22 @@ func TunEndpoint(c echo.Context) error { session.ConnectionId = tunnel.UUID session.Width = intWidth session.Height = intHeight + session.Status = model.Connecting session.Recording = configuration.GetParameter(guacd.RecordingPath) model.UpdateSessionById(&session, sessionId) } - go func() { - sftpClient, err := CreateSftpClient(session.AssetId) - if err != nil { - CloseSessionById(sessionId, 2002, err.Error()) - logrus.Errorf("创建sftp客户端失败:%v", err.Error()) - } - item, ok := global.Store.Get(sessionId) - if ok { - item.SftpClient = sftpClient - } - }() - go func() { for true { instruction, err := tunnel.Read() if err != nil { - CloseSessionById(sessionId, 523, err.Error()) - logrus.Printf("WebSocket读取错误: %v", err) + CloseSessionById(sessionId, Normal, "") break } err = ws.WriteMessage(websocket.TextMessage, instruction) if err != nil { - CloseSessionById(sessionId, 523, err.Error()) - logrus.Printf("WebSocket写入错误: %v", err) + CloseSessionById(sessionId, Normal, "") break } } @@ -166,14 +164,12 @@ func TunEndpoint(c echo.Context) error { for true { _, message, err := ws.ReadMessage() if err != nil { - CloseSessionById(sessionId, 523, err.Error()) - logrus.Printf("隧道读取错误: %v", err) + CloseSessionById(sessionId, Normal, "") break } _, err = tunnel.WriteAndFlush(message) if err != nil { - CloseSessionById(sessionId, 523, err.Error()) - logrus.Printf("隧道写入错误: %v", err) + CloseSessionById(sessionId, Normal, "") break } } diff --git a/pkg/handle/runner.go b/pkg/handle/runner.go index 1908cb3..68d92dc 100644 --- a/pkg/handle/runner.go +++ b/pkg/handle/runner.go @@ -11,20 +11,17 @@ import ( func RunTicker() { var ch chan int //定时任务 - ticker := time.NewTicker(time.Minute * 5) + ticker := time.NewTicker(time.Minute * 60) go func() { for range ticker.C { - items, _ := model.FindAllAsset() - - for i := range items { - item := items[i] - active := utils.Tcping(item.IP, item.Port) - - asset := model.Asset{ - Active: active, + sessions, _ := model.FindSessionByStatus(model.NoConnect) + if sessions != nil && len(sessions) > 0 { + now := time.Now() + for i := range sessions { + if now.Sub(sessions[i].ConnectedTime.Time) > time.Hour*1 { + model.DeleteSessionById(sessions[i].ID) + } } - - model.UpdateAssetById(&asset, item.ID) } } ch <- 1 diff --git a/pkg/model/session.go b/pkg/model/session.go index e5b4044..1bef16e 100644 --- a/pkg/model/session.go +++ b/pkg/model/session.go @@ -7,9 +7,10 @@ import ( ) const ( + NoConnect = "no_connect" + Connecting = "connecting" Connected = "connected" Disconnected = "disconnected" - NoConnect = "no_connect" ) type Session struct { @@ -29,6 +30,8 @@ type Session struct { Recording string `json:"recording"` PrivateKey string `json:"privateKey"` Passphrase string `json:"passphrase"` + Code int `json:"code"` + Message string `json:"message"` ConnectedTime utils.JsonTime `json:"connectedTime"` DisconnectedTime utils.JsonTime `json:"disconnectedTime"` } diff --git a/web/src/components/access/Access.js b/web/src/components/access/Access.js index 95f13a5..2b8f896 100644 --- a/web/src/components/access/Access.js +++ b/web/src/components/access/Access.js @@ -266,10 +266,11 @@ class Access extends Component { } }; - showMessage(message) { + showMessage(msg) { + message.destroy(); Modal.error({ title: '提示', - content: message, + content: msg, }); } @@ -464,11 +465,24 @@ class Access extends Component { keyboard.onkeydown = this.onKeyDown; keyboard.onkeyup = this.onKeyUp; + + let stateChecker = setInterval(async () => { + let result = await request.get(`/sessions/${sessionId}`); + if (result['code'] !== 1) { + message.error(result['message']); + } else { + let session = result['data']; + if (session['status'] === 'disconnected') { + this.showMessage(session['message']); + clearInterval(stateChecker); + } + } + }, 1000) this.setState({ client: client, containerWidth: width, containerHeight: height, - keyboard: keyboard + keyboard: keyboard, }); }