263 lines
8.3 KiB
Go
263 lines
8.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/beevik/guid"
|
|
"github.com/gorilla/websocket"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
upgrader = websocket.Upgrader{
|
|
//允许跨域访问
|
|
CheckOrigin: func(r *http.Request) bool {
|
|
return true
|
|
},
|
|
EnableCompression: false,
|
|
}
|
|
)
|
|
|
|
func serviceHandler(w http.ResponseWriter, r *http.Request) {
|
|
var mutex sync.Mutex
|
|
sessionId := r.FormValue("session_id")
|
|
build := r.FormValue("build")
|
|
role := r.FormValue("role")
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
if len(sessionId) < 10 {
|
|
sessionId = r.Header.Get("Sec-WebSocket-Protocol")
|
|
w.Header().Add("sec-websocket-protocol", sessionId)
|
|
}
|
|
|
|
session := parsecService.GetSession(sessionId)
|
|
if session == nil {
|
|
err := &ErrorResponse{
|
|
Error: "invalid session ID",
|
|
}
|
|
w.WriteHeader(401)
|
|
w.Write(formatJson(err))
|
|
return
|
|
}
|
|
|
|
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)
|
|
}
|
|
}()
|
|
|
|
hostPeer := parsecService.GetPeer(session.HostPeerId)
|
|
hostPeer.Build = build
|
|
|
|
sessionGuid := guid.New().String()
|
|
|
|
wsSession := parsecService.NewWsSession(sessionId, role, sessionGuid, wsConn)
|
|
|
|
go func() {
|
|
for {
|
|
mutex.Lock()
|
|
err2 := wsConn.WriteMessage(websocket.PingMessage, []byte{0x70, 0x69, 0x6E, 0x67})
|
|
mutex.Unlock()
|
|
if err2 != nil {
|
|
parsecService.RemoveWsSession(sessionId, role, sessionGuid)
|
|
if role == ROLE_HOST {
|
|
parsecService.SetupOnlineStatus(hostPeer)
|
|
}
|
|
wsConn.Close()
|
|
return
|
|
}
|
|
time.Sleep(30 * time.Second)
|
|
}
|
|
}()
|
|
|
|
for {
|
|
//wsConn.SetReadDeadline(time.Now().In(TimeLocation).Add(time.Second * 60))
|
|
messageType, p, readError := wsConn.ReadMessage()
|
|
if readError != nil {
|
|
Logger.Println("Service WebSocket断开,PeerId=" + hostPeer.PeerId + " Role=" + role + ",信息:" + readError.Error())
|
|
parsecService.RemoveWsSession(sessionId, role, sessionGuid)
|
|
if role == ROLE_HOST {
|
|
parsecService.SetupOnlineStatus(hostPeer)
|
|
}
|
|
wsConn.Close()
|
|
return
|
|
}
|
|
if messageType == websocket.CloseMessage {
|
|
Logger.Println("Service WebSocket断开,PeerId=" + hostPeer.PeerId + " Role=" + role)
|
|
parsecService.RemoveWsSession(sessionId, role, sessionGuid)
|
|
if role == ROLE_HOST {
|
|
parsecService.SetupOnlineStatus(hostPeer)
|
|
}
|
|
wsConn.Close()
|
|
return
|
|
}
|
|
strData := string(p)
|
|
Logger.Println("DATA:" + strData + "\n")
|
|
|
|
var baseRequest *SocketRequest
|
|
json.Unmarshal(p, &baseRequest)
|
|
mutex.Lock()
|
|
switch baseRequest.Action {
|
|
case "conn_update":
|
|
var connUpdateRequest *ConnUpdateRequest
|
|
json.Unmarshal(p, &connUpdateRequest)
|
|
peer := parsecService.GetPeer(session.HostPeerId)
|
|
peer.Name = connUpdateRequest.Payload.Name
|
|
peer.Players = connUpdateRequest.Payload.Players
|
|
peer.Public = connUpdateRequest.Payload.Public
|
|
peer.Secret = connUpdateRequest.Payload.Secret
|
|
peer.Online = true
|
|
case "offer":
|
|
var offerRequest *OfferModel
|
|
json.Unmarshal(p, &offerRequest)
|
|
|
|
targetPeer := parsecService.GetPeer(offerRequest.Payload.To)
|
|
if targetPeer != nil {
|
|
wsSession.AttemptId = offerRequest.Payload.AttemptId
|
|
targetWsSession := parsecService.GetWsSessionByPeerId(ROLE_HOST, targetPeer.PeerId)
|
|
if targetWsSession != nil && targetWsSession.WsConn != nil {
|
|
targetUser := parsecService.GetUserByEmail(targetPeer.Owner)
|
|
offerRelay := &OfferModel{
|
|
SocketRequest: SocketRequest{
|
|
Version: 1,
|
|
Action: "offer_relay",
|
|
},
|
|
Payload: OfferPayload{
|
|
To: offerRequest.Payload.To,
|
|
Data: offerRequest.Payload.Data,
|
|
AttemptId: offerRequest.Payload.AttemptId,
|
|
Secret: offerRequest.Payload.Secret,
|
|
AccessLinkId: offerRequest.Payload.AccessLinkId,
|
|
From: wsSession.HostPeerId,
|
|
IsOwner: targetPeer.Owner == wsSession.Email,
|
|
SkipApproval: targetPeer.Owner == wsSession.Email || targetPeer.Public || StringListContain(targetPeer.Assign, wsSession.Email),
|
|
Permissions: Permission{
|
|
Gamepad: targetPeer.Owner == wsSession.Email || targetPeer.Public || offerRequest.Payload.Secret == targetPeer.Secret || StringListContain(targetPeer.Assign, wsSession.Email),
|
|
Keyboard: targetPeer.Owner == wsSession.Email || targetPeer.Public || offerRequest.Payload.Secret == targetPeer.Secret || StringListContain(targetPeer.Assign, wsSession.Email),
|
|
Mouse: targetPeer.Owner == wsSession.Email || targetPeer.Public || offerRequest.Payload.Secret == targetPeer.Secret || StringListContain(targetPeer.Assign, wsSession.Email),
|
|
},
|
|
User: OfferUser{
|
|
Id: wsSession.UserId,
|
|
TeamId: "",
|
|
Name: wsSession.Email,
|
|
ExternalId: "",
|
|
ExternalProvider: "",
|
|
},
|
|
HostUser: OfferUser{
|
|
Id: targetUser.UserId,
|
|
TeamId: "",
|
|
Name: "",
|
|
ExternalId: "",
|
|
ExternalProvider: "",
|
|
},
|
|
},
|
|
}
|
|
|
|
targetWsSession.WsConn.WriteMessage(websocket.TextMessage, formatJson(offerRelay))
|
|
}
|
|
}
|
|
case "answer":
|
|
var answerRequest *AnswerModel
|
|
json.Unmarshal(p, &answerRequest)
|
|
targetSession := parsecService.GetWsSessionByAttemptId(answerRequest.Payload.To, answerRequest.Payload.AttemptId)
|
|
if targetSession != nil && targetSession.WsConn != nil {
|
|
|
|
answerRelay := &AnswerModel{
|
|
SocketRequest: SocketRequest{
|
|
Version: 1,
|
|
Action: "answer_relay",
|
|
},
|
|
Payload: AnswerPayload{
|
|
To: answerRequest.Payload.To,
|
|
Data: answerRequest.Payload.Data,
|
|
AttemptId: answerRequest.Payload.AttemptId,
|
|
Approved: answerRequest.Payload.Approved,
|
|
From: wsSession.HostPeerId,
|
|
UserId: wsSession.UserId,
|
|
},
|
|
}
|
|
targetSession.WsConn.WriteMessage(websocket.TextMessage, formatJson(answerRelay))
|
|
}
|
|
case "candex":
|
|
var candexRequest *CandexModel
|
|
json.Unmarshal(p, &candexRequest)
|
|
targetSession := parsecService.GetWsSessionByAttemptId(candexRequest.Payload.To, candexRequest.Payload.AttemptId)
|
|
if targetSession == nil {
|
|
targetSession = parsecService.GetWsSessionByPeerId(ROLE_HOST, candexRequest.Payload.To)
|
|
}
|
|
if targetSession != nil && targetSession.WsConn != nil {
|
|
candexRelay := &CandexModel{
|
|
SocketRequest: SocketRequest{
|
|
Version: 1,
|
|
Action: "candex_relay",
|
|
},
|
|
Payload: CandexPayload{
|
|
To: candexRequest.Payload.To,
|
|
Data: candexRequest.Payload.Data,
|
|
AttemptId: candexRequest.Payload.AttemptId,
|
|
From: wsSession.HostPeerId,
|
|
},
|
|
}
|
|
targetSession.WsConn.WriteMessage(websocket.TextMessage, formatJson(candexRelay))
|
|
|
|
if hostPeer.External != "" {
|
|
addr, _ := net.ResolveIPAddr("ip", hostPeer.External)
|
|
candexRelayExternal := &CandexModel{
|
|
SocketRequest: SocketRequest{
|
|
Version: 1,
|
|
Action: "candex_relay",
|
|
},
|
|
Payload: CandexPayload{
|
|
To: candexRequest.Payload.To,
|
|
AttemptId: candexRequest.Payload.AttemptId,
|
|
From: wsSession.HostPeerId,
|
|
Data: CandexData{
|
|
FromStun: true,
|
|
Ip: "::ffff:" + addr.IP.String(),
|
|
Lan: false,
|
|
Port: candexRequest.Payload.Data.Port,
|
|
Sync: false,
|
|
VerData: candexRequest.Payload.Data.VerData,
|
|
},
|
|
},
|
|
}
|
|
Logger.Println("UseCustom External: IP=" + addr.IP.String() + " PORT=" + strconv.Itoa(candexRequest.Payload.Data.Port))
|
|
targetSession.WsConn.WriteMessage(websocket.TextMessage, formatJson(candexRelayExternal))
|
|
}
|
|
}
|
|
|
|
case "offer_cancel":
|
|
var offerCancelRequest *OfferCancelModel
|
|
json.Unmarshal(p, &offerCancelRequest)
|
|
targetSession := parsecService.GetWsSessionByAttemptId(offerCancelRequest.Payload.To, offerCancelRequest.Payload.AttemptId)
|
|
if targetSession != nil && targetSession.WsConn != nil {
|
|
offerCancelRelay := &OfferCancelModel{
|
|
SocketRequest: SocketRequest{
|
|
Version: 1,
|
|
Action: "offer_cancel_relay",
|
|
},
|
|
Payload: OfferCancelPayload{
|
|
To: offerCancelRequest.Payload.To,
|
|
AttemptId: offerCancelRequest.Payload.AttemptId,
|
|
From: wsSession.HostPeerId,
|
|
UserId: wsSession.UserId,
|
|
},
|
|
}
|
|
targetSession.WsConn.WriteMessage(websocket.TextMessage, formatJson(offerCancelRelay))
|
|
}
|
|
|
|
}
|
|
mutex.Unlock()
|
|
|
|
}
|
|
}
|