Zippytal-Node/webrtcGrpcMiddleware.go
2021-12-08 15:58:40 +01:00

196 lines
6.1 KiB
Go

package localserver
import (
"context"
"fmt"
"strconv"
"github.com/pion/webrtc/v3"
)
type GrpcRequestType string
const (
PEER_CONNECTION_REQUEST GrpcRequestType = "peer_connection_request"
)
const (
OFFER ReqType = "offer"
ANSWER ReqType = "answer"
COUNTER_OFFER ReqType = "webrtc_counter_offer"
JOIN_HOSTED_SQUAD ReqType = "join_hosted_squad"
HOSTED_SQUAD_ACCESS_DENIED ReqType = "hosted_squad_access_denied"
HOSTED_SQUAD_STOP_CALL ReqType = "hosted_squad_stop_call"
HOSTED_SQUAD_ACCESS_GRANTED ReqType = "hosted_squad_access_granted"
LEAVE_HOSTED_SQUAD ReqType = "leave_hosted_squad"
INCOMING_MEMBER_HOSTED ReqType = "incoming_member_hosted"
LEAVING_MEMBER_HOSTED ReqType = "leaving_member_hosted"
HOSTED_SQUAD_WEBRTC_OFFER ReqType = "hosted_squad_offer"
HOSTED_SQUAD_WEBRTC_ANSWER ReqType = "hosted_squad_answer"
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER ReqType = "hosted_squad_rennegotiation_offer"
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "hosted_squad_rennegotiation_answer"
HOSTED_SQUAD_WEBRTC_COUNTER_OFFER ReqType = "hosted_squad_webrtc_counter_offer"
HOSTED_SQUAD_WEBRTC_CANDIDATE ReqType = "hosted_squad_webrtc_candidate"
HOSTED_SQUAD_REMOVE_VIDEO ReqType = "hosted_squad_remove_video"
GET_HOSTED_SQUAD_TRACKS ReqType = "hosted_squad_get_tracks"
NEW_HOSTED_SQUAD = "new_hosted_squad"
)
type WebRTCGrpcMiddleware struct {
Manager *WebRTCCallManager
stream GrpcManager_LinkClient
}
func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *WebRTCGrpcMiddleware) {
webrtcGrpcMiddleware = &WebRTCGrpcMiddleware{
Manager: manager,
}
return
}
func validateRequest(req map[string]string, entries ...string) (err error) {
for _, entry := range entries {
if _, ok := req[entry]; !ok {
err = fmt.Errorf("no field %s in req payload", entry)
return
}
}
return
}
func (wgm *WebRTCGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
err = wgm.stream.Send(&Request{
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
From: wgm.Manager.ID,
Token: "none",
Payload: map[string]string{
"from": wgm.Manager.ID,
"to": to,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
},
})
return
}
func (wgm *WebRTCGrpcMiddleware) Process(ctx context.Context, req *Response, stream GrpcManager_LinkClient) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
defer func() {
done <- struct{}{}
}()
switch req.Type {
case NEW_HOSTED_SQUAD:
if err := validateRequest(req.Payload, "ID"); err != nil {
errCh <- err
return
}
logger.Println("new squad incoming")
wgm.Manager.SquadMapMux.Lock()
wgm.Manager.Squads[req.Payload["ID"]] = &Squad{
ID: req.Payload["ID"],
Members: []string{},
}
wgm.Manager.SquadMapMux.Unlock()
case string(HOSTED_SQUAD_STOP_CALL):
logger.Println("quit squad called")
if err := validateRequest(req.Payload, FROM, "squadId"); err != nil {
errCh <- err
return
}
wgm.Manager.HandleLeavingMember(req.Payload[FROM], req.Payload["squadId"])
done <- struct{}{}
case string(PEER_CONNECTION_REQUEST):
if err := validateRequest(req.Payload, FROM, TO); err != nil {
errCh <- err
return
}
logger.Println("creating offer for peer")
if err := wgm.Manager.CreateOffer(ctx, req.Payload[FROM], req.Payload[TO], wgm.signalCandidate); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_OFFER):
if err := validateRequest(req.GetPayload(), FROM, TO, SDP, SQUAD_ID); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleOffer(ctx, req.GetPayload(), wgm.signalCandidate); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_ANSWER):
if err := validateRequest(req.GetPayload(), FROM, TO, SDP); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleAnswer(ctx, req.GetPayload()); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER):
if err := validateRequest(req.GetPayload(), FROM); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleCounterOffer(ctx, req.Payload); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
logger.Println("received negotiation answer")
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleRennegotiationAnswer(req.Payload[FROM], req.Payload[SDP]); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
logger.Println("received negotiation offer")
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleRennegotiationOffer(req.Payload[FROM], req.Payload[SDP]); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_CANDIDATE):
if err := validateRequest(req.GetPayload(), FROM, "candidate", "sdpMlineIndex", "sdpMid"); err != nil {
errCh <- err
return
}
logger.Println(req.Payload)
i, err := strconv.Atoi(req.Payload["sdpMlineIndex"])
if err != nil {
errCh <- err
return
}
sdpMlineIndex := uint16(i)
sdpMid := req.Payload["sdpMid"]
logger.Println(sdpMid, sdpMlineIndex)
if err := wgm.Manager.AddCandidate(&webrtc.ICECandidateInit{
Candidate: req.Payload["candidate"],
SDPMid: &sdpMid,
SDPMLineIndex: &sdpMlineIndex,
}, req.Payload[FROM]); err != nil {
errCh <- err
return
}
default:
}
}()
select {
case <-ctx.Done():
err = ctx.Err()
return
case <-done:
return
case err = <-errCh:
return
}
}