package controller import ( "encoding/json" "fmt" "github.com/garyburd/redigo/redis" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "log" "net/http" "ssh_manage/common" "ssh_manage/common/core" "ssh_manage/common/sftp_clients" "ssh_manage/database" "ssh_manage/model/Apiform" "strconv" ) var upGrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024 * 1024 * 10, CheckOrigin: func(r *http.Request) bool { return true }, } type Auth_msg struct { Type string `json:"type"` Token string `json:"token"` } // handle webSocket connection. // first,we establish a ssh connection to ssh server when a webSocket comes; // then we deliver ssh data via ssh connection between browser and ssh server. // That is, read webSocket data from browser (e.g. 'ls' command) and send data to ssh server via ssh connection; // the other hand, read returned ssh data from ssh server and write back to browser via webSocket API. func WsSsh(c *gin.Context) { wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) if core.HandleError(c, err) { return } defer wsConn.Close() cols, err := strconv.Atoi(c.DefaultQuery("cols", "120")) if core.WshandleError(wsConn, err) { return } rows, err := strconv.Atoi(c.DefaultQuery("rows", "32")) if core.WshandleError(wsConn, err) { return } var ser_info Apiform.SerInfo //接收反序列化数据 var auth Apiform.WsAuth if c.ShouldBindUri(&auth) != nil { wsConn.WriteMessage(websocket.TextMessage, []byte("参数错误\r\n")) wsConn.Close() return } for { _, wsData, err := wsConn.ReadMessage() if err != nil { log.Println(err.Error()) wsConn.Close() //logrus.WithError(err).Error("reading webSocket message failed") return } //unmashal bytes into struct msgObj := Auth_msg{} if err := json.Unmarshal(wsData, &msgObj); err != nil { log.Println("Auth : unmarshal websocket message failed:", string(wsData)) continue } token := msgObj.Token claims, err := common.ParseToken(token) valid := claims.Valid() if valid != nil || err != nil { wsConn.WriteMessage(websocket.TextMessage, []byte("身份验证失败\r\n")) wsConn.Close() return } cache := database.Cache.Get() defer cache.Close() //log.Println(auth) s_info, err := redis.Bytes(cache.Do("GET", auth.Sid)) //log.Println(string(s_info)) if err != nil || len(s_info) == 0 { wsConn.WriteMessage(websocket.TextMessage, []byte("连接超时,请重试!\r\n")) wsConn.Close() return } if json.Unmarshal(s_info, &ser_info) != nil { wsConn.WriteMessage(websocket.TextMessage, []byte("服务器信息获取失败,请重试!\r\n")) wsConn.Close() return } //log.Println(ser_info) if claims.Userid != ser_info.BindUser { //验证权限 wsConn.WriteMessage(websocket.TextMessage, []byte("权限验证失败,请重试!\r\n")) wsConn.Close() return } break //break } client, err := core.NewSshClient(core.Server{ser_info.Ip, ser_info.Port, ser_info.Username, ser_info.Password}) if core.WshandleError(wsConn, err) { return } defer client.Close() //startTime := time.Now() ssConn, err := core.NewSshConn(cols, rows, client) //加入sftp客户端 if core.WshandleError(wsConn, err) { return } sftp_clients.Client.Lock() sftp_clients.Client.C[auth.Sid] = &sftp_clients.MyClient{ser_info.BindUser, ssConn.SftpClient} sftp_clients.Client.Unlock() defer func() { sftp_clients.Client.Lock() delete(sftp_clients.Client.C, auth.Sid) //释放SFTP客户端 sftp_clients.Client.Unlock() }() defer ssConn.Close() quitChan := make(chan bool, 3) // most messages are ssh output, not webSocket input go ssConn.ReceiveWsMsg(wsConn, quitChan) go ssConn.SendComboOutput(wsConn, quitChan) go ssConn.SessionWait(quitChan) <-quitChan //任意协程退出则结束 fmt.Println("Exit") log.Println("websocket finished") }