added chat module first unrevised version

This commit is contained in:
Loïs BIBEHE 2022-11-29 17:46:32 +01:00
parent 5bffde75f5
commit f2ebf8cb4c
Signed by: Lois
GPG Key ID: 782967C8C0F78E79
26 changed files with 3155 additions and 333 deletions

176
chatGrpcMiddleware.go Normal file
View File

@ -0,0 +1,176 @@
package localserver
import (
"context"
"encoding/json"
"strconv"
"github.com/pion/webrtc/v3"
)
const (
NEW_CHAT = "new_chat"
CHAT_DELETED = "chat_deleted"
CHAT_SYNCED = "chat_synced"
SYNC_CHAT = "sync_chat"
EXPORT_CHAT = "export_chat"
CHAT_EXPORTED = "chat_exported"
GET_NODE_CHATS = "get_node_chats"
LEAVE_CHAT = "leave_chat"
CHAT_WEBRTC_OFFER = "chat_webrtc_offer"
CHAT_WEBRTC_ANSWER = "chat_webrtc_answer"
CHAT_WEBRTC_COUNTER_OFFER = "chat_webrtc_counter_offer"
CHAT_WEBRTC_RENNEGOTIATION_OFFER = "chat_webrtc_rennegotiation_offer"
CHAT_WEBRTC_RENNEGOTIATION_ANSWER = "chat_werbtc_rennegotiation_answer"
CHAT_WEBRTC_CANDIDATE = "chat_webrtc_candidate"
)
type ChatGrpcMiddleware struct {
Manager *ChatsManager
stream SignalingService_LinkClient
}
func NewChatGrpcMiddleware(manager *ChatsManager) (chatGrpcMiddleware *ChatGrpcMiddleware) {
chatGrpcMiddleware = &ChatGrpcMiddleware{
Manager: manager,
}
return
}
func (cm *ChatGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
bs, err := json.Marshal((map[string]string{
"from": NodeID,
"to": to,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
}))
if err != nil {
return
}
err = cm.stream.Send(&SignalingMessage{
Type: CHAT_WEBRTC_CANDIDATE,
From: NodeID,
To: to,
Payload: bs,
})
return
}
func (cm *ChatGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, streram SignalingService_LinkClient) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
var payload map[string]string
if e := json.Unmarshal(req.Payload, &payload); e != nil {
errCh <- e
return
}
switch req.GetType() {
case NEW_CHAT:
if err := validateRequest(payload, "chatID", "initiator", "target", "initiatorHostId", "targetHostId"); err != nil {
errCh <- err
return
}
chat, err := NewNodeChat(payload["chatID"], payload["chatID"], payload["initiator"], payload["target"], payload["initiatorHostId"], payload["targetHostId"], false)
if err != nil {
errCh <- err
return
}
_ = atomicallyExecute(cm.Manager.chatsFlag, func() (err error) {
cm.Manager.Chats[chat.ID] = chat
return
})
case CHAT_DELETED:
if err := validateRequest(payload, "chatID"); err != nil {
return
}
if err := cm.Manager.DeleteChat(payload["chatID"]); err != nil {
errCh <- err
return
}
case CHAT_EXPORTED:
//todo: implement chat exported
case EXPORT_CHAT:
//todo: implement export chat exported
case CHAT_SYNCED:
//todo: implement chat synced
case SYNC_CHAT:
//todo: implement sync chat
case CHAT_WEBRTC_OFFER:
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := cm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, cm.signalCandidate); err != nil {
errCh <- err
return
}
case CHAT_WEBRTC_ANSWER:
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := cm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
}
case CHAT_WEBRTC_COUNTER_OFFER:
if err := cm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
}
case CHAT_WEBRTC_RENNEGOTIATION_OFFER:
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := cm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
errCh <- err
return
}
case CHAT_WEBRTC_RENNEGOTIATION_ANSWER:
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := cm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
errCh <- err
return
}
case CHAT_WEBRTC_CANDIDATE:
if err := validateRequest(payload, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
errCh <- err
return
}
logger.Println(payload)
i, err := strconv.Atoi(payload["sdpMLineIndex"])
if err != nil {
errCh <- err
return
}
SDPMLineIndex := uint16(i)
sdpMid := payload["sdpMid"]
logger.Println(sdpMid, SDPMLineIndex)
if err := cm.Manager.AddCandidate(&webrtc.ICECandidateInit{
Candidate: payload["candidate"],
SDPMid: &sdpMid,
SDPMLineIndex: &SDPMLineIndex,
}, req.GetFrom()); err != nil {
errCh <- err
return
}
default:
logger.Println("no request for chats grpc middleware")
logger.Println(payload)
logger.Println(req.Type)
}
}()
select {
case <-ctx.Done():
return ctx.Err()
case err = <-errCh:
return
case <-done:
return
}
}

730
chatManager.go Normal file
View File

@ -0,0 +1,730 @@
package localserver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"sync"
"github.com/google/uuid"
"github.com/pion/webrtc/v3"
)
type ChatsManager struct {
ID string
Chats map[string]*NodeChat
LocalSD map[string]*webrtc.SessionDescription
RTCPeerConnections map[string]*RTCPeerConnection
DataChannels map[string]*DataChannel
PendingCandidates map[string][]*webrtc.ICECandidate
stream SignalingService_LinkClient
chatsFlag *uint32
peerConnectionFlag *uint32
localSDFlag *uint32
dataChannelFlag *uint32
candidateFlag *uint32
}
type NodeChat struct {
ID string `json:"id"`
Name string `json:"name"`
Initiator string `json:"initiator"`
Target string `json:"target"`
InitiatorHost string `json:"initiatorHost"`
TargetHost string `json:"targetHost"`
DataChannels map[string]*DataChannel `json:"-"`
DataChannelsFlag *uint32 `json:"-"`
ChatRequestScheduler *ChatRequestScheduler `json:"-"`
Initialized bool `json:"-"`
}
func NewNodeChat(id, name, initiator, target, initiatorHost, targetHost string, initialized bool) (chat *NodeChat, err error) {
dataChannels, dataChannelFlag := make(map[string]*DataChannel), uint32(0)
nodeChatMessageHandler, err := NewNodeChatChannelsHandler(chat.ID, chat.ID, chat.Initiator, chat.Target, chat.InitiatorHost, chat.TargetHost, dataChannels, &dataChannelFlag)
chatScheduler, e := NewChatRequestScheduler(initiator, target, initiatorHost, targetHost, nodeChatMessageHandler)
go func() {
for schedErr := range e {
logger.Println("chat error:", schedErr)
}
}()
chat = &NodeChat{
ID: id,
Name: name,
Initiator: initiator,
Target: target,
InitiatorHost: initiatorHost,
TargetHost: targetHost,
DataChannels: dataChannels,
DataChannelsFlag: &dataChannelFlag,
ChatRequestScheduler: chatScheduler,
}
return
}
func NewChatManager(id, token string) (chatManager *ChatsManager, err error) {
chatsFlag := uint32(0)
peerConnectionFlag := uint32(0)
localSDFlag := uint32(0)
dataChannelFlag := uint32(0)
candidateFlag := uint32(0)
dataChannels := make(map[string]*DataChannel)
chatsMap := make(map[string]*NodeChat)
chats, err := chatManager.fetchChats(id, token)
if err != nil {
return
}
for _, chat := range chats {
c, err := NewNodeChat(chat.ID, chat.Name, chat.Initiator, chat.Target, chat.InitiatorHost, chat.TargetHost, false)
if err != nil {
return nil, err
}
_ = atomicallyExecute(&chatsFlag, func() (err error) {
chatsMap[chat.ID] = c
return
})
}
chatsFolder, err := os.ReadDir(filepath.Join(dataPath, "data", "chats"))
if err != nil {
if os.IsNotExist(err) {
if err = os.MkdirAll(filepath.Join(dataPath, "data", "chats"), 0770); err != nil {
return
}
} else {
return nil, err
}
}
chatManager = &ChatsManager{
ID: id,
Chats: chatsMap,
LocalSD: make(map[string]*webrtc.SessionDescription),
RTCPeerConnections: make(map[string]*RTCPeerConnection),
PendingCandidates: make(map[string][]*webrtc.ICECandidate),
DataChannels: dataChannels,
chatsFlag: &chatsFlag,
peerConnectionFlag: &peerConnectionFlag,
localSDFlag: &localSDFlag,
dataChannelFlag: &dataChannelFlag,
candidateFlag: &candidateFlag,
}
for _, c := range chatsFolder {
if _, ok := chatsMap[c.Name()]; !ok {
logger.Println(chatManager.DeleteChat(c.Name()))
}
}
return
}
func (cm *ChatsManager) fetchChats(nodeId string, token string) (chats []*NodeChat, err error) {
em := NewEncryptionManager()
sig := em.SignRequestHMAC(nodeId)
body, err := json.Marshal(map[string]interface{}{
"type": GET_NODE_CHATS,
"mac": sig,
"from": nodeId,
"peerType": "node",
"payload": map[string]string{
"host": nodeId,
"lastIndex": "0",
},
})
if err != nil {
return
}
res, err := HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewReader(body))
if err != nil {
logger.Println("error come from there inn chat manager")
return
}
bs, err := io.ReadAll(res.Body)
if err != nil {
return
}
var payload map[string]any
if err = json.Unmarshal(bs, &payload); err != nil {
return
}
b, err := json.Marshal(payload["Chats"])
if err != nil {
return
}
err = json.Unmarshal(b, &chats)
return
}
func (cm *ChatsManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
bs, err := json.Marshal(payload)
if err != nil {
return
}
err = cm.stream.Send(&SignalingMessage{
Type: messageType,
From: from,
To: to,
Payload: bs,
})
return
}
func (cm *ChatsManager) DeleteChat(chatId string) error {
return os.RemoveAll(filepath.Join(dataPath, "data", "chats", chatId))
}
func (cm *ChatsManager) CreateOffer(ctx context.Context, target string, from string, chatId string, cb OnICECandidateFunc) (err error) {
peerConnection, err := cm.createPeerConnection(target, from, chatId, webrtc.SDPTypeOffer, cb)
if err != nil {
return
}
logger.Println("connection created")
rawOffer, err := peerConnection.CreateOffer(nil)
if err != nil {
return
}
if err = peerConnection.SetLocalDescription(rawOffer); err != nil {
return
}
_ = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
id := uuid.New().String()
logger.Println("adding for target", target)
cm.RTCPeerConnections[target] = &RTCPeerConnection{
id: id,
PeerConnection: peerConnection,
makingOffer: true,
makingOfferLock: &sync.Mutex{},
negotiate: cm.negotiate,
}
return
})
err = cm.sendSignalingMessage(string(CHAT_WEBRTC_OFFER), cm.ID, target, map[string]any{
"to": target,
"from": cm.ID,
"sdp": rawOffer.SDP,
})
return
}
func (cm *ChatsManager) HandleOffer(ctx context.Context, from string, to string, req map[string]string, cb OnICECandidateFunc) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
if _, ok := cm.Chats[req["chatId"]]; !ok {
err = fmt.Errorf("no corresponding chat")
errCh <- err
return
}
logger.Println("handling chat offer")
_ = atomicallyExecute(cm.chatsFlag, func() (err error) {
return
})
if _, ok := cm.RTCPeerConnections[from]; ok {
if e := cm.HandleLeavingMember(from, req["chatId"], false); e != nil {
logger.Println(e)
}
}
peerConnection, err := cm.createPeerConnection(from, to, req["chatId"], webrtc.SDPTypeAnswer, cb)
if err != nil {
errCh <- err
return
}
logger.Println("peer connection created")
_ = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
id := uuid.New().String()
cm.RTCPeerConnections[from] = &RTCPeerConnection{
PeerConnection: peerConnection,
id: id,
makingOffer: false,
makingOfferLock: &sync.Mutex{},
negotiate: cm.negotiate,
}
logger.Println("peer connection added to map")
offer := webrtc.SessionDescription{
Type: webrtc.SDPTypeOffer,
SDP: req[SDP],
}
if err = peerConnection.SetRemoteDescription(offer); err != nil {
errCh <- err
return
}
rawAnswer, err := peerConnection.CreateAnswer(nil)
if err != nil {
errCh <- err
return
}
_ = atomicallyExecute(cm.localSDFlag, func() (err error) {
cm.LocalSD[from] = &rawAnswer
return
})
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
errCh <- err
return
}
if err = cm.sendSignalingMessage(string(CHAT_WEBRTC_ANSWER), cm.ID, from, map[string]any{
"to": from,
"from": cm.ID,
"sdp": rawAnswer.SDP,
}); err != nil {
errCh <- err
return
}
done <- struct{}{}
return
})
}()
select {
case <-done:
return
case err = <-errCh:
return
case <-ctx.Done():
err = ctx.Err()
return
}
}
func (cm *ChatsManager) HandleAnswer(ctx context.Context, from string, to string, req map[string]string) (err error) {
defer func() {
if r := recover(); err != nil {
logger.Printf("recover from panic in handle answer : %v\n", r)
}
}()
if err = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
if _, ok := cm.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id : %s", from)
return
}
peerConnnection := cm.RTCPeerConnections[from]
logger.Println("---------------------")
logger.Println(req[SDP])
logger.Println("---------------------")
if err = peerConnnection.SetRemoteDescription(webrtc.SessionDescription{
Type: webrtc.SDPTypeAnswer,
SDP: req[SDP],
}); err != nil {
logger.Println("error occured while setting remote description in handle answer")
return
}
return
}); err != nil {
return
}
if err = cm.sendSignalingMessage(string(CHAT_WEBRTC_COUNTER_OFFER), cm.ID, from, map[string]any{
"from": cm.ID,
"to": from,
}); err != nil {
return
}
_ = atomicallyExecute(cm.candidateFlag, func() (err error) {
for _, candidate := range cm.PendingCandidates[from] {
logger.Println("sending candidate from answer to", from)
if err = cm.sendSignalingMessage(string(CHAT_WEBRTC_CANDIDATE), cm.ID, from, map[string]any{
"from": cm.ID,
"to": from,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
}); err != nil {
logger.Println(err)
continue
}
}
delete(cm.PendingCandidates, from)
return
})
_ = atomicallyExecute(cm.localSDFlag, func() (err error) {
delete(cm.LocalSD, from)
return
})
return
}
func (cm *ChatsManager) HandleCounterOffer(ctx context.Context, from string, to string, req map[string]string) (err error) {
_ = atomicallyExecute(cm.candidateFlag, func() (err error) {
for _, candidate := range cm.PendingCandidates[from] {
logger.Println("sending candidate to", from)
if err = cm.sendSignalingMessage(string(CHAT_WEBRTC_CANDIDATE), cm.ID, from, map[string]any{
"from": cm.ID,
"to": from,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
}); err != nil {
return
}
}
delete(cm.PendingCandidates, from)
return
})
_ = atomicallyExecute(cm.localSDFlag, func() (err error) {
delete(cm.LocalSD, from)
return
})
return
}
func (cm *ChatsManager) createPeerConnection(target string, from string, chatId string, peerType webrtc.SDPType, cb OnICECandidateFunc) (peerConnection *webrtc.PeerConnection, err error) {
defer func() {
if r := recover(); err != nil {
logger.Printf("recover from panic : %v\n", r)
}
}()
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478"},
},
},
SDPSemantics: webrtc.SDPSemanticsUnifiedPlan,
}
peerConnection, err = webrtc.NewPeerConnection(config)
if err != nil {
return
}
logger.Println("---------------------------------------------------")
if peerType == webrtc.SDPTypeOffer {
channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{})
if err != nil {
return nil, err
}
reqChan := make(chan *ChatRequest)
channel.OnOpen(func() {
logger.Println(chatId)
if _, ok := cm.Chats[chatId]; ok {
logger.Println("this chat exist")
_ = atomicallyExecute(cm.Chats[chatId].DataChannelsFlag, func() (err error) {
x := uint32(0)
cm.Chats[chatId].DataChannels[target] = &DataChannel{DataChannel: channel, bufferedAmountLowThresholdReached: make(<-chan struct{}), l: &x}
return
})
if _, ok := cm.Chats[chatId]; !ok {
err = fmt.Errorf("no corresponding Chats")
return
}
done, err := cm.Chats[chatId].ChatRequestScheduler.Schedule(reqChan)
bs, jsonErr := json.Marshal(&ZoneResponse{
Type: "user_chat_init",
From: chatId,
To: target,
Payload: map[string]interface{}{},
})
if jsonErr != nil {
logger.Println("error in open channel", jsonErr)
return
}
if sendErr := channel.SendText(string(bs)); sendErr != nil {
logger.Println("error in open channel send", sendErr)
return
}
go func() {
for {
select {
case <-done:
return
case e := <-err:
logger.Println("----- error from scheduler:", e)
}
}
}()
}
})
channel.OnClose(func() {
close(reqChan)
//_ = cm.HandleLeavingMember(target, chatId, true)
})
channel.OnError(func(err error) {
close(reqChan)
//_ = cm.HandleLeavingMember(target, chatId, true)
})
channel.OnMessage(func(msg webrtc.DataChannelMessage) {
var req ChatRequest
if err := json.Unmarshal(msg.Data, &req); err != nil {
logger.Println(err)
return
}
logger.Println("incoming request", req)
reqChan <- &req
})
logger.Println("new channel for target : ", target)
logger.Println(target)
_ = atomicallyExecute(cm.dataChannelFlag, func() (err error) {
l := uint32(0)
cm.DataChannels[target] = &DataChannel{
DataChannel: channel,
bufferedAmountLowThresholdReached: make(<-chan struct{}),
l: &l,
}
return
})
} else {
peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
_ = atomicallyExecute(cm.dataChannelFlag, func() (err error) {
l := uint32(0)
cm.DataChannels[target] = &DataChannel{
DataChannel: dc,
l: &l,
}
return
})
reqChan := make(chan *ChatRequest, 100)
if dc.Label() == "data" {
dc.OnOpen(func() {
logger.Println(chatId)
if _, ok := cm.Chats[chatId]; ok {
logger.Println("this chat exist")
_ = atomicallyExecute(cm.Chats[chatId].DataChannelsFlag, func() (err error) {
logger.Println("adding dc to dc map")
x := uint32(0)
cm.Chats[chatId].DataChannels[target] = &DataChannel{DataChannel: dc, bufferedAmountLowThresholdReached: make(<-chan struct{}), l: &x}
return
})
if _, ok := cm.Chats[chatId]; !ok {
err = fmt.Errorf("no corresponding Chats")
return
}
done, err := cm.Chats[chatId].ChatRequestScheduler.Schedule(reqChan)
go func() {
for {
select {
case <-done:
return
case <-err:
}
}
}()
}
})
dc.OnClose(func() {
fmt.Println("closing gracefully event dc...")
close(reqChan)
})
dc.OnError(func(err error) {
logger.Println("--------------- error in dc:", err)
close(reqChan)
})
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
var req ChatRequest
if err := json.Unmarshal(msg.Data, &req); err != nil {
logger.Println(err)
return
}
logger.Println("incoming request", req)
go func() {
reqChan <- &req
}()
})
_ = atomicallyExecute(cm.dataChannelFlag, func() (err error) {
l := uint32(0)
cm.DataChannels[target] = &DataChannel{
DataChannel: dc,
bufferedAmountLowThresholdReached: make(<-chan struct{}),
l: &l,
}
return
})
} else {
if _, ok := cm.Chats[chatId]; ok {
fmt.Println("got new mtfking datachannel")
fmt.Println(dc.Label())
scheduler := cm.Chats[chatId].ChatRequestScheduler
l := uint32(0)
datachannel := &DataChannel{
DataChannel: dc,
bufferedAmountLowThresholdReached: make(<-chan struct{}),
l: &l,
}
catched := scheduler.DispatchDataChannel(context.Background(), datachannel)
if !catched {
if closeErr := datachannel.DataChannel.Close(); closeErr != nil {
logger.Println(closeErr)
}
}
}
}
})
}
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
if pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
logger.Println(pcs)
if err = cm.HandleLeavingMember(target, chatId, true); err != nil {
logger.Println(err)
}
}
})
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
logger.Printf("ICE connection state has changed %s\n", is.String())
})
peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
if i == nil {
return
}
_ = atomicallyExecute(cm.candidateFlag, func() (err error) {
desc := peerConnection.RemoteDescription()
if desc == nil {
logger.Println("generated candidate appended to list : ", i)
cm.PendingCandidates[target] = append(cm.PendingCandidates[target], i)
} else {
logger.Println("generated candidate : ", i)
if iceCandidateErr := cb(target, i); iceCandidateErr != nil {
logger.Println(iceCandidateErr)
}
}
return
})
})
return
}
func (cm *ChatsManager) HandleRennegotiationOffer(from, sdp string) (err error) {
err = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
if _, ok := cm.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
if err = cm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
return
}
localSd, err := cm.RTCPeerConnections[from].CreateAnswer(nil)
if err != nil {
return
}
if err = cm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
return
}
if err = cm.sendSignalingMessage(string(CHAT_WEBRTC_RENNEGOTIATION_ANSWER), cm.ID, from, map[string]any{
"to": from,
"sdp": localSd.SDP,
}); err != nil {
logger.Println(err)
return
}
return
})
return
}
func (cm *ChatsManager) HandleRennegotiationAnswer(from string, sdp string) (err error) {
_ = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
if _, ok := cm.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
err = cm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
return
})
return
}
func (cm *ChatsManager) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
_ = atomicallyExecute(cm.candidateFlag, func() (err error) {
if candidate != nil {
if connection, ok := cm.RTCPeerConnections[from]; ok {
err = connection.AddICECandidate(*candidate)
}
}
return
})
return
}
func (cm *ChatsManager) HandleLeavingMember(id, chatId string, signalLeaving bool) (err error) {
logger.Println("---------------- handling leaving member", id)
if err = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
if _, ok := cm.RTCPeerConnections[id]; !ok {
err = fmt.Errorf("no correponding peerconnection for id %s", id)
return
}
return
}); err != nil {
return
}
if signalLeaving {
nerr := cm.notifyLeavingMember(id, chatId, NodeID)
fmt.Println(nerr)
}
err = atomicallyExecute(cm.chatsFlag, func() (err error) {
logger.Println(err)
logger.Println("---------------- cleaning chat handlers", id)
if chat, ok := cm.Chats[chatId]; ok {
for _, handlersPublishers := range chat.ChatRequestScheduler.handlersPublishers {
go func(hp chan<- *ChatRequest) {
hp <- &ChatRequest{
ReqType: LEAVE_CHAT,
From: id,
Payload: map[string]interface{}{
"userId": id,
},
}
}(handlersPublishers)
}
if err = atomicallyExecute(chat.DataChannelsFlag, func() (err error) {
defer delete(chat.DataChannels, id)
if dataChannel, ok := chat.DataChannels[id]; ok {
if err = dataChannel.DataChannel.Close(); err != nil {
return
}
}
return
}); err != nil {
fmt.Println(err)
}
logger.Println("datachannels cleaned", id)
} else {
err = fmt.Errorf("no corresponding chat for chatId %s", chatId)
}
logger.Println(err)
err = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
if _, ok := cm.RTCPeerConnections[id]; ok {
defer delete(cm.RTCPeerConnections, id)
if err = cm.RTCPeerConnections[id].Close(); err != nil {
return
}
}
return
})
fmt.Println(err)
_ = atomicallyExecute(cm.candidateFlag, func() (err error) {
delete(cm.PendingCandidates, id)
return
})
return
})
return
}
func (cm *ChatsManager) notifyLeavingMember(userId, chatId, hostId string) (err error) {
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
body, err := json.Marshal(map[string]interface{}{
"type": "DISCONNECT_CHAT_MEMBER",
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]string{
"chatId": chatId,
"userId": userId,
},
})
if err != nil {
return
}
_, err = HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewReader(body))
if err != nil {
logger.Println("error come from there in chat manager")
return
}
return
}
func (cm *ChatsManager) negotiate(target string, chatId string) {
_ = atomicallyExecute(cm.peerConnectionFlag, func() (err error) {
if _, ok := cm.RTCPeerConnections[target]; !ok {
err = fmt.Errorf("no peerConnections")
return
}
return
})
}

322
chatMessagesDBHandler.go Normal file
View File

@ -0,0 +1,322 @@
package localserver
import (
"encoding/binary"
"encoding/json"
"os"
"path/filepath"
"sync"
"github.com/dgraph-io/badger/v3"
)
type NodeChatDBHandler struct {
ChatID string
PreviousId uint64
ItemCount uint64
db func(func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
}
func NewNodeChatDBHandler(chatID string) (nodeChatDBHandler *NodeChatDBHandler, err error) {
nodeChatDBHandler = &NodeChatDBHandler{
db: func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join(dataPath, "data", "chats", chatID, "messages")).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
},
ChatID: chatID,
lock: new(sync.RWMutex),
}
err = nodeChatDBHandler.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt)
defer it.Close()
var counter uint64 = 1
var itemCounter uint64 = 0
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
counter = chatMessage.ID
itemCounter++
return
}); err != nil {
return err
}
}
nodeChatDBHandler.PreviousId = counter
nodeChatDBHandler.ItemCount = itemCounter
return nil
})
return
})
return
}
func (ncdbh *NodeChatDBHandler) calculateNewChatCount(previousId uint64) (count uint, err error) {
err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt)
defer it.Close()
count = 0
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, previousId)
if previousId == 0 || previousId == 1 {
count++
for it.Rewind(); it.Valid(); it.Next() {
count++
}
} else {
for it.Seek(b); it.Valid(); it.Next() {
count++
}
}
if count > 0 {
count--
}
return nil
})
return
})
return
}
func (ncdbh *NodeChatDBHandler) revertPreviousId() (err error) {
err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
opt.Reverse = true
it := txn.NewIterator(opt)
defer it.Close()
it.Rewind()
if it.Valid() {
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
ncdbh.PreviousId = chatMessage.ID
return
}); err != nil {
return err
}
} else {
ncdbh.PreviousId = 1
}
return nil
})
return
})
return
}
func (ncdbh *NodeChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) {
b := make([]byte, bufferSize)
ncdbh.PreviousId++
binary.BigEndian.PutUint64(b, ncdbh.PreviousId)
chatMessage.ID = ncdbh.PreviousId
bs, err := json.Marshal(chatMessage)
if err != nil {
return
}
if err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) (err error) {
if updateErr := txn.Set(b, bs); updateErr != nil {
return updateErr
}
return nil
})
return
}); err != nil {
return
}
return
}
func (ncdbh *NodeChatDBHandler) DeleteChatMessage(key uint64) (err error) {
if err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) (err error) {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key)
if err = txn.Delete(b); err != nil {
return
}
ncdbh.ItemCount--
return
})
return
}); err != nil {
return
}
return
}
func (ncdbh *NodeChatDBHandler) DeleteChatFile(filename string, key uint64) (err error) {
if err = ncdbh.DeleteChatMessage(key); err != nil {
return
}
err = os.Remove(filepath.Join(dataPath, "data", "chats", ncdbh.ChatID, "__files__", filename))
return
}
func (ncdbh *NodeChatDBHandler) ListChatMessages(lastIndex int, limit int) (chatMessages []*ChatMessage, l int, done bool, err error) {
err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) {
opt := badger.DefaultIteratorOptions
opt.Reverse = true
it := txn.NewIterator(opt)
defer it.Close()
b := make([]byte, bufferSize)
if lastIndex <= 0 {
binary.BigEndian.PutUint64(b, uint64(ncdbh.PreviousId))
} else {
binary.BigEndian.PutUint64(b, uint64(lastIndex))
}
x := 0
defer func() {
if x < limit {
done = true
}
}()
chatMessages = make([]*ChatMessage, 0)
for it.Seek(b); it.Valid(); it.Next() {
if x >= limit {
break
}
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
l = int(chatMessage.ID)
chatMessages = append(chatMessages, chatMessage)
return
}); err != nil {
return err
}
x++
}
return
})
return
})
return
}
func (ncdbh *NodeChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMessages []*ChatFile, l int, err error) {
err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) {
opt := badger.DefaultIteratorOptions
opt.Reverse = true
it := txn.NewIterator(opt)
defer it.Close()
b := make([]byte, bufferSize)
var li int
if lastIndex <= 0 {
binary.BigEndian.PutUint64(b, uint64(ncdbh.PreviousId))
li = int(ncdbh.PreviousId)
} else {
binary.BigEndian.PutUint64(b, uint64(lastIndex))
li = lastIndex
}
x := 0
y := 0
defer func() {
if li > x {
l = li - x
} else if li == 0 {
if ncdbh.PreviousId > uint64(x) {
l = int(ncdbh.PreviousId) - x
} else {
l = 0
}
} else {
l = 0
}
}()
defer it.Close()
chatMessages = make([]*ChatFile, 0)
for it.Seek(b); it.Valid(); it.Next() {
if y >= limit || x >= int(ncdbh.PreviousId) {
break
}
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
if chatMessage.File != nil {
chatMessages = append(chatMessages, chatMessage.File)
l = lastIndex - x
y++
}
return
}); err != nil {
return err
}
x++
}
return
})
return
})
return
}
func (ncdbh *NodeChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatMessage, err error) {
err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, uint64(index))
item, err := txn.Get(b)
if err != nil {
return
}
err = item.Value(func(val []byte) error {
return json.Unmarshal(val, &chatMessage)
})
return
})
return
})
return
}
func (ncdbh *NodeChatDBHandler) ModifyChatMessage(key uint64, newContent string) (err error) {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key)
chatMessage, err := ncdbh.GetChatMessage(key)
if err != nil {
return
}
chatMessage.Content = newContent
bs, err := json.Marshal(chatMessage)
if err != nil {
return
}
if err = ncdbh.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) (err error) {
if updateErr := txn.Set(b, bs); updateErr != nil {
return updateErr
}
return nil
})
return
}); err != nil {
return
}
return
}

164
chatMessagesFSInstance.go Normal file
View File

@ -0,0 +1,164 @@
package localserver
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"github.com/pion/webrtc/v3"
)
type NodeChatFSInstance struct {
ChatID string `json:"id"`
OpenFiles map[string]*os.File `json:"-"`
OpenFilesForUser map[string][]string `json:"-"`
filesFlag *uint32 `json:"-"`
}
func NewNodeChatFSInstance(chatID string) (chatFSInstance *NodeChatFSInstance) {
filesFlag := uint32(0)
chatFSInstance = &NodeChatFSInstance{
ChatID: chatID,
OpenFiles: make(map[string]*os.File),
OpenFilesForUser: make(map[string][]string),
filesFlag: &filesFlag,
}
return
}
func (fs *NodeChatFSInstance) SetupFileUpload(chatId, filename, userId string, dc *webrtc.DataChannel) (writePipe chan []byte, err error) {
concretePath := filepath.Join(dataPath, "data", "chats", chatId, "__files__", filename)
if _, err = os.ReadDir(filepath.Join(dataPath, "data", "chats", chatId)); err != nil {
return
}
if _, rErr := os.ReadDir(filepath.Join(dataPath, "data", "chats", chatId, "__files__")); os.IsNotExist(rErr) {
if err = os.MkdirAll(filepath.Join(dataPath, "data", "chats", chatId, "__files__"), 0700); err != nil {
return
}
} else if rErr != nil {
return nil, rErr
}
if err = os.Remove(concretePath); err != nil {
logger.Println(err)
}
file, err := os.OpenFile(concretePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
return
}
writePipe = make(chan []byte)
go func(f *os.File) {
defer func() {
_ = f.Close()
}()
for chunk := range writePipe {
if _, err = file.Write(chunk); err != nil {
return
}
}
}(file)
return
}
func (fs *NodeChatFSInstance) FileUploadFailed(chatId, filename, userId string) (err error) {
concretePath := filepath.Join(dataPath, "data", "chats", chatId, "__files__", filename)
err = os.Remove(concretePath)
return
}
func (fs *NodeChatFSInstance) SetupFileDownload(chatId, filename, userId string, dc *webrtc.DataChannel) (err error) {
concretePath := filepath.Join(dataPath, "data", "chats", chatId, "__files__", filename)
file, err := os.OpenFile(concretePath, os.O_RDONLY, 0755)
if err != nil {
return
}
if dc != nil {
dc.SetBufferedAmountLowThreshold(12000000)
bufferedAmountLock := make(chan struct{})
go func(f *os.File) {
defer func() {
close(bufferedAmountLock)
bufferedAmountLock = nil
_ = f.Close()
}()
r := bufio.NewReader(file)
buf := make([]byte, 0, 50000)
sendingLoop:
for {
n, readErr := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
logger.Println("n is 0 weird")
break sendingLoop
}
if err == io.EOF {
break sendingLoop
}
logger.Println(readErr)
return
}
if err = dc.Send(buf); err != nil {
dc.Close()
logger.Println(err)
break sendingLoop
}
if dc.BufferedAmount() > dc.
BufferedAmountLowThreshold() {
<-bufferedAmountLock
}
}
logger.Println("done")
if err = dc.SendText("download_done"); err != nil {
logger.Println(err)
}
}(file)
dc.OnBufferedAmountLow(func() {
if bufferedAmountLock != nil {
bufferedAmountLock <- struct{}{}
}
})
} else {
err = fmt.Errorf("datachannel not created")
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
if file, ok := fs.OpenFiles[fmt.Sprintf("%s/%s", filename, userId)]; ok {
file.Close()
}
delete(fs.OpenFiles, fmt.Sprintf("%s/%s", filename, userId))
return
})
}
return
}
func (fs *NodeChatFSInstance) FileDownloadFailed(chatId, filename, userId string) (err error) {
err = atomicallyExecute(fs.filesFlag, func() (err error) {
if file, ok := fs.OpenFiles[fmt.Sprintf("%s/%s", filename, userId)]; ok {
file.Close()
}
delete(fs.OpenFiles, fmt.Sprintf("%s/%s", filename, userId))
if _, ok := fs.OpenFilesForUser[userId]; ok {
var index int
for i, v := range fs.OpenFilesForUser[userId] {
if v == fmt.Sprintf("%s/%s", filename, userId) {
index = i
break
}
}
if len(fs.OpenFilesForUser[userId]) > 1 {
fs.OpenFilesForUser[userId] = append(fs.OpenFilesForUser[userId][:index], fs.OpenFilesForUser[userId][:index+1]...)
} else {
delete(fs.OpenFilesForUser, userId)
}
}
return
})
return
}
func (fs *NodeChatFSInstance) HandleDataChannelEvents(from, eventId string, payload map[string]interface{}) (err error) {
switch eventId {
}
return
}

827
chatMessagesHandler.go Normal file
View File

@ -0,0 +1,827 @@
package localserver
import (
"context"
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"time"
"github.com/dgraph-io/badger/v3"
"github.com/pion/webrtc/v3"
)
type NodeChatConfig struct {
ID string `json:"id"`
Name string `json:"name"`
Initiator string `json:"initiator"`
Target string `json:"target"`
InitiatorHost string `json:"initiatorHost"`
TargetHost string `json:"targetHost"`
}
type NodeChatChannel struct {
ID string `json:"id"`
Name string `json:"name"`
Initiator string `json:"initiator"`
Target string `json:"target"`
InitiatorHost string `json:"initiatorHost"`
TargetHost string `json:"targetHost"`
LastReadIndex uint `json:"lastReadIndex"`
Unread uint `json:"unread"`
DB *NodeChatDBHandler `json:"-"`
Tracking *NodeChatTrackingDB `json:"-"`
}
type NodeChatChannelsHandler[T ZippytalFSInstance] struct {
ChatID string
ChatFSInstance T
DataChannels map[string]*DataChannel
ChatDataChannels map[string]*DataChannel
ChatDataChannelsFlag *uint32
Flag *uint32
ChatFSInstanceFlag *uint32
ChatFlag *uint32
Chats map[string]*NodeChatChannel
reqChans []chan<- *ChatRequest
init bool
}
func NewNodeChatChannelsHandler(chatID, chatName, initiator, target, initiatorHostId, targetHostId string, dataChannels map[string]*DataChannel, flag *uint32) (nodeChatsHandler *NodeChatChannelsHandler[*NodeChatFSInstance], err error) {
var dirs []fs.DirEntry
dirs, err = os.ReadDir(filepath.Join(dataPath, "data", "chats", chatID))
if err != nil {
if os.IsNotExist(err) {
logger.Printf("creating chat directory for chat %s...\n", chatID)
mkdirErr := os.MkdirAll(filepath.Join(dataPath, "data", "chats", chatID), 0700)
if mkdirErr != nil {
return nil, mkdirErr
}
file, ferr := os.Create(filepath.Join(dataPath, "data", "chats", chatID, "chatConfig.json"))
if ferr != nil {
return nil, ferr
}
baseConfig := NodeChatConfig{
ID: chatID,
Name: chatName,
Initiator: initiator,
InitiatorHost: initiatorHostId,
Target: target,
TargetHost: targetHostId,
}
bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil {
return nil, jsonErr
}
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
return nil, writeErr
}
_ = file.Close()
dirs, err = os.ReadDir(filepath.Join(dataPath, "data", "chats", chatID))
if err != nil {
return nil, err
}
} else {
return
}
}
chats := make(map[string]*NodeChatChannel)
for _, chat := range dirs {
if strings.HasPrefix(chat.Name(), ".") {
continue
}
nodeChatDBHandler, err := NewNodeChatDBHandler(chat.Name())
if err != nil {
return nil, err
}
var bs []byte
bs, err = os.ReadFile(filepath.Join(dataPath, "data", "chats", chat.Name(), "chatConfig.json"))
if err != nil {
return nil, err
}
logger.Println(string(bs))
var c NodeChatChannel
if err = json.Unmarshal(bs, &c); err != nil {
return nil, err
}
nodeChatTracking, err := NewNodeChatTracking(chatID, initiator, target)
if err != nil {
return nil, err
}
logger.Println("chats data :", c.ID, c.Initiator, c.InitiatorHost, c.Target)
c.DB = nodeChatDBHandler
c.Tracking = nodeChatTracking
chats[c.ID] = &c
}
chatFlag := uint32(0)
chatFSFlag := uint32(0)
chatDCFlag := uint32(0)
nodeChatsHandler = &NodeChatChannelsHandler[*NodeChatFSInstance]{
ChatID: chatID,
ChatFSInstance: NewNodeChatFSInstance(chatID),
ChatFSInstanceFlag: &chatFSFlag,
DataChannels: dataChannels,
ChatDataChannels: make(map[string]*DataChannel),
ChatDataChannelsFlag: &chatDCFlag,
Flag: flag,
Chats: chats,
ChatFlag: &chatFlag,
init: false,
}
return
}
func (zch *NodeChatChannelsHandler[T]) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
go func() {
for _, rc := range zch.reqChans {
rc <- &ChatRequest{
ReqType: reqType,
From: from,
Payload: payload,
}
}
}()
}
func (zch *NodeChatChannelsHandler[T]) sendDataChannelMessage(reqType string, from string, to string, payload map[string]interface{}) (<-chan struct{}, <-chan error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
if err := atomicallyExecute(zch.ChatDataChannelsFlag, func() (err error) {
if _, ok := zch.ChatDataChannels[to]; ok {
bs, jsonErr := json.Marshal(&ZoneResponse{
Type: reqType,
From: from,
To: to,
Payload: payload,
})
if jsonErr != nil {
return jsonErr
}
err = zch.ChatDataChannels[to].DataChannel.SendText(string(bs))
} else {
err = fmt.Errorf("no corresponding dataChannel")
}
return
}); err != nil {
errCh <- err
return
}
done <- struct{}{}
}()
return done, errCh
}
func (zch *NodeChatChannelsHandler[T]) Init(ctx context.Context, initiator, target, initiatorNodeID, targetNodeID string) (err error) {
// for _, member := range authorizedMembers {
// if serr := zch.SetAllPublicChatForUser(member); serr != nil {
// logger.Println(serr)
// }
// }
zch.init = true
return
}
func (zch *NodeChatChannelsHandler[T]) Subscribe(ctx context.Context, publisher <-chan *ChatRequest) (reqChan chan *ChatRequest, done chan struct{}, errCh chan error) {
reqChan, done, errCh = make(chan *ChatRequest), make(chan struct{}), make(chan error)
zch.reqChans = append(zch.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := zch.handleChatRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (zch *NodeChatChannelsHandler[T]) GetChats(userId string) (err error) {
chats := make([]*NodeChatChannel, 0)
for _, chat := range zch.Chats {
if chat.Initiator == userId || chat.Target == userId {
chats = append(chats, chat)
}
}
for _, chat := range chats {
index, err := chat.Tracking.GetUserLastIndex(userId)
if err != nil {
return err
}
unread, err := chat.DB.calculateNewChatCount(uint64(index))
if err != nil {
return err
}
chat.LastReadIndex = index
chat.Unread = unread
}
done, e := zch.sendDataChannelMessage(GET_CHATS_RESPONSE, "node", userId, map[string]interface{}{
"chats": chats,
})
select {
case <-done:
case err = <-e:
}
return
}
func (zch *NodeChatChannelsHandler[T]) ListChats() (chats []*NodeChatChannel, err error) {
chats = make([]*NodeChatChannel, 0)
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
for _, chat := range zch.Chats {
chats = append(chats, chat)
}
return
})
return
}
func (zch *NodeChatChannelsHandler[T]) AddNewChat(chatID, initiator, target, initiatorHostId, targetHostId string) (err error) {
if chatID == "" {
err = fmt.Errorf("not a valid chat name provided")
return
}
if _, ok := zch.Chats[chatID]; ok {
err = fmt.Errorf("a chat with this name already exist")
return
}
mkdirErr := os.MkdirAll(filepath.Join(dataPath, "data", "chats", chatID), 0700)
if mkdirErr != nil {
return mkdirErr
}
mkdirErr = os.Mkdir(filepath.Join(dataPath, "data", "chats", chatID, "__tracking__"), 0700)
if mkdirErr != nil {
return mkdirErr
}
file, ferr := os.Create(filepath.Join(dataPath, "data", "chats", chatID, "chatConfig.json"))
defer func() {
_ = file.Close()
}()
if ferr != nil {
return ferr
}
baseConfig := &NodeChatConfig{
ID: chatID,
}
bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil {
return jsonErr
}
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
return writeErr
}
err = file.Close()
if err != nil {
return err
}
nodeChatDBHandler, err := NewNodeChatDBHandler(chatID)
if err != nil {
return err
}
nodeChatTrackingDB, err := NewNodeChatTracking(chatID, initiator, target)
if err != nil {
return err
}
if err = nodeChatTrackingDB.Initialize(1, initiator, target); err != nil {
return err
}
var c NodeChatChannel
if err = json.Unmarshal(bs, &c); err != nil {
return err
}
c.DB = nodeChatDBHandler
c.Tracking = nodeChatTrackingDB
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
zch.Chats[c.ID] = &c
return
})
return
}
func (zch *NodeChatChannelsHandler[T]) DeleteChat(chatID string) (err error) {
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
defer delete(zch.Chats, chatID)
if _, ok := zch.Chats[chatID]; !ok {
err = fmt.Errorf("no corresponding chat")
return
}
return
}); err != nil {
return
}
if err = os.RemoveAll(filepath.Join(dataPath, "data", "chats", chatID)); err != nil {
return
}
return
}
func (zch *NodeChatChannelsHandler[T]) ReadLastMessage(userId, chatID string) (err error) {
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatID]; ok {
err = chat.Tracking.SetUserLastIndex(userId, chat.DB.PreviousId)
}
return
})
return
}
func (zch *NodeChatChannelsHandler[T]) ListLatestChatMessages(userId, chatID string, lastIndex, limit float64) (err error) {
var list []*ChatMessage
var i int
var done bool
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatID]; ok {
list, i, done, err = zch.Chats[chatID].DB.ListChatMessages(int(lastIndex), int(limit))
if err != nil {
return
}
err = chat.Tracking.SetUserLastIndex(userId, chat.DB.PreviousId)
}
return
}); err != nil {
return
}
success, e := zch.sendDataChannelMessage(CHAT_MESSAGE_LIST, "node", userId, map[string]interface{}{
"done": done || i <= 0,
"lastIndex": i - 1,
"chatID": chatID,
"chatMessages": list,
})
select {
case <-success:
fmt.Println("done getting latest messages")
case err = <-e:
}
return
}
func (zch *NodeChatChannelsHandler[T]) ListLatestChatFiles(userId, chatID string, lastIndex, limit float64) (err error) {
var list []*ChatFile
var i int
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if _, ok := zch.Chats[chatID]; ok {
list, i, err = zch.Chats[chatID].DB.ListChatFiles(int(lastIndex), int(limit))
}
return
}); err != nil {
return
}
done, e := zch.sendDataChannelMessage(CHAT_FILES_LIST, "node", userId, map[string]interface{}{
"done": i <= 0,
"lastIndex": i,
"chatID": chatID,
"chatMessages": list,
})
select {
case <-done:
case err = <-e:
}
return
}
func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content string, isResponse bool, chatResponseId uint64, file *ChatFile) (err error) {
if _, ok := zch.Chats[chatID]; !ok {
err = fmt.Errorf("no such chat")
return
}
chat := zch.Chats[chatID]
chatMessage := &ChatMessage{
Content: content,
From: userId,
IsResponse: isResponse,
ResponseOf: nil,
File: file,
Tags: make([]string, 0),
Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"),
}
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatID]; ok {
if isResponse {
parentMessage, getErr := chat.DB.GetChatMessage(chatResponseId)
if err != nil {
if getErr != badger.ErrKeyNotFound {
return getErr
}
}
chatMessage.ResponseOf = parentMessage
}
if err = zch.Chats[chatID].DB.AddNewChatMessage(chatMessage); err != nil {
return
}
chatMessage.ID = zch.Chats[chatID].DB.PreviousId
} else {
err = fmt.Errorf("no corresponding chats")
}
return
}); err != nil {
return
}
notifyActivity := func(done <-chan struct{}, e <-chan error, target, initiator string) {
select {
case <-done:
case <-e:
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatID]; ok {
li, err := chat.Tracking.GetUserLastIndex(target)
if err != nil {
return err
}
count, err := chat.DB.calculateNewChatCount(uint64(li))
if err != nil {
return err
}
bs, err := json.Marshal(map[string]any{
"chatID": chatID,
"chatHost": NodeID,
})
if err != nil {
return err
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "new_chat_message",
"title": "Unread messages 👀",
"body": fmt.Sprintf("%d new messages from %s", count, initiator),
"isPushed": true,
"payload": string(bs),
"recipients": []string{target},
})
}
return
})
}
}
d1, e1 := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", chat.Target, map[string]interface{}{
"chatMessage": chatMessage,
"chatID": chatID,
})
go notifyActivity(d1, e1, chat.Target, chat.Initiator)
d2, e2 := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", chat.Initiator, map[string]interface{}{
"chatMessage": chatMessage,
"chatID": chatID,
})
go notifyActivity(d2, e2, chat.Initiator, chat.Target)
return
}
func (zch *NodeChatChannelsHandler[T]) RemoveAllUserChat(userId string) (err error) {
chats, err := zch.ListChats()
if err != nil {
return
}
for _, chat := range chats {
if chat.Initiator == userId || chat.Target == userId {
if derr := zch.DeleteChat(chat.ID); derr != nil {
logger.Println("**************", derr)
}
logger.Println("deleted chat", chat.ID)
}
}
return
}
func (zch *NodeChatChannelsHandler[T]) DeleteChatMessage(key uint64, chatID string) (err error) {
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if _, ok := zch.Chats[chatID]; !ok {
err = fmt.Errorf("no file corresponding to id %s", chatID)
return
}
chat := zch.Chats[chatID]
if err = chat.DB.DeleteChatMessage(key); err != nil {
return
}
for _, member := range [2]string{chat.Initiator, chat.Target} {
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_DELETED, "node", member, map[string]interface{}{
"chatID": chatID,
"messageId": key,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
previousId := zch.Chats[chatID].DB.PreviousId
if previousId == key {
if err = zch.Chats[chatID].DB.revertPreviousId(); err != nil {
return
}
previousId = zch.Chats[chatID].DB.PreviousId
if previousId == 1 {
previousId = 0
}
if err = zch.Chats[chatID].Tracking.RevertTrackingLastIndex(previousId); err != nil {
return
}
}
return
})
return
}
func (zch *NodeChatChannelsHandler[T]) UpdateChatMessage(key uint64, chatID, newContent string) (err error) {
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if _, ok := zch.Chats[chatID]; !ok {
err = fmt.Errorf("no chat corresponding to id %s", chatID)
return
}
chat := zch.Chats[chatID]
if err = chat.DB.ModifyChatMessage(key, newContent); err != nil {
return
}
for _, member := range [2]string{chat.Target, chat.Initiator} {
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_EDITED, "node", member, map[string]interface{}{
"chatID": chatID,
"messageId": key,
"newContent": newContent,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
return
})
return
}
func (zch *NodeChatChannelsHandler[T]) DeleteChatFile(key uint64, fileName, chatID string) (err error) {
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if _, ok := zch.Chats[chatID]; !ok {
err = fmt.Errorf("no file corresponding to id %s", chatID)
return
}
chat := zch.Chats[chatID]
if err = chat.DB.DeleteChatFile(fileName, key); err != nil {
return
}
for _, member := range [2]string{chat.Target, chat.Initiator} {
d, e := zch.sendDataChannelMessage(CHAT_FILE_DELETED, "node", member, map[string]interface{}{
"chatID": chatID,
"fileId": key,
"fileName": fileName,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
return
})
return
}
func (zch *NodeChatChannelsHandler[T]) chatFileUpload(chatID string, filename string, userId string, dc *DataChannel) {
var writePipe chan<- []byte
var done bool
uploadDone := func() {
if writePipe != nil {
close(writePipe)
writePipe = nil
}
done = true
}
dc.DataChannel.OnError(func(err error) {
logger.Println(err)
logger.Println("abort...")
if !done {
uploadDone()
}
if fufErr := zch.ChatFSInstance.FileUploadFailed(chatID, filename, userId); fufErr != nil {
logger.Println(fufErr)
}
})
dc.DataChannel.OnClose(func() {
if done {
logger.Println("closing gracefully...")
} else {
logger.Println("abort...")
uploadDone()
if fufErr := zch.ChatFSInstance.FileUploadFailed(chatID, filename, userId); fufErr != nil {
logger.Println(fufErr)
}
}
})
dc.DataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
if msg.IsString {
if string(msg.Data) == "init_upload" {
logger.Println("init upload....")
var initErr error
if writePipe, initErr = zch.ChatFSInstance.SetupFileUpload(chatID, filename, userId, dc.DataChannel); initErr != nil {
_ = dc.DataChannel.SendText("abort")
_ = dc.DataChannel.Close()
return
}
logger.Println("upload ready !")
_ = dc.DataChannel.SendText("upload_ready")
} else if string(msg.Data) == "upload_done" {
uploadDone()
}
} else {
writePipe <- msg.Data
}
})
dc.DataChannel.OnOpen(func() {
_ = dc.DataChannel.SendText("channel_ready")
})
}
func (zch *NodeChatChannelsHandler[T]) chatFileDownload(chatID string, filename string, userId string, dc *DataChannel) {
var done bool
dc.DataChannel.OnError(func(err error) {
if !done {
logger.Println("abort...")
if fdf := zch.ChatFSInstance.FileDownloadFailed(chatID, filename, userId); fdf != nil {
logger.Println(fdf)
}
}
})
dc.DataChannel.OnClose(func() {
if !done {
logger.Println("abort...")
if fdf := zch.ChatFSInstance.FileDownloadFailed(chatID, filename, userId); fdf != nil {
logger.Println(fdf)
}
}
})
dc.DataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
if msg.IsString {
if string(msg.Data) == "init_download" {
logger.Println("init download....")
var initErr error
if initErr = zch.ChatFSInstance.SetupFileDownload(chatID, filename, userId, dc.DataChannel); initErr != nil {
_ = dc.DataChannel.SendText("abort")
_ = dc.DataChannel.Close()
return
}
logger.Println("download started !")
} else if string(msg.Data) == "download_done" {
done = true
}
}
})
dc.DataChannel.OnOpen(func() {
_ = dc.DataChannel.SendText("channel_ready")
})
}
func (zch *NodeChatChannelsHandler[T]) handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool) {
var label string
_ = atomicallyExecute(dc.l, func() (err error) {
label = dc.DataChannel.Label()
return
})
if strings.Contains(label, "chat_upload") {
command := strings.Split(label, "|")
if len(command) == 4 {
catched = true
go zch.chatFileUpload(command[1], command[2], command[3], dc)
}
logger.Println(command)
} else if strings.Contains(label, "chat_download") {
command := strings.Split(label, "|")
catched = true
go zch.chatFileDownload(command[1], command[2], command[3], dc)
logger.Println(command)
} else if strings.Contains(label, "chat_data") {
command := strings.Split(label, "|")
catched = true
_ = atomicallyExecute(zch.ChatDataChannelsFlag, func() (err error) {
zch.ChatDataChannels[command[1]] = dc
return
})
dc.DataChannel.OnClose(func() {
fmt.Println("closing gratefully chat dc...")
_ = atomicallyExecute(zch.ChatDataChannelsFlag, func() (err error) {
delete(zch.ChatDataChannels, command[1])
return
})
})
dc.DataChannel.OnError(func(err error) {
fmt.Println("error in chat dc...")
_ = atomicallyExecute(zch.ChatDataChannelsFlag, func() (err error) {
delete(zch.ChatDataChannels, command[1])
return
})
})
}
return
}
func (zch *NodeChatChannelsHandler[T]) handleChatRequest(ctx context.Context, req *ChatRequest) (err error) {
logger.Println("got request in zone chat handler", req)
switch req.ReqType {
case LEAVE_CHAT:
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
// err = zch.LeaveChatFSInstance(req.Payload["userId"].(string))
case DELETE_CHAT:
if err = VerifyFieldsString(req.Payload, "chatID"); err != nil {
return
}
err = zch.DeleteChat(req.Payload["chatID"].(string))
case CREATE_CHAT:
if err = VerifyFieldsString(req.Payload, "chatID", "owner", "chatType"); err != nil {
return
}
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zch.AddNewChat(req.Payload["chatID"].(string), req.Payload["initiator"].(string), req.Payload["target"].(string), req.Payload["initiatorHostId"].(string), req.Payload["targetHostId"].(string))
case GET_CHATS:
err = zch.GetChats(req.From)
case LIST_LATEST_CHATS:
if err = VerifyFieldsString(req.Payload, "chatID"); err != nil {
return
}
if err = VerifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
return
}
err = zch.ListLatestChatMessages(req.From, req.Payload["chatID"].(string), req.Payload["lastIndex"].(float64), req.Payload["limit"].(float64))
return
case LIST_LATEST_FILES:
if err = VerifyFieldsString(req.Payload, "chatID"); err != nil {
return
}
if err = VerifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
return
}
err = zch.ListLatestChatFiles(req.From, req.Payload["chatID"].(string), req.Payload["lastIndex"].(float64), req.Payload["limit"].(float64))
return
case READ_LATEST_MESSAGE:
if err = VerifyFieldsString(req.Payload, "chatID"); err != nil {
return
}
err = zch.ReadLastMessage(req.From, req.Payload["chatID"].(string))
case ADD_CHAT_MESSAGE:
logger.Println("got request in zone chat handler", req)
if err = VerifyFieldsString(req.Payload, "chatID", "content"); err != nil {
return
}
if err = VerifyFieldsBool(req.Payload, "isResponse"); err != nil {
return
}
var parentChatId uint64
if req.Payload["isResponse"].(bool) {
if err = VerifyFieldsFloat64(req.Payload, "parentChatId"); err != nil {
return
}
parentChatId = uint64(req.Payload["parentChatId"].(float64))
}
var file *ChatFile = nil
if _, ok := req.Payload["file"]; ok {
bs, jsonErr := json.Marshal(req.Payload["file"])
if jsonErr != nil {
return jsonErr
}
var f ChatFile
if err = json.Unmarshal(bs, &f); err != nil {
err = fmt.Errorf("the file payload dont match ChatFile struct pattern : %v", err)
return
}
file = &f
}
err = zch.AddChatMessage(req.From, req.Payload["chatID"].(string), req.Payload["content"].(string), req.Payload["isResponse"].(bool), parentChatId, file)
case DELETE_CHAT_MESSAGE:
if err = VerifyFieldsString(req.Payload, "chatID"); err != nil {
return
}
if err = VerifyFieldsFloat64(req.Payload, "messageId"); err != nil {
return
}
err = zch.DeleteChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatID"].(string))
case EDIT_CHAT_MESSAGE:
if err = VerifyFieldsString(req.Payload, "chatID", "newContent"); err != nil {
return
}
if err = VerifyFieldsFloat64(req.Payload, "messageId"); err != nil {
return
}
err = zch.UpdateChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatID"].(string), req.Payload["newContent"].(string))
case DELETE_CHAT_FILE:
if err = VerifyFieldsString(req.Payload, "chatID", "fileName"); err != nil {
return
}
if err = VerifyFieldsFloat64(req.Payload, "fileId"); err != nil {
return
}
err = zch.DeleteChatFile(uint64(req.Payload["fileId"].(float64)), req.Payload["fileName"].(string), req.Payload["chatID"].(string))
}
return
}

151
chatMessagesTracking.go Normal file
View File

@ -0,0 +1,151 @@
package localserver
import (
"encoding/binary"
"os"
"path/filepath"
"sync"
"github.com/dgraph-io/badger/v3"
)
type NodeChatTrackingDB struct {
ChatID string
db func(cb func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
}
func NewNodeChatTracking(chatId, initiator, target string) (*NodeChatTrackingDB, error) {
if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "chats", chatId, "__tracking__")); os.IsNotExist(dirErr) {
_ = os.MkdirAll(filepath.Join(dataPath, "data", "chats", chatId, "__tracking__"), 0700)
}
db := func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join(dataPath, "data", "chats", chatId, "__tracking__")).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
}
lock := new(sync.RWMutex)
if err := db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, 0)
for _, member := range [2]string{initiator, target} {
if _, rerr := txn.Get([]byte(member)); rerr == badger.ErrKeyNotFound {
_ = txn.Set([]byte(member), b)
} else if rerr != nil {
return rerr
}
}
return nil
})
if err != nil {
return
}
return
}); err != nil {
return nil, err
}
return &NodeChatTrackingDB{chatId, db, lock}, nil
}
func (nctdb *NodeChatTrackingDB) Initialize(lastIndex uint64, users ...string) (err error) {
for _, user := range users {
if err = nctdb.SetUserLastIndex(user, lastIndex); err != nil {
return
}
}
return
}
func (nctdb *NodeChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err error) {
nctdb.lock.Lock()
defer nctdb.lock.Unlock()
err = nctdb.db(func(d *badger.DB) (err error) {
keys := [][]byte{}
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
if err = item.Value(func(val []byte) error {
li := binary.BigEndian.Uint64(val)
if li >= lastIndex {
keys = append(keys, item.Key())
}
return nil
}); err != nil {
return err
}
}
return nil
})
if err != nil {
return
}
err = d.Update(func(txn *badger.Txn) error {
for _, key := range keys {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, lastIndex)
if updateErr := txn.Set(key, b); updateErr != nil {
return updateErr
}
}
return nil
})
return
})
return
}
func (nctdb *NodeChatTrackingDB) SetUserLastIndex(userId string, lastIndex uint64) (err error) {
nctdb.lock.Lock()
defer nctdb.lock.Unlock()
err = nctdb.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, lastIndex)
updateErr := txn.Set([]byte(userId), b)
return updateErr
})
return
})
return
}
func (nctdb *NodeChatTrackingDB) GetUserLastIndex(userId string) (index uint, err error) {
nctdb.lock.Lock()
defer nctdb.lock.Unlock()
err = nctdb.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error {
item, rerr := txn.Get([]byte(userId))
if rerr != nil {
return rerr
}
_ = item.Value(func(val []byte) error {
index = uint(binary.BigEndian.Uint64(val))
return nil
})
return nil
})
return
})
return
}
func (nctdb *NodeChatTrackingDB) DeleteUserTracking(userId string) (err error) {
nctdb.lock.Lock()
defer nctdb.lock.Unlock()
err = nctdb.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error {
updateErr := txn.Delete([]byte(userId))
return updateErr
})
return
})
return
}

120
chatRequestScheduler.go Normal file
View File

@ -0,0 +1,120 @@
package localserver
import (
"context"
"sync"
"time"
)
type ChatRequestScheduler struct {
handlersPublishers []chan<- *ChatRequest
handlersDataChannelDispatchCallbacks []DispatchDataChannelCallBack
}
type ChatRequest struct {
ReqType string `json:"reqType"`
Payload map[string]any
From string
}
type ChatResponse struct {
Type string `json:"type"`
To string `json:"to"`
From string `json:"from"`
Payload map[string]any `json:"payload"`
}
type ChatRequestHandler interface {
Init(ctx context.Context, initiator, target, initiatorNodeID, targetNodeID string) (err error)
Subscribe(ctx context.Context, publisher <-chan *ChatRequest) (reqChan chan *ChatRequest, done chan struct{}, errCh chan error)
handleChatRequest(ctx context.Context, req *ChatRequest) (err error)
handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool)
}
func NewChatRequestScheduler(initiator, target, initiatorNodeID, targetNodeID string, handlers ...ChatRequestHandler) (chatRequestScheduler *ChatRequestScheduler, handlerErrCh chan error) {
chatRequestScheduler = new(ChatRequestScheduler)
chatRequestScheduler.handlersPublishers = make([]chan<- *ChatRequest, 0)
chatRequestScheduler.handlersDataChannelDispatchCallbacks = make([]DispatchDataChannelCallBack, 0)
handlerErrCh = make(chan error)
reqChans := []chan *ChatRequest{}
for _, handler := range handlers {
publisher := make(chan *ChatRequest, 100)
chatRequestScheduler.handlersPublishers = append(chatRequestScheduler.handlersPublishers, publisher)
chatRequestScheduler.handlersDataChannelDispatchCallbacks = append(chatRequestScheduler.handlersDataChannelDispatchCallbacks, handler.handleDataChannel)
reqChan, done, errCh := handler.Subscribe(context.Background(), publisher)
go func(done <-chan struct{}, errCh <-chan error) {
for {
select {
case <-done:
return
case handlerErrCh <- <-errCh:
}
}
}(done, errCh)
reqChans = append(reqChans, reqChan)
}
for _, reqChan := range reqChans {
go func(reqChan <-chan *ChatRequest) {
done, errCh := chatRequestScheduler.Schedule(reqChan)
for {
select {
case <-done:
return
case e := <-errCh:
logger.Println(e)
}
}
}(reqChan)
}
for _, handler := range handlers {
if ierr := handler.Init(context.Background(), initiator, target, initiatorNodeID, targetNodeID); ierr != nil {
logger.Println(ierr)
}
}
return
}
func (crs *ChatRequestScheduler) Schedule(reqChan <-chan *ChatRequest) (done chan struct{}, errCh chan error) {
done, errCh = make(chan struct{}), make(chan error)
for req := range reqChan {
go func(r *ChatRequest) {
for _, publisher := range crs.handlersPublishers {
go func(p chan<- *ChatRequest) {
p <- r
}(publisher)
}
}(req)
}
return
}
func (crs *ChatRequestScheduler) DispatchDataChannel(ctx context.Context, dc *DataChannel) (catched bool) {
wg, lock := sync.WaitGroup{}, &sync.Mutex{}
timeoutCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
done := make(chan struct{})
for _, dispatchCallback := range crs.handlersDataChannelDispatchCallbacks {
wg.Add(1)
go func(w *sync.WaitGroup, dispatchCallback DispatchDataChannelCallBack) {
defer w.Done()
val := dispatchCallback(timeoutCtx, dc)
if val {
lock.Lock()
catched = true
lock.Unlock()
return
}
}(&wg, dispatchCallback)
}
go func() {
wg.Wait()
done <- struct{}{}
}()
select {
case <-done:
return
case <-timeoutCtx.Done():
return false
}
}

View File

@ -1 +1,11 @@
{"chatId":"general 💬","chatType":"public","owner":"Dev","members":["Dev","Loïs","Pascal","Dev2"]}
{
"chatId": "general 💬",
"chatType": "public",
"owner": "Dev",
"members": [
"Dev",
"Loïs",
"Pascal",
"Dev2"
]
}

View File

@ -1 +1,8 @@
{"chatId":"test","chatType":"private","owner":"Dev2","members":["Dev2"]}
{
"chatId": "test",
"chatType": "private",
"owner": "Dev2",
"members": [
"Dev2"
]
}

50
cmd/go.mod Normal file
View File

@ -0,0 +1,50 @@
module github.com/loisBN/zippytal_node/Zippytal-Node/cmd
replace github.com/loisBN/zippytal_node/localserver => ../
go 1.18
require github.com/loisBN/zippytal_node/localserver v0.0.0-00010101000000-000000000000
require (
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/dgraph-io/badger/v3 v3.2103.2 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/klauspost/compress v1.12.3 // indirect
github.com/pion/datachannel v1.5.2 // indirect
github.com/pion/dtls/v2 v2.0.10 // indirect
github.com/pion/ice/v2 v2.1.14 // indirect
github.com/pion/interceptor v0.1.2 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.5 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.9 // indirect
github.com/pion/rtp v1.7.4 // indirect
github.com/pion/sctp v1.8.0 // indirect
github.com/pion/sdp/v3 v3.0.4 // indirect
github.com/pion/srtp/v2 v2.0.5 // indirect
github.com/pion/stun v0.3.5 // indirect
github.com/pion/transport v0.12.3 // indirect
github.com/pion/turn/v2 v2.0.5 // indirect
github.com/pion/udp v0.1.1 // indirect
github.com/pion/webrtc/v3 v3.1.11 // indirect
github.com/pkg/errors v0.9.1 // indirect
go.opencensus.io v0.22.5 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)

303
cmd/go.sum Normal file
View File

@ -0,0 +1,303 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8=
github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M=
github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
github.com/pion/dtls/v2 v2.0.10 h1:wgys7gPR1NMbWjmjJ3CW7lkUGaun8djgH8nahpNLnxI=
github.com/pion/dtls/v2 v2.0.10/go.mod h1:00OxfeCRWHShcqT9jx8pKKmBWuTt0NCZoVPCaC4VKvU=
github.com/pion/ice/v2 v2.1.14 h1:nD9GZs3MiR1/dPa5EiMRMe8hLBG3/qqCdx/hTS2g8VE=
github.com/pion/ice/v2 v2.1.14/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
github.com/pion/interceptor v0.1.2 h1:1IfrJ+AQ0HhwxNl4hqh9hMvl1hBKiNhAAr7DrUHsC6s=
github.com/pion/interceptor v0.1.2/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.8.0 h1:6erMF2qmQwXr+0iB1lm0AUSmDr9LdmpaBzgSVAEgehw=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.3 h1:vdBfvfU/0Wq8kd2yhUMSDB/x+O4Z9MYVl2fJ5BT4JZw=
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.11 h1:8Q5BEsxvlDn3botM8U8n/Haln745FBa5TWgm8v2c2FA=
github.com/pion/webrtc/v3 v3.1.11/go.mod h1:h9pbP+CADYb/99s5rfjflEcBLgdVKm55Rm7heQ/gIvY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

Binary file not shown.

16
go.mod
View File

@ -16,13 +16,17 @@ require (
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/goccy/go-graphviz v0.0.9 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/klauspost/compress v1.12.3 // indirect
github.com/ofabry/go-callvis v0.6.1 // indirect
github.com/pion/datachannel v1.5.2 // indirect
github.com/pion/dtls/v2 v2.0.10 // indirect
github.com/pion/ice/v2 v2.1.14 // indirect
@ -38,12 +42,16 @@ require (
github.com/pion/transport v0.12.3 // indirect
github.com/pion/turn/v2 v2.0.5 // indirect
github.com/pion/udp v0.1.1 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
go.opencensus.io v0.22.5 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.org/x/image v0.1.0 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/tools v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
)

42
go.sum
View File

@ -20,6 +20,7 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/corona10/goimagehash v1.0.2/go.mod h1:/l9umBhvcHQXVtQO1V6Gp1yD20STawkhRnnX0D1bvVI=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -38,12 +39,19 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-graphviz v0.0.6/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk=
github.com/goccy/go-graphviz v0.0.9 h1:s/FMMJ1Joj6La3S5ApO3Jk2cwM4LpXECC2muFx3IPQQ=
github.com/goccy/go-graphviz v0.0.9/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
@ -83,6 +91,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
@ -93,8 +102,11 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/ofabry/go-callvis v0.6.1 h1:JSVl4QdS5+997C38Bu0lMPXOs5NLOoKaY32sgKcgdUI=
github.com/ofabry/go-callvis v0.6.1/go.mod h1:0rRJ5J4UM3gOuKEWcoSng8RJmDUGJCJRAd+nY+zT2KE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
@ -141,6 +153,9 @@ github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.11 h1:8Q5BEsxvlDn3botM8U8n/Haln745FBa5TWgm8v2c2FA=
github.com/pion/webrtc/v3 v3.1.11/go.mod h1:h9pbP+CADYb/99s5rfjflEcBLgdVKm55Rm7heQ/gIvY=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -169,22 +184,30 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -207,6 +230,9 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -216,6 +242,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -233,27 +260,42 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200305224536-de023d59a5d1/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

View File

@ -1,6 +1,19 @@
package localserver
import "fmt"
import (
"fmt"
"sync/atomic"
)
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 ToStringSlice(slice []any) (strSlice []string, err error) {
strSlice = []string{}
@ -14,3 +27,66 @@ func ToStringSlice(slice []any) (strSlice []string, err error) {
}
return
}
func atomicallyExecute(flag *uint32, job func() (err error)) (err error) {
for {
if atomic.CompareAndSwapUint32(flag, 0, 1) {
defer atomic.SwapUint32(flag, 0)
err = job()
break
}
}
return
}
func VerifyFieldsString(payload map[string]any, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(string); !ok {
err = fmt.Errorf("field %s in payload is not a string", field)
return
}
}
return
}
func VerifyFieldsBool(payload map[string]any, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(bool); !ok {
err = fmt.Errorf("field %s in payload is not a bool", field)
return
}
}
return
}
func VerifyFieldsFloat64(payload map[string]any, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(float64); !ok {
err = fmt.Errorf("field %s in payload is not a float64", field)
return
}
}
return
}
func VerifyFieldsSliceInterface(payload map[string]any, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].([]any); !ok {
err = fmt.Errorf("field %s in payload is not a []any", field)
return
}
}
return
}

View File

@ -3,7 +3,6 @@ package localserver
import (
"context"
"encoding/json"
"fmt"
"strconv"
"github.com/pion/webrtc/v3"
@ -49,16 +48,6 @@ func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *
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) {
bs, err := json.Marshal(map[string]string{
"from": wgm.Manager.ID,

View File

@ -884,7 +884,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
switch req.ReqType {
case LEAVE_ZONE:
logger.Println("*-----------------handling leaving zone---------------*")
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
for _, ac := range zach.AudioChannels {
@ -904,7 +904,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
}
}
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var index int
@ -926,7 +926,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
}
err = zach.RemoveUserFromAllAudioChannels(req.Payload["userId"].(string))
case string(NEW_AUTHORIZED_ZONE_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var contain bool
@ -941,25 +941,25 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
}
err = zach.SetAllPublicAudioChannelForUser(req.Payload["userId"].(string))
case JOIN_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = zach.JoinAudioChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string), req.Payload["sdp"].(string))
case LEAVE_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zach.LeaveAudioChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case ADD_AUDIO_CHANNEL_MEMBERS:
if err = verifyFieldsString(req.Payload, "channelId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zach.AddAudioChannelsMembers(req.Payload["channelId"].(string), req.Payload["members"].([]interface{}))
case REMOVE_AUDIO_CHANNEL_MEMBER:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zach.RemoveAudioChannelMember(req.Payload["channelId"].(string), req.Payload["userId"].(string))
@ -968,40 +968,40 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
return
}
case EDIT_AUDIO_CHANNEL_NAME:
if err = verifyFieldsString(req.Payload, "channelId", "newAudioChannelId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "newAudioChannelId"); err != nil {
return
}
if err = zach.EditAudioChannelName(req.Payload["channelId"].(string), req.Payload["newAudioChannelId"].(string)); err != nil {
return
}
case EDIT_AUDIO_CHANNEL_TYPE:
if err = verifyFieldsString(req.Payload, "channelId", "channelType"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "channelType"); err != nil {
return
}
if err = zach.EditAudioChannelType(req.Payload["channelId"].(string), req.Payload["channelType"].(string)); err != nil {
return
}
case DELETE_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId"); err != nil {
return
}
err = zach.DeleteAudioChannel(req.Payload["channelId"].(string))
case CREATE_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "owner", "channelType"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "owner", "channelType"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zach.AddNewAudioChannel(req.Payload["channelId"].(string), req.Payload["owner"].(string), req.Payload["channelType"].(string), req.Payload["members"].([]interface{}))
case GET_AUDIO_CHANNELS:
if err = verifyFieldsSliceInterface(req.Payload, "channelsId"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "channelsId"); err != nil {
return
}
err = zach.GetAudioChannels(req.From, req.Payload["channelsId"].([]interface{})...)
case string(AUDIO_CHANNEL_WEBRTC_COUNTER_OFFER):
logger.Println("handling audio channel counter offer")
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
@ -1013,7 +1013,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
return
})
case string(AUDIO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER):
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
@ -1025,7 +1025,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
return
})
case string(AUDIO_CHANNEL_WEBRTC_RENNEGOTIATION_ANSWER):
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
@ -1039,7 +1039,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
case string(AUDIO_CHANNEL_WEBRTC_CANDIDATE):
logger.Println("handling audio channel webrtc candidate")
logger.Println(req.Payload)
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
return
}
logger.Println(req.Payload)

View File

@ -1364,12 +1364,12 @@ func (zch *ZoneChatsHandler[T]) handleZoneRequest(ctx context.Context, req *Zone
logger.Println("got request in zone chat handler", req)
switch req.ReqType {
case LEAVE_ZONE:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
// err = zch.LeaveChatFSInstance(req.Payload["userId"].(string))
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var index int
@ -1391,7 +1391,7 @@ func (zch *ZoneChatsHandler[T]) handleZoneRequest(ctx context.Context, req *Zone
}
err = zch.RemoveUserFromAllChats(req.Payload["userId"].(string))
case string(NEW_AUTHORIZED_ZONE_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var contain bool
@ -1406,15 +1406,15 @@ func (zch *ZoneChatsHandler[T]) handleZoneRequest(ctx context.Context, req *Zone
}
err = zch.SetAllPublicChatForUser(req.Payload["userId"].(string))
case ADD_CHAT_MEMBERS:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zch.AddChatMembers(req.Payload["chatId"].(string), req.Payload["members"].([]interface{}))
case REMOVE_CHAT_MEMBER:
if err = verifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
return
}
err = zch.RemoveChatMember(req.Payload["chatId"].(string), req.Payload["userId"].(string))
@ -1423,71 +1423,71 @@ func (zch *ZoneChatsHandler[T]) handleZoneRequest(ctx context.Context, req *Zone
return
}
case EDIT_CHAT_NAME:
if err = verifyFieldsString(req.Payload, "chatId", "newChatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "newChatId"); err != nil {
return
}
if err = zch.EditChatName(req.Payload["chatId"].(string), req.Payload["newChatId"].(string)); err != nil {
return
}
case EDIT_CHAT_TYPE:
if err = verifyFieldsString(req.Payload, "chatId", "chatType"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "chatType"); err != nil {
return
}
if err = zch.EditChatType(req.Payload["chatId"].(string), req.Payload["chatType"].(string)); err != nil {
return
}
case DELETE_CHAT:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
err = zch.DeleteChat(req.Payload["chatId"].(string))
case CREATE_CHAT:
if err = verifyFieldsString(req.Payload, "chatId", "owner", "chatType"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "owner", "chatType"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zch.AddNewChat(req.Payload["chatId"].(string), req.Payload["owner"].(string), req.Payload["chatType"].(string), req.Payload["members"].([]interface{}))
case GET_CHATS:
if err = verifyFieldsSliceInterface(req.Payload, "chatsId"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "chatsId"); err != nil {
return
}
err = zch.GetChats(req.From, req.Payload["chatsId"].([]interface{})...)
case LIST_LATEST_CHATS:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
return
}
err = zch.ListLatestChatMessages(req.From, req.Payload["chatId"].(string), req.Payload["lastIndex"].(float64), req.Payload["limit"].(float64))
return
case LIST_LATEST_FILES:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
return
}
err = zch.ListLatestChatFiles(req.From, req.Payload["chatId"].(string), req.Payload["lastIndex"].(float64), req.Payload["limit"].(float64))
return
case READ_LATEST_MESSAGE:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
err = zch.ReadLastMessage(req.From, req.Payload["chatId"].(string))
case ADD_CHAT_MESSAGE:
logger.Println("got request in zone chat handler", req)
if err = verifyFieldsString(req.Payload, "chatId", "content"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "content"); err != nil {
return
}
if err = verifyFieldsBool(req.Payload, "isResponse"); err != nil {
if err = VerifyFieldsBool(req.Payload, "isResponse"); err != nil {
return
}
var parentChatId uint64
if req.Payload["isResponse"].(bool) {
if err = verifyFieldsFloat64(req.Payload, "parentChatId"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "parentChatId"); err != nil {
return
}
parentChatId = uint64(req.Payload["parentChatId"].(float64))
@ -1507,26 +1507,26 @@ func (zch *ZoneChatsHandler[T]) handleZoneRequest(ctx context.Context, req *Zone
}
err = zch.AddChatMessage(req.From, req.Payload["chatId"].(string), req.Payload["content"].(string), req.Payload["isResponse"].(bool), parentChatId, file)
case DELETE_CHAT_MESSAGE:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "messageId"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "messageId"); err != nil {
return
}
err = zch.DeleteChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatId"].(string))
case EDIT_CHAT_MESSAGE:
if err = verifyFieldsString(req.Payload, "chatId", "newContent"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "newContent"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "messageId"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "messageId"); err != nil {
return
}
err = zch.UpdateChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatId"].(string), req.Payload["newContent"].(string))
case DELETE_CHAT_FILE:
if err = verifyFieldsString(req.Payload, "chatId", "fileName"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "fileName"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "fileId"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "fileId"); err != nil {
return
}
err = zch.DeleteChatFile(uint64(req.Payload["fileId"].(float64)), req.Payload["fileName"].(string), req.Payload["chatId"].(string))

View File

@ -1073,7 +1073,7 @@ func (zfh *ZoneFileHandler[T]) handleDataChannel(ctx context.Context, dc *DataCh
func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneRequest) (err error) {
switch req.ReqType {
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var index int
@ -1091,7 +1091,7 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
zfh.ZoneMembersId = append(zfh.ZoneMembersId[:index], zfh.ZoneMembersId[index+1:]...)
err = zfh.DeleteFolder("", req.Payload["userId"].(string))
case string(NEW_AUTHORIZED_ZONE_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var contain bool
@ -1123,18 +1123,18 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
})
case LEAVE_ZONE:
logger.Println("*-----------------handling leaving zone---------------*")
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
//err = zfh.LeaveFSInstance(req.Payload["userId"].(string))
case ZONE_UPLOAD_FILE_DONE:
if err = verifyFieldsBool(req.Payload, "failed"); err != nil {
if err = VerifyFieldsBool(req.Payload, "failed"); err != nil {
return
}
if err = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
return
}
if err = verifyFieldsFloat64(req.Payload, "size"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "size"); err != nil {
return
}
if req.Payload["failed"].(bool) {
@ -1173,20 +1173,20 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
// err = zfh.FSInstance.SetupFileDownload(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))
case GET_FS_ENTITIES:
logger.Println("getting files entities")
if err = verifyFieldsString(req.Payload, "path", "userId", "section"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "userId", "section"); err != nil {
return
}
var backward bool
if err = verifyFieldsBool(req.Payload, "backward"); err == nil {
if err = VerifyFieldsBool(req.Payload, "backward"); err == nil {
backward = req.Payload["backward"].(bool)
}
if err = verifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
if err = VerifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
return
}
err = zfh.GetFSEntities(req.Payload["userId"].(string), req.Payload["section"].(string), req.Payload["path"].(string), 0, 100, backward)
case CREATE_FOLDER:
logger.Println("creating folder")
if err = verifyFieldsString(req.Payload, "path"); err != nil {
if err = VerifyFieldsString(req.Payload, "path"); err != nil {
return
}
if _, ok := req.Payload["config"]; !ok {
@ -1204,17 +1204,17 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
}
err = zfh.CreateFolder(req.Payload["path"].(string), &config)
case RENAME_FOLDER:
if err = verifyFieldsString(req.Payload, "path", "name", "newName"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "name", "newName"); err != nil {
return
}
err = zfh.RenameFolder(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["newName"].(string))
case RENAME_FILE:
if err = verifyFieldsString(req.Payload, "path", "name", "newName"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "name", "newName"); err != nil {
return
}
err = zfh.RenameFile(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["newName"].(string))
case COPY_FOLDER:
if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
return
}
if _, ok := req.Payload["config"]; !ok {
@ -1235,7 +1235,7 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
logger.Println(err)
}()
case COPY_FILE:
if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
return
}
if _, ok := req.Payload["config"]; !ok {
@ -1256,7 +1256,7 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
logger.Println(err)
}()
case CUT_FOLDER:
if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
return
}
if _, ok := req.Payload["config"]; !ok {
@ -1277,7 +1277,7 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
logger.Println(err)
}()
case CUT_FILE:
if err = verifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId", "path", "dstPath"); err != nil {
return
}
if _, ok := req.Payload["config"]; !ok {
@ -1298,10 +1298,10 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
logger.Println(err)
}()
case UPDATE_PERMISSIONS:
if err = verifyFieldsString(req.Payload, "path", "name", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "name", "userId"); err != nil {
return
}
if err = verifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil {
if err = VerifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil {
return
}
fsAcessRights := &FSEntityAccessRights{
@ -1312,31 +1312,31 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
}
err = zfh.UpdatePermissions(req.Payload["path"].(string), req.Payload["name"].(string), req.Payload["userId"].(string), fsAcessRights)
case DELETE_FOLDER:
if err = verifyFieldsString(req.Payload, "path", "name"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "name"); err != nil {
return
}
err = zfh.DeleteFolder(req.Payload["path"].(string), req.Payload["name"].(string))
case DELETE_FILE:
if err = verifyFieldsString(req.Payload, "path", "name"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "name"); err != nil {
return
}
err = zfh.DeleteFile(req.Payload["path"].(string), req.Payload["name"].(string))
case ADD_FS_ENTITY_MEMBERS:
if err = verifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
if err = verifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil {
if err = VerifyFieldsBool(req.Payload, "read", "write", "download", "rename"); err != nil {
return
}
err = zfh.AddFolderMember(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["folderName"].(string), req.Payload["members"].([]interface{}), req.Payload["read"].(bool), req.Payload["write"].(bool), req.Payload["download"].(bool), req.Payload["rename"].(bool))
case REMOVE_FS_ENTITY_MEMBERS:
if err = verifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil {
if err = VerifyFieldsString(req.Payload, "path", "userId", "folderName"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zfh.RemoveFolderMember(req.Payload["userId"].(string), req.Payload["path"].(string), req.Payload["folderName"].(string), req.Payload["members"].([]interface{}))

View File

@ -64,7 +64,7 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
done, errCh := make(chan struct{}), make(chan error)
go func() {
var payload map[string]string
if e := json.Unmarshal(req.Payload, &payload); err != nil {
if e := json.Unmarshal(req.Payload, &payload); e != nil {
errCh <- e
return
}
@ -233,7 +233,7 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
return
}
default:
logger.Println("no request for zon grpc middleware")
logger.Println("no request for zone grpc middleware")
logger.Println(payload)
logger.Println(req.Type)
}

View File

@ -10,7 +10,6 @@ import (
"path/filepath"
"strconv"
sync "sync"
"sync/atomic"
"github.com/google/uuid"
"github.com/pion/webrtc/v3"
@ -146,17 +145,6 @@ func NewZoneManager(id string, token string) (zoneManager *ZoneManager, err erro
return
}
func atomicallyExecute(flag *uint32, job func() (err error)) (err error) {
for {
if atomic.CompareAndSwapUint32(flag, 0, 1) {
defer atomic.SwapUint32(flag, 0)
err = job()
break
}
}
return
}
func (zm *ZoneManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
bs, err := json.Marshal(payload)
if err != nil {
@ -380,28 +368,6 @@ func (zm *ZoneManager) HandleAnswer(ctx context.Context, from string, to string,
}
func (zm *ZoneManager) HandleCounterOffer(ctx context.Context, from string, to string, req map[string]string) (err error) {
logger.Println("handling counter offer 1")
// if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
// logger.Println("start job")
// if _, ok := zm.RTCPeerConnections[from]; !ok {
// logger.Println("error here")
// err = fmt.Errorf("no field corresponding peer connection for id %s", from)
// return
// }
// logger.Println("handling counter offer")
// connection := zm.RTCPeerConnections[from]
// err = atomicallyExecute(zm.localSDFlag, func() (err error) {
// if err = connection.SetLocalDescription(*zm.LocalSD[from]); err != nil {
// logger.Println(err)
// return
// }
// return
// })
// return
// }); err != nil {
// return
// }
logger.Println("handling counter offer 2")
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
for _, candidate := range zm.PendingCandidates[from] {
logger.Println("sending candidate to", from)
@ -546,21 +512,6 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
return
}
done, err := zm.Zones[zoneId].ZoneRequestScheduler.Schedule(reqChan)
// bs, jsonErr := json.Marshal(&ZoneResponse{
// Type: "user_zone_init",
// From: zoneId,
// To: target,
// Payload: map[string]interface{}{},
// })
// if jsonErr != nil {
// logger.Println("error in open channel", jsonErr)
// return
// }
// if sendErr := dc.SendText(string(bs)); sendErr != nil {
// logger.Println("error in open channel send", sendErr)
// return
// }
go func() {
for {
select {
@ -575,14 +526,10 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
dc.OnClose(func() {
fmt.Println("closing gracefully event dc...")
close(reqChan)
//_ = zm.HandleLeavingMember(target, zoneId, true)
})
dc.OnError(func(err error) {
logger.Println("--------------- error in dc:", err)
close(reqChan)
//_ = zm.HandleLeavingMember(target, zoneId, true)
})
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
var req ZoneRequest
@ -633,39 +580,8 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
}
}
})
// peerConnection.OnNegotiationNeeded(func() {
// logger.Println("------------------- negotiation is needed --------------------")
// if pc, ok := zm.RTCPeerConnections[target]; ok {
// if pc.SignalingState() == webrtc.ICETransportStateConnected {
// localSd, err := pc.CreateOffer(nil)
// if err != nil {
// logger.Println(err)
// return
// }
// if err = pc.SetLocalDescription(localSd); err != nil {
// logger.Println(err)
// return
// }
// if err = zm.stream.Send(&Request{
// Type: string(ZONE_WEBRTC_RENNEGOTIATION_OFFER),
// From: zm.ID,
// Token: "",
// Payload: map[string]string{
// "to": target,
// "sdp": localSd.SDP,
// },
// }); err != nil {
// logger.Println(err)
// return
// }
// }
// }
// })
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
logger.Printf("ICE connection state has changed %s\n", is.String())
// if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
// _ = zm.HandleLeavingMember(target, zoneId,true)
// }
})
peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
if i == nil {
@ -694,13 +610,6 @@ func (zm *ZoneManager) HandleRennegotiationOffer(from, sdp string) (err error) {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
//zm.RTCPeerConnections[from].makingOfferLock.Lock()
// if zm.RTCPeerConnections[from].makingOffer {
// //zm.RTCPeerConnections[from].makingOfferLock.Unlock()
// err = fmt.Errorf("already making an offer or state is stable")
// return
// }
//zm.RTCPeerConnections[from].makingOfferLock.Unlock()
if err = zm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
return
}
@ -839,16 +748,9 @@ func (zm *ZoneManager) notifyLeavingMember(userId, zoneId, hostId string) (err e
func (zm *ZoneManager) negotiate(target string, zoneId string) {
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[target]; !ok {
err = fmt.Errorf("no peerConnections")
return
}
//zm.RTCPeerConnections[target].makingOfferLock.Lock()
//zm.RTCPeerConnections[target].makingOffer = true
//zm.RTCPeerConnections[target].makingOfferLock.Unlock()
defer func() {
//zm.RTCPeerConnections[target].makingOfferLock.Lock()
//zm.RTCPeerConnections[target].makingOffer = false
//zm.RTCPeerConnections[target].makingOfferLock.Unlock()
}()
return
})
}

View File

@ -155,10 +155,10 @@ func (znh ZoneNotificationsHandler) handleDataChannel(ctx context.Context, dc *D
func (znh *ZoneNotificationsHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
switch req.ReqType {
case CREATE_NOTIFICATION:
if err = verifyFieldsString(req.Payload, "type", "title", "body", "payload"); err != nil {
if err = VerifyFieldsString(req.Payload, "type", "title", "body", "payload"); err != nil {
return
}
if err = verifyFieldsBool(req.Payload, "isPushed"); err != nil {
if err = VerifyFieldsBool(req.Payload, "isPushed"); err != nil {
return
}
if _, ok := req.Payload["recipients"]; !ok {

View File

@ -2,7 +2,6 @@ package localserver
import (
"context"
"fmt"
"sync"
"time"
)
@ -16,7 +15,7 @@ type ZoneRequestScheduler struct {
type ZoneRequest struct {
ReqType string `json:"reqType"`
Payload map[string]interface{} `json:"payload"`
Payload map[string]any `json:"payload"`
From string `json:"from"`
}
@ -24,7 +23,7 @@ type ZoneResponse struct {
Type string `json:"type"`
To string `json:"to"`
From string `json:"from"`
Payload map[string]interface{} `json:"payload"`
Payload map[string]any `json:"payload"`
}
type ZoneRequestHandler interface {
@ -34,58 +33,6 @@ type ZoneRequestHandler interface {
handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool)
}
func verifyFieldsString(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(string); !ok {
err = fmt.Errorf("field %s in payload is not a string", field)
return
}
}
return
}
func verifyFieldsBool(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(bool); !ok {
err = fmt.Errorf("field %s in payload is not a bool", field)
return
}
}
return
}
func verifyFieldsFloat64(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(float64); !ok {
err = fmt.Errorf("field %s in payload is not a float64", field)
return
}
}
return
}
func verifyFieldsSliceInterface(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].([]any); !ok {
err = fmt.Errorf("field %s in payload is not a []interface{}", field)
return
}
}
return
}
func NewZoneRequestScheduler(authorizedMembers []string, handlers ...ZoneRequestHandler) (zoneRequestScheduler *ZoneRequestScheduler, handlerErrCh chan error) {
zoneRequestScheduler = new(ZoneRequestScheduler)
zoneRequestScheduler.handlersPublishers = make([]chan<- *ZoneRequest, 0)
@ -133,7 +80,6 @@ func NewZoneRequestScheduler(authorizedMembers []string, handlers ...ZoneRequest
func (zrs *ZoneRequestScheduler) Schedule(reqChan <-chan *ZoneRequest) (done chan struct{}, errCh chan error) {
done, errCh = make(chan struct{}), make(chan error)
go func() {
for req := range reqChan {
go func(r *ZoneRequest) {
for _, publisher := range zrs.handlersPublishers {
@ -144,7 +90,6 @@ func (zrs *ZoneRequestScheduler) Schedule(reqChan <-chan *ZoneRequest) (done cha
}(req)
}
done <- struct{}{}
}()
return
}

View File

@ -626,7 +626,7 @@ func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
}
err = zuh.EditDefaultRights(config.DefaultChatRights, config.DefaultAudioChannelRights, config.DefaultVideoChannelRights, config.DefaultMediaRights, config.DefaultFileRights)
case EDIT_USERS_RIGHTS:
if err = verifyFieldsSliceInterface(req.Payload, "users"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "users"); err != nil {
return
}
if _, ok := req.Payload["defaultRights"]; !ok {
@ -644,52 +644,52 @@ func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
}
err = zuh.EditUsersRights(req.Payload["users"].([]interface{}), config.DefaultChatRights, config.DefaultAudioChannelRights, config.DefaultVideoChannelRights, config.DefaultMediaRights, config.DefaultFileRights)
case REMOVE_USER:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
err = zuh.RemoveUser(req.Payload["userId"].(string))
case ADD_USER:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
err = zuh.AddUser(req.Payload["userId"].(string))
case REMOVE_KNOWN_CHAT:
if err = verifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
return
}
err = zuh.RemoveKnownChat(req.Payload["chatId"].(string), req.Payload["userId"].(string))
case ADD_KNOWN_CHAT:
if err = verifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
return
}
err = zuh.AddKnownChat(req.Payload["chatId"].(string), req.Payload["userId"].(string))
case REMOVE_KNOWN_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.RemoveKnownAudioChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case ADD_KNOWN_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.AddKnownAudioChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case REMOVE_KNOWN_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.RemoveKnownVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case ADD_KNOWN_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.AddKnownVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case GET_DEFAULT_RIGHTS:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
err = zuh.GetDefaultRights(req.Payload["userId"].(string))
case GET_USER:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
if _, ok := req.Payload["init"]; !ok {

View File

@ -520,39 +520,39 @@ func (vc *VideoChannel) createPeerConnection(target string, from string, peerTyp
return
})
})
peerConnection.OnNegotiationNeeded(func() {
logger.Println("---------------- rennego is needed -----------")
// _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// for _, id := range vc.CurrentMembersId {
// logger.Println("----------------- sending renego to peer with id", id)
// if _, ok := vc.rtcPeerConnections[id]; !ok {
// continue
// }
// if peerConnection.SignalingState() == webrtc.SignalingStateStable {
// localSd, localSdErr := peerConnection.CreateOffer(nil)
// if localSdErr != nil {
// logger.Println(localSdErr)
// return localSdErr
// }
// if err = peerConnection.SetLocalDescription(localSd); err != nil {
// logger.Println(err)
// return
// }
// d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER), vc.ID, id, map[string]interface{}{
// "from": vc.ID,
// "to": id,
// "sdp": localSd.SDP,
// peerConnection.OnNegotiationNeeded(func() {
// logger.Println("---------------- rennego is needed -----------")
// // _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// // for _, id := range vc.CurrentMembersId {
// // logger.Println("----------------- sending renego to peer with id", id)
// // if _, ok := vc.rtcPeerConnections[id]; !ok {
// // continue
// // }
// // if peerConnection.SignalingState() == webrtc.SignalingStateStable {
// // localSd, localSdErr := peerConnection.CreateOffer(nil)
// // if localSdErr != nil {
// // logger.Println(localSdErr)
// // return localSdErr
// // }
// // if err = peerConnection.SetLocalDescription(localSd); err != nil {
// // logger.Println(err)
// // return
// // }
// // d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER), vc.ID, id, map[string]interface{}{
// // "from": vc.ID,
// // "to": id,
// // "sdp": localSd.SDP,
// // })
// // select {
// // case <-d:
// // case err = <-e:
// // logger.Println(err)
// // }
// // }
// // }
// // return
// // })
// })
// select {
// case <-d:
// case err = <-e:
// logger.Println(err)
// }
// }
// }
// return
// })
})
return
}

View File

@ -886,7 +886,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
switch req.ReqType {
case LEAVE_ZONE:
logger.Println("*-----------------handling leaving zone---------------*")
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
for _, vc := range zvch.VideoChannels {
@ -906,7 +906,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
}
}
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var index int
@ -928,7 +928,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
}
err = zvch.RemoveUserFromAllVideoChannels(req.Payload["userId"].(string))
case string(NEW_AUTHORIZED_ZONE_MEMBER):
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var contain bool
@ -943,25 +943,25 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
}
err = zvch.SetAllPublicVideoChannelForUser(req.Payload["userId"].(string))
case JOIN_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = zvch.JoinVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string), req.Payload["sdp"].(string))
case LEAVE_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zvch.LeaveVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case ADD_VIDEO_CHANNEL_MEMBERS:
if err = verifyFieldsString(req.Payload, "channelId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zvch.AddVideoChannelsMembers(req.Payload["channelId"].(string), req.Payload["members"].([]interface{}))
case REMOVE_VIDEO_CHANNEL_MEMBER:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zvch.RemoveVideoChannelMember(req.Payload["channelId"].(string), req.Payload["userId"].(string))
@ -970,40 +970,40 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
return
}
case EDIT_VIDEO_CHANNEL_NAME:
if err = verifyFieldsString(req.Payload, "channelId", "newVideoChannelId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "newVideoChannelId"); err != nil {
return
}
if err = zvch.EditVideoChannelName(req.Payload["channelId"].(string), req.Payload["newVideoChannelId"].(string)); err != nil {
return
}
case EDIT_VIDEO_CHANNEL_TYPE:
if err = verifyFieldsString(req.Payload, "channelId", "channelType"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "channelType"); err != nil {
return
}
if err = zvch.EditVideoChannelType(req.Payload["channelId"].(string), req.Payload["channelType"].(string)); err != nil {
return
}
case DELETE_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId"); err != nil {
return
}
err = zvch.DeleteVideoChannel(req.Payload["channelId"].(string))
case CREATE_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "owner", "channelType"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "owner", "channelType"); err != nil {
return
}
if err = verifyFieldsSliceInterface(req.Payload, "members"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "members"); err != nil {
return
}
err = zvch.AddNewVideoChannel(req.Payload["channelId"].(string), req.Payload["owner"].(string), req.Payload["channelType"].(string), req.Payload["members"].([]interface{}))
case GET_VIDEO_CHANNELS:
if err = verifyFieldsSliceInterface(req.Payload, "channelsId"); err != nil {
if err = VerifyFieldsSliceInterface(req.Payload, "channelsId"); err != nil {
return
}
err = zvch.GetVideoChannels(req.From, req.Payload["channelsId"].([]interface{})...)
case string(VIDEO_CHANNEL_WEBRTC_COUNTER_OFFER):
logger.Println("handling video channel counter offer")
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
@ -1015,7 +1015,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
return
})
case string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER):
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
@ -1027,7 +1027,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
return
})
case string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_ANSWER):
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
@ -1041,7 +1041,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
case string(VIDEO_CHANNEL_WEBRTC_CANDIDATE):
logger.Println("handling video channel webrtc candidate")
logger.Println(req.Payload)
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
if err = VerifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
return
}
logger.Println(req.Payload)