99 "time"
1010
1111 "github.com/1Panel-dev/1Panel/agent/app/dto"
12+ "github.com/1Panel-dev/1Panel/agent/app/model"
1213 "github.com/1Panel-dev/1Panel/agent/app/service"
1314 "github.com/1Panel-dev/1Panel/agent/global"
1415 "github.com/1Panel-dev/1Panel/agent/utils/cmd"
@@ -19,59 +20,86 @@ import (
1920 "github.com/pkg/errors"
2021)
2122
22- func (b * BaseApi ) WsSSH (c * gin.Context ) {
23+ func (b * BaseApi ) WsLocalTerminal (c * gin.Context ) {
24+ client , err := loadLocalConn ()
25+ b .runSSHSession (c , client , err , c .DefaultQuery ("command" , "" ))
26+ }
27+
28+ func (b * BaseApi ) WsHostSSH (c * gin.Context ) {
29+ hostID , _ := strconv .Atoi (c .DefaultQuery ("id" , "0" ))
30+ if hostID <= 0 {
31+ b .runSSHSession (c , nil , errors .New ("missing host id" ), c .DefaultQuery ("command" , "" ))
32+ return
33+ }
34+ host , err := service .GetHostInfo (uint (hostID ))
35+ client , err := newHostSSHClient (host , err )
36+ b .runSSHSession (c , client , err , c .DefaultQuery ("command" , "" ))
37+ }
38+
39+ func (b * BaseApi ) WsContainerTerminal (c * gin.Context ) {
40+ wsConn , cols , rows , ok := prepareTerminalSession (c )
41+ if ! ok {
42+ return
43+ }
44+ defer wsConn .Close ()
45+
46+ slave , err := loadContainerTerminalCommand (c )
47+ if wshandleError (wsConn , err ) {
48+ return
49+ }
50+ defer slave .Close ()
51+
52+ tty , err := terminal .NewLocalWsSession (cols , rows , wsConn , slave , false )
53+ if wshandleError (wsConn , err ) {
54+ return
55+ }
56+
57+ quitChan := make (chan bool , 3 )
58+ tty .Start (quitChan )
59+ go slave .Wait (quitChan )
60+
61+ <- quitChan
62+
63+ global .LOG .Info ("websocket finished" )
64+ closeTerminalConn (wsConn )
65+ }
66+
67+ func prepareTerminalSession (c * gin.Context ) (* websocket.Conn , int , int , bool ) {
2368 wsConn , err := upGrader .Upgrade (c .Writer , c .Request , nil )
2469 if err != nil {
2570 global .LOG .Errorf ("gin context http handler failed, err: %v" , err )
26- return
71+ return nil , 0 , 0 , false
2772 }
28- defer wsConn .Close ()
2973
3074 if global .CONF .Base .IsDemo {
3175 if wshandleError (wsConn , errors .New (" demo server, prohibit this operation!" )) {
32- return
76+ return nil , 0 , 0 , false
3377 }
3478 }
3579
3680 cols , err := strconv .Atoi (c .DefaultQuery ("cols" , "80" ))
3781 if wshandleError (wsConn , errors .WithMessage (err , "invalid param cols in request" )) {
38- return
82+ return nil , 0 , 0 , false
3983 }
4084 rows , err := strconv .Atoi (c .DefaultQuery ("rows" , "40" ))
4185 if wshandleError (wsConn , errors .WithMessage (err , "invalid param rows in request" )) {
86+ return nil , 0 , 0 , false
87+ }
88+ return wsConn , cols , rows , true
89+ }
90+
91+ func (b * BaseApi ) runSSHSession (c * gin.Context , client * ssh.SSHClient , clientErr error , command string ) {
92+ wsConn , cols , rows , ok := prepareTerminalSession (c )
93+ if ! ok {
4294 return
4395 }
96+ defer wsConn .Close ()
4497
45- hostID , _ := strconv .Atoi (c .DefaultQuery ("id" , "0" ))
46- var client * ssh.SSHClient
47- if hostID > 0 {
48- host , err := service .GetHostInfo (uint (hostID ))
49- if wshandleError (wsConn , errors .WithMessage (err , "load host info by id failed" )) {
50- return
51- }
52- connInfo := ssh.ConnInfo {
53- Addr : host .Addr ,
54- Port : int (host .Port ),
55- User : host .User ,
56- AuthMode : host .AuthMode ,
57- Password : host .Password ,
58- PrivateKey : []byte (host .PrivateKey ),
59- }
60- if len (host .PassPhrase ) != 0 {
61- connInfo .PassPhrase = []byte (host .PassPhrase )
62- }
63- client , err = ssh .NewClient (connInfo )
64- if wshandleError (wsConn , errors .WithMessage (err , "failed to set up the connection. Please check the host information" )) {
65- return
66- }
67- } else {
68- client , err = loadLocalConn ()
69- if wshandleError (wsConn , errors .WithMessage (err , "failed to set up the connection. Please check the host information" )) {
70- return
71- }
98+ if wshandleError (wsConn , errors .WithMessage (clientErr , "failed to set up the connection. Please check the host information" )) {
99+ return
72100 }
73101 defer client .Close ()
74- command := c . DefaultQuery ( "command" , "" )
102+
75103 sws , err := terminal .NewLogicSshWsSession (cols , rows , client .Client , wsConn , command )
76104 if wshandleError (wsConn , err ) {
77105 return
@@ -84,34 +112,38 @@ func (b *BaseApi) WsSSH(c *gin.Context) {
84112
85113 <- quitChan
86114
115+ closeTerminalConn (wsConn )
116+ }
117+
118+ func closeTerminalConn (wsConn * websocket.Conn ) {
87119 dt := time .Now ().Add (time .Second )
88120 _ = wsConn .WriteControl (websocket .CloseMessage , nil , dt )
89121}
90122
91- func (b * BaseApi ) ContainerWsSSH (c * gin.Context ) {
92- wsConn , err := upGrader .Upgrade (c .Writer , c .Request , nil )
123+ func newHostSSHClient (host * model.Host , err error ) (* ssh.SSHClient , error ) {
93124 if err != nil {
94- global .LOG .Errorf ("gin context http handler failed, err: %v" , err )
95- return
96- }
97- defer wsConn .Close ()
98-
99- if global .CONF .Base .IsDemo {
100- if wshandleError (wsConn , errors .New (" demo server, prohibit this operation!" )) {
101- return
102- }
125+ return nil , errors .WithMessage (err , "load host info by id failed" )
103126 }
104-
105- cols , err := strconv .Atoi (c .DefaultQuery ("cols" , "80" ))
106- if wshandleError (wsConn , errors .WithMessage (err , "invalid param cols in request" )) {
107- return
127+ connInfo := ssh.ConnInfo {
128+ Addr : host .Addr ,
129+ Port : int (host .Port ),
130+ User : host .User ,
131+ AuthMode : host .AuthMode ,
132+ Password : host .Password ,
133+ PrivateKey : []byte (host .PrivateKey ),
108134 }
109- rows , err := strconv .Atoi (c .DefaultQuery ("rows" , "40" ))
110- if wshandleError (wsConn , errors .WithMessage (err , "invalid param rows in request" )) {
111- return
135+ if len (host .PassPhrase ) != 0 {
136+ connInfo .PassPhrase = []byte (host .PassPhrase )
112137 }
138+ return ssh .NewClient (connInfo )
139+ }
140+
141+ func loadContainerTerminalCommand (c * gin.Context ) (* terminal.LocalCommand , error ) {
113142 source := c .Query ("source" )
114- var initCmd []string
143+ var (
144+ initCmd []string
145+ err error
146+ )
115147 switch source {
116148 case "redis" , "redis-cluster" :
117149 initCmd , err = loadRedisInitCmd (c , source )
@@ -122,33 +154,12 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
122154 case "database" :
123155 initCmd , err = loadDatabaseInitCmd (c )
124156 default :
125- if wshandleError (wsConn , fmt .Errorf ("not support such source %s" , source )) {
126- return
127- }
157+ return nil , fmt .Errorf ("not support such source %s" , source )
128158 }
129- if wshandleError (wsConn , err ) {
130- return
131- }
132- slave , err := terminal .NewCommand ("docker" , initCmd ... )
133- if wshandleError (wsConn , err ) {
134- return
135- }
136- defer slave .Close ()
137-
138- tty , err := terminal .NewLocalWsSession (cols , rows , wsConn , slave , false )
139- if wshandleError (wsConn , err ) {
140- return
159+ if err != nil {
160+ return nil , err
141161 }
142-
143- quitChan := make (chan bool , 3 )
144- tty .Start (quitChan )
145- go slave .Wait (quitChan )
146-
147- <- quitChan
148-
149- global .LOG .Info ("websocket finished" )
150- dt := time .Now ().Add (time .Second )
151- _ = wsConn .WriteControl (websocket .CloseMessage , nil , dt )
162+ return terminal .NewCommand ("docker" , initCmd ... )
152163}
153164
154165func loadRedisInitCmd (c * gin.Context , redisType string ) ([]string , error ) {
0 commit comments