@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
@ -105,14 +106,9 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
|
||||
utils.Disconnect(ws, AccessGatewayCreateError, "创建SSH隧道失败:"+err.Error())
|
||||
return nil
|
||||
}
|
||||
defer g.CloseSshTunnel(s.ID)
|
||||
ip = exposedIP
|
||||
port = exposedPort
|
||||
}
|
||||
active, err := utils.Tcping(ip, port)
|
||||
if !active {
|
||||
utils.Disconnect(ws, AssetNotActive, "目标资产不在线: "+err.Error())
|
||||
return nil
|
||||
defer g.CloseSshTunnel(s.ID)
|
||||
}
|
||||
|
||||
configuration.SetParameter("hostname", ip)
|
||||
@ -135,14 +131,15 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
|
||||
}
|
||||
|
||||
addr := config.GlobalCfg.Guacd.Hostname + ":" + strconv.Itoa(config.GlobalCfg.Guacd.Port)
|
||||
log.Debugf("[%v:%v] 创建guacd隧道[%v]", sessionId, connectionId, addr)
|
||||
asset := fmt.Sprintf("%s:%s", configuration.GetParameter("hostname"), configuration.GetParameter("port"))
|
||||
log.Debugf("[%v] 新建 guacd 会话, guacd=%v, asset=%v", sessionId, addr, asset)
|
||||
|
||||
guacdTunnel, err := guacd.NewTunnel(addr, configuration)
|
||||
if err != nil {
|
||||
if connectionId == "" {
|
||||
utils.Disconnect(ws, NewTunnelError, err.Error())
|
||||
}
|
||||
log.Printf("[%v:%v] 建立连接失败: %v", sessionId, connectionId, err.Error())
|
||||
log.Printf("[%v] 建立连接失败: %v", sessionId, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
@ -164,7 +161,7 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
|
||||
|
||||
nextSession.Observer = session.NewObserver(sessionId)
|
||||
session.GlobalSessionManager.Add <- nextSession
|
||||
go nextSession.Observer.Run()
|
||||
go nextSession.Observer.Start()
|
||||
sess := model.Session{
|
||||
ConnectionId: guacdTunnel.UUID,
|
||||
Width: intWidth,
|
||||
@ -177,7 +174,7 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
|
||||
sess.Reviewed = true
|
||||
}
|
||||
// 创建新会话
|
||||
log.Debugf("[%v:%v] 创建新会话: %v", sessionId, connectionId, sess.ConnectionId)
|
||||
log.Debugf("[%v] 新建会话成功: %v", sessionId, sess.ConnectionId)
|
||||
if err := repository.SessionRepository.UpdateById(ctx, &sess, sessionId); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -199,7 +196,7 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
|
||||
for {
|
||||
_, message, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
log.Debugf("[%v:%v] WebSocket已关闭", sessionId, connectionId)
|
||||
log.Debugf("[%v:%v] WebSocket已关闭, %v", sessionId, connectionId, err.Error())
|
||||
// guacdTunnel.Read() 会阻塞,所以要先把guacdTunnel客户端关闭,才能退出Guacd循环
|
||||
_ = guacdTunnel.Close()
|
||||
|
||||
|
@ -152,7 +152,7 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error {
|
||||
NextTerminal: nextTerminal,
|
||||
Observer: session.NewObserver(s.ID),
|
||||
}
|
||||
go nextSession.Observer.Run()
|
||||
go nextSession.Observer.Start()
|
||||
session.GlobalSessionManager.Add <- nextSession
|
||||
|
||||
termHandler := NewTermHandler(sessionId, isRecording, ws, nextTerminal)
|
||||
|
@ -1,26 +1,56 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"next-terminal/server/api"
|
||||
"next-terminal/server/config"
|
||||
"next-terminal/server/log"
|
||||
"next-terminal/server/resource"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
)
|
||||
|
||||
func getFS(useOS bool) fs.FS {
|
||||
if useOS {
|
||||
log.Debug("using live mode")
|
||||
return os.DirFS("web/build")
|
||||
}
|
||||
|
||||
log.Debug("using embed mode")
|
||||
fsys, err := fs.Sub(resource.Resource, "build")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return fsys
|
||||
}
|
||||
|
||||
func WrapHandler(h http.Handler) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
c.Response().Header().Set("Cache-Control", `public, max-age=31536000`)
|
||||
h.ServeHTTP(c.Response(), c.Request())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func setupRoutes() *echo.Echo {
|
||||
|
||||
e := echo.New()
|
||||
e.HideBanner = true
|
||||
//e.Logger = log.GetEchoLogger()
|
||||
//e.Use(log.Hook())
|
||||
e.File("/", "web/build/index.html")
|
||||
e.File("/asciinema.html", "web/build/asciinema.html")
|
||||
e.File("/", "web/build/index.html")
|
||||
e.File("/favicon.ico", "web/build/favicon.ico")
|
||||
e.File("/logo.png", "web/build/logo.png")
|
||||
e.Static("/static", "web/build/static")
|
||||
|
||||
fsys := getFS(config.GlobalCfg.Debug)
|
||||
fileServer := http.FileServer(http.FS(fsys))
|
||||
handler := WrapHandler(fileServer)
|
||||
e.GET("/", handler)
|
||||
e.GET("/asciinema.html", handler)
|
||||
e.GET("/favicon.ico", handler)
|
||||
e.GET("/static/*", handler)
|
||||
|
||||
e.Use(middleware.Recover())
|
||||
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
||||
|
@ -44,7 +44,7 @@ func (g *Gateway) Run() {
|
||||
select {
|
||||
case t := <-g.Add:
|
||||
g.tunnels[t.ID] = t
|
||||
go t.Run()
|
||||
go t.Open()
|
||||
case k := <-g.Del:
|
||||
if _, ok := g.tunnels[k]; ok {
|
||||
g.tunnels[k].Close()
|
||||
|
@ -15,7 +15,7 @@ func NewManager() *Manager {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Run() {
|
||||
func (m *Manager) Start() {
|
||||
for {
|
||||
select {
|
||||
case g := <-m.Add:
|
||||
@ -38,5 +38,5 @@ var GlobalGatewayManager *Manager
|
||||
|
||||
func init() {
|
||||
GlobalGatewayManager = NewManager()
|
||||
go GlobalGatewayManager.Run()
|
||||
go GlobalGatewayManager.Start()
|
||||
}
|
||||
|
@ -22,36 +22,35 @@ type Tunnel struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *Tunnel) Run() {
|
||||
func (r *Tunnel) Open() {
|
||||
localAddr := fmt.Sprintf("%s:%d", r.LocalHost, r.LocalPort)
|
||||
log.Debugf("等待客户端访问 [%v] ...", localAddr)
|
||||
|
||||
go func() {
|
||||
<-r.ctx.Done()
|
||||
_ = r.listener.Close()
|
||||
log.Debugf("SSH 隧道 %v 关闭", localAddr)
|
||||
}()
|
||||
log.Debugf("等待客户端访问 %v", localAddr)
|
||||
localConn, err := r.listener.Accept()
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("客户端 [%v] 已连接至 [%v]", localConn.RemoteAddr().String(), localAddr)
|
||||
log.Debugf("客户端 %v 连接至 %v", localConn.RemoteAddr().String(), localAddr)
|
||||
remoteAddr := fmt.Sprintf("%s:%d", r.RemoteHost, r.RemotePort)
|
||||
log.Debugf("连接远程主机 [%v] ...", remoteAddr)
|
||||
log.Debugf("连接远程主机 %v ...", remoteAddr)
|
||||
remoteConn, err := r.Gateway.SshClient.Dial("tcp", remoteAddr)
|
||||
if err != nil {
|
||||
log.Debugf("连接远程主机 [%v] 失败", remoteAddr)
|
||||
log.Debugf("连接远程主机 %v 失败", remoteAddr)
|
||||
r.err = err
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("连接远程主机 [%v] 成功", remoteAddr)
|
||||
log.Debugf("连接远程主机 %v 成功", remoteAddr)
|
||||
go copyConn(localConn, remoteConn)
|
||||
go copyConn(remoteConn, localConn)
|
||||
log.Debugf("开始转发数据 [%v]->[%v]", localAddr, remoteAddr)
|
||||
go func() {
|
||||
<-r.ctx.Done()
|
||||
_ = r.listener.Close()
|
||||
_ = localConn.Close()
|
||||
_ = remoteConn.Close()
|
||||
log.Debugf("SSH隧道 [%v]-[%v] 已关闭", localAddr, remoteAddr)
|
||||
}()
|
||||
log.Debugf("转发数据 [%v]->[%v]", localAddr, remoteAddr)
|
||||
}
|
||||
|
||||
func (r Tunnel) Close() {
|
||||
|
@ -25,7 +25,7 @@ func NewManager() *Manager {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Run() {
|
||||
func (m *Manager) Start() {
|
||||
for {
|
||||
select {
|
||||
case s := <-m.Add:
|
||||
@ -66,5 +66,5 @@ var GlobalSecurityManager *Manager
|
||||
|
||||
func init() {
|
||||
GlobalSecurityManager = NewManager()
|
||||
go GlobalSecurityManager.Run()
|
||||
go GlobalSecurityManager.Start()
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ func NewObserver(id string) *Manager {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Run() {
|
||||
func (m *Manager) Start() {
|
||||
defer fmt.Printf("Session Manager %v End\n", m.id)
|
||||
fmt.Printf("Session Manager %v Run\n", m.id)
|
||||
fmt.Printf("Session Manager %v Open\n", m.id)
|
||||
for {
|
||||
select {
|
||||
case s := <-m.Add:
|
||||
@ -94,5 +94,5 @@ var GlobalSessionManager *Manager
|
||||
|
||||
func init() {
|
||||
GlobalSessionManager = NewManager()
|
||||
go GlobalSessionManager.Run()
|
||||
go GlobalSessionManager.Start()
|
||||
}
|
||||
|
6
server/resource/resource.go
Normal file
6
server/resource/resource.go
Normal file
@ -0,0 +1,6 @@
|
||||
package resource
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *
|
||||
var Resource embed.FS
|
@ -268,7 +268,7 @@ func (gui Gui) handleAccessAsset(sess *ssh.Session, sessionId string) (err error
|
||||
NextTerminal: nextTerminal,
|
||||
Observer: session.NewObserver(s.ID),
|
||||
}
|
||||
go nextSession.Observer.Run()
|
||||
go nextSession.Observer.Start()
|
||||
session.GlobalSessionManager.Add <- nextSession
|
||||
|
||||
if err := sshSession.Wait(); err != nil {
|
||||
|
Reference in New Issue
Block a user