package main import ( "encoding/base64" "encoding/json" "fmt" "github.com/beevik/guid" "github.com/gorilla/websocket" "net/http" "strings" "time" ) var ( upgrader = websocket.Upgrader{ //允许跨域访问 CheckOrigin: func(r *http.Request) bool { return true }, EnableCompression: false, } ) func serviceHandler(w http.ResponseWriter, r *http.Request) { deviceNo := r.FormValue("deviceNo") sessionId := r.FormValue("session_id") clientType := r.FormValue("client_type") wsConn, upgradeErr := upgrader.Upgrade(w, r, w.Header()) if upgradeErr != nil { return } defer func() { if reco := recover(); reco != any(nil) { fmt.Printf("Service Runtime error caught: %v", reco) } }() tokenOfSession := fastLinkService.GetTokenBySession(sessionId) sessionGuid := guid.New().String() fastLinkService.NewSession(deviceNo, sessionId, sessionGuid, clientType, wsConn) wsConn.WriteMessage(websocket.TextMessage, []byte("0{\"sid\":\""+guid.New().String()+"\",\"upgrades\":[\"websocket\"],\"pingInterval\":25000,\"pingTimeout\":60000}")) wsConn.WriteMessage(websocket.TextMessage, []byte("40")) if clientType == CLIENT_TYPE_FASTLINK_SERVICE { Logger.Println("Online DeviceNo:" + deviceNo + " Session:" + sessionId) fastLinkService.SetOnlineStatus(deviceNo) device := fastLinkService.GetDeviceByNo(deviceNo) if device != nil && device.BelongUser != "" { notifyDeviceChange(device.BelongUser) } } for { wsConn.SetReadDeadline(time.Now().In(TimeLocation).Add(time.Second * 60)) messageType, p, readError := wsConn.ReadMessage() if readError != nil { Logger.Println("Service WebSocket异常断开," + wsConn.RemoteAddr().String() + ",异常信息:" + readError.Error()) fastLinkService.RemoveSession(sessionId, sessionGuid) if clientType == CLIENT_TYPE_FASTLINK_SERVICE { Logger.Println("Offline DeviceNo:" + deviceNo + " Session:" + sessionId) fastLinkService.SetOnlineStatus(deviceNo) device := fastLinkService.GetDeviceByNo(deviceNo) if device != nil { //推送通知 notifyDeviceChange(device.BelongUser) } } wsConn.Close() return } if messageType == websocket.CloseMessage { Logger.Println("Service WebSocket断开," + wsConn.RemoteAddr().String()) fastLinkService.RemoveSession(sessionId, sessionGuid) if clientType == CLIENT_TYPE_FASTLINK_SERVICE { Logger.Println("Offline DeviceNo:" + deviceNo + " Session:" + sessionId) fastLinkService.SetOnlineStatus(deviceNo) device := fastLinkService.GetDeviceByNo(deviceNo) if device != nil { //推送通知 notifyDeviceChange(device.BelongUser) } } wsConn.Close() return } strData := string(p) //fmt.Printf("DATA:" + strData + "\n") index := strings.Index(strData, "[") cmd := "" var items []interface{} if index != -1 { cmd = strData[0:index] json.Unmarshal([]byte(strData[index:]), &items) } else { cmd = strData } switch cmd { case "2": if tokenOfSession != "" { fastLinkService.RenewToken(tokenOfSession) } wsConn.WriteMessage(websocket.TextMessage, []byte("3")) case "42": if items[0] == "KeepAlive" { wsConn.WriteMessage(websocket.TextMessage, []byte("42[\"KeepAliveAck\",{\"code\":200,\"message\":\"\",\"success\":true,\"error\":false}]")) } else if items[0] == "message" { msg := items[1].(map[string]interface{})["message"].(string) var messageInfo *MessageInfo json.Unmarshal([]byte(msg), &messageInfo) if messageInfo != nil { switch messageInfo.Method { case "AddDevice": var param AddDeviceParam param.DeviceName = messageInfo.Params.(map[string]interface{})["deviceName"].(string) param.DeviceNo = messageInfo.Params.(map[string]interface{})["deviceNo"].(string) device := fastLinkService.AddDevice(param.DeviceNo, param.DeviceName) addDeviceResp := &MessageResponse{ Id: messageInfo.Id, Method: "AddDeviceAck", Result: &AddDeviceResponse{ Code: 200, DeviceId: device.DeviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, addDeviceResp)) case "CheckVersion": checkVersionResp := &MessageResponse{ Id: messageInfo.Id, Method: "CheckVersionAck", Result: &CheckVersionResponse{ Code: 200, DownloadUrl: "", IsUpdate: false, NewVersion: "1.4.2.0", }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, checkVersionResp)) case "GetDeviceRemoteControlInfo": var param GetDeviceRemoteControlInfoParam param.DeviceNo = messageInfo.Params.(map[string]interface{})["deviceNo"].(string) param.DeviceId = int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) device := fastLinkService.GetDeviceByNo(param.DeviceNo) if device != nil { getDeviceRemoteControlInfoResp := &MessageResponse{ Id: messageInfo.Id, Method: "GetDeviceRemoteControlInfoAck", Result: &GetDeviceRemoteControlInfoResponse{ Code: 200, DeviceId: device.DeviceId, IdentificationCode: device.IdentificationCode, ShareUrl: WEB_URL + "?d=" + base64.StdEncoding.EncodeToString([]byte(device.DeviceNo)) + "&r=" + device.ShareRand, VerificationCode: device.VerificationCode, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getDeviceRemoteControlInfoResp)) } case "GetFileTransferConfig": getFileTransferConfigResp := &MessageResponse{ Id: messageInfo.Id, Method: "GetFileTransferConfigAck", Result: &GetFileTransferConfigResponse{ Code: 200, DownloadSpeedRatio: 80, UploadSpeedRatio: 80, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo+"_service", getFileTransferConfigResp)) case "GetTurnTransferConfig": getTurnTransferConfigResp := &MessageResponse{ Id: messageInfo.Id, Method: "GetTurnTransferConfigAck", Result: &GetTurnTransferConfigResponse{ Code: 200, VideoBitrate: 4194377, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo+"_service", getTurnTransferConfigResp)) case "Login": var param LoginParam param.PhoneNo = messageInfo.Params.(map[string]interface{})["phoneNo"].(string) param.Password = messageInfo.Params.(map[string]interface{})["password"].(string) param.DeviceId = int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) token := fastLinkService.Login(param.PhoneNo, param.Password, param.DeviceId) loginResp := &MessageResponse{ Id: messageInfo.Id, Method: "LoginAck", } result := &LoginResponse{} if token == "" { result.Code = 1009 } else { result.Code = 200 result.Token = token notifyDeviceChange(param.PhoneNo) } loginResp.Result = result wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, loginResp)) tokenOfSession = token fastLinkService.BindSessionToToken(sessionId, token) case "Logout": token := messageInfo.Params.(map[string]interface{})["token"].(string) fastLinkService.RemoveToken(token) logoutResp := &MessageResponse{ Id: messageInfo.Id, Method: "LogoutAck", } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, logoutResp)) case "GetDevices": token := messageInfo.Params.(map[string]interface{})["token"].(string) deviceList := fastLinkService.GetDeviceByToken(token) var dList []*DeviceResponse for _, info := range deviceList { d := &DeviceResponse{ DeviceId: info.DeviceId, DeviceName: info.DeviceName, DeviceNo: info.DeviceNo, } if info.CustomName != "" { d.DeviceName = info.CustomName } if info.Online { d.OnlineState = 1 } else { d.OnlineState = 0 } dList = append(dList, d) } getDevicesResp := &MessageResponse{ Id: messageInfo.Id, Method: "GetDevicesAck", Result: &GetDeviceResponse{ Code: 200, Devices: dList, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getDevicesResp)) case "UpdateDeviceVerificationCode": paramDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string) device := fastLinkService.RefreshDeviceVerificationCode(paramDeviceNo) if device != nil { updateDeviceVerificationCodeResp := &MessageResponse{ Id: messageInfo.Id, Method: "UpdateDeviceVerificationCodeAck", Result: &GetDeviceRemoteControlInfoResponse{ Code: 200, DeviceId: device.DeviceId, IdentificationCode: device.IdentificationCode, ShareUrl: WEB_URL + "?d=" + device.DeviceNo + "&r=" + device.ShareRand, VerificationCode: device.VerificationCode, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, updateDeviceVerificationCodeResp)) } case "GetDeviceVerificationType": paramDeviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) device := fastLinkService.GetDeviceById(paramDeviceId) verificationType := 0 if device != nil { verificationType = device.VerificationType } getDeviceVerificationTypeResp := &MessageResponse{ Id: messageInfo.Id, Method: "GetDeviceVerificationTypeAck", Result: &GetDeviceVerificationTypeResponse{ Code: 200, VerificationType: verificationType, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getDeviceVerificationTypeResp)) case "UpdateDeviceVerificationType": verifyDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string) verifyPass := messageInfo.Params.(map[string]interface{})["password"].(string) verifyType := int(messageInfo.Params.(map[string]interface{})["verificationType"].(float64)) deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) device := fastLinkService.GetDeviceByNo(verifyDeviceNo) if device != nil { switch verifyType { case 0: device.VerificationType = 0 device.TwoStepPass = "" case 1: //未实现 device.VerificationType = 0 device.TwoStepPass = "" case 2: device.VerificationType = 2 device.TwoStepPass = verifyPass } } updateDeviceVerificationTypeResp := &MessageResponse{ Id: messageInfo.Id, Method: "UpdateDeviceVerificationTypeAck", Result: &DeleteDeviceResponse{ Code: 200, DeviceId: deviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, updateDeviceVerificationTypeResp)) case "StartRemoteControl": remoteControlParam := StartRemoteControlParam{ Type: int(messageInfo.Params.(map[string]interface{})["type"].(float64)), Token: messageInfo.Params.(map[string]interface{})["token"].(string), RemoteDeviceId: int(messageInfo.Params.(map[string]interface{})["remoteDeviceId"].(float64)), RemoteIdentificationCode: messageInfo.Params.(map[string]interface{})["remoteIdentificationCode"].(string), RemoteVerificationCode: messageInfo.Params.(map[string]interface{})["remoteVerificationCode"].(string), VerificationType: int(messageInfo.Params.(map[string]interface{})["verificationType"].(float64)), UserName: messageInfo.Params.(map[string]interface{})["userName"].(string), Password: messageInfo.Params.(map[string]interface{})["password"].(string), } var device *DeviceInfo if remoteControlParam.RemoteDeviceId != 0 { device = fastLinkService.GetDeviceById(remoteControlParam.RemoteDeviceId) } else { device = fastLinkService.GetDeviceByIdentificationCode(remoteControlParam.RemoteIdentificationCode) } if device.Online && device.Visible { verifyResult := true userName := "游客" if remoteControlParam.Token != "" { userName = fastLinkService.GetUserByToken(remoteControlParam.Token) if device.BelongUser != userName { verifyResult = false } } else { if device.VerificationCode != remoteControlParam.RemoteVerificationCode || device.IdentificationCode != remoteControlParam.RemoteIdentificationCode { verifyResult = false } } if device.VerificationType == 2 && device.TwoStepPass != "" { if device.TwoStepPass != remoteControlParam.Password { verifyResult = false } } if !verifyResult { errorResp := &MessageResponse{ Id: messageInfo.Id, Method: "StartRemoteControlAck", Result: &ErrorResponse{ Code: 5004, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, errorResp)) } else { fastLinkService.RenewToken(remoteControlParam.Token) clientId := GenShortGUID() streamToken := GenShortGUID() fastLinkService.PrepareSignalSession(clientId, device.DeviceId, device.DeviceNo, streamToken, userName) targetRemoteControlResp := &RemoteStartRemoteControlResponse{ Id: guid.New().String(), Method: "SetStreamingConfig", Params: RemoteStreamingConfig{ ClientId: clientId, SignalServer: globalConfig.SignalServer, StunAddrs: globalConfig.StunServers, Token: streamToken, TurnAddrs: globalConfig.TurnServers, }, } remoteSession := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE) remoteSession.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(device.DeviceNo+"_service", targetRemoteControlResp)) //推送UI提示 notifyOnlineUserChange(device.DeviceNo) startRemoteControlResp := &MessageResponse{ Id: messageInfo.Id, Method: "StartRemoteControlAck", Result: &StartRemoteControlResponse{ Code: 200, StreamingConfig: StreamingConfig{ ClientId: clientId, ClientIds: []string{}, ServiceId: device.DeviceNo, SignalServer: globalConfig.SignalServer, StunAddrs: globalConfig.StunServers, Token: streamToken, TurnAddrs: globalConfig.TurnServers, }, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, startRemoteControlResp)) } } else { errorResp := &MessageResponse{ Id: messageInfo.Id, Method: "StartRemoteControlAck", Result: &ErrorResponse{ Code: 5007, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, errorResp)) } case "GetOnlineUsers": paramDeviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) clients := fastLinkService.GetSignalSessionByDeviceId(paramDeviceId) var onlineUsers []OnlineUser onlineUsers = []OnlineUser{} for _, client := range clients { onlineUsers = append(onlineUsers, OnlineUser{ ClientId: client.Token, ClientOS: "Windows 8(OS build number: 9200)", UserName: client.StreamUser, VisitTime: client.CreateTime.Format("2006-01-02 15:04"), }) } getOnlineUsersResp := &MessageResponse{ Id: messageInfo.Id, Method: "GetOnlineUsersAck", Result: &GetOnlineUsersResponse{ Code: 200, DeviceId: paramDeviceId, Users: onlineUsers, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getOnlineUsersResp)) case "VerifyStreamingToken": streamToken := messageInfo.Params.(map[string]interface{})["token"].(string) clientId := messageInfo.Params.(map[string]interface{})["clientId"].(string) signalSession := fastLinkService.GetSignalSession(clientId) if streamToken == signalSession.StreamToken { verifyStreamingTokenResp := &MessageResponse{ Id: messageInfo.Id, Method: "VerifyStreamingTokenAck", Result: &SimpleResponse{ Code: 200, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo+"_service", verifyStreamingTokenResp)) } case "DeleteDevice": token := messageInfo.Params.(map[string]interface{})["token"].(string) deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) userName := fastLinkService.GetUserByToken(token) device := fastLinkService.GetDeviceById(deviceId) if device != nil && userName != "" && device.BelongUser == userName { fastLinkService.RenewToken(token) device.Visible = false //推送通知 notifyDeviceChange(userName) } deleteDeviceResp := &MessageResponse{ Id: messageInfo.Id, Method: "DeleteDeviceAck", Result: &DeleteDeviceResponse{ Code: 200, DeviceId: deviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, deleteDeviceResp)) case "BindDevice": token := messageInfo.Params.(map[string]interface{})["token"].(string) bindDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string) deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) userName := fastLinkService.GetUserByToken(token) device := fastLinkService.GetDeviceByNo(bindDeviceNo) if device != nil && userName != "" { fastLinkService.RenewToken(token) device.BelongUser = userName device.Visible = true //推送通知 notifyDeviceChange(userName) } deleteDeviceResp := &MessageResponse{ Id: messageInfo.Id, Method: "BindDeviceAck", Result: &DeleteDeviceResponse{ Code: 200, DeviceId: deviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, deleteDeviceResp)) case "UpdateDeviceVerificationUpdateFrequency": //未实现,直接返回 deleteDeviceResp := &MessageResponse{ Id: messageInfo.Id, Method: "UpdateDeviceVerificationUpdateFrequencyAck", Result: &SimpleResponse{ Code: 200, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, deleteDeviceResp)) case "RebootDevice": token := messageInfo.Params.(map[string]interface{})["token"].(string) deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) device := fastLinkService.GetDeviceById(deviceId) user := fastLinkService.GetUserByToken(token) if device != nil && user != "" && device.BelongUser == user { fastLinkService.RenewToken(token) session := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE) if session != nil { notifyResp := &NotifyResponse{ Id: guid.New().String(), Method: "NotifyReboot", Params: EmptyObj{}, } session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo+"_service", notifyResp)) } } rebootDeviceResp := &MessageResponse{ Id: messageInfo.Id, Method: "RebootDeviceAck", Result: &AddDeviceResponse{ Code: 200, DeviceId: deviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, rebootDeviceResp)) case "ShutdownDevice": token := messageInfo.Params.(map[string]interface{})["token"].(string) deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) device := fastLinkService.GetDeviceById(deviceId) user := fastLinkService.GetUserByToken(token) if device != nil && user != "" && device.BelongUser == user { fastLinkService.RenewToken(token) session := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE) if session != nil { notifyResp := &NotifyResponse{ Id: guid.New().String(), Method: "NotifyShutdown", Params: EmptyObj{}, } session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo+"_service", notifyResp)) } } shutdownDeviceResp := &MessageResponse{ Id: messageInfo.Id, Method: "ShutdownDeviceAck", Result: &AddDeviceResponse{ Code: 200, DeviceId: deviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, shutdownDeviceResp)) case "UpdateDeviceName": token := messageInfo.Params.(map[string]interface{})["token"].(string) deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) newDeviceName := messageInfo.Params.(map[string]interface{})["newDeviceName"].(string) user := fastLinkService.GetUserByToken(token) device := fastLinkService.GetDeviceById(deviceId) if user != "" && device != nil && device.BelongUser == user { fastLinkService.RenewToken(token) device.CustomName = newDeviceName notifyDeviceChange(user) } updateDeviceNameResp := &MessageResponse{ Id: messageInfo.Id, Method: "UpdateDeviceNameAck", Result: &AddDeviceResponse{ Code: 200, DeviceId: deviceId, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, updateDeviceNameResp)) case "ForceClientOffline": deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64)) offlineDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string) device := fastLinkService.GetDeviceByNo(offlineDeviceNo) if device != nil && device.DeviceId == deviceId { session := fastLinkService.GetSession(offlineDeviceNo, CLIENT_TYPE_FASTLINK_SERVICE) if session != nil { tClientIds := messageInfo.Params.(map[string]interface{})["clientIds"].([]interface{}) var clientIds []string clientIds = []string{} for _, id := range tClientIds { clientIds = append(clientIds, id.(string)) } notifyResp := &NotifyResponse{ Id: guid.New().String(), Method: "NotifyClientOffline", Params: ForceClientOfflineParam{ ClientIds: clientIds, Reason: 3, }, } session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo+"_service", notifyResp)) } } forceClientOfflineResp := &MessageResponse{ Id: messageInfo.Id, Method: "ForceClientOfflineAck", Result: &SimpleResponse{ Code: 200, }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, forceClientOfflineResp)) case "SetStreamingConfigAck": default: errorResp := &MessageErrorResponse{ Method: messageInfo.Method, Error: &ErrorResponse{ Code: 2004, Message: "请求调用的方法不存在", }, } wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, errorResp)) } } } } } } func notifyDeviceChange(user string) { userUISessions := fastLinkService.GetSessionsByUser(user, CLIENT_TYPE_FASTLINK_UI) for _, session := range userUISessions { notifyResp := &NotifyResponse{ Id: guid.New().String(), Method: "NotifyDevicesChange", Params: EmptyObj{}, } Logger.Println("notifyDeviceChange: DeviceNo:" + session.DeviceNo + " User:" + user) session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo, notifyResp)) } } func notifyOnlineUserChange(deviceNo string) { remoteUISession := fastLinkService.GetSession(deviceNo, CLIENT_TYPE_FASTLINK_UI) if remoteUISession != nil { notifyResp := &NotifyResponse{ Id: guid.New().String(), Method: "NotifyOnlineUsersChange", Params: EmptyObj{}, } Logger.Println("notifyOnlineUserChange: DeviceNo:" + deviceNo) remoteUISession.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, notifyResp)) } } func makeMessageResponse(deviceNo string, params interface{}) []byte { var result []interface{} result = append(result, "message") var msg map[string]interface{} msg = make(map[string]interface{}) msg["deviceNo"] = deviceNo marshal, _ := json.Marshal(params) msg["message"] = string(marshal) result = append(result, msg) bytes, _ := json.Marshal(result) return append([]byte("42"), bytes...) }