added chat module first unrevised version
This commit is contained in:
parent
5bffde75f5
commit
f2ebf8cb4c
176
chatGrpcMiddleware.go
Normal file
176
chatGrpcMiddleware.go
Normal 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
730
chatManager.go
Normal 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
322
chatMessagesDBHandler.go
Normal 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
164
chatMessagesFSInstance.go
Normal 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
827
chatMessagesHandler.go
Normal 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
151
chatMessagesTracking.go
Normal 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
120
chatRequestScheduler.go
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
]
|
||||
}
|
||||
@ -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
50
cmd/go.mod
Normal 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
303
cmd/go.sum
Normal 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=
|
||||
BIN
cmd/node.linux
BIN
cmd/node.linux
Binary file not shown.
16
go.mod
16
go.mod
@ -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
42
go.sum
@ -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=
|
||||
|
||||
78
utitlity.go
78
utitlity.go
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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{}))
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
100
zoneManager.go
100
zoneManager.go
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user