parsec/socket_service.go
2023-06-02 15:41:51 +08:00

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()
}
}