hosted squads working on node

This commit is contained in:
Loïs BIBEHE 2022-12-25 19:09:54 +01:00
parent f2ebf8cb4c
commit 79cc675c43
Signed by: Lois
GPG Key ID: 782967C8C0F78E79
101 changed files with 258918 additions and 2605 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
cmd/data
cmd/node
cmd/node.linux
cmd/config/102ed1ef-61cb-40fa-be62-77abe79aff95
cmd/config/102ed1ef-61cb-40fa-be62-77abe79aff95.pub
cmd/config/node_config.json

View File

@ -3,6 +3,7 @@ package localserver
import (
"context"
"encoding/json"
"fmt"
"strconv"
"github.com/pion/webrtc/v3"
@ -97,6 +98,7 @@ func (cm *ChatGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
case SYNC_CHAT:
//todo: implement sync chat
case CHAT_WEBRTC_OFFER:
fmt.Println("got offer in chat")
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
@ -115,6 +117,7 @@ func (cm *ChatGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
return
}
case CHAT_WEBRTC_COUNTER_OFFER:
fmt.Println("got counter offer in chat")
if err := cm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
@ -138,6 +141,7 @@ func (cm *ChatGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
return
}
case CHAT_WEBRTC_CANDIDATE:
fmt.Println("got candidate in chat")
if err := validateRequest(payload, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
errCh <- err
return
@ -160,10 +164,14 @@ func (cm *ChatGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
return
}
default:
fmt.Println("no request for chat grpc middleware")
fmt.Println(req.Type)
fmt.Println(req.Payload)
logger.Println("no request for chats grpc middleware")
logger.Println(payload)
logger.Println(req.Type)
}
done <- struct{}{}
}()
select {
case <-ctx.Done():

View File

@ -15,6 +15,12 @@ import (
"github.com/pion/webrtc/v3"
)
const (
UPDATE_UNREAD_COUNT = "update_unread_count"
UPDATE_LAST_INTERACTION_TIME = "update_last_interaction_time"
DISCONNECT_USER_FROM_CHAT = "disconnect_user_from_chat"
)
type ChatsManager struct {
ID string
Chats map[string]*NodeChat
@ -45,8 +51,17 @@ type NodeChat struct {
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)
nodeChatMessageHandler, err := NewNodeChatChannelsHandler(id, id, initiator, target, initiatorHost, targetHost, dataChannels, &dataChannelFlag)
if err != nil {
fmt.Println("error occured there")
fmt.Println(err)
return
}
nodeChatNotificationsHandler, err := NewChatNotificationsHandler(id, initiator, target, initiatorHost, targetHost, dataChannels, &dataChannelFlag)
if err != nil {
return
}
chatScheduler, e := NewChatRequestScheduler(initiator, target, initiatorHost, targetHost, nodeChatMessageHandler, nodeChatNotificationsHandler)
go func() {
for schedErr := range e {
logger.Println("chat error:", schedErr)
@ -148,11 +163,13 @@ func (cm *ChatsManager) fetchChats(nodeId string, token string) (chats []*NodeCh
if err = json.Unmarshal(bs, &payload); err != nil {
return
}
b, err := json.Marshal(payload["Chats"])
fmt.Println(payload)
b, err := json.Marshal(payload["chats"])
if err != nil {
return
}
err = json.Unmarshal(b, &chats)
return
}
@ -210,8 +227,12 @@ func (cm *ChatsManager) CreateOffer(ctx context.Context, target string, from str
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 {
if id, ok := cm.Chats[req["chatId"]]; !ok {
err = fmt.Errorf("no corresponding chat")
fmt.Println(req["chatId"])
fmt.Println(cm.Chats)
fmt.Println(id)
fmt.Println(err)
errCh <- err
return
}
@ -374,7 +395,7 @@ func (cm *ChatsManager) createPeerConnection(target string, from string, chatId
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478"},
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
SDPSemantics: webrtc.SDPSemanticsUnifiedPlan,
@ -511,6 +532,7 @@ func (cm *ChatsManager) createPeerConnection(target string, from string, chatId
logger.Println(err)
return
}
fmt.Println("incoming req", req)
logger.Println("incoming request", req)
go func() {
reqChan <- &req
@ -699,7 +721,7 @@ func (cm *ChatsManager) notifyLeavingMember(userId, chatId, hostId string) (err
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
body, err := json.Marshal(map[string]interface{}{
"type": "DISCONNECT_CHAT_MEMBER",
"type": DISCONNECT_USER_FROM_CHAT,
"mac": sig,
"from": NodeID,
"peerType": "node",

View File

@ -259,6 +259,7 @@ func (ncdbh *NodeChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMes
return err
}
if chatMessage.File != nil {
chatMessage.File.ID = chatMessage.ID
chatMessages = append(chatMessages, chatMessage.File)
l = lastIndex - x
y++

View File

@ -1,10 +1,11 @@
package localserver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/fs"
"io"
"os"
"path/filepath"
"strings"
@ -51,8 +52,8 @@ type NodeChatChannelsHandler[T ZippytalFSInstance] struct {
}
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))
_, 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)
@ -80,7 +81,7 @@ func NewNodeChatChannelsHandler(chatID, chatName, initiator, target, initiatorHo
return nil, writeErr
}
_ = file.Close()
dirs, err = os.ReadDir(filepath.Join(dataPath, "data", "chats", chatID))
_, err = os.ReadDir(filepath.Join(dataPath, "data", "chats"))
if err != nil {
return nil, err
}
@ -89,33 +90,30 @@ func NewNodeChatChannelsHandler(chatID, chatName, initiator, target, initiatorHo
}
}
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
nodeChatDBHandler, err := NewNodeChatDBHandler(chatID)
if err != nil {
return nil, err
}
var bs []byte
bs, err = os.ReadFile(filepath.Join(dataPath, "data", "chats", chatID, "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)
@ -134,7 +132,7 @@ func NewNodeChatChannelsHandler(chatID, chatName, initiator, target, initiatorHo
return
}
func (zch *NodeChatChannelsHandler[T]) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
func (zch *NodeChatChannelsHandler[T]) sendChatRequest(reqType string, from string, payload map[string]interface{}) {
go func() {
for _, rc := range zch.reqChans {
rc <- &ChatRequest{
@ -186,6 +184,8 @@ func (zch *NodeChatChannelsHandler[T]) Init(ctx context.Context, initiator, targ
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)
fmt.Println("subscribing...")
fmt.Println(zch)
zch.reqChans = append(zch.reqChans, reqChan)
go func() {
for {
@ -200,6 +200,7 @@ func (zch *NodeChatChannelsHandler[T]) Subscribe(ctx context.Context, publisher
}
}
}()
fmt.Println(zch.reqChans)
return
}
@ -351,7 +352,7 @@ func (zch *NodeChatChannelsHandler[T]) ListLatestChatMessages(userId, chatID str
success, e := zch.sendDataChannelMessage(CHAT_MESSAGE_LIST, "node", userId, map[string]interface{}{
"done": done || i <= 0,
"lastIndex": i - 1,
"chatID": chatID,
"chatId": chatID,
"chatMessages": list,
})
select {
@ -359,6 +360,9 @@ func (zch *NodeChatChannelsHandler[T]) ListLatestChatMessages(userId, chatID str
fmt.Println("done getting latest messages")
case err = <-e:
}
go func() {
_ = zch.signalUnreadCount(context.Background(), userId, 0)
}()
return
}
@ -376,7 +380,7 @@ func (zch *NodeChatChannelsHandler[T]) ListLatestChatFiles(userId, chatID string
done, e := zch.sendDataChannelMessage(CHAT_FILES_LIST, "node", userId, map[string]interface{}{
"done": i <= 0,
"lastIndex": i,
"chatID": chatID,
"chatId": chatID,
"chatMessages": list,
})
select {
@ -392,6 +396,7 @@ func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content st
return
}
chat := zch.Chats[chatID]
dateTime := time.Now().Format(time.RFC3339)
chatMessage := &ChatMessage{
Content: content,
From: userId,
@ -399,7 +404,7 @@ func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content st
ResponseOf: nil,
File: file,
Tags: make([]string, 0),
Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"),
Date: dateTime,
}
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatID]; ok {
@ -416,7 +421,7 @@ func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content st
return
}
chatMessage.ID = zch.Chats[chatID].DB.PreviousId
_ = chat.Tracking.SetUserLastIndex(userId, chatMessage.ID)
} else {
err = fmt.Errorf("no corresponding chats")
}
@ -425,13 +430,14 @@ func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content st
return
}
notifyActivity := func(done <-chan struct{}, e <-chan error, target, initiator string) {
notifyActivity := func(done <-chan struct{}, e <-chan error, destination string) {
select {
case <-done:
fmt.Println(destination, "is connected to this chat")
case <-e:
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatID]; ok {
li, err := chat.Tracking.GetUserLastIndex(target)
li, err := chat.Tracking.GetUserLastIndex(destination)
if err != nil {
return err
}
@ -439,23 +445,40 @@ func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content st
if err != nil {
return err
}
fmt.Println("********_**_*")
fmt.Println(count)
bs, err := json.Marshal(map[string]any{
"chatID": chatID,
"chatId": chatID,
"chatHost": NodeID,
})
if err != nil {
return err
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
fmt.Println("noooo errrrrooooorr")
fmt.Println(destination)
fmt.Println(userId)
zch.sendChatRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "new_chat_message",
"title": "Unread messages 👀",
"body": fmt.Sprintf("%d new messages from %s", count, initiator),
"title": fmt.Sprintf("%d Unread messages 👀", count),
"body": fmt.Sprintf("%d new messages from %s", count, userId),
"isPushed": true,
"payload": string(bs),
"recipients": []string{target},
"recipients": []string{destination},
})
go func() {
if e := zch.signalUnreadCount(context.Background(), destination, count); e != nil {
fmt.Println(e)
}
}()
fmt.Println("done without error 1")
go func() {
if e := zch.signalLastInteractionTime(context.Background(), dateTime); e != nil {
fmt.Println(e)
}
}()
fmt.Println("done without error 2")
fmt.Println("sending notification")
}
return
})
@ -463,14 +486,17 @@ func (zch *NodeChatChannelsHandler[T]) AddChatMessage(userId, chatID, content st
}
d1, e1 := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", chat.Target, map[string]interface{}{
"chatMessage": chatMessage,
"chatID": chatID,
"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,
"chatId": chatID,
})
go notifyActivity(d2, e2, chat.Initiator, chat.Target)
if userId == chat.Target {
go notifyActivity(d2, e2, chat.Initiator)
} else {
go notifyActivity(d1, e1, chat.Target)
}
return
}
@ -502,7 +528,7 @@ func (zch *NodeChatChannelsHandler[T]) DeleteChatMessage(key uint64, chatID stri
}
for _, member := range [2]string{chat.Initiator, chat.Target} {
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_DELETED, "node", member, map[string]interface{}{
"chatID": chatID,
"chatId": chatID,
"messageId": key,
})
select {
@ -542,7 +568,7 @@ func (zch *NodeChatChannelsHandler[T]) UpdateChatMessage(key uint64, chatID, new
}
for _, member := range [2]string{chat.Target, chat.Initiator} {
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_EDITED, "node", member, map[string]interface{}{
"chatID": chatID,
"chatId": chatID,
"messageId": key,
"newContent": newContent,
})
@ -570,7 +596,7 @@ func (zch *NodeChatChannelsHandler[T]) DeleteChatFile(key uint64, fileName, chat
}
for _, member := range [2]string{chat.Target, chat.Initiator} {
d, e := zch.sendDataChannelMessage(CHAT_FILE_DELETED, "node", member, map[string]interface{}{
"chatID": chatID,
"chatId": chatID,
"fileId": key,
"fileName": fileName,
})
@ -705,6 +731,24 @@ func (zch *NodeChatChannelsHandler[T]) handleDataChannel(ctx context.Context, dc
zch.ChatDataChannels[command[1]] = dc
return
})
dc.DataChannel.OnOpen(func() {
bs, err := json.Marshal(map[string]any{
"type": "chat_init",
"from": NodeID,
"to": command[1],
"payload": map[string]any{
"chatId": zch.ChatID,
},
})
if err != nil {
fmt.Println(err)
}
_ = dc.DataChannel.SendText(string(bs))
})
dc.DataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
fmt.Println("received message there")
fmt.Println(msg.Data)
})
dc.DataChannel.OnClose(func() {
fmt.Println("closing gratefully chat dc...")
_ = atomicallyExecute(zch.ChatDataChannelsFlag, func() (err error) {
@ -723,8 +767,65 @@ func (zch *NodeChatChannelsHandler[T]) handleDataChannel(ctx context.Context, dc
return
}
func (zch *NodeChatChannelsHandler[T]) signalUnreadCount(ctx context.Context, userId string, count uint) (err error) {
fmt.Println("this function has been called")
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
body, err := json.Marshal(map[string]interface{}{
"type": UPDATE_UNREAD_COUNT,
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]string{
"chatId": zch.ChatID,
"userId": userId,
"count": fmt.Sprintf("%d", count),
},
})
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 inn chat manager")
return
}
return
}
func (zch *NodeChatChannelsHandler[T]) signalLastInteractionTime(ctx context.Context, dateTime string) (err error) {
fmt.Println("this function has been called too")
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
body, err := json.Marshal(map[string]interface{}{
"type": UPDATE_LAST_INTERACTION_TIME,
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]string{
"chatId": zch.ChatID,
"lastInteractionTime": dateTime,
},
})
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
}
_, err = io.ReadAll(res.Body)
if err != nil {
return
}
return
}
func (zch *NodeChatChannelsHandler[T]) handleChatRequest(ctx context.Context, req *ChatRequest) (err error) {
logger.Println("got request in zone chat handler", req)
fmt.Println(req)
switch req.ReqType {
case LEAVE_CHAT:
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
@ -732,46 +833,46 @@ func (zch *NodeChatChannelsHandler[T]) handleChatRequest(ctx context.Context, re
}
// err = zch.LeaveChatFSInstance(req.Payload["userId"].(string))
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))
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 {
return
}
err = zch.AddNewChat(req.Payload["chatID"].(string), req.Payload["initiator"].(string), req.Payload["target"].(string), req.Payload["initiatorHostId"].(string), req.Payload["targetHostId"].(string))
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 {
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))
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 {
return
}
err = zch.ListLatestChatFiles(req.From, req.Payload["chatID"].(string), req.Payload["lastIndex"].(float64), req.Payload["limit"].(float64))
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))
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 {
@ -797,31 +898,31 @@ func (zch *NodeChatChannelsHandler[T]) handleChatRequest(ctx context.Context, re
}
file = &f
}
err = zch.AddChatMessage(req.From, req.Payload["chatID"].(string), req.Payload["content"].(string), req.Payload["isResponse"].(bool), parentChatId, file)
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 {
return
}
err = zch.DeleteChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatID"].(string))
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 {
return
}
err = zch.UpdateChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatID"].(string), req.Payload["newContent"].(string))
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 {
return
}
err = zch.DeleteChatFile(uint64(req.Payload["fileId"].(float64)), req.Payload["fileName"].(string), req.Payload["chatID"].(string))
err = zch.DeleteChatFile(uint64(req.Payload["fileId"].(float64)), req.Payload["fileName"].(string), req.Payload["chatId"].(string))
}
return
}

133
chatNotificationsHandler.go Normal file
View File

@ -0,0 +1,133 @@
package localserver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
)
type ChatNotificationsHandler struct {
ChatId string
Initiator string
Target string
InitiatorHost string
TargetHost string
DataChannels map[string]*DataChannel
Flag *uint32
//DB *ChatNotificationDBHandler
Publishers []<-chan *ChatRequest
reqChans []chan<- *ChatRequest
}
func NewChatNotificationsHandler(chatId, initiator, target, initiatorHost, targetHost string, dataChannels map[string]*DataChannel, flag *uint32) (chatNotificationsHandler *ChatNotificationsHandler, err error) {
// if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "zones", zoneId, "notifications")); os.IsNotExist(dirErr) {
// dirErr := os.MkdirAll(filepath.Join(dataPath, "data", "zones", zoneId, "notifications"), 0700)
// if dirErr != nil {
// return
// }
// }
chatNotificationsHandler = &ChatNotificationsHandler{
ChatId: chatId,
Initiator: initiator,
Target: target,
InitiatorHost: initiatorHost,
TargetHost: targetHost,
DataChannels: dataChannels,
Flag: flag,
}
return
}
func (znh *ChatNotificationsHandler) Init(ctx context.Context, initiator, target, initiatorNodeID, targetNodeID string) (err error) {
//? initialization code here
return
}
func (znh *ChatNotificationsHandler) 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)
znh.reqChans = append(znh.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := znh.handleChatRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (znh *ChatNotificationsHandler) ListNotifications(userId string) {}
func (znh *ChatNotificationsHandler) CreateNotification(notificationType, title, body, payload string, isPushed bool, recipients ...string) (err error) {
if isPushed {
err = znh.PushNotification(notificationType, title, body, payload, recipients...)
}
return
}
func (znh *ChatNotificationsHandler) DeleteNotification() {}
func (znh *ChatNotificationsHandler) PushNotification(notificationType, title, body, payload string, recipients ...string) (err error) {
fmt.Println("*E*Z*E*Z*Z*E*Z**E*Z**E**Z*E****ZD*Z*")
fmt.Println("this function has been called")
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
b, err := json.Marshal(map[string]interface{}{
"type": NOTIFY,
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]interface{}{
"type": notificationType,
"title": title,
"body": body,
"recipients": recipients,
"payload": payload,
},
})
if err != nil {
return
}
_, err = http.Post("https://dev.zippytal.com/req", "application/json", bytes.NewReader(b))
if err != nil {
fmt.Println("error inn notification sender", err)
logger.Println("error come from there in zone manager")
return
}
return
}
func (znh ChatNotificationsHandler) handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool) {
return
}
func (znh *ChatNotificationsHandler) handleChatRequest(ctx context.Context, req *ChatRequest) (err error) {
switch req.ReqType {
case CREATE_NOTIFICATION:
if err = VerifyFieldsString(req.Payload, "type", "title", "body", "payload"); err != nil {
return
}
if err = VerifyFieldsBool(req.Payload, "isPushed"); err != nil {
return
}
if _, ok := req.Payload["recipients"]; !ok {
err = fmt.Errorf("no field recipient in payload")
return
}
if _, ok := req.Payload["recipients"].([]string); !ok {
err = fmt.Errorf(" field recipient in payload is wrong type")
return
}
err = znh.CreateNotification(req.Payload["type"].(string), req.Payload["title"].(string), req.Payload["body"].(string), req.Payload["payload"].(string), req.Payload["isPushed"].(bool), req.Payload["recipients"].([]string)...)
}
return
}

View File

@ -2,6 +2,7 @@ package localserver
import (
"context"
"fmt"
"sync"
"time"
)
@ -41,6 +42,8 @@ func NewChatRequestScheduler(initiator, target, initiatorNodeID, targetNodeID st
publisher := make(chan *ChatRequest, 100)
chatRequestScheduler.handlersPublishers = append(chatRequestScheduler.handlersPublishers, publisher)
chatRequestScheduler.handlersDataChannelDispatchCallbacks = append(chatRequestScheduler.handlersDataChannelDispatchCallbacks, handler.handleDataChannel)
fmt.Println("this is the fking handler")
fmt.Println(handler)
reqChan, done, errCh := handler.Subscribe(context.Background(), publisher)
go func(done <-chan struct{}, errCh <-chan error) {
for {
@ -76,16 +79,16 @@ func NewChatRequestScheduler(initiator, target, initiatorNodeID, targetNodeID st
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)
}
go func() {
for req := range reqChan {
go func(r *ChatRequest) {
for _, publisher := range crs.handlersPublishers {
publisher <- r
}
}(req)
}
done <- struct{}{}
}()
return
}

View File

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

View File

@ -1 +0,0 @@
<>ª—¤ÓHè±7EÃ3Hello Badger

File diff suppressed because it is too large Load Diff

BIN
cmd/node

Binary file not shown.

Binary file not shown.

View File

@ -90,6 +90,9 @@ func (em *EncryptionManager) LoadPrivKey(privKeyPath string, password string) (e
}
if password != "" {
privePemBytes, err = x509.DecryptPEMBlock(privPem, []byte(password))
if err != nil {
return
}
} else {
privePemBytes = privPem.Bytes
}

View File

@ -82,32 +82,34 @@ var dataPath = ""
func NewLocalServer(grpcAddr uint, appDataPath, id, token string) (localServer *LocalServer, err error) {
dataPath = appDataPath
webRTCCallManager, err := NewWebRTCCallManager(id, token, NewWebrtcCallSoundManager(), NewWebrtcCallChatManager(), NewWebrtcCallVideoManager(), NewWebrtcCallFileManager())
if err != nil {
err = fmt.Errorf("error from call manager")
return
}
zoneManager, err := NewZoneManager(id, token)
if err != nil {
fmt.Println(err)
err = fmt.Errorf("error from zone manager")
return
}
// webrtcFsManager, err := NewWebrtcFsManager(NewP2PFSDatachannelManager())
// if err != nil {
// err = fmt.Errorf("error from fs manager")
// return
// }
webrtcGrpcMiddleware := NewWebRTCGrpcMiddleware(webRTCCallManager)
ZoneGrpcMiddleware := NewZoneGrpcMiddleware(zoneManager)
signalingClientManager, err := NewGrpcClientManager(grpcAddr, id, webrtcGrpcMiddleware, ZoneGrpcMiddleware)
chatManager, err := NewChatManager(id, token)
if err != nil {
fmt.Println(err)
return
}
squadManager, err := NewSquadManager(id, token)
if err != nil {
fmt.Println(err)
return
}
zoneGrpcMiddleware := NewZoneGrpcMiddleware(zoneManager)
chatGrpcMiddleware := NewChatGrpcMiddleware(chatManager)
squadGrpcMiddleware := NewSquadGrpcMiddleware(squadManager)
signalingClientManager, err := NewGrpcClientManager(grpcAddr, id, zoneGrpcMiddleware, chatGrpcMiddleware, squadGrpcMiddleware)
if err != nil {
return
}
webrtcGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
webRTCCallManager.stream = signalingClientManager.GrpcLinkClient
zoneManager.stream = signalingClientManager.GrpcLinkClient
ZoneGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
zoneGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
chatManager.stream = signalingClientManager.GrpcLinkClient
chatGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
squadManager.stream = signalingClientManager.GrpcLinkClient
squadGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
localServer = &LocalServer{
ID: id,
GrpcClientManager: signalingClientManager,

323
squadChatDBHandler.go Normal file
View File

@ -0,0 +1,323 @@
package localserver
import (
"encoding/binary"
"encoding/json"
"os"
"path/filepath"
"sync"
"github.com/dgraph-io/badger/v3"
)
type SquadChatDBHandler struct {
SquadID string
PreviousId uint64
ItemCount uint64
db func(func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
}
func NewSquadChatDBHandler(squadId string) (squadChatDBHandler *SquadChatDBHandler, err error) {
squadChatDBHandler = &SquadChatDBHandler{
db: func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join(dataPath, "data", "squads", squadId, "chat")).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
},
SquadID: squadId,
lock: new(sync.RWMutex),
}
err = squadChatDBHandler.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
}
}
squadChatDBHandler.PreviousId = counter
squadChatDBHandler.ItemCount = itemCounter
return nil
})
return
})
return
}
func (zcdbh *SquadChatDBHandler) calculateNewChatCount(previousId uint64) (count uint, err error) {
err = zcdbh.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 (zcdbh *SquadChatDBHandler) revertPreviousId() (err error) {
err = zcdbh.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
}
zcdbh.PreviousId = chatMessage.ID
return
}); err != nil {
return err
}
} else {
zcdbh.PreviousId = 1
}
return nil
})
return
})
return
}
func (zcdbh *SquadChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) {
b := make([]byte, bufferSize)
zcdbh.PreviousId++
binary.BigEndian.PutUint64(b, zcdbh.PreviousId)
chatMessage.ID = zcdbh.PreviousId
bs, err := json.Marshal(chatMessage)
if err != nil {
return
}
if err = zcdbh.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 (zcdbh *SquadChatDBHandler) DeleteChatMessage(key uint64) (err error) {
if err = zcdbh.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
}
zcdbh.ItemCount--
return
})
return
}); err != nil {
return
}
return
}
func (zcdbh *SquadChatDBHandler) DeleteChatFile(filename string, key uint64) (err error) {
if err = zcdbh.DeleteChatMessage(key); err != nil {
return
}
err = os.Remove(filepath.Join(dataPath, "data", "squads", zcdbh.SquadID, "chat", "__files__", filename))
return
}
func (zcdbh *SquadChatDBHandler) ListChatMessages(lastIndex int, limit int) (chatMessages []*ChatMessage, l int, done bool, err error) {
err = zcdbh.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(zcdbh.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 (zcdbh *SquadChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMessages []*ChatFile, l int, err error) {
err = zcdbh.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(zcdbh.PreviousId))
li = int(zcdbh.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 zcdbh.PreviousId > uint64(x) {
l = int(zcdbh.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(zcdbh.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 (zcdbh *SquadChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatMessage, err error) {
err = zcdbh.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 (zcdbh *SquadChatDBHandler) ModifyChatMessage(key uint64, newContent string) (err error) {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key)
chatMessage, err := zcdbh.GetChatMessage(key)
if err != nil {
return
}
chatMessage.Content = newContent
bs, err := json.Marshal(chatMessage)
if err != nil {
return
}
if err = zcdbh.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
}

178
squadChatFSInstance.go Normal file
View File

@ -0,0 +1,178 @@
package localserver
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"github.com/pion/webrtc/v3"
)
const (
SQUAD_CHAT_WEBRTC_OFFER ReqType = "squad_chat_offer"
SQUAD_CHAT_WEBRTC_ANSWER ReqType = "squad_chat_answer"
SQUAD_CHAT_WEBRTC_RENNEGOTIATION_OFFER ReqType = "squad_chat_rennegotiation_offer"
SQUAD_CHAT_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "squad_chat_rennegotiation_answer"
SQUAD_CHAT_WEBRTC_COUNTER_OFFER ReqType = "squad_chat_webrtc_counter_offer"
SQUAD_CHAT_WEBRTC_CANDIDATE ReqType = "squad_chat_webrtc_candidate"
)
type SquadFSInstance struct {
SquadID string `json:"id"`
Owner string `json:"owner"`
Members []string `json:"members"`
OpenFiles map[string]*os.File `json:"-"`
OpenFilesForUser map[string][]string `json:"-"`
filesFlag *uint32 `json:"-"`
}
func NewSquadFSInstance(id, owner string, members []string) (squadFSInstance *SquadFSInstance) {
filesFlag := uint32(0)
squadFSInstance = &SquadFSInstance{
SquadID: id,
Owner: owner,
Members: members,
OpenFiles: make(map[string]*os.File),
OpenFilesForUser: make(map[string][]string),
filesFlag: &filesFlag,
}
return
}
func (fs *SquadFSInstance) SetupFileUpload(chatId, filename, userId string, dc *webrtc.DataChannel) (writePipe chan []byte, err error) {
concretePath := filepath.Join(dataPath, "data", "squads", fs.SquadID, "chat", "__files__", filename)
if _, err = os.ReadDir(filepath.Join(dataPath, "data", "squads", fs.SquadID, "chat")); err != nil {
return
}
if _, rErr := os.ReadDir(filepath.Join(dataPath, "data", "squads", fs.SquadID, "chat", "__files__")); os.IsNotExist(rErr) {
if err = os.MkdirAll(filepath.Join(dataPath, "data", "squads", fs.SquadID, "chat", "__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 *SquadFSInstance) FileUploadFailed(chatId, filename, userId string) (err error) {
concretePath := filepath.Join(dataPath, "data", "squads", fs.SquadID, "chat", "__files__", filename)
err = os.Remove(concretePath)
return
}
func (fs *SquadFSInstance) SetupFileDownload(chatId, filename, userId string, dc *webrtc.DataChannel) (err error) {
concretePath := filepath.Join(dataPath, "data", "squads", fs.SquadID, "chat", "__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 *SquadFSInstance) 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 *SquadFSInstance) HandleDataChannelEvents(from, eventId string, payload map[string]interface{}) (err error) {
switch eventId {
}
return
}

750
squadChatHandler.go Normal file
View File

@ -0,0 +1,750 @@
package localserver
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/dgraph-io/badger/v3"
"github.com/pion/webrtc/v3"
)
type SquadChatConfig struct {
ChatId string `json:"chatId"`
ChatType string `json:"chatType"`
Owner string `json:"owner"`
Members []string `json:"members"`
}
type SquadChat struct {
ChatId string `json:"chatId"`
ChatType string `json:"chatType"`
Owner string `json:"owner"`
Members []string `json:"members"`
LastReadIndex uint `json:"lastReadIndex"`
Unread uint `json:"unread"`
DB *SquadChatDBHandler `json:"-"`
Tracking *SquadChatTrackingDB `json:"-"`
}
type SquadChatsHandler[T ZippytalFSInstance] struct {
SquadName string
SquadId string
HostId string
ChatFSInstance T
SquadMembersId []string
DataChannels map[string]*DataChannel
ChatDataChannels map[string]*DataChannel
ChatDataChannelsFlag *uint32
Flag *uint32
ChatFSInstanceFlag *uint32
ChatFlag *uint32
Chat *SquadChat
reqChans []chan<- *SquadRequest
init bool
}
func NewSquadChatsHandler(hostId, squadId, squadName, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (squadChatsHandler *SquadChatsHandler[*SquadFSInstance], err error) {
_, err = os.ReadDir(filepath.Join(dataPath, "data", "squads", squadId, "chat"))
if err != nil {
if os.IsNotExist(err) {
logger.Printf("creating chat directory for squad %s...\n", squadId)
mkdirErr := os.MkdirAll(filepath.Join(dataPath, "data", "squads", squadId, "chat"), 0700)
if mkdirErr != nil {
return nil, mkdirErr
}
file, ferr := os.Create(filepath.Join(dataPath, "data", "squads", squadId, "chat", "chatConfig.json"))
if ferr != nil {
return nil, ferr
}
baseConfig := ChatConfig{
ChatId: squadName,
Owner: owner,
ChatType: "public",
Members: authorizedMembers,
}
bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil {
return nil, jsonErr
}
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
return nil, writeErr
}
_ = file.Close()
_, err = os.ReadDir(filepath.Join(dataPath, "data", "squads", squadId, "chat"))
if err != nil {
return nil, err
}
} else {
return
}
}
squadChatDBHandler, err := NewSquadChatDBHandler(squadId)
if err != nil {
return nil, err
}
var bs []byte
bs, err = os.ReadFile(filepath.Join(dataPath, "data", "squads", squadId, "chat", "chatConfig.json"))
if err != nil {
return nil, err
}
logger.Println(string(bs))
var c SquadChat
if err = json.Unmarshal(bs, &c); err != nil {
return nil, err
}
squadChatTracking, err := NewSquadChatTracking(squadId, c.ChatId, c.Members...)
if err != nil {
return nil, err
}
logger.Println("chats data :", c.ChatId, c.ChatType, c.Owner, c.Members)
c.DB = squadChatDBHandler
c.Tracking = squadChatTracking
chatFlag := uint32(0)
chatFSFlag := uint32(0)
chatDCFlag := uint32(0)
squadChatsHandler = &SquadChatsHandler[*SquadFSInstance]{
HostId: hostId,
SquadName: squadName,
ChatFSInstance: NewSquadFSInstance(squadId, owner, authorizedMembers),
ChatFSInstanceFlag: &chatFSFlag,
SquadId: squadId,
SquadMembersId: authorizedMembers,
DataChannels: dataChannels,
ChatDataChannels: make(map[string]*DataChannel),
ChatDataChannelsFlag: &chatDCFlag,
Flag: flag,
Chat: &c,
ChatFlag: &chatFlag,
init: false,
}
return
}
func (sch *SquadChatsHandler[T]) sendSquadRequest(reqType string, from string, payload map[string]interface{}) {
go func() {
for _, rc := range sch.reqChans {
rc <- &SquadRequest{
ReqType: reqType,
From: from,
Payload: payload,
}
}
}()
}
func (sch *SquadChatsHandler[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(sch.ChatDataChannelsFlag, func() (err error) {
if _, ok := sch.ChatDataChannels[to]; ok {
bs, jsonErr := json.Marshal(&SquadResponse{
Type: reqType,
From: from,
To: to,
Payload: payload,
})
if jsonErr != nil {
return jsonErr
}
err = sch.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 (sch *SquadChatsHandler[T]) Init(ctx context.Context, authorizedMembers []string) (err error) {
sch.init = true
return
}
func (sch *SquadChatsHandler[T]) Subscribe(ctx context.Context, publisher <-chan *SquadRequest) (reqChan chan *SquadRequest, done chan struct{}, errCh chan error) {
reqChan, done, errCh = make(chan *SquadRequest), make(chan struct{}), make(chan error)
sch.reqChans = append(sch.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := sch.handleSquadRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (sch *SquadChatsHandler[T]) ReadLastMessage(userId, chatId string) (err error) {
err = atomicallyExecute(sch.ChatFlag, func() (err error) {
err = sch.Chat.Tracking.SetUserLastIndex(userId, sch.Chat.DB.PreviousId)
return
})
return
}
func (sch *SquadChatsHandler[T]) ListLatestChatMessages(userId, chatId string, lastIndex, limit float64) (err error) {
var list []*ChatMessage
var i int
var done bool
if err = atomicallyExecute(sch.ChatFlag, func() (err error) {
list, i, done, err = sch.Chat.DB.ListChatMessages(int(lastIndex), int(limit))
if err != nil {
return
}
err = sch.Chat.Tracking.SetUserLastIndex(userId, sch.Chat.DB.PreviousId)
return
}); err != nil {
return
}
success, e := sch.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 (sch *SquadChatsHandler[T]) ListLatestChatFiles(userId, chatId string, lastIndex, limit float64) (err error) {
var list []*ChatFile
var i int
if err = atomicallyExecute(sch.ChatFlag, func() (err error) {
list, i, err = sch.Chat.DB.ListChatFiles(int(lastIndex), int(limit))
return
}); err != nil {
return
}
done, e := sch.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 (sch *SquadChatsHandler[T]) AddChatMessage(userId, chatId, content string, isResponse bool, chatResponseId uint64, file *ChatFile) (err error) {
chatMessage := &ChatMessage{
Content: content,
From: userId,
IsResponse: isResponse,
ResponseOf: nil,
File: file,
Tags: make([]string, 0),
Date: time.Now().Format(time.RFC3339),
}
if err = atomicallyExecute(sch.ChatFlag, func() (err error) {
if isResponse {
parentMessage, getErr := sch.Chat.DB.GetChatMessage(chatResponseId)
if err != nil {
if getErr != badger.ErrKeyNotFound {
return getErr
}
}
chatMessage.ResponseOf = parentMessage
}
if err = sch.Chat.DB.AddNewChatMessage(chatMessage); err != nil {
return
}
chatMessage.ID = sch.Chat.DB.PreviousId
return
}); err != nil {
return
}
notifyActivity := func(done <-chan struct{}, e <-chan error, member string) {
select {
case <-done:
case <-e:
chat := sch.Chat
_ = atomicallyExecute(sch.ChatFlag, func() (err error) {
li, err := chat.Tracking.GetUserLastIndex(member)
if err != nil {
return err
}
count, err := chat.DB.calculateNewChatCount(uint64(li))
if err != nil {
return err
}
if count == 1 {
bs, err := json.Marshal(map[string]any{
"squadId": sch.SquadId,
"chatId": chatId,
"squadHost": NodeID,
})
if err != nil {
return err
}
sch.sendSquadRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "new_chat_activity",
"title": "Unread messages 👀",
"body": fmt.Sprintf("New messages in %s", sch.SquadName),
"isPushed": true,
"payload": string(bs),
"recipients": []string{member},
})
}
return
})
}
}
for _, v := range sch.SquadMembersId {
done, e := sch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", v, map[string]interface{}{
"chatMessage": chatMessage,
"chatId": chatId,
})
go notifyActivity(done, e, v)
}
return
}
// func (sch *SquadChatsHandler[T]) ConnectToChatFSInstance(channelId string, userId string, sdp string) (err error) {
// err = atomicallyExecute(sch.ChatFSInstanceFlag, func() (err error) {
// d, e := sch.ChatFSInstance.HandleOffer(context.Background(), channelId, userId, sdp, sch.HostId, sch.sendDataChannelMessage, sch.signalCandidate)
// select {
// case <-d:
// case <-e:
// }
// return
// })
// return
// }
// func (sch *SquadChatsHandler[T]) LeaveChatFSInstance(
// userId string) (err error) {
// sch.ChatFSInstance.HandleLeavingMember(userId)
// return
// }
func (sch *SquadChatsHandler[T]) DeleteChatMessage(key uint64, chatId string) (err error) {
err = atomicallyExecute(sch.ChatFlag, func() (err error) {
chat := sch.Chat
if err = chat.DB.DeleteChatMessage(key); err != nil {
return
}
if chat.ChatType == PRIVATE {
for _, member := range chat.Members {
d, e := sch.sendDataChannelMessage(CHAT_MESSAGE_DELETED, "node", member, map[string]interface{}{
"chatId": chatId,
"messageId": key,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
} else {
for _, member := range sch.SquadMembersId {
d, e := sch.sendDataChannelMessage(CHAT_MESSAGE_DELETED, "node", member, map[string]interface{}{
"chatId": chatId,
"messageId": key,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
}
previousId := chat.DB.PreviousId
if previousId == key {
if err = chat.DB.revertPreviousId(); err != nil {
return
}
previousId = chat.DB.PreviousId
if previousId == 1 {
previousId = 0
}
if err = chat.Tracking.RevertTrackingLastIndex(previousId); err != nil {
return
}
}
return
})
return
}
func (sch *SquadChatsHandler[T]) UpdateChatMessage(key uint64, chatId, newContent string) (err error) {
err = atomicallyExecute(sch.ChatFlag, func() (err error) {
chat := sch.Chat
if err = chat.DB.ModifyChatMessage(key, newContent); err != nil {
return
}
if chat.ChatType == PRIVATE {
for _, member := range chat.Members {
d, e := sch.sendDataChannelMessage(CHAT_MESSAGE_EDITED, "node", member, map[string]interface{}{
"chatId": chatId,
"messageId": key,
"newContent": newContent,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
} else {
for _, member := range sch.SquadMembersId {
d, e := sch.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 (sch *SquadChatsHandler[T]) DeleteChatFile(key uint64, fileName, chatId string) (err error) {
err = atomicallyExecute(sch.ChatFlag, func() (err error) {
chat := sch.Chat
if err = chat.DB.DeleteChatFile(fileName, key); err != nil {
return
}
if chat.ChatType == PRIVATE {
for _, member := range chat.Members {
d, e := sch.sendDataChannelMessage(CHAT_FILE_DELETED, "node", member, map[string]interface{}{
"chatId": chatId,
"fileId": key,
"fileName": fileName,
})
select {
case <-d:
case tempErr := <-e:
logger.Println(tempErr)
}
}
} else {
for _, member := range sch.SquadMembersId {
d, e := sch.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 (sch *SquadChatsHandler[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 := sch.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 := sch.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 = sch.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 (sch *SquadChatsHandler[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 := sch.ChatFSInstance.FileDownloadFailed(chatId, filename, userId); fdf != nil {
logger.Println(fdf)
}
}
})
dc.DataChannel.OnClose(func() {
if !done {
logger.Println("abort...")
if fdf := sch.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 = sch.ChatFSInstance.SetupFileDownload(chatId, filename, userId, dc.DataChannel); initErr != nil {
fmt.Println("uwuwuwuwuwuwuwuwu")
fmt.Println(initErr)
_ = 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 (sch *SquadChatsHandler[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 sch.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 sch.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(sch.ChatDataChannelsFlag, func() (err error) {
sch.ChatDataChannels[command[1]] = dc
return
})
dc.DataChannel.OnOpen(func() {
fmt.Println("datachann in squad chat fking created")
bs, err := json.Marshal(map[string]any{
"type": "chat_init",
"from": NodeID,
"to": command[1],
"payload": map[string]any{
"chatId": sch.SquadId,
},
})
if err != nil {
fmt.Println(err)
}
_ = dc.DataChannel.SendText(string(bs))
})
dc.DataChannel.OnClose(func() {
fmt.Println("closing gratefully chat dc...")
_ = atomicallyExecute(sch.ChatDataChannelsFlag, func() (err error) {
delete(sch.ChatDataChannels, command[1])
return
})
})
dc.DataChannel.OnError(func(err error) {
fmt.Println("error in chat dc...")
_ = atomicallyExecute(sch.ChatDataChannelsFlag, func() (err error) {
delete(sch.ChatDataChannels, command[1])
return
})
})
}
return
}
func (sch *SquadChatsHandler[T]) handleSquadRequest(ctx context.Context, req *SquadRequest) (err error) {
logger.Println("got request in squad chat handler", req)
switch req.ReqType {
case LEAVE_ZONE:
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
// err = sch.LeaveChatFSInstance(req.Payload["userId"].(string))
case string(NEW_AUTHORIZED_SQUAD_MEMBER):
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var contain bool
for _, m := range sch.SquadMembersId {
if m == req.Payload["userId"].(string) {
contain = true
break
}
}
if !contain {
sch.SquadMembersId = append(sch.SquadMembersId, req.Payload["userId"].(string))
}
return
case string(REMOVED_SQUAD_AUTHORIZED_MEMBER):
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var index int
var found bool
for i, m := range sch.SquadMembersId {
if m == req.Payload["userId"].(string) {
index = i
found = true
break
}
}
if !found {
err = fmt.Errorf("no such user in zone")
return
}
sch.SquadMembersId = append(sch.SquadMembersId[:index], sch.SquadMembersId[index+1:]...)
return
case LIST_LATEST_CHATS:
if err = VerifyFieldsString(req.Payload, "chatId"); err != nil {
return
}
if err = VerifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
return
}
err = sch.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 = sch.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 = sch.ReadLastMessage(req.From, req.Payload["chatId"].(string))
case ADD_CHAT_MESSAGE:
logger.Println("got request in squad 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 = sch.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 = sch.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 = sch.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 = sch.DeleteChatFile(uint64(req.Payload["fileId"].(float64)), req.Payload["fileName"].(string), req.Payload["chatId"].(string))
}
return
}

151
squadChatTracking.go Normal file
View File

@ -0,0 +1,151 @@
package localserver
import (
"encoding/binary"
"os"
"path/filepath"
"sync"
"github.com/dgraph-io/badger/v3"
)
type SquadChatTrackingDB struct {
SquadID string
db func(cb func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
}
func NewSquadChatTracking(squadId, chatId string, members ...string) (*SquadChatTrackingDB, error) {
if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "squads", squadId, "chat", "__tracking__")); os.IsNotExist(dirErr) {
_ = os.MkdirAll(filepath.Join(dataPath, "data", "squads", squadId, "chat", "__tracking__"), 0700)
}
db := func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join(dataPath, "data", "squads", squadId, "chat", "__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 members {
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 &SquadChatTrackingDB{squadId, db, lock}, nil
}
func (zctdb *SquadChatTrackingDB) Initialize(lastIndex uint64, users ...string) (err error) {
for _, user := range users {
if err = zctdb.SetUserLastIndex(user, lastIndex); err != nil {
return
}
}
return
}
func (zctdb *SquadChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err error) {
zctdb.lock.Lock()
defer zctdb.lock.Unlock()
err = zctdb.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 (zctdb *SquadChatTrackingDB) SetUserLastIndex(userId string, lastIndex uint64) (err error) {
zctdb.lock.Lock()
defer zctdb.lock.Unlock()
err = zctdb.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 (zctdb *SquadChatTrackingDB) GetUserLastIndex(userId string) (index uint, err error) {
zctdb.lock.Lock()
defer zctdb.lock.Unlock()
err = zctdb.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 (zctdb *SquadChatTrackingDB) DeleteUserTracking(userId string) (err error) {
zctdb.lock.Lock()
defer zctdb.lock.Unlock()
err = zctdb.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error {
updateErr := txn.Delete([]byte(userId))
return updateErr
})
return
})
return
}

238
squadGrpcMiddleware.go Normal file
View File

@ -0,0 +1,238 @@
package localserver
import (
"context"
"encoding/json"
"fmt"
"strconv"
"github.com/pion/webrtc/v3"
)
const (
HOSTED_SQUAD_OFFER ReqType = "hosted_squad_offer"
HOSTED_SQUAD_ANSWER ReqType = "hosted_squad_answer"
HOSTED_SQUAD_COUNTER_OFFER ReqType = "hosted_squad_counter_offer"
JOIN_SQUAD ReqType = "join_hosted_squad"
HOSTED_SQUAD_ACCESS_DENIED ReqType = "hosted_squad_hosted_squad_access_denied"
QUIT_SQUAD ReqType = "hosted_squad_stop_call"
HOSTED_SQUAD_ACCESS_GRANTED ReqType = "hosted_squad_access_granted"
INCOMING_HOSTED_SQUAD_MEMBER ReqType = "incoming_hosted_squad_member"
LEAVING_HOSTED_SQUAD_MEMBER ReqType = "leaving_hosted_squad_member"
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER ReqType = "hosted_squad_rennegotiation_offer"
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "hosted_squad_rennegotiation_answer"
HOSTED_SQUAD_WEBRTC_CANDIDATE ReqType = "hosted_squad_webrtc_candidate"
NEW_SQUAD ReqType = "new_hosted_squad"
NEW_AUTHORIZED_SQUAD_MEMBER = "new_authorized_squad_member"
REMOVED_SQUAD_AUTHORIZED_MEMBER = "removed_squad_authorized_member"
DELETE_SQUAD = "delete_hosted_squad"
DISCONNECT_SQUAD_MEMBER = "disconnect_squad_member"
)
type SquadGrpcMiddleware struct {
Manager *SquadManager
stream SignalingService_LinkClient
}
func NewSquadGrpcMiddleware(manager *SquadManager) (squadGrpcMiddleware *SquadGrpcMiddleware) {
squadGrpcMiddleware = &SquadGrpcMiddleware{
Manager: manager,
}
return
}
func (zm *SquadGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
bs, err := json.Marshal(map[string]string{
"from": zm.Manager.ID,
"to": to,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
})
if err != nil {
return
}
err = zm.stream.Send(&SignalingMessage{
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
From: zm.Manager.ID,
To: to,
Payload: bs,
})
return
}
func (zm *SquadGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
defer func() {
done <- struct{}{}
}()
var payload map[string]string
if e := json.Unmarshal(req.Payload, &payload); e != nil {
errCh <- e
return
}
switch req.Type {
case string(INCOMING_HOSTED_SQUAD_MEMBER):
case string(DELETE_SQUAD):
if err := validateRequest(payload, "squadId"); err != nil {
return
}
if err := zm.Manager.DeleteSquad(payload["squadId"]); err != nil {
errCh <- err
return
}
case string(LEAVING_HOSTED_SQUAD_MEMBER):
if err := validateRequest(payload, "squadId"); err != nil {
return
}
if err := zm.Manager.HandleLeavingMember(req.GetFrom(), payload["squadId"], false); err != nil {
errCh <- err
return
}
case string(REMOVED_SQUAD_AUTHORIZED_MEMBER):
fmt.Println("got there biatch")
if err := validateRequest(payload, "squadId", "userId"); err != nil {
return
}
reqChan := make(chan *SquadRequest)
d, e := zm.Manager.Squads[payload["squadId"]].SquadRequestScheduler.Schedule(reqChan)
go func() {
defer close(reqChan)
reqChan <- &SquadRequest{
ReqType: string(REMOVED_SQUAD_AUTHORIZED_MEMBER),
From: payload["userId"],
Payload: map[string]interface{}{
"userId": payload["userId"],
},
}
}()
select {
case <-d:
fmt.Println("uwuwuwuwuwuwuw donnnnee")
case ee := <-e:
fmt.Println("uuuuuuwuuuuuu", ee)
}
return
case string(NEW_AUTHORIZED_SQUAD_MEMBER):
if err := validateRequest(payload, "squadId", "userId"); err != nil {
return
}
reqChan := make(chan *SquadRequest)
d, e := zm.Manager.Squads[payload["squadId"]].SquadRequestScheduler.Schedule(reqChan)
go func() {
defer close(reqChan)
reqChan <- &SquadRequest{
ReqType: string(NEW_AUTHORIZED_SQUAD_MEMBER),
From: payload["userId"],
Payload: map[string]interface{}{
"userId": payload["userId"],
},
}
}()
select {
case <-d:
fmt.Println("uwuwuwuwuwuwuw donnnnee")
case ee := <-e:
fmt.Println("uuuuuuwuuuuuu", ee)
}
return
case string(NEW_SQUAD):
logger.Println(payload)
if err := validateRequest(payload, "squadId", "squadName", "squadImageURL", "squadOwner", "squadCreationDate"); err != nil {
errCh <- err
return
}
squad, err := NewSquad(zm.Manager.ID, payload["squadId"], payload["squadName"], payload["squadImageURL"], payload["squadOwner"], payload["squadCreationDate"], true, []string{payload["squadOwner"]})
if err != nil {
errCh <- err
return
}
_ = atomicallyExecute(zm.Manager.squadFlag, func() (err error) {
zm.Manager.Squads[squad.ID] = squad
return
})
case string(HOSTED_SQUAD_OFFER):
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := zm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, zm.signalCandidate); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_ANSWER):
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := zm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_COUNTER_OFFER):
if err := zm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
logger.Println("received negotiation offer")
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := zm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
logger.Println("received negotiation answer")
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := zm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_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 := zm.Manager.AddCandidate(&webrtc.ICECandidateInit{
Candidate: payload["candidate"],
SDPMid: &sdpMid,
SDPMLineIndex: &SDPMLineIndex,
}, req.GetFrom()); err != nil {
errCh <- err
return
}
default:
logger.Println("no request for squad grpc middleware")
logger.Println(payload)
logger.Println(req.Type)
}
}()
select {
case <-ctx.Done():
return ctx.Err()
case err = <-errCh:
return
case <-done:
return
}
}

742
squadManager.go Normal file
View File

@ -0,0 +1,742 @@
package localserver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
sync "sync"
"github.com/google/uuid"
"github.com/pion/webrtc/v3"
)
type SquadManager struct {
ID string
Squads map[string]*Squad
LocalSD map[string]*webrtc.SessionDescription
RTCPeerConnections map[string]*RTCPeerConnection
DataChannels map[string]*DataChannel
PendingCandidates map[string][]*webrtc.ICECandidate
stream SignalingService_LinkClient
squadFlag *uint32
peerConnectionFlag *uint32
localSDFlag *uint32
dataChannelFlag *uint32
candidateFlag *uint32
}
type Squad struct {
ID string
Name string
ImageURL string
Owner string
CreationDate string
AuthorizedMembers []string
DataChannels map[string]*DataChannel
DataChannelsFlag *uint32
SquadRequestScheduler *SquadRequestScheduler
Initialized bool
}
func NewSquad(hostId string, squadId string, squadName string, imageUrl string, owner string, creationDate string, initialized bool, authorizedMembers []string) (squad *Squad, err error) {
dataChannels, dataChannelFlag := make(map[string]*DataChannel), uint32(0)
squadChatHandler, err := NewSquadChatsHandler(hostId, squadId, squadName, owner, authorizedMembers, dataChannels, &dataChannelFlag)
if err != nil {
return nil, err
}
squadVideoChannelsHandler, err := NewSquadVideoChannelsHandler(hostId, squadId, owner, authorizedMembers, dataChannels, &dataChannelFlag)
if err != nil {
return
}
squadNotificationsHandler, err := NewSquadNotificationsHandler(hostId, squadId, owner, authorizedMembers, dataChannels, &dataChannelFlag)
if err != nil {
return
}
squadScheduler, e := NewSquadRequestScheduler(authorizedMembers, squadVideoChannelsHandler, squadChatHandler, squadNotificationsHandler)
go func() {
for schedErr := range e {
logger.Println("from scheduler :", schedErr)
}
}()
squad = &Squad{
ID: squadId,
Name: squadName,
ImageURL: imageUrl,
Owner: owner,
CreationDate: creationDate,
Initialized: initialized,
SquadRequestScheduler: squadScheduler,
DataChannels: dataChannels,
DataChannelsFlag: &dataChannelFlag,
}
fmt.Println("squad fking creeaeted", squad.Name)
return
}
func NewSquadManager(id string, token string) (squadManager *SquadManager, err error) {
squadFlag := uint32(0)
peerConnectionFlag := uint32(0)
localSDFlag := uint32(0)
dataChannelFlag := uint32(0)
candidateFlag := uint32(0)
dataChannels := make(map[string]*DataChannel)
squadMap := make(map[string]*Squad)
squads, err := squadManager.fetchSquads(id, token)
if err != nil {
return
}
for _, squad := range squads {
z, err := NewSquad(id, squad.ID, squad.Name, squad.ImageURL, squad.Owner, squad.CreationDate, true, squad.AuthorizedMembers)
if err != nil {
return nil, err
}
squadMap[squad.ID] = z
}
squadsFolder, err := os.ReadDir(filepath.Join(dataPath, "data", "squads"))
if err != nil {
if os.IsNotExist(err) {
if err = os.MkdirAll(filepath.Join(dataPath, "data", "squads"), 0770); err != nil {
return
}
} else {
return nil, err
}
}
logger.Println(squadMap)
squadManager = &SquadManager{
ID: id,
Squads: squadMap,
LocalSD: make(map[string]*webrtc.SessionDescription),
RTCPeerConnections: make(map[string]*RTCPeerConnection),
DataChannels: dataChannels,
PendingCandidates: make(map[string][]*webrtc.ICECandidate),
squadFlag: &squadFlag,
peerConnectionFlag: &peerConnectionFlag,
localSDFlag: &localSDFlag,
dataChannelFlag: &dataChannelFlag,
candidateFlag: &candidateFlag,
}
for _, z := range squadsFolder {
if _, ok := squadMap[z.Name()]; !ok {
logger.Println(squadManager.DeleteSquad(z.Name()))
}
}
return
}
func (zm *SquadManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
bs, err := json.Marshal(payload)
if err != nil {
return
}
err = zm.stream.Send(&SignalingMessage{
Type: messageType,
From: from,
To: to,
Payload: bs,
})
return
}
func (zm *SquadManager) DeleteSquad(squadId string) error {
return os.RemoveAll(filepath.Join(dataPath, "data", "squads", squadId))
}
func (zm *SquadManager) fetchSquads(nodeId string, token string) (squads []*Squad, err error) {
em := NewEncryptionManager()
sig := em.SignRequestHMAC(nodeId)
body, err := json.Marshal(map[string]interface{}{
"type": LIST_HOSTED_SQUADS_BY_HOST,
"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 squad 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["squads"])
if err != nil {
return
}
err = json.Unmarshal(b, &squads)
return
}
func (zm *SquadManager) CreateOffer(ctx context.Context, target string, from string, squadId string, cb OnICECandidateFunc) (err error) {
peerConnection, err := zm.createPeerConnection(target, from, squadId, 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(zm.peerConnectionFlag, func() (err error) {
id := uuid.New().String()
logger.Println("adding for target", target)
zm.RTCPeerConnections[target] = &RTCPeerConnection{
id: id,
PeerConnection: peerConnection,
makingOffer: true,
makingOfferLock: &sync.Mutex{},
negotiate: zm.negotiate,
}
return
})
err = zm.sendSignalingMessage(string(HOSTED_SQUAD_OFFER), zm.ID, target, map[string]any{
"to": target,
"from": zm.ID,
"sdp": rawOffer.SDP,
})
return
}
func (zm *SquadManager) 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 := zm.Squads[req["squadId"]]; !ok {
err = fmt.Errorf("no corresponding squad")
errCh <- err
return
}
logger.Println("handling squad offer")
_ = atomicallyExecute(zm.squadFlag, func() (err error) {
return
})
if _, ok := zm.RTCPeerConnections[from]; ok {
if e := zm.HandleLeavingMember(from, req["squadId"], false); e != nil {
logger.Println(e)
}
}
peerConnection, err := zm.createPeerConnection(from, to, req["squadId"], webrtc.SDPTypeAnswer, cb)
if err != nil {
errCh <- err
return
}
logger.Println("peer connection created")
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
id := uuid.New().String()
zm.RTCPeerConnections[from] = &RTCPeerConnection{
PeerConnection: peerConnection,
id: id,
makingOffer: false,
makingOfferLock: &sync.Mutex{},
negotiate: zm.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(zm.localSDFlag, func() (err error) {
zm.LocalSD[from] = &rawAnswer
return
})
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
errCh <- err
return
}
if err = zm.sendSignalingMessage(string(HOSTED_SQUAD_ANSWER), zm.ID, from, map[string]any{
"to": from,
"from": zm.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 (zm *SquadManager) 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(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id : %s", from)
return
}
peerConnnection := zm.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 = zm.sendSignalingMessage(string(HOSTED_SQUAD_COUNTER_OFFER), zm.ID, from, map[string]any{
"from": zm.ID,
"to": from,
}); err != nil {
return
}
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
for _, candidate := range zm.PendingCandidates[from] {
logger.Println("sending candidate from answer to", from)
if err = zm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_CANDIDATE), zm.ID, from, map[string]any{
"from": zm.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(zm.PendingCandidates, from)
return
})
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
delete(zm.LocalSD, from)
return
})
return
}
func (zm *SquadManager) HandleCounterOffer(ctx context.Context, from string, to string, req map[string]string) (err error) {
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
for _, candidate := range zm.PendingCandidates[from] {
logger.Println("sending candidate to", from)
if err = zm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_CANDIDATE), zm.ID, from, map[string]any{
"from": zm.ID,
"to": from,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
}); err != nil {
return
}
}
delete(zm.PendingCandidates, from)
return
})
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
delete(zm.LocalSD, from)
return
})
return
}
func (zm *SquadManager) createPeerConnection(target string, from string, squadId 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"},
},
},
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 *SquadRequest)
channel.OnOpen(func() {
logger.Println(squadId)
if _, ok := zm.Squads[squadId]; ok {
logger.Println("this squad exist")
_ = atomicallyExecute(zm.Squads[squadId].DataChannelsFlag, func() (err error) {
x := uint32(0)
zm.Squads[squadId].DataChannels[target] = &DataChannel{DataChannel: channel, bufferedAmountLowThresholdReached: make(<-chan struct{}), l: &x}
return
})
if _, ok := zm.Squads[squadId]; !ok {
err = fmt.Errorf("no corresponding squads")
return
}
done, err := zm.Squads[squadId].SquadRequestScheduler.Schedule(reqChan)
bs, jsonErr := json.Marshal(&SquadResponse{
Type: "user_squad_init",
From: squadId,
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)
//_ = zm.HandleLeavingMember(target, squadId, true)
})
channel.OnError(func(err error) {
close(reqChan)
//_ = zm.HandleLeavingMember(target, squadId, true)
})
channel.OnMessage(func(msg webrtc.DataChannelMessage) {
var req SquadRequest
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(zm.dataChannelFlag, func() (err error) {
l := uint32(0)
zm.DataChannels[target] = &DataChannel{
DataChannel: channel,
bufferedAmountLowThresholdReached: make(<-chan struct{}),
l: &l,
}
return
})
} else {
peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
_ = atomicallyExecute(zm.dataChannelFlag, func() (err error) {
l := uint32(0)
zm.DataChannels[target] = &DataChannel{
DataChannel: dc,
l: &l,
}
return
})
reqChan := make(chan *SquadRequest, 100)
if dc.Label() == "data" {
dc.OnOpen(func() {
logger.Println(squadId)
if _, ok := zm.Squads[squadId]; ok {
logger.Println("this squad exist")
_ = atomicallyExecute(zm.Squads[squadId].DataChannelsFlag, func() (err error) {
logger.Println("adding dc to dc map")
x := uint32(0)
zm.Squads[squadId].DataChannels[target] = &DataChannel{DataChannel: dc, bufferedAmountLowThresholdReached: make(<-chan struct{}), l: &x}
return
})
if _, ok := zm.Squads[squadId]; !ok {
err = fmt.Errorf("no corresponding squads")
return
}
done, err := zm.Squads[squadId].SquadRequestScheduler.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 SquadRequest
if err := json.Unmarshal(msg.Data, &req); err != nil {
logger.Println(err)
return
}
logger.Println("incoming request", req)
go func() {
reqChan <- &req
}()
})
_ = atomicallyExecute(zm.dataChannelFlag, func() (err error) {
l := uint32(0)
zm.DataChannels[target] = &DataChannel{
DataChannel: dc,
bufferedAmountLowThresholdReached: make(<-chan struct{}),
l: &l,
}
return
})
} else {
if _, ok := zm.Squads[squadId]; ok {
fmt.Println("got new mtfking datachannel")
fmt.Println(dc.Label())
scheduler := zm.Squads[squadId].SquadRequestScheduler
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 = zm.HandleLeavingMember(target, squadId, 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(zm.candidateFlag, func() (err error) {
desc := peerConnection.RemoteDescription()
if desc == nil {
logger.Println("generated candidate appended to list : ", i)
zm.PendingCandidates[target] = append(zm.PendingCandidates[target], i)
} else {
logger.Println("generated candidate : ", i)
if iceCandidateErr := cb(target, i); iceCandidateErr != nil {
logger.Println(iceCandidateErr)
}
}
return
})
})
return
}
func (zm *SquadManager) HandleRennegotiationOffer(from, sdp string) (err error) {
err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
if err = zm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
return
}
localSd, err := zm.RTCPeerConnections[from].CreateAnswer(nil)
if err != nil {
return
}
if err = zm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
return
}
if err = zm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER), zm.ID, from, map[string]any{
"to": from,
"sdp": localSd.SDP,
}); err != nil {
logger.Println(err)
return
}
return
})
return
}
func (zm *SquadManager) HandleRennegotiationAnswer(from string, sdp string) (err error) {
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
err = zm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
return
})
return
}
func (zm *SquadManager) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
if candidate != nil {
if connection, ok := zm.RTCPeerConnections[from]; ok {
err = connection.AddICECandidate(*candidate)
}
}
return
})
return
}
func (zm *SquadManager) HandleLeavingMember(id, squadId string, signalLeaving bool) (err error) {
fmt.Println("uwuwuwuuwuwuwuwuuwuwuuwuwuwuwuuwwuwu")
fmt.Println("handling leaving member")
logger.Println("---------------- handling leaving member", id)
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[id]; !ok {
err = fmt.Errorf("no correponding peerconnection for id %s", id)
return
}
return
}); err != nil {
return
}
if signalLeaving {
nerr := zm.notifyLeavingMember(id, squadId, NodeID)
fmt.Println(nerr)
}
err = atomicallyExecute(zm.squadFlag, func() (err error) {
logger.Println(err)
logger.Println("---------------- cleaning squad handlers", id)
if squad, ok := zm.Squads[squadId]; ok {
for _, handlersPublishers := range squad.SquadRequestScheduler.handlersPublishers {
go func(hp chan<- *SquadRequest) {
hp <- &SquadRequest{
ReqType: LEAVE_SQUAD,
From: id,
Payload: map[string]interface{}{
"userId": id,
},
}
}(handlersPublishers)
}
if err = atomicallyExecute(squad.DataChannelsFlag, func() (err error) {
defer delete(squad.DataChannels, id)
if dataChannel, ok := squad.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 squad for squadId %s", squadId)
}
logger.Println(err)
err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[id]; ok {
defer delete(zm.RTCPeerConnections, id)
if err = zm.RTCPeerConnections[id].Close(); err != nil {
return
}
}
return
})
fmt.Println(err)
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
delete(zm.PendingCandidates, id)
return
})
return
})
return
}
func (zm *SquadManager) notifyLeavingMember(userId, squadId, hostId string) (err error) {
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
body, err := json.Marshal(map[string]interface{}{
"type": DISCONNECT_SQUAD_MEMBER,
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]string{
"squadId": squadId,
"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 squad manager")
return
}
return
}
func (zm *SquadManager) negotiate(target string, squadId string) {
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
if _, ok := zm.RTCPeerConnections[target]; !ok {
err = fmt.Errorf("no peerConnections")
return
}
return
})
}

124
squadNotificationHandler.go Normal file
View File

@ -0,0 +1,124 @@
package localserver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
)
type SquadNotificationsHandler struct {
SquadId string
SquadMembersId []string
DataChannels map[string]*DataChannel
Flag *uint32
Publishers []<-chan *SquadRequest
reqChans []chan<- *SquadRequest
}
func NewSquadNotificationsHandler(_ string, squadId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (squadNotificationsHandler *SquadNotificationsHandler, err error) {
if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "squads", squadId, "notifications")); os.IsNotExist(dirErr) {
dirErr := os.MkdirAll(filepath.Join(dataPath, "data", "squads", squadId, "notifications"), 0700)
if dirErr != nil {
return
}
}
squadNotificationsHandler = &SquadNotificationsHandler{
SquadId: squadId,
SquadMembersId: authorizedMembers,
DataChannels: dataChannels,
Flag: flag,
}
return
}
func (znh *SquadNotificationsHandler) Init(ctx context.Context, authorizedMembers []string) (err error) {
//? initialization code here
return
}
func (znh *SquadNotificationsHandler) Subscribe(ctx context.Context, publisher <-chan *SquadRequest) (reqChan chan *SquadRequest, done chan struct{}, errCh chan error) {
reqChan, done, errCh = make(chan *SquadRequest), make(chan struct{}), make(chan error)
znh.reqChans = append(znh.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := znh.handleSquadRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (znh *SquadNotificationsHandler) ListNotifications(userId string) {}
func (znh *SquadNotificationsHandler) CreateNotification(notificationType, title, body, payload string, isPushed bool, recipients ...string) (err error) {
if isPushed {
err = znh.PushNotification(notificationType, title, body, payload, recipients...)
}
return
}
func (znh *SquadNotificationsHandler) DeleteNotification() {}
func (znh *SquadNotificationsHandler) PushNotification(notificationType, title, body, payload string, recipients ...string) (err error) {
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
b, err := json.Marshal(map[string]interface{}{
"type": NOTIFY,
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]interface{}{
"type": notificationType,
"title": title,
"body": body,
"recipients": recipients,
"payload": payload,
},
})
if err != nil {
return
}
_, err = HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewReader(b))
if err != nil {
logger.Println("error come from there in squad manager")
return
}
return
}
func (znh SquadNotificationsHandler) handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool) {
return
}
func (znh *SquadNotificationsHandler) handleSquadRequest(ctx context.Context, req *SquadRequest) (err error) {
switch req.ReqType {
case CREATE_NOTIFICATION:
if err = VerifyFieldsString(req.Payload, "type", "title", "body", "payload"); err != nil {
return
}
if err = VerifyFieldsBool(req.Payload, "isPushed"); err != nil {
return
}
if _, ok := req.Payload["recipients"]; !ok {
err = fmt.Errorf("no field recipient in payload")
return
}
if _, ok := req.Payload["recipients"].([]string); !ok {
err = fmt.Errorf(" field recipient in payload is wrong type")
return
}
err = znh.CreateNotification(req.Payload["type"].(string), req.Payload["title"].(string), req.Payload["body"].(string), req.Payload["payload"].(string), req.Payload["isPushed"].(bool), req.Payload["recipients"].([]string)...)
}
return
}

122
squadRequestScheduler.go Normal file
View File

@ -0,0 +1,122 @@
package localserver
import (
"context"
"sync"
"time"
)
type SquadRequestScheduler struct {
handlersPublishers []chan<- *SquadRequest
handlersDataChannelDispatchCallbacks []DispatchDataChannelCallBack
}
type SquadRequest struct {
ReqType string `json:"reqType"`
Payload map[string]any `json:"payload"`
From string `json:"from"`
}
type SquadResponse struct {
Type string `json:"type"`
To string `json:"to"`
From string `json:"from"`
Payload map[string]any `json:"payload"`
}
type SquadRequestHandler interface {
Init(ctx context.Context, authorizedMembers []string) (err error)
Subscribe(ctx context.Context, publisher <-chan *SquadRequest) (reqChan chan *SquadRequest, done chan struct{}, errCh chan error)
handleSquadRequest(ctx context.Context, req *SquadRequest) (err error)
handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool)
}
func NewSquadRequestScheduler(authorizedMembers []string, handlers ...SquadRequestHandler) (squadRequestScheduler *SquadRequestScheduler, handlerErrCh chan error) {
squadRequestScheduler = new(SquadRequestScheduler)
squadRequestScheduler.handlersPublishers = make([]chan<- *SquadRequest, 0)
squadRequestScheduler.handlersDataChannelDispatchCallbacks = make([]DispatchDataChannelCallBack, 0)
handlerErrCh = make(chan error)
reqChans := []chan *SquadRequest{}
for _, handler := range handlers {
publisher := make(chan *SquadRequest, 100)
squadRequestScheduler.handlersPublishers = append(squadRequestScheduler.handlersPublishers, publisher)
squadRequestScheduler.handlersDataChannelDispatchCallbacks = append(squadRequestScheduler.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 *SquadRequest) {
done, errCh := squadRequestScheduler.Schedule(reqChan)
for {
select {
case <-done:
return
case e := <-errCh:
logger.Println("from there", e)
}
}
}(reqChan)
}
for i, handler := range handlers {
if ierr := handler.Init(context.Background(), authorizedMembers); ierr != nil {
logger.Println(ierr)
}
logger.Println("init done for handler", i)
}
return
}
func (zrs *SquadRequestScheduler) Schedule(reqChan <-chan *SquadRequest) (done chan struct{}, errCh chan error) {
done, errCh = make(chan struct{}), make(chan error)
go func() {
for req := range reqChan {
go func(r *SquadRequest) {
for _, publisher := range zrs.handlersPublishers {
publisher <- r
}
}(req)
}
done <- struct{}{}
}()
return
}
func (zrs *SquadRequestScheduler) DispatchDatachannel(ctx context.Context, dc *DataChannel) (catched bool) {
wg, lock := sync.WaitGroup{}, &sync.Mutex{}
timeoutCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
done := make(chan struct{})
defer cancel()
for _, dispatchCallback := range zrs.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
}
}

828
squadVideoChannel.go Normal file
View File

@ -0,0 +1,828 @@
package localserver
// import (
// "context"
// "encoding/json"
// "errors"
// "fmt"
// "io"
// "strconv"
// sync "sync"
// "sync/atomic"
// "time"
// "github.com/google/uuid"
// "github.com/pion/rtcp"
// "github.com/pion/webrtc/v3"
// )
// type VideoChannel struct {
// ID string `json:"id"`
// Owner string `json:"owner"`
// ChannelType string `json:"channelType"`
// Members []string `json:"members"`
// CurrentMembersId []string `json:"currentMembersId"`
// CurrentMembers map[string]*VideoChannelMember `json:"currentMembers"`
// localSD map[string]*webrtc.SessionDescription `json:"-"`
// rtcPeerConnections map[string]*ZoneRTCPeerConnection `json:"-"`
// audioTransceiver map[string][]*PeerSender `json:"-"`
// videoTransceiver map[string][]*PeerSender `json:"-"`
// videoChannelDataChannels map[string]*DataChannel `json:"-"`
// pendingCandidates map[string][]*webrtc.ICECandidate `json:"-"`
// remoteTracks map[string][]*RemoteTrack `json:"-"`
// middlewares []interface{} `json:"-"`
// candidateFlag *uint32 `json:"-"`
// remoteTracksFlag *uint32 `json:"-"`
// rtcPeerConnectionMapFlag *uint32 `json:"-"`
// dataChannelMapFlag *uint32 `json:"-"`
// localSDMapFlag *uint32 `json:"-"`
// audioSenderFlag *uint32 `json:"-"`
// videoSenderFlag *uint32 `json:"-"`
// }
// type VideoChannelOnICECandidateFunc = func(string, string, *webrtc.ICECandidate) error
// func NewVideoChannel(id string, owner string, channelType string, members []string, currentMembersId []string, currentMembers map[string]*VideoChannelMember) (audioChannel *VideoChannel) {
// candidateFlag := uint32(0)
// remoteTracksFlag := uint32(0)
// rtcPeerConnectionMapFlag := uint32(0)
// dataChannelMapFlag := uint32(0)
// localSDMapFlag := uint32(0)
// audioSenderFlag := uint32(0)
// videoSenderFlag := uint32(0)
// audioChannel = &VideoChannel{
// ID: id,
// Owner: owner,
// ChannelType: channelType,
// Members: members,
// CurrentMembersId: currentMembersId,
// CurrentMembers: currentMembers,
// localSD: make(map[string]*webrtc.SessionDescription),
// videoTransceiver: make(map[string][]*PeerSender),
// rtcPeerConnections: make(map[string]*ZoneRTCPeerConnection),
// audioTransceiver: make(map[string][]*PeerSender),
// videoChannelDataChannels: make(map[string]*DataChannel),
// pendingCandidates: make(map[string][]*webrtc.ICECandidate),
// remoteTracks: make(map[string][]*RemoteTrack),
// middlewares: make([]interface{}, 0),
// candidateFlag: &candidateFlag,
// remoteTracksFlag: &remoteTracksFlag,
// rtcPeerConnectionMapFlag: &rtcPeerConnectionMapFlag,
// dataChannelMapFlag: &dataChannelMapFlag,
// localSDMapFlag: &localSDMapFlag,
// audioSenderFlag: &audioSenderFlag,
// videoSenderFlag: &videoSenderFlag,
// }
// return
// }
// func (vc *VideoChannel) HandleOffer(ctx context.Context, channelId string, userId string, sdp string, hostId string, sendDCMessage SendDCMessageFunc, cb VideoChannelOnICECandidateFunc) (done chan struct{}, errCh chan error) {
// done, errCh = make(chan struct{}), make(chan error)
// go func() {
// peerConnection, err := vc.createPeerConnection(userId, vc.ID, webrtc.SDPTypeAnswer, cb, sendDCMessage)
// if err != nil {
// errCh <- err
// return
// }
// _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// vc.rtcPeerConnections[userId] = &ZoneRTCPeerConnection{
// PeerConnection: peerConnection,
// makingOffer: false,
// makingOfferLock: &sync.Mutex{},
// negotiate: vc.negotiate,
// }
// return
// })
// offer := webrtc.SessionDescription{
// Type: webrtc.SDPTypeOffer,
// SDP: sdp,
// }
// if err = peerConnection.SetRemoteDescription(offer); err != nil {
// errCh <- err
// return
// }
// rawAnswer, err := peerConnection.CreateAnswer(nil)
// if err != nil {
// errCh <- err
// return
// }
// if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
// errCh <- err
// return
// }
// _, _ = sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
// "to": userId,
// "from": vc.ID,
// "channelId": channelId,
// "sdp": rawAnswer.SDP,
// })
// done <- struct{}{}
// logger.Println("handle offer done")
// }()
// return
// }
// func (vc *VideoChannel) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
// // if err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// // if _, ok := vc.rtcPeerConnections[userId]; !ok {
// // err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
// // return
// // }
// // logger.Println("handling counter offer")
// // connection := vc.rtcPeerConnections[userId]
// // err = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
// // err = connection.SetLocalDescription(*vc.localSD[userId])
// // return
// // })
// // return
// // }); err != nil {
// // return
// // }
// // _ = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
// // delete(vc.localSD, userId)
// // return
// // })
// if err = atomicallyExecute(vc.candidateFlag, func() (err error) {
// for _, candidate := range vc.pendingCandidates[userId] {
// logger.Println("sending candidate to", userId, candidate)
// d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_CANDIDATE), "", userId, map[string]interface{}{
// "from": vc.ID,
// "to": userId,
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// })
// select {
// case <-d:
// case err = <-e:
// return
// }
// }
// delete(vc.pendingCandidates, userId)
// return
// }); err != nil {
// return
// }
// return
// }
// func (vc *VideoChannel) HandleRennegotiationOffer(from string, sdp string, sendDCMessage SendDCMessageFunc) (err error) {
// err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// if _, ok := vc.rtcPeerConnections[from]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id %s", from)
// return
// }
// // vc.rtcPeerConnections[from].makingOfferLock.Lock()
// // if vc.rtcPeerConnections[from].makingOffer {
// // vc.rtcPeerConnections[from].makingOfferLock.Unlock()
// // return fmt.Errorf("already making an offer or state is stable")
// // }
// // vc.rtcPeerConnections[from].makingOfferLock.Unlock()
// if err = vc.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
// return
// }
// localSd, err := vc.rtcPeerConnections[from].CreateAnswer(nil)
// if err != nil {
// return
// }
// if err = vc.rtcPeerConnections[from].SetLocalDescription(localSd); err != nil {
// return
// }
// d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_ANSWER), vc.ID, from, map[string]interface{}{
// "from": vc.ID,
// "to": from,
// "sdp": localSd.SDP,
// })
// select {
// case <-d:
// case err = <-e:
// }
// return
// })
// return
// }
// func (vc *VideoChannel) HandleRennegotiationAnswer(from string, sdp string) (err error) {
// logger.Println("---------------------handling rennego answer")
// err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// // vc.rtcPeerConnections[from].makingOfferLock.Lock()
// // if vc.rtcPeerConnections[from].makingOffer {
// // vc.rtcPeerConnections[from].makingOfferLock.Unlock()
// // return fmt.Errorf("already making an offer or state is stable")
// // }
// // vc.rtcPeerConnections[from].makingOfferLock.Unlock()
// // if _, ok := vc.rtcPeerConnections[from]; !ok {
// // err = fmt.Errorf("no corresponding peer connection for id %s", from)
// // return
// // }
// err = vc.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
// return
// })
// return
// }
// func (vc *VideoChannel) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
// logger.Println("adding ice candidate", candidate)
// err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// if _, ok := vc.rtcPeerConnections[from]; ok && candidate != nil {
// err = vc.rtcPeerConnections[from].AddICECandidate(*candidate)
// }
// return
// })
// return
// }
// func (vc *VideoChannel) createPeerConnection(target string, from string, peerType webrtc.SDPType, cb VideoChannelOnICECandidateFunc, sendDCMessage SendDCMessageFunc) (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:stun.l.google.com:19302"},
// },
// },
// SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
// }
// peerConnection, err = webrtc.NewPeerConnection(config)
// if err != nil {
// return
// }
// logger.Println("---------------------------------------------------")
// if peerType == webrtc.SDPTypeAnswer {
// maxRetransmits := uint16(100)
// channel, err := peerConnection.CreateDataChannel("video-channel", &webrtc.DataChannelInit{
// MaxRetransmits: &maxRetransmits,
// })
// if err != nil {
// return nil, err
// }
// channel.OnOpen(func() {
// logger.Println("channel opened")
// if chanErr := channel.SendText("yooo man this is open"); chanErr != nil {
// logger.Println(chanErr)
// }
// })
// channel.OnMessage(func(msg webrtc.DataChannelMessage) {
// var event CallEvent
// if err := json.Unmarshal(msg.Data, &event); err != nil {
// logger.Println(err)
// return
// }
// if e := vc.HandleDataChannelEvents(event.From, event.EventId, event.Payload); e != nil {
// logger.Println("*-------------- datachannel error: ", e)
// }
// })
// logger.Println("new channel for target : ", target)
// _ = atomicallyExecute(vc.dataChannelMapFlag, func() (err error) {
// logger.Println(target)
// l := uint32(0)
// vc.videoChannelDataChannels[target] = &DataChannel{
// DataChannel: channel,
// l: &l,
// }
// return
// })
// } else {
// peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
// _ = atomicallyExecute(vc.dataChannelMapFlag, func() (err error) {
// l := uint32(0)
// vc.videoChannelDataChannels[target] = &DataChannel{
// DataChannel: dc,
// l: &l,
// }
// return
// })
// dc.OnOpen(func() {
// logger.Printf("got a new open datachannel %s\n", dc.Label())
// })
// dc.OnMessage(func(msg webrtc.DataChannelMessage) {
// var event CallEvent
// if err := json.Unmarshal(msg.Data, &event); err != nil {
// logger.Println(err)
// return
// }
// if e := vc.HandleDataChannelEvents(event.From, event.EventId, event.Payload); e != nil {
// logger.Println("*-------------- datachannel error: ", e)
// }
// })
// })
// }
// err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// logger.Println("------------------", vc.CurrentMembersId)
// for _, id := range vc.CurrentMembersId {
// logger.Println(id)
// if id != target {
// if _, ok := vc.remoteTracks[id]; !ok {
// continue
// }
// for _, track := range vc.remoteTracks[id] {
// transceiver, err := peerConnection.AddTransceiverFromKind(track.Track.Kind(), webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly})
// if err != nil {
// logger.Println("add track error")
// continue
// }
// if err := transceiver.Sender().ReplaceTrack(track.Track); err != nil {
// logger.Println("add track error")
// continue
// }
// if track.Track.Kind() == webrtc.RTPCodecTypeVideo {
// _ = atomicallyExecute(vc.videoSenderFlag, func() (err error) {
// if len(vc.videoTransceiver) == 0 {
// vc.videoTransceiver[id] = []*PeerSender{{ID: target, Transceiver: transceiver}}
// } else {
// vc.videoTransceiver[id] = append(vc.videoTransceiver[id], &PeerSender{ID: target, Transceiver: transceiver})
// }
// return
// })
// } else if track.Track.Kind() == webrtc.RTPCodecTypeAudio {
// _ = atomicallyExecute(vc.audioSenderFlag, func() (err error) {
// if len(vc.audioTransceiver) == 0 {
// vc.audioTransceiver[id] = []*PeerSender{{ID: target, Transceiver: transceiver}}
// } else {
// vc.audioTransceiver[id] = append(vc.audioTransceiver[id], &PeerSender{ID: target, Transceiver: transceiver})
// }
// return
// })
// }
// logger.Println("track added", track)
// }
// }
// }
// return
// })
// return
// })
// peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
// if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
// logger.Println(pcs)
// //vc.HandleLeavingMember(target, squadId)
// }
// })
// peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
// logger.Printf("ICE connection state has changed %s\n", is.String())
// if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
// logger.Println(is)
// }
// })
// peerConnection.OnTrack(func(tr *webrtc.TrackRemote, r *webrtc.RTPReceiver) {
// logger.Println("got new track")
// defer func() {
// if stopErr := r.Stop(); stopErr != nil {
// logger.Println(stopErr)
// }
// }()
// go func() {
// ticker := time.NewTicker(1500 * time.Millisecond)
// for range ticker.C {
// if rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(tr.SSRC())}}); rtcpSendErr != nil {
// logger.Println(rtcpSendErr)
// break
// }
// }
// }()
// uniqId := uuid.New()
// i := fmt.Sprintf("%s/%s", target, uniqId.String())
// logger.Println("*************************----------------", i, "-----------------------***************")
// localTrack, newTrackErr := webrtc.NewTrackLocalStaticRTP(tr.Codec().RTPCodecCapability, i, i)
// if newTrackErr != nil {
// return
// }
// logger.Println(localTrack)
// rtpbuf := make([]byte, 1400)
// flag := int32(0)
// remote := &RemoteTrack{ID: target, Track: localTrack, rdv: &flag}
// _ = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// if len(vc.remoteTracks[target]) == 0 {
// vc.remoteTracks[target] = []*RemoteTrack{remote}
// } else {
// vc.remoteTracks[target] = append(vc.remoteTracks[target], remote)
// }
// index := len(vc.remoteTracks[target])
// logger.Println(index, vc.remoteTracks)
// return
// })
// _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// for _, id := range vc.CurrentMembersId {
// if id != target {
// if _, ok := vc.rtcPeerConnections[id]; !ok {
// continue
// }
// connection := vc.rtcPeerConnections[id]
// transceiver, tranceiverErr := connection.AddTransceiverFromKind(localTrack.Kind(), webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly})
// if tranceiverErr != nil {
// logger.Println(tranceiverErr)
// continue
// }
// if replaceTrackErr := transceiver.Sender().ReplaceTrack(localTrack); replaceTrackErr != nil {
// logger.Println(replaceTrackErr)
// continue
// }
// go func() {
// rtcpBuf := make([]byte, 1500)
// for {
// if _, _, rtcpErr := transceiver.Sender().Read(rtcpBuf); rtcpErr != nil {
// return
// }
// }
// }()
// if localTrack.Kind() == webrtc.RTPCodecTypeAudio {
// _ = atomicallyExecute(vc.audioSenderFlag, func() (err error) {
// if len(vc.audioTransceiver) == 0 {
// vc.audioTransceiver[target] = []*PeerSender{{ID: id, Transceiver: transceiver}}
// } else {
// vc.audioTransceiver[target] = append(vc.audioTransceiver[target], &PeerSender{ID: id, Transceiver: transceiver})
// }
// return
// })
// } else if localTrack.Kind() == webrtc.RTPCodecTypeVideo {
// _ = atomicallyExecute(vc.videoSenderFlag, func() (err error) {
// if len(vc.videoTransceiver) == 0 {
// vc.videoTransceiver[target] = []*PeerSender{{ID: id, Transceiver: transceiver}}
// } else {
// vc.videoTransceiver[target] = append(vc.videoTransceiver[target], &PeerSender{ID: id, Transceiver: transceiver})
// }
// return
// })
// }
// go func() {
// <-time.After(time.Second * 1)
// connection.negotiate(id, sendDCMessage)
// }()
// }
// }
// return
// })
// d := make(chan struct{})
// go func() {
// for {
// i, _, readErr := tr.Read(rtpbuf)
// if readErr != nil {
// logger.Println(readErr)
// break
// }
// f := atomic.LoadInt32(remote.rdv)
// if f == 0 {
// if _, writeErr := localTrack.Write(rtpbuf[:i]); writeErr != nil && !errors.Is(writeErr, io.ErrClosedPipe) {
// logger.Println(writeErr)
// break
// } else {
// _ = rtpbuf[:i]
// }
// }
// }
// d <- struct{}{}
// }()
// <-d
// })
// peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
// if i == nil {
// return
// }
// _ = atomicallyExecute(vc.candidateFlag, func() (err error) {
// desc := peerConnection.RemoteDescription()
// if desc == nil {
// logger.Println("generated candidate appended to list : ", i)
// vc.pendingCandidates[target] = append(vc.pendingCandidates[target], i)
// } else {
// logger.Println("generated candidate : ", i)
// if iceCandidateErr := cb(from, target, i); iceCandidateErr != nil {
// logger.Println(iceCandidateErr)
// }
// }
// 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,
// // // })
// // // select {
// // // case <-d:
// // // case err = <-e:
// // // logger.Println(err)
// // // }
// // // }
// // // }
// // // return
// // // })
// // })
// return
// }
// func (vc *VideoChannel) HandleLeavingMember(id string) {
// if err := atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// if _, ok := vc.rtcPeerConnections[id]; !ok {
// err = fmt.Errorf("no corresponding peerconnection for audio channel leaving member")
// }
// return
// }); err != nil {
// logger.Println(err)
// } else {
// defer func() {
// _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// if _, ok := vc.rtcPeerConnections[id]; ok {
// if closeErr := vc.rtcPeerConnections[id].Close(); closeErr != nil {
// err = closeErr
// logger.Println("peer connection close error", closeErr)
// }
// }
// delete(vc.rtcPeerConnections, id)
// return
// })
// }()
// }
// logger.Printf("peer %s is leaving the squad\n", id)
// _ = atomicallyExecute(vc.dataChannelMapFlag, func() (err error) {
// if _, ok := vc.videoChannelDataChannels[id]; ok {
// vc.videoChannelDataChannels[id].DataChannel.Close()
// }
// delete(vc.videoChannelDataChannels, id)
// return
// })
// _ = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
// delete(vc.localSD, id)
// return
// })
// _ = atomicallyExecute(vc.candidateFlag, func() (err error) {
// delete(vc.pendingCandidates, id)
// return
// })
// _ = atomicallyExecute(vc.audioSenderFlag, func() (err error) {
// for peerId, peerSender := range vc.audioTransceiver {
// if peerId != id {
// logger.Println("senders", peerSender)
// c := 0
// for i, sender := range peerSender {
// if sender.ID == id {
// if senderErr := sender.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if transceiverErr := sender.Transceiver.Stop(); transceiverErr != nil {
// logger.Println("transceiverErr occured with video", transceiverErr)
// }
// peerSender[len(peerSender)-i-1], peerSender[i] = peerSender[i], peerSender[len(peerSender)-i-1]
// c++
// }
// }
// vc.audioTransceiver[peerId] = vc.audioTransceiver[peerId][:len(peerSender)-(c)]
// logger.Println(vc.audioTransceiver[peerId])
// }
// }
// for _, transceiver := range vc.audioTransceiver[id] {
// if senderErr := transceiver.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if stopErr := transceiver.Transceiver.Stop(); stopErr != nil {
// logger.Println("transceiver audio stop error", stopErr)
// }
// }
// delete(vc.audioTransceiver, id)
// return
// })
// _ = atomicallyExecute(vc.videoSenderFlag, func() (err error) {
// for peerId, peerSender := range vc.videoTransceiver {
// if peerId != id {
// logger.Println("senders", peerSender)
// c := 0
// for i, sender := range peerSender {
// if sender.ID == id {
// if senderErr := sender.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if transceiverErr := sender.Transceiver.Stop(); transceiverErr != nil {
// logger.Println("transceiverErr occured with video", transceiverErr)
// }
// peerSender[len(peerSender)-i-1], peerSender[i] = peerSender[i], peerSender[len(peerSender)-i-1]
// c++
// }
// }
// vc.videoTransceiver[peerId] = vc.videoTransceiver[peerId][:len(peerSender)-(c)]
// logger.Println(vc.videoTransceiver[peerId])
// }
// }
// for _, transceiver := range vc.videoTransceiver[id] {
// if senderErr := transceiver.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if stopErr := transceiver.Transceiver.Stop(); stopErr != nil {
// logger.Println("transceiver video stop error", stopErr)
// }
// }
// delete(vc.videoTransceiver, id)
// return
// })
// _ = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// delete(vc.remoteTracks, id)
// return
// })
// }
// func (vc *VideoChannel) negotiate(target string, sendDCMessage SendDCMessageFunc) {
// logger.Println("------------------negotiate is called")
// _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
// if _, ok := vc.rtcPeerConnections[target]; !ok {
// return
// }
// // vc.rtcPeerConnections[target].makingOfferLock.Lock()
// // vc.rtcPeerConnections[target].makingOffer = true
// // vc.rtcPeerConnections[target].makingOfferLock.Unlock()
// defer func() {
// // vc.rtcPeerConnections[target].makingOfferLock.Lock()
// // vc.rtcPeerConnections[target].makingOffer = false
// // vc.rtcPeerConnections[target].makingOfferLock.Unlock()
// }()
// for _, id := range vc.CurrentMembersId {
// logger.Println("----------------- sending renego to peer with id", id)
// if _, ok := vc.rtcPeerConnections[id]; !ok {
// continue
// }
// connection := vc.rtcPeerConnections[id]
// if connection.SignalingState() == webrtc.SignalingStateStable {
// localSd, err := connection.CreateOffer(nil)
// if err != nil {
// logger.Println(err)
// return err
// }
// if err = connection.SetLocalDescription(localSd); err != nil {
// logger.Println(err)
// return err
// }
// 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
// })
// }
// func (vc *VideoChannel) broadcastDatachannelMessage(from string, eventId string, payload map[string]interface{}) (done chan struct{}, errCh chan error) {
// done, errCh = make(chan struct{}), make(chan error)
// go func() {
// bs, jsonErr := json.Marshal(&ZoneResponse{
// Type: eventId,
// From: vc.ID,
// Payload: payload,
// })
// if jsonErr != nil {
// errCh <- jsonErr
// return
// }
// if err := atomicallyExecute(vc.dataChannelMapFlag, func() (err error) {
// for id, dc := range vc.videoChannelDataChannels {
// if from != id {
// if err = dc.DataChannel.SendText(string(bs)); err != nil {
// return
// }
// }
// }
// return
// }); err != nil {
// errCh <- err
// }
// done <- struct{}{}
// }()
// return
// }
// func (vc *VideoChannel) HandleDataChannelEvents(from string, eventId string, payload map[string]interface{}) (err error) {
// switch eventId {
// case VIDEO_CHANNEL_USER_VIDEO_STOP:
// if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// if _, ok := vc.remoteTracks[from]; !ok {
// err = fmt.Errorf("no corresponding remote tracks entry for id %s", from)
// return
// }
// for _, track := range vc.remoteTracks[from] {
// if track.Track.Kind() == webrtc.RTPCodecTypeVideo {
// atomic.SwapInt32(track.rdv, 1)
// }
// }
// return
// }); err != nil {
// return
// }
// done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_VIDEO_STOP, map[string]interface{}{
// "userId": from,
// })
// select {
// case <-done:
// case err = <-errCh:
// }
// case VIDEO_CHANNEL_USER_VIDEO_RESUME:
// if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// if _, ok := vc.remoteTracks[from]; !ok {
// err = fmt.Errorf("no corresponding remote tracks entry for id %s", from)
// return
// }
// for _, track := range vc.remoteTracks[from] {
// if track.Track.Kind() == webrtc.RTPCodecTypeVideo {
// atomic.SwapInt32(track.rdv, 0)
// }
// }
// return
// }); err != nil {
// return
// }
// done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_VIDEO_RESUME, map[string]interface{}{
// "userId": from,
// })
// select {
// case <-done:
// case err = <-errCh:
// }
// case VIDEO_CHANNEL_USER_MUTE:
// if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// if _, ok := vc.remoteTracks[from]; !ok {
// err = fmt.Errorf("no corresponding remote tracks entry for id %s", from)
// return
// }
// for _, track := range vc.remoteTracks[from] {
// if track.Track.Kind() == webrtc.RTPCodecTypeAudio {
// atomic.SwapInt32(track.rdv, 1)
// }
// }
// return
// }); err != nil {
// return
// }
// done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_MUTE, map[string]interface{}{
// "userId": from,
// })
// select {
// case <-done:
// case err = <-errCh:
// }
// case VIDEO_CHANNEL_USER_UNMUTE:
// if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) {
// if _, ok := vc.remoteTracks[from]; !ok {
// err = fmt.Errorf("no corresponding remote tracks entry for id %s", from)
// return
// }
// for _, track := range vc.remoteTracks[from] {
// if track.Track.Kind() == webrtc.RTPCodecTypeAudio {
// atomic.SwapInt32(track.rdv, 0)
// }
// }
// return
// }); err != nil {
// return
// }
// done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_UNMUTE, map[string]interface{}{
// "userId": from,
// })
// select {
// case <-done:
// case err = <-errCh:
// }
// case VIDEO_CHANNEL_USER_SPEAKING:
// done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_SPEAKING, map[string]interface{}{
// "userId": from,
// })
// select {
// case <-done:
// case err = <-errCh:
// }
// case VIDEO_CHANNEL_USER_STOPPED_SPEAKING:
// done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_STOPPED_SPEAKING, map[string]interface{}{
// "userId": from,
// })
// select {
// case <-done:
// case err = <-errCh:
// }
// }
// return
// }

398
squadVideoChannelHandler.go Normal file
View File

@ -0,0 +1,398 @@
package localserver
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/pion/webrtc/v3"
)
type SquadVideoChannelsHandler struct {
SquadId string
SquadName string
HostId string
SquadMembersId []string
DataChannels map[string]*DataChannel
VideoChanDataChannels map[string]*DataChannel
VideoChanDataChannelsFlag *uint32
DataChannelsFlag *uint32
VideoChannelsFlag *uint32
VideoChannel *VideoChannel
reqChans []chan<- *SquadRequest
}
func NewSquadVideoChannelsHandler(hostId string, squadId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, dataChannelFlag *uint32) (squadVideoChannelsHandler *SquadVideoChannelsHandler, err error) {
_, err = os.ReadDir(filepath.Join(dataPath, "data", "squads", squadId, "videoChannel"))
if err != nil {
if os.IsNotExist(err) {
logger.Printf("creating videoChannels directory for squad %s...\n", squadId)
mkdirErr := os.MkdirAll(filepath.Join(dataPath, "data", "squads", squadId, "videoChannel"), 0700)
if mkdirErr != nil {
return nil, mkdirErr
}
file, ferr := os.Create(filepath.Join(dataPath, "data", "squads", squadId, "videoChannel", "videoChannelConfig.json"))
defer func() {
_ = file.Close()
}()
if ferr != nil {
return nil, ferr
}
baseConfig := VideoChannelConfig{
ID: MEETING,
Owner: owner,
ChannelType: "public",
CurrentMembersId: make([]string, 0),
Members: make([]string, 0),
}
bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil {
return nil, jsonErr
}
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
return nil, writeErr
}
_, err = os.ReadDir(filepath.Join(dataPath, "data", "squads", squadId, "videoChannel"))
if err != nil {
return nil, err
}
} else {
return
}
}
var bs []byte
bs, err = os.ReadFile(filepath.Join(dataPath, "data", "squads", squadId, "videoChannel", "videoChannelConfig.json"))
if err != nil {
return nil, err
}
logger.Println(string(bs))
var vcc VideoChannelConfig
if err = json.Unmarshal(bs, &vcc); err != nil {
return nil, err
}
logger.Println("videoChannels data :", vcc.ID, vcc.ChannelType, vcc.Owner, vcc.Members)
vc := NewVideoChannel(vcc.ID, vcc.Owner, vcc.ChannelType, vcc.Members, make([]string, 0), make(map[string]*VideoChannelMember))
videoChannelFlag := uint32(0)
videoChanDCFlag := uint32(0)
squadVideoChannelsHandler = &SquadVideoChannelsHandler{
SquadId: squadId,
HostId: hostId,
SquadMembersId: authorizedMembers,
DataChannels: dataChannels,
VideoChanDataChannels: make(map[string]*DataChannel),
VideoChanDataChannelsFlag: &videoChanDCFlag,
DataChannelsFlag: dataChannelFlag,
VideoChannel: vc,
VideoChannelsFlag: &videoChannelFlag,
}
return
}
func (zvch *SquadVideoChannelsHandler) 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(zvch.VideoChanDataChannelsFlag, func() (err error) {
if _, ok := zvch.VideoChanDataChannels[to]; ok {
bs, jsonErr := json.Marshal(&SquadResponse{
Type: reqType,
From: from,
To: to,
Payload: payload,
})
if jsonErr != nil {
return jsonErr
}
err = zvch.VideoChanDataChannels[to].DataChannel.SendText(string(bs))
}
return
}); err != nil {
errCh <- err
return
}
done <- struct{}{}
}()
return done, errCh
}
func (zvch *SquadVideoChannelsHandler) Init(ctx context.Context, authorizedMembers []string) (err error) {
return
}
func (zvch *SquadVideoChannelsHandler) Subscribe(ctx context.Context, publisher <-chan *SquadRequest) (reqChan chan *SquadRequest, done chan struct{}, errCh chan error) {
reqChan, done, errCh = make(chan *SquadRequest), make(chan struct{}), make(chan error)
zvch.reqChans = append(zvch.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := zvch.handleSquadRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (zvch *SquadVideoChannelsHandler) signalCandidate(from string, to string, candidate *webrtc.ICECandidate) (err error) {
d, e := zvch.sendDataChannelMessage(string(VIDEO_CHANNEL_WEBRTC_CANDIDATE), from, to, map[string]interface{}{
"from": from,
"to": to,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
})
select {
case <-d:
case err = <-e:
}
return
}
func (zvch *SquadVideoChannelsHandler) JoinVideoChannel(channelId string, userId string, sdp string) (err error) {
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
videoChannel := zvch.VideoChannel
videoChannel.CurrentMembersId = append(videoChannel.CurrentMembersId, userId)
videoChannel.CurrentMembers[userId] = &VideoChannelMember{}
signalMembers := func(members []string) {
for _, u := range members {
done, e := zvch.sendDataChannelMessage(USER_JOINED_VIDEO_CHANNEL, "node", u, map[string]interface{}{
"userId": userId,
"channelId": channelId,
})
select {
case <-done:
case err := <-e:
logger.Println(err)
}
}
}
signalMembers(zvch.SquadMembersId)
d, e := videoChannel.HandleOffer(context.Background(), channelId, userId, sdp, zvch.HostId, zvch.sendDataChannelMessage, zvch.signalCandidate)
select {
case <-d:
case err = <-e:
}
return
})
return
}
func (zvch *SquadVideoChannelsHandler) LeaveVideoChannel(channelId string, userId string) (err error) {
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
videoChannel := zvch.VideoChannel
var index int
var contain bool
for i, v := range videoChannel.CurrentMembersId {
if v == userId {
index = i
contain = true
}
}
if !contain {
err = fmt.Errorf("this channel does not contain the provided user Id")
return
}
defer videoChannel.HandleLeavingMember(userId)
if len(videoChannel.CurrentMembersId) <= 1 {
videoChannel.CurrentMembersId = make([]string, 0)
} else {
videoChannel.CurrentMembersId = append(videoChannel.CurrentMembersId[:index], videoChannel.CurrentMembersId[index+1:]...)
}
delete(videoChannel.CurrentMembers, userId)
signalMembers := func(members []string) {
for _, u := range members {
done, e := zvch.sendDataChannelMessage(USER_LEFT_VIDEO_CHANNEL, "node", u, map[string]interface{}{
"userId": userId,
"channelId": channelId,
})
select {
case <-done:
case err := <-e:
logger.Println(err)
}
}
}
signalMembers(zvch.SquadMembersId)
return
})
return
}
func (zvch *SquadVideoChannelsHandler) 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, "video_channel_data") {
command := strings.Split(label, "|")
catched = true
_ = atomicallyExecute(zvch.VideoChanDataChannelsFlag, func() (err error) {
zvch.VideoChanDataChannels[command[1]] = dc
return
})
dc.DataChannel.OnOpen(func() {
fmt.Println("datachann in squad video chann fking created")
bs, err := json.Marshal(map[string]any{
"type": "init_video_channel",
"from": NodeID,
"to": command[1],
"payload": map[string]any{
"videoChannel": zvch.VideoChannel,
},
})
if err != nil {
fmt.Println(err)
}
_ = dc.DataChannel.SendText(string(bs))
})
dc.DataChannel.OnClose(func() {
fmt.Println("closing gratefully video channel dc...")
_ = atomicallyExecute(zvch.VideoChanDataChannelsFlag, func() (err error) {
delete(zvch.VideoChanDataChannels, command[1])
fmt.Println("dc closed gracefully...")
return
})
})
dc.DataChannel.OnError(func(err error) {
fmt.Println("error in video channel dc...")
_ = atomicallyExecute(zvch.VideoChanDataChannelsFlag, func() (err error) {
delete(zvch.VideoChanDataChannels, command[1])
fmt.Println("dc closed on error...")
return
})
})
}
return
}
func (zvch *SquadVideoChannelsHandler) handleSquadRequest(ctx context.Context, req *SquadRequest) (err error) {
switch req.ReqType {
case LEAVE_ZONE:
logger.Println("*-----------------handling leaving squad---------------*")
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
vc := zvch.VideoChannel
var contain bool
var id string
for _, member := range vc.CurrentMembersId {
if member == req.Payload["userId"].(string) {
id = member
contain = true
logger.Printf("*------------------id is %s--------------*\n", id)
break
}
}
if contain {
err = zvch.LeaveVideoChannel(vc.ID, id)
break
}
case string(REMOVED_SQUAD_AUTHORIZED_MEMBER):
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var index int
var found bool
for i, m := range zvch.SquadMembersId {
if m == req.Payload["userId"].(string) {
index = i
found = true
break
}
}
if !found {
err = fmt.Errorf("no such member in squad")
return
}
zvch.SquadMembersId = append(zvch.SquadMembersId[:index], zvch.SquadMembersId[index+1:]...)
case string(NEW_AUTHORIZED_SQUAD_MEMBER):
if err = VerifyFieldsString(req.Payload, "userId"); err != nil {
return
}
var contain bool
for _, m := range zvch.SquadMembersId {
if m == req.Payload["userId"].(string) {
contain = true
break
}
}
if !contain {
zvch.SquadMembersId = append(zvch.SquadMembersId, req.Payload["userId"].(string))
}
case JOIN_VIDEO_CHANNEL:
fmt.Println("wuwuuwuwwuuwuw i got this")
fmt.Println(req.Payload)
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 {
return
}
err = zvch.LeaveVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case string(VIDEO_CHANNEL_WEBRTC_COUNTER_OFFER):
logger.Println("handling video channel counter offer")
if err = VerifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
err = zvch.VideoChannel.HandleCounterOffer(ctx, req.Payload["userId"].(string), zvch.sendDataChannelMessage)
return
})
case string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER):
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
err = zvch.VideoChannel.HandleRennegotiationOffer(req.Payload["userId"].(string), req.Payload["sdp"].(string), zvch.sendDataChannelMessage)
return
})
case string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_ANSWER):
if err = VerifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
return
}
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
err = zvch.VideoChannel.HandleRennegotiationAnswer(req.Payload["userId"].(string), req.Payload["sdp"].(string))
return
})
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 {
return
}
logger.Println(req.Payload)
i, convErr := strconv.Atoi(req.Payload["sdpMLineIndex"].(string))
if convErr != nil {
return convErr
}
SDPMLineIndex := uint16(i)
sdpMid := req.Payload["sdpMid"].(string)
logger.Println(sdpMid, SDPMLineIndex)
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
fmt.Println("uwuwuw adding candidate",req.Payload["candidate"].(string))
err = zvch.VideoChannel.AddCandidate(&webrtc.ICECandidateInit{
Candidate: req.Payload["candidate"].(string),
SDPMid: &sdpMid,
SDPMLineIndex: &SDPMLineIndex,
}, req.Payload["userId"].(string))
return
})
default:
logger.Println("video channel handler still in process of implementation")
}
return
}

View File

@ -2,9 +2,63 @@ package localserver
import (
"fmt"
"sync"
"sync/atomic"
"github.com/pion/webrtc/v3"
)
const (
NAME = "name"
ID = "ID"
SDP = "sdp"
CANDIDATE = "webrtc_candidate"
SQUAD_ID = "squadId"
FROM = "from"
TO = "to"
STOP_CALL = "stop_call"
LIST_HOSTED_SQUADS_BY_HOST = "list_hosted_squads_by_host"
LEAVE_SQUAD
bufferedAmountLowThreshold uint64 = 512 * 1024
)
type OnICECandidateFunc func(string, *webrtc.ICECandidate) error
type RTCPeerConnection struct {
*webrtc.PeerConnection
id string
makingOffer bool
negotiate func(string, string)
makingOfferLock *sync.Mutex
}
type DataChannel struct {
DataChannel *webrtc.DataChannel
bufferedAmountLowThresholdReached <-chan struct{}
l *uint32
}
type PeerSender struct {
ID string
Transceiver *webrtc.RTPTransceiver
Sender *webrtc.RTPSender
}
type CallEvent struct {
EventId string `json:"eventId"`
From string `json:"from"`
Data []byte `json:"data"`
Payload map[string]interface{} `json:"payload"`
}
type RemoteTrack struct {
ID string
Track *webrtc.TrackLocalStaticRTP
rdv *int32
}
func validateRequest(req map[string]string, entries ...string) (err error) {
for _, entry := range entries {
if _, ok := req[entry]; !ok {

View File

@ -1,136 +1,136 @@
package localserver
import (
"encoding/json"
"fmt"
"sync/atomic"
)
// import (
// "encoding/json"
// "fmt"
// "sync/atomic"
// )
const (
CHAT_MESSAGE_BROADCAST = "chat_message_broadcast"
CHAT_MESSAGE_PRIVATE = "chat_message_private"
)
// const (
// CHAT_MESSAGE_BROADCAST = "chat_message_broadcast"
// CHAT_MESSAGE_PRIVATE = "chat_message_private"
// )
type WebrtcCallChatManager struct{}
// type WebrtcCallChatManager struct{}
func NewWebrtcCallChatManager() *WebrtcCallChatManager {
return new(WebrtcCallChatManager)
}
// func NewWebrtcCallChatManager() *WebrtcCallChatManager {
// return new(WebrtcCallChatManager)
// }
func (w *WebrtcCallChatManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
logger.Println("got an event in call chat manager", from, eventId, payload)
switch eventId {
case CHAT_MESSAGE_BROADCAST:
if e := validateEvent(payload, "message"); e != nil {
errCh <- e
return
}
if e := w.sendBrodcastChatMessage(from, payload["message"].(string), squadId, manager); e != nil {
errCh <- e
return
}
case CHAT_MESSAGE_PRIVATE:
if e := validateEvent(payload, "message", "dst"); e != nil {
errCh <- e
return
}
if e := w.sendPrivateChatMessage(from, payload["message"].(string), squadId, manager, payload["message"].([]string)...); e != nil {
errCh <- e
return
}
}
done <- struct{}{}
}()
select {
case <-done:
return nil
case err = <-errCh:
return
}
}
// func (w *WebrtcCallChatManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// logger.Println("got an event in call chat manager", from, eventId, payload)
// switch eventId {
// case CHAT_MESSAGE_BROADCAST:
// if e := validateEvent(payload, "message"); e != nil {
// errCh <- e
// return
// }
// if e := w.sendBrodcastChatMessage(from, payload["message"].(string), squadId, manager); e != nil {
// errCh <- e
// return
// }
// case CHAT_MESSAGE_PRIVATE:
// if e := validateEvent(payload, "message", "dst"); e != nil {
// errCh <- e
// return
// }
// if e := w.sendPrivateChatMessage(from, payload["message"].(string), squadId, manager, payload["message"].([]string)...); e != nil {
// errCh <- e
// return
// }
// }
// done <- struct{}{}
// }()
// select {
// case <-done:
// return nil
// case err = <-errCh:
// return
// }
// }
func (w WebrtcCallChatManager) sendBrodcastChatMessage(from string, message string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
for _, member := range manager.Squads[squadId].Members {
if _, ok := manager.DataChannels[member]; ok && member != from {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": "send_chat_message",
"from": from,
"payload": map[string]string{
"message": message,
},
})
if marshalErr != nil {
logger.Println(err)
continue
}
lock:
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break lock
} else {
continue
}
}
}
}
return
}
// func (w WebrtcCallChatManager) sendBrodcastChatMessage(from string, message string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// for _, member := range manager.Squads[squadId].Members {
// if _, ok := manager.DataChannels[member]; ok && member != from {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": "send_chat_message",
// "from": from,
// "payload": map[string]string{
// "message": message,
// },
// })
// if marshalErr != nil {
// logger.Println(err)
// continue
// }
// lock:
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break lock
// } else {
// continue
// }
// }
// }
// }
// return
// }
func (w WebrtcCallChatManager) sendPrivateChatMessage(from string, message string, squadId string, manager *WebRTCCallManager, dst ...string) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
for _, member := range manager.Squads[squadId].Members {
for _, id := range dst {
if id == member {
if _, ok := manager.DataChannels[member]; ok && member != from {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": "",
"from": from,
"payload": map[string]string{
"message": message,
},
})
if marshalErr != nil {
logger.Println(err)
continue
}
lock:
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break lock
} else {
continue
}
}
}
}
}
}
return
}
// func (w WebrtcCallChatManager) sendPrivateChatMessage(from string, message string, squadId string, manager *WebRTCCallManager, dst ...string) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// for _, member := range manager.Squads[squadId].Members {
// for _, id := range dst {
// if id == member {
// if _, ok := manager.DataChannels[member]; ok && member != from {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": "",
// "from": from,
// "payload": map[string]string{
// "message": message,
// },
// })
// if marshalErr != nil {
// logger.Println(err)
// continue
// }
// lock:
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break lock
// } else {
// continue
// }
// }
// }
// }
// }
// }
// return
// }
func validateEvent(event map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := event[field]; !ok {
err = fmt.Errorf("no field %s in req payload", field)
return
}
}
return
}
// func validateEvent(event map[string]interface{}, fields ...string) (err error) {
// for _, field := range fields {
// if _, ok := event[field]; !ok {
// err = fmt.Errorf("no field %s in req payload", field)
// return
// }
// }
// return
// }

View File

@ -1,5 +1,5 @@
package localserver
type WebrtcCallEventManager interface {
HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error)
}
// type WebrtcCallEventManager interface {
// HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error)
// }

View File

@ -1,311 +1,311 @@
package localserver
import (
"bufio"
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
"sync/atomic"
// import (
// "bufio"
// "encoding/json"
// "fmt"
// "io"
// "log"
// "os"
// "path/filepath"
// "sync/atomic"
"github.com/pion/webrtc/v3"
)
// "github.com/pion/webrtc/v3"
// )
const (
UPLOAD_INIT = "upload_init"
UPLOAD = "upload"
UPLOAD_DONE = "upload_done"
DOWNLOAD_INIT = "download_init"
DOWNLOAD = "download"
DOWNLOAD_DONE = "download_done"
HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_INIT = "hosted_squad_download_file_response_init"
HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE = "hosted_squad_download_file_response"
HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_END = "hosted_squad_download_file_response_end"
)
// const (
// UPLOAD_INIT = "upload_init"
// UPLOAD = "upload"
// UPLOAD_DONE = "upload_done"
// DOWNLOAD_INIT = "download_init"
// DOWNLOAD = "download"
// DOWNLOAD_DONE = "download_done"
// HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_INIT = "hosted_squad_download_file_response_init"
// HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE = "hosted_squad_download_file_response"
// HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_END = "hosted_squad_download_file_response_end"
// )
const (
bufferedAmountLowThreshold uint64 = 512 * 1024
//maxBufferedAmount uint64 = 1024 * 1024
)
// const (
// bufferedAmountLowThreshold uint64 = 512 * 1024
// //maxBufferedAmount uint64 = 1024 * 1024
// )
type WebrtcCallFileManager struct {
files map[string]*os.File
l *uint32
}
// type WebrtcCallFileManager struct {
// files map[string]*os.File
// l *uint32
// }
func NewWebrtcCallFileManager() *WebrtcCallFileManager {
l := uint32(0)
return &WebrtcCallFileManager{
files: make(map[string]*os.File),
l: &l,
}
}
// func NewWebrtcCallFileManager() *WebrtcCallFileManager {
// l := uint32(0)
// return &WebrtcCallFileManager{
// files: make(map[string]*os.File),
// l: &l,
// }
// }
func (w *WebrtcCallFileManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
logger.Println("got an event in call file manager", from, eventId, payload)
switch eventId {
case UPLOAD_INIT:
if _, ok := payload["filename"]; !ok {
errCh <- fmt.Errorf("no field filename in payload")
return
}
if _, ok := payload["filename"].(string); !ok {
errCh <- fmt.Errorf("field filename in payload is not a string")
return
}
if err = w.initUpload(squadId, from, payload["filename"].(string)); err != nil {
errCh <- err
return
}
case UPLOAD:
if _, ok := payload["filename"]; !ok {
errCh <- fmt.Errorf("no field filename in payload")
return
}
if _, ok := payload["filename"].(string); !ok {
errCh <- fmt.Errorf("field filename in payload is not a string")
return
}
if err = w.upload(squadId, from, payload["filename"].(string), data); err != nil {
errCh <- err
return
}
case UPLOAD_DONE:
if _, ok := payload["filename"]; !ok {
errCh <- fmt.Errorf("no field filename in payload")
return
}
if _, ok := payload["filename"].(string); !ok {
errCh <- fmt.Errorf("field filename in payload is not a string")
return
}
if _, ok := payload["targets"]; !ok {
errCh <- fmt.Errorf("no field targets in payload")
return
}
if _, ok := payload["targets"].([]interface{}); !ok {
errCh <- fmt.Errorf("field targets in payload is not a string")
return
}
channels := []*DataChannel{}
manager.DataChannelMapMux.RLock()
for _, target := range payload["targets"].([]interface{}) {
if _, ok := manager.DataChannels[target.(string)]; !ok {
manager.DataChannelMapMux.RUnlock()
errCh <- fmt.Errorf("no corresponding datachannel : %s", target.(string))
return
}
channel := manager.DataChannels[target.(string)]
for {
if atomic.CompareAndSwapUint32(channel.l, 0, 1) {
defer atomic.SwapUint32(channel.l, 0)
break
}
}
channels = append(channels, channel)
}
manager.DataChannelMapMux.RUnlock()
if err = w.uploadDone(squadId, from, payload["filename"].(string), channels); err != nil {
errCh <- err
return
}
case DOWNLOAD:
if _, ok := payload["filename"]; !ok {
errCh <- fmt.Errorf("no field filename in payload")
return
}
if _, ok := payload["filename"].(string); !ok {
errCh <- fmt.Errorf("field filename in payload is not a string")
return
}
if _, ok := payload["peerId"]; !ok {
errCh <- fmt.Errorf("no field peerId in payload")
return
}
if _, ok := payload["peerId"].(string); !ok {
errCh <- fmt.Errorf("field peerId in payload is not a string")
return
}
manager.DataChannelMapMux.RLock()
if _, ok := manager.DataChannels[payload["peerId"].(string)]; !ok {
manager.DataChannelMapMux.RUnlock()
errCh <- fmt.Errorf("no corresponding datachannel")
return
}
channel := manager.DataChannels[payload["peerId"].(string)]
for {
if atomic.CompareAndSwapUint32(channel.l, 0, 1) {
logger.Println("atomic lock unlocked")
defer atomic.SwapUint32(channel.l, 0)
break
}
}
manager.DataChannelMapMux.RUnlock()
if err = w.download(squadId, from, payload["filename"].(string), channel.DataChannel); err != nil {
errCh <- err
return
}
}
done <- struct{}{}
}()
select {
case <-done:
return nil
case err = <-errCh:
return
}
}
// func (w *WebrtcCallFileManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// logger.Println("got an event in call file manager", from, eventId, payload)
// switch eventId {
// case UPLOAD_INIT:
// if _, ok := payload["filename"]; !ok {
// errCh <- fmt.Errorf("no field filename in payload")
// return
// }
// if _, ok := payload["filename"].(string); !ok {
// errCh <- fmt.Errorf("field filename in payload is not a string")
// return
// }
// if err = w.initUpload(squadId, from, payload["filename"].(string)); err != nil {
// errCh <- err
// return
// }
// case UPLOAD:
// if _, ok := payload["filename"]; !ok {
// errCh <- fmt.Errorf("no field filename in payload")
// return
// }
// if _, ok := payload["filename"].(string); !ok {
// errCh <- fmt.Errorf("field filename in payload is not a string")
// return
// }
// if err = w.upload(squadId, from, payload["filename"].(string), data); err != nil {
// errCh <- err
// return
// }
// case UPLOAD_DONE:
// if _, ok := payload["filename"]; !ok {
// errCh <- fmt.Errorf("no field filename in payload")
// return
// }
// if _, ok := payload["filename"].(string); !ok {
// errCh <- fmt.Errorf("field filename in payload is not a string")
// return
// }
// if _, ok := payload["targets"]; !ok {
// errCh <- fmt.Errorf("no field targets in payload")
// return
// }
// if _, ok := payload["targets"].([]interface{}); !ok {
// errCh <- fmt.Errorf("field targets in payload is not a string")
// return
// }
// channels := []*DataChannel{}
// manager.DataChannelMapMux.RLock()
// for _, target := range payload["targets"].([]interface{}) {
// if _, ok := manager.DataChannels[target.(string)]; !ok {
// manager.DataChannelMapMux.RUnlock()
// errCh <- fmt.Errorf("no corresponding datachannel : %s", target.(string))
// return
// }
// channel := manager.DataChannels[target.(string)]
// for {
// if atomic.CompareAndSwapUint32(channel.l, 0, 1) {
// defer atomic.SwapUint32(channel.l, 0)
// break
// }
// }
// channels = append(channels, channel)
// }
// manager.DataChannelMapMux.RUnlock()
// if err = w.uploadDone(squadId, from, payload["filename"].(string), channels); err != nil {
// errCh <- err
// return
// }
// case DOWNLOAD:
// if _, ok := payload["filename"]; !ok {
// errCh <- fmt.Errorf("no field filename in payload")
// return
// }
// if _, ok := payload["filename"].(string); !ok {
// errCh <- fmt.Errorf("field filename in payload is not a string")
// return
// }
// if _, ok := payload["peerId"]; !ok {
// errCh <- fmt.Errorf("no field peerId in payload")
// return
// }
// if _, ok := payload["peerId"].(string); !ok {
// errCh <- fmt.Errorf("field peerId in payload is not a string")
// return
// }
// manager.DataChannelMapMux.RLock()
// if _, ok := manager.DataChannels[payload["peerId"].(string)]; !ok {
// manager.DataChannelMapMux.RUnlock()
// errCh <- fmt.Errorf("no corresponding datachannel")
// return
// }
// channel := manager.DataChannels[payload["peerId"].(string)]
// for {
// if atomic.CompareAndSwapUint32(channel.l, 0, 1) {
// logger.Println("atomic lock unlocked")
// defer atomic.SwapUint32(channel.l, 0)
// break
// }
// }
// manager.DataChannelMapMux.RUnlock()
// if err = w.download(squadId, from, payload["filename"].(string), channel.DataChannel); err != nil {
// errCh <- err
// return
// }
// }
// done <- struct{}{}
// }()
// select {
// case <-done:
// return nil
// case err = <-errCh:
// return
// }
// }
func (w *WebrtcCallFileManager) initUpload(squadId string, from string, fileName string) (err error) {
for {
if atomic.CompareAndSwapUint32(w.l, 0, 1) {
defer atomic.SwapUint32(w.l, 0)
if _, dirErr := os.Stat(filepath.Join(dataPath, dataPath, "data", "squads", squadId)); os.IsNotExist(dirErr) {
if err = os.MkdirAll(filepath.Join(dataPath, dataPath, "data", "squads", squadId), 0700); err != nil {
return
}
}
f, fErr := os.Create(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName))
if err != nil {
return fErr
}
f.Close()
f, fErr = os.OpenFile(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName), os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fErr
}
w.files[fileName] = f
break
} else {
continue
}
}
return
}
// func (w *WebrtcCallFileManager) initUpload(squadId string, from string, fileName string) (err error) {
// for {
// if atomic.CompareAndSwapUint32(w.l, 0, 1) {
// defer atomic.SwapUint32(w.l, 0)
// if _, dirErr := os.Stat(filepath.Join(dataPath, dataPath, "data", "squads", squadId)); os.IsNotExist(dirErr) {
// if err = os.MkdirAll(filepath.Join(dataPath, dataPath, "data", "squads", squadId), 0700); err != nil {
// return
// }
// }
// f, fErr := os.Create(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName))
// if err != nil {
// return fErr
// }
// f.Close()
// f, fErr = os.OpenFile(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName), os.O_APPEND|os.O_WRONLY, 0644)
// if err != nil {
// return fErr
// }
// w.files[fileName] = f
// break
// } else {
// continue
// }
// }
// return
// }
func (w *WebrtcCallFileManager) upload(squadId string, from string, fileName string, data []byte) (err error) {
for {
if atomic.CompareAndSwapUint32(w.l, 0, 1) {
defer atomic.SwapUint32(w.l, 0)
if _, ok := w.files[fileName]; !ok {
err = fmt.Errorf("no open file with name %s", fileName)
return
}
_, err = w.files[fileName].Write(data)
break
} else {
continue
}
}
return
}
// func (w *WebrtcCallFileManager) upload(squadId string, from string, fileName string, data []byte) (err error) {
// for {
// if atomic.CompareAndSwapUint32(w.l, 0, 1) {
// defer atomic.SwapUint32(w.l, 0)
// if _, ok := w.files[fileName]; !ok {
// err = fmt.Errorf("no open file with name %s", fileName)
// return
// }
// _, err = w.files[fileName].Write(data)
// break
// } else {
// continue
// }
// }
// return
// }
func (w *WebrtcCallFileManager) uploadDone(squadId string, from string, fileName string, channels []*DataChannel) (err error) {
for {
if atomic.CompareAndSwapUint32(w.l, 0, 1) {
defer atomic.SwapUint32(w.l, 0)
if _, ok := w.files[fileName]; !ok {
err = fmt.Errorf("no open file with name %s", fileName)
return
}
err = w.files[fileName].Close()
delete(w.files, fileName)
bsInit, jsonErr := json.Marshal(map[string]interface{}{
"type": UPLOAD_DONE,
"from": "server",
"payload": map[string]string{
"path": fileName,
},
})
if jsonErr != nil {
return jsonErr
}
for _, channel := range channels {
if err = channel.DataChannel.SendText(string(bsInit)); err != nil {
return
}
}
break
} else {
continue
}
}
return
}
// func (w *WebrtcCallFileManager) uploadDone(squadId string, from string, fileName string, channels []*DataChannel) (err error) {
// for {
// if atomic.CompareAndSwapUint32(w.l, 0, 1) {
// defer atomic.SwapUint32(w.l, 0)
// if _, ok := w.files[fileName]; !ok {
// err = fmt.Errorf("no open file with name %s", fileName)
// return
// }
// err = w.files[fileName].Close()
// delete(w.files, fileName)
// bsInit, jsonErr := json.Marshal(map[string]interface{}{
// "type": UPLOAD_DONE,
// "from": "server",
// "payload": map[string]string{
// "path": fileName,
// },
// })
// if jsonErr != nil {
// return jsonErr
// }
// for _, channel := range channels {
// if err = channel.DataChannel.SendText(string(bsInit)); err != nil {
// return
// }
// }
// break
// } else {
// continue
// }
// }
// return
// }
func (w *WebrtcCallFileManager) download(squadId string, dst string, fileName string, channel *webrtc.DataChannel) (err error) {
logger.Println("got called")
if _, dirErr := os.Stat(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName)); os.IsNotExist(dirErr) {
logger.Println("file does not exist :", filepath.Join(dataPath, "data", "squads", squadId, fileName))
return
}
f, err := os.Open(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName))
if err != nil {
return
}
defer f.Close()
bsInit, err := json.Marshal(map[string]interface{}{
"type": HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_INIT,
"from": "server",
"payload": map[string]string{
"path": fileName,
},
})
if err != nil {
return
}
if err = channel.SendText(string(bsInit)); err != nil {
return
}
r := bufio.NewReader(f)
buf := make([]byte, 0, 30000)
logger.Println("start reading")
for {
n, readErr := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
logger.Println("n is 0 weird")
break
}
if err == io.EOF {
break
}
log.Fatal(readErr)
}
bs, jsonErr := json.Marshal(map[string]interface{}{
"type": HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE,
"from": "server",
"payload": map[string]interface{}{
"path": fileName,
"content": buf,
},
})
if jsonErr != nil {
return jsonErr
}
if err = channel.SendText(string(bs)); err != nil {
return
}
}
logger.Println("stop reading")
bs, err := json.Marshal(map[string]interface{}{
"type": HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_END,
"from": "server",
"payload": map[string]string{
"path": fileName,
},
})
if err != nil {
return
}
if err = channel.SendText(string(bs)); err != nil {
return
}
logger.Println("done")
return
}
// func (w *WebrtcCallFileManager) download(squadId string, dst string, fileName string, channel *webrtc.DataChannel) (err error) {
// logger.Println("got called")
// if _, dirErr := os.Stat(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName)); os.IsNotExist(dirErr) {
// logger.Println("file does not exist :", filepath.Join(dataPath, "data", "squads", squadId, fileName))
// return
// }
// f, err := os.Open(filepath.Join(dataPath, dataPath, "data", "squads", squadId, fileName))
// if err != nil {
// return
// }
// defer f.Close()
// bsInit, err := json.Marshal(map[string]interface{}{
// "type": HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_INIT,
// "from": "server",
// "payload": map[string]string{
// "path": fileName,
// },
// })
// if err != nil {
// return
// }
// if err = channel.SendText(string(bsInit)); err != nil {
// return
// }
// r := bufio.NewReader(f)
// buf := make([]byte, 0, 30000)
// logger.Println("start reading")
// for {
// n, readErr := r.Read(buf[:cap(buf)])
// buf = buf[:n]
// if n == 0 {
// if err == nil {
// logger.Println("n is 0 weird")
// break
// }
// if err == io.EOF {
// break
// }
// log.Fatal(readErr)
// }
// bs, jsonErr := json.Marshal(map[string]interface{}{
// "type": HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE,
// "from": "server",
// "payload": map[string]interface{}{
// "path": fileName,
// "content": buf,
// },
// })
// if jsonErr != nil {
// return jsonErr
// }
// if err = channel.SendText(string(bs)); err != nil {
// return
// }
// }
// logger.Println("stop reading")
// bs, err := json.Marshal(map[string]interface{}{
// "type": HOSTED_SQUAD_DOWNLOAD_FILE_RESPONSE_END,
// "from": "server",
// "payload": map[string]string{
// "path": fileName,
// },
// })
// if err != nil {
// return
// }
// if err = channel.SendText(string(bs)); err != nil {
// return
// }
// logger.Println("done")
// return
// }

File diff suppressed because it is too large Load Diff

View File

@ -1,234 +1,234 @@
package localserver
import (
"encoding/json"
"fmt"
"sync/atomic"
// import (
// "encoding/json"
// "fmt"
// "sync/atomic"
"github.com/pion/webrtc/v3"
)
// "github.com/pion/webrtc/v3"
// )
const (
SPEAKING = "speaking"
STOP_SPEAKING = "stop_speaking"
MUTE = "mute"
UNMUTE = "unmute"
)
// const (
// SPEAKING = "speaking"
// STOP_SPEAKING = "stop_speaking"
// MUTE = "mute"
// UNMUTE = "unmute"
// )
type WebrtcCallSoundManager struct{}
// type WebrtcCallSoundManager struct{}
func NewWebrtcCallSoundManager() *WebrtcCallSoundManager {
return new(WebrtcCallSoundManager)
}
// func NewWebrtcCallSoundManager() *WebrtcCallSoundManager {
// return new(WebrtcCallSoundManager)
// }
func (w *WebrtcCallSoundManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
logger.Println("got an event in call sound manager", from, eventId, payload)
switch eventId {
case UNMUTE:
if e := w.unmute(from, squadId, manager); e != nil {
errCh <- e
return
}
case MUTE:
if e := w.mute(from, squadId, manager); e != nil {
errCh <- e
return
}
case SPEAKING:
if e := w.sendSpeakingEvent(from, squadId, manager); e != nil {
errCh <- e
return
}
case STOP_SPEAKING:
if e := w.sendStopSpeakingEvent(from, squadId, manager); e != nil {
errCh <- e
return
}
}
done <- struct{}{}
}()
select {
case <-done:
return nil
case err = <-errCh:
return
}
}
// func (w *WebrtcCallSoundManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// logger.Println("got an event in call sound manager", from, eventId, payload)
// switch eventId {
// case UNMUTE:
// if e := w.unmute(from, squadId, manager); e != nil {
// errCh <- e
// return
// }
// case MUTE:
// if e := w.mute(from, squadId, manager); e != nil {
// errCh <- e
// return
// }
// case SPEAKING:
// if e := w.sendSpeakingEvent(from, squadId, manager); e != nil {
// errCh <- e
// return
// }
// case STOP_SPEAKING:
// if e := w.sendStopSpeakingEvent(from, squadId, manager); e != nil {
// errCh <- e
// return
// }
// }
// done <- struct{}{}
// }()
// select {
// case <-done:
// return nil
// case err = <-errCh:
// return
// }
// }
func (w *WebrtcCallSoundManager) unmute(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
logger.Println("sending unnmute event", peerId)
manager.RemoteTracksMux.RLock()
for _, v := range manager.RemoteTracks[peerId] {
if v.Track.Kind() == webrtc.RTPCodecTypeAudio {
atomic.SwapInt32(v.rdv, 0)
}
}
manager.RemoteTracksMux.RUnlock()
manager.SquadMapMux.Lock()
defer manager.SquadMapMux.Unlock()
for _, member := range manager.Squads[squadId].Members {
manager.DataChannelMapMux.Lock()
if _, ok := manager.DataChannels[member]; ok && member != peerId {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": UNMUTE,
"from": peerId,
"payload": map[string]interface{}{},
})
if marshalErr != nil {
logger.Println(err)
manager.DataChannelMapMux.Unlock()
continue
}
lock:
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break lock
} else {
continue
}
}
}
manager.DataChannelMapMux.Unlock()
}
return
}
// func (w *WebrtcCallSoundManager) unmute(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// logger.Println("sending unnmute event", peerId)
// manager.RemoteTracksMux.RLock()
// for _, v := range manager.RemoteTracks[peerId] {
// if v.Track.Kind() == webrtc.RTPCodecTypeAudio {
// atomic.SwapInt32(v.rdv, 0)
// }
// }
// manager.RemoteTracksMux.RUnlock()
// manager.SquadMapMux.Lock()
// defer manager.SquadMapMux.Unlock()
// for _, member := range manager.Squads[squadId].Members {
// manager.DataChannelMapMux.Lock()
// if _, ok := manager.DataChannels[member]; ok && member != peerId {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": UNMUTE,
// "from": peerId,
// "payload": map[string]interface{}{},
// })
// if marshalErr != nil {
// logger.Println(err)
// manager.DataChannelMapMux.Unlock()
// continue
// }
// lock:
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break lock
// } else {
// continue
// }
// }
// }
// manager.DataChannelMapMux.Unlock()
// }
// return
// }
func (w *WebrtcCallSoundManager) mute(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
logger.Println("sending mute event", peerId)
manager.RemoteTracksMux.RLock()
for _, v := range manager.RemoteTracks[peerId] {
if v.Track.Kind() == webrtc.RTPCodecTypeAudio {
atomic.SwapInt32(v.rdv, 1)
}
}
manager.RemoteTracksMux.RUnlock()
manager.SquadMapMux.Lock()
defer manager.SquadMapMux.Unlock()
for _, member := range manager.Squads[squadId].Members {
manager.DataChannelMapMux.Lock()
if _, ok := manager.DataChannels[member]; ok && member != peerId {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": MUTE,
"from": peerId,
"payload": map[string]interface{}{},
})
if marshalErr != nil {
logger.Println(err)
manager.DataChannelMapMux.Unlock()
continue
}
lock:
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break lock
} else {
continue
}
}
}
manager.DataChannelMapMux.Unlock()
}
return
}
// func (w *WebrtcCallSoundManager) mute(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// logger.Println("sending mute event", peerId)
// manager.RemoteTracksMux.RLock()
// for _, v := range manager.RemoteTracks[peerId] {
// if v.Track.Kind() == webrtc.RTPCodecTypeAudio {
// atomic.SwapInt32(v.rdv, 1)
// }
// }
// manager.RemoteTracksMux.RUnlock()
// manager.SquadMapMux.Lock()
// defer manager.SquadMapMux.Unlock()
// for _, member := range manager.Squads[squadId].Members {
// manager.DataChannelMapMux.Lock()
// if _, ok := manager.DataChannels[member]; ok && member != peerId {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": MUTE,
// "from": peerId,
// "payload": map[string]interface{}{},
// })
// if marshalErr != nil {
// logger.Println(err)
// manager.DataChannelMapMux.Unlock()
// continue
// }
// lock:
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break lock
// } else {
// continue
// }
// }
// }
// manager.DataChannelMapMux.Unlock()
// }
// return
// }
func (w *WebrtcCallSoundManager) sendSpeakingEvent(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
logger.Println("sending speaking event", peerId)
manager.SquadMapMux.Lock()
defer manager.SquadMapMux.Unlock()
for _, member := range manager.Squads[squadId].Members {
manager.DataChannelMapMux.Lock()
if _, ok := manager.DataChannels[member]; ok && member != peerId {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": SPEAKING,
"from": peerId,
"payload": map[string]interface{}{
"userId": peerId,
"speaking": true,
},
})
if marshalErr != nil {
logger.Println(err)
manager.DataChannelMapMux.Unlock()
continue
}
lock:
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break lock
} else {
continue
}
}
}
manager.DataChannelMapMux.Unlock()
}
return
}
// func (w *WebrtcCallSoundManager) sendSpeakingEvent(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// logger.Println("sending speaking event", peerId)
// manager.SquadMapMux.Lock()
// defer manager.SquadMapMux.Unlock()
// for _, member := range manager.Squads[squadId].Members {
// manager.DataChannelMapMux.Lock()
// if _, ok := manager.DataChannels[member]; ok && member != peerId {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": SPEAKING,
// "from": peerId,
// "payload": map[string]interface{}{
// "userId": peerId,
// "speaking": true,
// },
// })
// if marshalErr != nil {
// logger.Println(err)
// manager.DataChannelMapMux.Unlock()
// continue
// }
// lock:
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break lock
// } else {
// continue
// }
// }
// }
// manager.DataChannelMapMux.Unlock()
// }
// return
// }
func (w *WebrtcCallSoundManager) sendStopSpeakingEvent(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
logger.Println("sending stop speaking event", peerId)
manager.SquadMapMux.Lock()
defer manager.SquadMapMux.Unlock()
for _, member := range manager.Squads[squadId].Members {
manager.DataChannelMapMux.Lock()
if _, ok := manager.DataChannels[member]; ok && member != peerId {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": STOP_SPEAKING,
"from": peerId,
"payload": map[string]interface{}{
"userId": peerId,
"speaking": false,
},
})
if marshalErr != nil {
logger.Println(err)
manager.DataChannelMapMux.Unlock()
continue
}
lock:
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break lock
} else {
continue
}
}
}
manager.DataChannelMapMux.Unlock()
}
return
}
// func (w *WebrtcCallSoundManager) sendStopSpeakingEvent(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// logger.Println("sending stop speaking event", peerId)
// manager.SquadMapMux.Lock()
// defer manager.SquadMapMux.Unlock()
// for _, member := range manager.Squads[squadId].Members {
// manager.DataChannelMapMux.Lock()
// if _, ok := manager.DataChannels[member]; ok && member != peerId {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": STOP_SPEAKING,
// "from": peerId,
// "payload": map[string]interface{}{
// "userId": peerId,
// "speaking": false,
// },
// })
// if marshalErr != nil {
// logger.Println(err)
// manager.DataChannelMapMux.Unlock()
// continue
// }
// lock:
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break lock
// } else {
// continue
// }
// }
// }
// manager.DataChannelMapMux.Unlock()
// }
// return
// }

View File

@ -1,131 +1,131 @@
package localserver
import (
"encoding/json"
"fmt"
"sync/atomic"
// import (
// "encoding/json"
// "fmt"
// "sync/atomic"
"github.com/pion/webrtc/v3"
)
// "github.com/pion/webrtc/v3"
// )
const (
VIDEO = "video"
STOP_VIDEO = "stop_video"
)
// const (
// VIDEO = "video"
// STOP_VIDEO = "stop_video"
// )
type WebrtcCallVideoManager struct{}
// type WebrtcCallVideoManager struct{}
func NewWebrtcCallVideoManager() *WebrtcCallVideoManager {
return new(WebrtcCallVideoManager)
}
// func NewWebrtcCallVideoManager() *WebrtcCallVideoManager {
// return new(WebrtcCallVideoManager)
// }
func (w *WebrtcCallVideoManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
logger.Println("got an event in call video manager", from, eventId, payload)
switch eventId {
case VIDEO:
if e := w.video(from, squadId, manager); e != nil {
errCh <- e
return
}
case STOP_VIDEO:
if e := w.stopVideo(from, squadId, manager); e != nil {
errCh <- e
return
}
}
done <- struct{}{}
}()
select {
case <-done:
return nil
case err = <-errCh:
return
}
}
// func (w *WebrtcCallVideoManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// logger.Println("got an event in call video manager", from, eventId, payload)
// switch eventId {
// case VIDEO:
// if e := w.video(from, squadId, manager); e != nil {
// errCh <- e
// return
// }
// case STOP_VIDEO:
// if e := w.stopVideo(from, squadId, manager); e != nil {
// errCh <- e
// return
// }
// }
// done <- struct{}{}
// }()
// select {
// case <-done:
// return nil
// case err = <-errCh:
// return
// }
// }
func (w *WebrtcCallVideoManager) video(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
logger.Println("sending video event", peerId)
manager.RemoteTracksMux.RLock()
for _, v := range manager.RemoteTracks[peerId] {
if v.Track.Kind() == webrtc.RTPCodecTypeVideo {
atomic.SwapInt32(v.rdv, 0)
}
}
manager.RemoteTracksMux.RUnlock()
manager.SquadMapMux.Lock()
defer manager.SquadMapMux.Unlock()
for _, member := range manager.Squads[squadId].Members {
manager.DataChannelMapMux.Lock()
if _, ok := manager.DataChannels[member]; ok && member != peerId {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": VIDEO,
"from": peerId,
"payload": map[string]interface{}{},
})
if marshalErr != nil {
logger.Println(err)
manager.DataChannelMapMux.Unlock()
continue
}
if sendErr := atomicallyExecute(manager.DataChannels[member].l, func() (err error) {
err = manager.DataChannels[member].DataChannel.SendText(string(bs))
return
}); sendErr != nil {
logger.Println(sendErr)
}
}
manager.DataChannelMapMux.Unlock()
}
return
}
// func (w *WebrtcCallVideoManager) video(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// logger.Println("sending video event", peerId)
// manager.RemoteTracksMux.RLock()
// for _, v := range manager.RemoteTracks[peerId] {
// if v.Track.Kind() == webrtc.RTPCodecTypeVideo {
// atomic.SwapInt32(v.rdv, 0)
// }
// }
// manager.RemoteTracksMux.RUnlock()
// manager.SquadMapMux.Lock()
// defer manager.SquadMapMux.Unlock()
// for _, member := range manager.Squads[squadId].Members {
// manager.DataChannelMapMux.Lock()
// if _, ok := manager.DataChannels[member]; ok && member != peerId {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": VIDEO,
// "from": peerId,
// "payload": map[string]interface{}{},
// })
// if marshalErr != nil {
// logger.Println(err)
// manager.DataChannelMapMux.Unlock()
// continue
// }
// if sendErr := atomicallyExecute(manager.DataChannels[member].l, func() (err error) {
// err = manager.DataChannels[member].DataChannel.SendText(string(bs))
// return
// }); sendErr != nil {
// logger.Println(sendErr)
// }
// }
// manager.DataChannelMapMux.Unlock()
// }
// return
// }
func (w *WebrtcCallVideoManager) stopVideo(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
if _, ok := manager.Squads[squadId]; !ok {
err = fmt.Errorf("no correponding squad found")
return
}
logger.Println("sending stop video event", peerId)
manager.RemoteTracksMux.RLock()
for _, v := range manager.RemoteTracks[peerId] {
if v.Track.Kind() == webrtc.RTPCodecTypeVideo {
atomic.SwapInt32(v.rdv, 1)
}
}
manager.RemoteTracksMux.RUnlock()
manager.SquadMapMux.Lock()
defer manager.SquadMapMux.Unlock()
for _, member := range manager.Squads[squadId].Members {
manager.DataChannelMapMux.Lock()
if _, ok := manager.DataChannels[member]; ok && member != peerId {
bs, marshalErr := json.Marshal(map[string]interface{}{
"type": STOP_VIDEO,
"from": peerId,
"payload": map[string]interface{}{},
})
if marshalErr != nil {
logger.Println(err)
manager.DataChannelMapMux.Unlock()
continue
}
for {
if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
logger.Println(sendErr)
}
break
} else {
continue
}
}
}
manager.DataChannelMapMux.Unlock()
}
return
}
// func (w *WebrtcCallVideoManager) stopVideo(peerId string, squadId string, manager *WebRTCCallManager) (err error) {
// if _, ok := manager.Squads[squadId]; !ok {
// err = fmt.Errorf("no correponding squad found")
// return
// }
// logger.Println("sending stop video event", peerId)
// manager.RemoteTracksMux.RLock()
// for _, v := range manager.RemoteTracks[peerId] {
// if v.Track.Kind() == webrtc.RTPCodecTypeVideo {
// atomic.SwapInt32(v.rdv, 1)
// }
// }
// manager.RemoteTracksMux.RUnlock()
// manager.SquadMapMux.Lock()
// defer manager.SquadMapMux.Unlock()
// for _, member := range manager.Squads[squadId].Members {
// manager.DataChannelMapMux.Lock()
// if _, ok := manager.DataChannels[member]; ok && member != peerId {
// bs, marshalErr := json.Marshal(map[string]interface{}{
// "type": STOP_VIDEO,
// "from": peerId,
// "payload": map[string]interface{}{},
// })
// if marshalErr != nil {
// logger.Println(err)
// manager.DataChannelMapMux.Unlock()
// continue
// }
// for {
// if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
// defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
// if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
// logger.Println(sendErr)
// }
// break
// } else {
// continue
// }
// }
// }
// manager.DataChannelMapMux.Unlock()
// }
// return
// }

View File

@ -1,449 +1,449 @@
package localserver
import (
context "context"
"encoding/json"
"fmt"
"io"
sync "sync"
// import (
// context "context"
// "encoding/json"
// "fmt"
// "io"
// sync "sync"
"github.com/pion/webrtc/v3"
)
// "github.com/pion/webrtc/v3"
// )
type WebrtcFsManager struct {
stream SignalingService_LinkClient
DatachannelManager DataChannelManager
LocalSD map[string]*webrtc.SessionDescription
RTCPeerConnections map[string]*webrtc.PeerConnection
DataChannels map[string]*webrtc.DataChannel
PendingCandidates map[string][]*webrtc.ICECandidate
CandidateChannel chan *IncomingCandidate
CandidateMux *sync.RWMutex
RTCPeerConnectionMapMux *sync.RWMutex
DataChannelMapMux *sync.RWMutex
LocalSDMapMux *sync.RWMutex
}
// type WebrtcFsManager struct {
// stream SignalingService_LinkClient
// DatachannelManager DataChannelManager
// LocalSD map[string]*webrtc.SessionDescription
// RTCPeerConnections map[string]*webrtc.PeerConnection
// DataChannels map[string]*webrtc.DataChannel
// PendingCandidates map[string][]*webrtc.ICECandidate
// CandidateChannel chan *IncomingCandidate
// CandidateMux *sync.RWMutex
// RTCPeerConnectionMapMux *sync.RWMutex
// DataChannelMapMux *sync.RWMutex
// LocalSDMapMux *sync.RWMutex
// }
func NewWebrtcFsManager(dataChannelManager DataChannelManager) (webrtcFsManager *WebrtcFsManager, err error) {
webrtcFsManager = &WebrtcFsManager{
DatachannelManager: dataChannelManager,
DataChannels: make(map[string]*webrtc.DataChannel),
PendingCandidates: make(map[string][]*webrtc.ICECandidate),
LocalSD: make(map[string]*webrtc.SessionDescription),
RTCPeerConnections: make(map[string]*webrtc.PeerConnection),
RTCPeerConnectionMapMux: &sync.RWMutex{},
LocalSDMapMux: &sync.RWMutex{},
CandidateMux: &sync.RWMutex{},
DataChannelMapMux: &sync.RWMutex{},
}
return
}
// func NewWebrtcFsManager(dataChannelManager DataChannelManager) (webrtcFsManager *WebrtcFsManager, err error) {
// webrtcFsManager = &WebrtcFsManager{
// DatachannelManager: dataChannelManager,
// DataChannels: make(map[string]*webrtc.DataChannel),
// PendingCandidates: make(map[string][]*webrtc.ICECandidate),
// LocalSD: make(map[string]*webrtc.SessionDescription),
// RTCPeerConnections: make(map[string]*webrtc.PeerConnection),
// RTCPeerConnectionMapMux: &sync.RWMutex{},
// LocalSDMapMux: &sync.RWMutex{},
// CandidateMux: &sync.RWMutex{},
// DataChannelMapMux: &sync.RWMutex{},
// }
// return
// }
func (wf *WebrtcFsManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
bs, err := json.Marshal(payload)
if err != nil {
return
}
err = wf.stream.Send(&SignalingMessage{
Type: messageType,
From: from,
To: to,
Payload: bs,
})
return
}
// func (wf *WebrtcFsManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
// bs, err := json.Marshal(payload)
// if err != nil {
// return
// }
// err = wf.stream.Send(&SignalingMessage{
// Type: messageType,
// From: from,
// To: to,
// Payload: bs,
// })
// return
// }
func (wf *WebrtcFsManager) CreateOffer(ctx context.Context, target string, from string, cb OnICECandidateFunc) (err error) {
peerConnection, err := wf.createPeerConnection(target, from, webrtc.SDPTypeOffer, cb)
if err != nil {
return
}
rawOffer, err := peerConnection.CreateOffer(nil)
if err != nil {
return
}
if err = peerConnection.SetLocalDescription(rawOffer); err != nil {
return
}
wf.RTCPeerConnectionMapMux.Lock()
logger.Println("adding for target", target)
wf.RTCPeerConnections[target] = peerConnection
wf.RTCPeerConnectionMapMux.Unlock()
err = wf.sendSignalingMessage(string(WEBRTC_OFFER_FS), "lolo_local_serv", target, map[string]any{
"to": target,
"from": "lolo_local_serv",
"sdp": rawOffer.SDP,
})
return
}
// func (wf *WebrtcFsManager) CreateOffer(ctx context.Context, target string, from string, cb OnICECandidateFunc) (err error) {
// peerConnection, err := wf.createPeerConnection(target, from, webrtc.SDPTypeOffer, cb)
// if err != nil {
// return
// }
// rawOffer, err := peerConnection.CreateOffer(nil)
// if err != nil {
// return
// }
// if err = peerConnection.SetLocalDescription(rawOffer); err != nil {
// return
// }
// wf.RTCPeerConnectionMapMux.Lock()
// logger.Println("adding for target", target)
// wf.RTCPeerConnections[target] = peerConnection
// wf.RTCPeerConnectionMapMux.Unlock()
// err = wf.sendSignalingMessage(string(WEBRTC_OFFER_FS), "lolo_local_serv", target, map[string]any{
// "to": target,
// "from": "lolo_local_serv",
// "sdp": rawOffer.SDP,
// })
// return
// }
func (wf *WebrtcFsManager) HandleOffer(ctx context.Context, req map[string]string, cb OnICECandidateFunc) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
peerConnection, err := wf.createPeerConnection(req[FROM], req[TO], webrtc.SDPTypeAnswer, cb)
if err != nil {
errCh <- err
return
}
wf.RTCPeerConnectionMapMux.Lock()
wf.RTCPeerConnections[req[FROM]] = peerConnection
wf.RTCPeerConnectionMapMux.Unlock()
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
}
wf.LocalSDMapMux.Lock()
wf.LocalSD[req[FROM]] = &rawAnswer
wf.LocalSDMapMux.Unlock()
// if err = wf.stream.Send(&Request{
// Type: string(WEBRTC_ANSWER_FS),
// From: "lolo_local_serv",
// Token: "none",
// Payload: map[string]string{
// "to": req[FROM],
// "from": "lolo_local_serv",
// "sdp": rawAnswer.SDP,
// },
// }); err != nil {
// errCh <- err
// return
// }
done <- struct{}{}
}()
select {
case <-done:
return
case err = <-errCh:
return
case <-ctx.Done():
err = ctx.Err()
return
}
}
// func (wf *WebrtcFsManager) HandleOffer(ctx context.Context, req map[string]string, cb OnICECandidateFunc) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// peerConnection, err := wf.createPeerConnection(req[FROM], req[TO], webrtc.SDPTypeAnswer, cb)
// if err != nil {
// errCh <- err
// return
// }
// wf.RTCPeerConnectionMapMux.Lock()
// wf.RTCPeerConnections[req[FROM]] = peerConnection
// wf.RTCPeerConnectionMapMux.Unlock()
// 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
// }
// wf.LocalSDMapMux.Lock()
// wf.LocalSD[req[FROM]] = &rawAnswer
// wf.LocalSDMapMux.Unlock()
// // if err = wf.stream.Send(&Request{
// // Type: string(WEBRTC_ANSWER_FS),
// // From: "lolo_local_serv",
// // Token: "none",
// // Payload: map[string]string{
// // "to": req[FROM],
// // "from": "lolo_local_serv",
// // "sdp": rawAnswer.SDP,
// // },
// // }); err != nil {
// // errCh <- err
// // return
// // }
// done <- struct{}{}
// }()
// select {
// case <-done:
// return
// case err = <-errCh:
// return
// case <-ctx.Done():
// err = ctx.Err()
// return
// }
// }
func (wf *WebrtcFsManager) HandleAnswer(ctx context.Context, req map[string]string) (err error) {
wf.RTCPeerConnectionMapMux.RLock()
defer wf.RTCPeerConnectionMapMux.RUnlock()
defer func() {
if r := recover(); err != nil {
logger.Printf("recover from panic : %v\n", r)
}
}()
if _, ok := wf.RTCPeerConnections[req[FROM]]; !ok {
err = fmt.Errorf("no corresponding peer connection for id : %s", req[FROM])
return
}
peerConnnection := wf.RTCPeerConnections[req[FROM]]
if err = peerConnnection.SetRemoteDescription(webrtc.SessionDescription{
Type: webrtc.SDPTypeAnswer,
SDP: req[SDP],
}); err != nil {
return
}
// if err = wf.stream.Send(&Request{
// Type: string(WEBRTC_COUNTER_OFFER_FS),
// From: "lolo_local_serv",
// Token: "none",
// Payload: map[string]string{
// "from": "lolo_local_serv",
// "to": req[FROM],
// },
// }); err != nil {
// return
// }
wf.CandidateMux.RLock()
for range wf.PendingCandidates[req[FROM]] {
logger.Println("sending candidate to", req[FROM])
// if err = wf.stream.Send(&Request{
// Type: string(WEBRTC_CANDIDATE_FS),
// From: "lolo_local_serv",
// Token: "none",
// Payload: map[string]string{
// "from": "lolo_local_serv",
// "to": req[FROM],
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// },
// }); err != nil {
// return
// }
}
wf.CandidateMux.RUnlock()
wf.CandidateMux.Lock()
delete(wf.PendingCandidates, req[FROM])
wf.CandidateMux.Unlock()
wf.LocalSDMapMux.Lock()
delete(wf.LocalSD, req[FROM])
wf.LocalSDMapMux.Unlock()
return
}
// func (wf *WebrtcFsManager) HandleAnswer(ctx context.Context, req map[string]string) (err error) {
// wf.RTCPeerConnectionMapMux.RLock()
// defer wf.RTCPeerConnectionMapMux.RUnlock()
// defer func() {
// if r := recover(); err != nil {
// logger.Printf("recover from panic : %v\n", r)
// }
// }()
// if _, ok := wf.RTCPeerConnections[req[FROM]]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id : %s", req[FROM])
// return
// }
// peerConnnection := wf.RTCPeerConnections[req[FROM]]
// if err = peerConnnection.SetRemoteDescription(webrtc.SessionDescription{
// Type: webrtc.SDPTypeAnswer,
// SDP: req[SDP],
// }); err != nil {
// return
// }
// // if err = wf.stream.Send(&Request{
// // Type: string(WEBRTC_COUNTER_OFFER_FS),
// // From: "lolo_local_serv",
// // Token: "none",
// // Payload: map[string]string{
// // "from": "lolo_local_serv",
// // "to": req[FROM],
// // },
// // }); err != nil {
// // return
// // }
// wf.CandidateMux.RLock()
// for range wf.PendingCandidates[req[FROM]] {
// logger.Println("sending candidate to", req[FROM])
// // if err = wf.stream.Send(&Request{
// // Type: string(WEBRTC_CANDIDATE_FS),
// // From: "lolo_local_serv",
// // Token: "none",
// // Payload: map[string]string{
// // "from": "lolo_local_serv",
// // "to": req[FROM],
// // "candidate": candidate.ToJSON().Candidate,
// // "sdpMid": *candidate.ToJSON().SDPMid,
// // "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// // },
// // }); err != nil {
// // return
// // }
// }
// wf.CandidateMux.RUnlock()
// wf.CandidateMux.Lock()
// delete(wf.PendingCandidates, req[FROM])
// wf.CandidateMux.Unlock()
// wf.LocalSDMapMux.Lock()
// delete(wf.LocalSD, req[FROM])
// wf.LocalSDMapMux.Unlock()
// return
// }
func (wf *WebrtcFsManager) HandleCounterOffer(ctx context.Context, req map[string]string) (err error) {
wf.RTCPeerConnectionMapMux.RLock()
if _, ok := wf.RTCPeerConnections[req[FROM]]; !ok {
err = fmt.Errorf("no field corresponding peer connection for id %s", req[FROM])
return
}
connection := wf.RTCPeerConnections[req[FROM]]
wf.RTCPeerConnectionMapMux.RUnlock()
wf.LocalSDMapMux.RLock()
if err = connection.SetLocalDescription(*wf.LocalSD[req[FROM]]); err != nil {
return
}
wf.LocalSDMapMux.RUnlock()
wf.CandidateMux.RLock()
for range wf.PendingCandidates[req[FROM]] {
// logger.Println("sending candidate to", req[FROM])
// if err = wf.stream.Send(&Request{
// Type: string(WEBRTC_CANDIDATE_FS),
// From: "lolo_local_serv",
// Token: "none",
// Payload: map[string]string{
// "from": "lolo_local_serv",
// "to": req[FROM],
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// },
// }); err != nil {
// return
// }
}
wf.CandidateMux.RUnlock()
return
}
// func (wf *WebrtcFsManager) HandleCounterOffer(ctx context.Context, req map[string]string) (err error) {
// wf.RTCPeerConnectionMapMux.RLock()
// if _, ok := wf.RTCPeerConnections[req[FROM]]; !ok {
// err = fmt.Errorf("no field corresponding peer connection for id %s", req[FROM])
// return
// }
// connection := wf.RTCPeerConnections[req[FROM]]
// wf.RTCPeerConnectionMapMux.RUnlock()
// wf.LocalSDMapMux.RLock()
// if err = connection.SetLocalDescription(*wf.LocalSD[req[FROM]]); err != nil {
// return
// }
// wf.LocalSDMapMux.RUnlock()
// wf.CandidateMux.RLock()
// for range wf.PendingCandidates[req[FROM]] {
// // logger.Println("sending candidate to", req[FROM])
// // if err = wf.stream.Send(&Request{
// // Type: string(WEBRTC_CANDIDATE_FS),
// // From: "lolo_local_serv",
// // Token: "none",
// // Payload: map[string]string{
// // "from": "lolo_local_serv",
// // "to": req[FROM],
// // "candidate": candidate.ToJSON().Candidate,
// // "sdpMid": *candidate.ToJSON().SDPMid,
// // "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// // },
// // }); err != nil {
// // return
// // }
// }
// wf.CandidateMux.RUnlock()
// return
// }
func (wf *WebrtcFsManager) createPeerConnection(target string, from 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)
}
}()
s := webrtc.SettingEngine{}
s.DetachDataChannels()
// func (wf *WebrtcFsManager) createPeerConnection(target string, from 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)
// }
// }()
// s := webrtc.SettingEngine{}
// s.DetachDataChannels()
api := webrtc.NewAPI(webrtc.WithSettingEngine(s))
// api := webrtc.NewAPI(webrtc.WithSettingEngine(s))
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478", "stun:stun.l.google.com:19302?transport=tcp"},
},
},
SDPSemantics: webrtc.SDPSemanticsUnifiedPlan,
}
peerConnection, err = api.NewPeerConnection(config)
if err != nil {
return
}
if peerType == webrtc.SDPTypeOffer {
maxRetransmits := uint16(100)
channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{
MaxRetransmits: &maxRetransmits,
})
if err != nil {
return nil, err
}
channel.OnOpen(func() {
logger.Println("channel opened")
if chanErr := channel.SendText("yooo man this is open"); chanErr != nil {
logger.Println(chanErr)
}
})
channel.OnMessage(func(msg webrtc.DataChannelMessage) {
logger.Printf("new message %s\n", string(msg.Data))
done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{
From: target,
Type: "test",
Payload: &DatachannelMessagePayload{},
}, channel)
select {
case <-done:
//logger.Println("done with success")
case e := <-errCh:
logger.Println(e)
logger.Println("this is impossible")
}
})
wf.DataChannelMapMux.Lock()
wf.DataChannels[target] = channel
wf.DataChannelMapMux.Unlock()
}
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
logger.Printf("ICE connection state has changed %s\n", is.String())
if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
logger.Println(is)
}
})
peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
dc.OnOpen(func() {
logger.Printf("got a new open datachannel %s\n", dc.Label())
dataChann, err := dc.Detach()
if err != nil {
logger.Println(err)
return
}
for {
var x []byte = make([]byte, 2<<15)
n, _, err := dataChann.ReadDataChannel(x)
if err != nil {
logger.Println(err)
if err == io.EOF {
return
}
continue
}
go func(msg []byte) {
var dataChannelMessage DatachannelMessage
if unmarshalErr := json.Unmarshal(msg, &dataChannelMessage); unmarshalErr != nil {
logger.Println(unmarshalErr)
return
}
done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{
From: dataChannelMessage.From,
Type: dataChannelMessage.Type,
Payload: dataChannelMessage.Payload,
}, dc)
select {
case <-done:
//logger.Println("done with success")
case e := <-errCh:
logger.Println(e)
logger.Println("this is impossible")
}
}(x[:n])
}
})
// dc.OnMessage(func(msg webrtc.DataChannelMessage) {
// var dataChannelMessage DatachannelMessage
// if unmarshalErr := json.Unmarshal(msg.Data, &dataChannelMessage); unmarshalErr != nil {
// logger.Println(unmarshalErr)
// return
// }
// done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{
// From: dataChannelMessage.From,
// Type: dataChannelMessage.Type,
// Payload: dataChannelMessage.Payload,
// }, dc)
// select {
// case <-done:
// //logger.Println("done with success")
// case e := <-errCh:
// logger.Println(e)
// logger.Println("this is impossible")
// }
// })
})
peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
if i == nil {
return
}
wf.CandidateMux.Lock()
defer wf.CandidateMux.Unlock()
desc := peerConnection.RemoteDescription()
if desc == nil {
wf.PendingCandidates[target] = append(wf.PendingCandidates[target], i)
} else {
logger.Println(i)
if iceCandidateErr := cb(target, i); iceCandidateErr != nil {
logger.Println(iceCandidateErr)
}
}
})
peerConnection.OnNegotiationNeeded(func() {
if peerConnection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && peerConnection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
wf.RTCPeerConnectionMapMux.Lock()
defer wf.RTCPeerConnectionMapMux.Unlock()
for _, connection := range wf.RTCPeerConnections {
if connection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && connection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
localSd, err := connection.CreateOffer(nil)
if err != nil {
logger.Println(err)
return
}
if err = connection.SetLocalDescription(localSd); err != nil {
logger.Println(err)
return
}
// if err = wf.stream.Send(&Request{
// Type: string(WEBRTC_RENNEGOTIATION_OFFER_FS),
// From: "lolo_local_serv",
// Token: "",
// Payload: map[string]string{
// "to": id,
// "sdp": localSd.SDP,
// },
// }); err != nil {
// logger.Println(err)
// return
// }
}
}
}
})
return
}
// config := webrtc.Configuration{
// ICEServers: []webrtc.ICEServer{
// {
// URLs: []string{"stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302?transport=tcp"},
// },
// },
// SDPSemantics: webrtc.SDPSemanticsUnifiedPlan,
// }
// peerConnection, err = api.NewPeerConnection(config)
// if err != nil {
// return
// }
// if peerType == webrtc.SDPTypeOffer {
// maxRetransmits := uint16(100)
// channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{
// MaxRetransmits: &maxRetransmits,
// })
// if err != nil {
// return nil, err
// }
// channel.OnOpen(func() {
// logger.Println("channel opened")
// if chanErr := channel.SendText("yooo man this is open"); chanErr != nil {
// logger.Println(chanErr)
// }
// })
// channel.OnMessage(func(msg webrtc.DataChannelMessage) {
// logger.Printf("new message %s\n", string(msg.Data))
// done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{
// From: target,
// Type: "test",
// Payload: &DatachannelMessagePayload{},
// }, channel)
// select {
// case <-done:
// //logger.Println("done with success")
// case e := <-errCh:
// logger.Println(e)
// logger.Println("this is impossible")
// }
// })
// wf.DataChannelMapMux.Lock()
// wf.DataChannels[target] = channel
// wf.DataChannelMapMux.Unlock()
// }
// peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
// logger.Printf("ICE connection state has changed %s\n", is.String())
// if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
// logger.Println(is)
// }
// })
// peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
// dc.OnOpen(func() {
// logger.Printf("got a new open datachannel %s\n", dc.Label())
// dataChann, err := dc.Detach()
// if err != nil {
// logger.Println(err)
// return
// }
// for {
// var x []byte = make([]byte, 2<<15)
// n, _, err := dataChann.ReadDataChannel(x)
// if err != nil {
// logger.Println(err)
// if err == io.EOF {
// return
// }
// continue
// }
// go func(msg []byte) {
// var dataChannelMessage DatachannelMessage
// if unmarshalErr := json.Unmarshal(msg, &dataChannelMessage); unmarshalErr != nil {
// logger.Println(unmarshalErr)
// return
// }
// done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{
// From: dataChannelMessage.From,
// Type: dataChannelMessage.Type,
// Payload: dataChannelMessage.Payload,
// }, dc)
// select {
// case <-done:
// //logger.Println("done with success")
// case e := <-errCh:
// logger.Println(e)
// logger.Println("this is impossible")
// }
// }(x[:n])
// }
// })
// // dc.OnMessage(func(msg webrtc.DataChannelMessage) {
// // var dataChannelMessage DatachannelMessage
// // if unmarshalErr := json.Unmarshal(msg.Data, &dataChannelMessage); unmarshalErr != nil {
// // logger.Println(unmarshalErr)
// // return
// // }
// // done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{
// // From: dataChannelMessage.From,
// // Type: dataChannelMessage.Type,
// // Payload: dataChannelMessage.Payload,
// // }, dc)
// // select {
// // case <-done:
// // //logger.Println("done with success")
// // case e := <-errCh:
// // logger.Println(e)
// // logger.Println("this is impossible")
// // }
// // })
// })
// peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
// if i == nil {
// return
// }
// wf.CandidateMux.Lock()
// defer wf.CandidateMux.Unlock()
// desc := peerConnection.RemoteDescription()
// if desc == nil {
// wf.PendingCandidates[target] = append(wf.PendingCandidates[target], i)
// } else {
// logger.Println(i)
// if iceCandidateErr := cb(target, i); iceCandidateErr != nil {
// logger.Println(iceCandidateErr)
// }
// }
// })
// peerConnection.OnNegotiationNeeded(func() {
// if peerConnection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && peerConnection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
// wf.RTCPeerConnectionMapMux.Lock()
// defer wf.RTCPeerConnectionMapMux.Unlock()
// for _, connection := range wf.RTCPeerConnections {
// if connection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && connection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
// localSd, err := connection.CreateOffer(nil)
// if err != nil {
// logger.Println(err)
// return
// }
// if err = connection.SetLocalDescription(localSd); err != nil {
// logger.Println(err)
// return
// }
// // if err = wf.stream.Send(&Request{
// // Type: string(WEBRTC_RENNEGOTIATION_OFFER_FS),
// // From: "lolo_local_serv",
// // Token: "",
// // Payload: map[string]string{
// // "to": id,
// // "sdp": localSd.SDP,
// // },
// // }); err != nil {
// // logger.Println(err)
// // return
// // }
// }
// }
// }
// })
// return
// }
func (wf *WebrtcFsManager) HandleRennegotiationOffer(from string, dst string, sdp string) (err error) {
wf.RTCPeerConnectionMapMux.Lock()
defer wf.RTCPeerConnectionMapMux.Unlock()
if _, ok := wf.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
if wf.RTCPeerConnections[from].SignalingState() != webrtc.SignalingStateStable {
err = fmt.Errorf("rennego called in wrong state")
return
}
if err = wf.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
return
}
localSd, err := wf.RTCPeerConnections[from].CreateAnswer(nil)
if err != nil {
return
}
if err = wf.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
return
}
// if err = wf.stream.Send(&Request{
// Type: string(WEBRTC_RENNEGOTIATION_ANSWER_FS),
// From: "lolo_local_serv",
// Token: "",
// Payload: map[string]string{
// "to": from,
// "sdp": localSd.SDP,
// },
// }); err != nil {
// logger.Println(err)
// return
// }
return
}
// func (wf *WebrtcFsManager) HandleRennegotiationOffer(from string, dst string, sdp string) (err error) {
// wf.RTCPeerConnectionMapMux.Lock()
// defer wf.RTCPeerConnectionMapMux.Unlock()
// if _, ok := wf.RTCPeerConnections[from]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id %s", from)
// return
// }
// if wf.RTCPeerConnections[from].SignalingState() != webrtc.SignalingStateStable {
// err = fmt.Errorf("rennego called in wrong state")
// return
// }
// if err = wf.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
// return
// }
// localSd, err := wf.RTCPeerConnections[from].CreateAnswer(nil)
// if err != nil {
// return
// }
// if err = wf.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
// return
// }
// // if err = wf.stream.Send(&Request{
// // Type: string(WEBRTC_RENNEGOTIATION_ANSWER_FS),
// // From: "lolo_local_serv",
// // Token: "",
// // Payload: map[string]string{
// // "to": from,
// // "sdp": localSd.SDP,
// // },
// // }); err != nil {
// // logger.Println(err)
// // return
// // }
// return
// }
func (wf *WebrtcFsManager) HandleRennegotiationAnswer(from string, dst string, sdp string) (err error) {
wf.RTCPeerConnectionMapMux.Lock()
defer wf.RTCPeerConnectionMapMux.Unlock()
if _, ok := wf.RTCPeerConnections[from]; !ok {
err = fmt.Errorf("no corresponding peer connection for id %s", from)
return
}
err = wf.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
return
}
// func (wf *WebrtcFsManager) HandleRennegotiationAnswer(from string, dst string, sdp string) (err error) {
// wf.RTCPeerConnectionMapMux.Lock()
// defer wf.RTCPeerConnectionMapMux.Unlock()
// if _, ok := wf.RTCPeerConnections[from]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id %s", from)
// return
// }
// err = wf.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
// return
// }
func (wf *WebrtcFsManager) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
wf.RTCPeerConnectionMapMux.Lock()
defer wf.RTCPeerConnectionMapMux.Unlock()
err = wf.RTCPeerConnections[from].AddICECandidate(*candidate)
return
}
// func (wf *WebrtcFsManager) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
// wf.RTCPeerConnectionMapMux.Lock()
// defer wf.RTCPeerConnectionMapMux.Unlock()
// err = wf.RTCPeerConnections[from].AddICECandidate(*candidate)
// return
// }

View File

@ -1,167 +1,167 @@
package localserver
import (
context "context"
"encoding/json"
"strconv"
// import (
// context "context"
// "encoding/json"
// "strconv"
"github.com/pion/webrtc/v3"
)
// "github.com/pion/webrtc/v3"
// )
const (
INCOMING_PEER_FS ReqType = "incoming_peer_fs"
LEAVING_PEER_FS ReqType = "leaving_peer_fs"
WEBRTC_OFFER_FS ReqType = "offer_fs"
WEBRTC_ANSWER_FS ReqType = "answer_fs"
WEBRTC_RENNEGOTIATION_OFFER_FS ReqType = "rennegotiation_offer_fs"
WEBRTC_RENNEGOTIATION_ANSWER_FS ReqType = "rennegotiation_answer_fs"
WEBRTC_COUNTER_OFFER_FS ReqType = "webrtc_counter_offer_fs"
WEBRTC_CANDIDATE_FS ReqType = "webrtc_candidate_fs"
)
// const (
// INCOMING_PEER_FS ReqType = "incoming_peer_fs"
// LEAVING_PEER_FS ReqType = "leaving_peer_fs"
// WEBRTC_OFFER_FS ReqType = "offer_fs"
// WEBRTC_ANSWER_FS ReqType = "answer_fs"
// WEBRTC_RENNEGOTIATION_OFFER_FS ReqType = "rennegotiation_offer_fs"
// WEBRTC_RENNEGOTIATION_ANSWER_FS ReqType = "rennegotiation_answer_fs"
// WEBRTC_COUNTER_OFFER_FS ReqType = "webrtc_counter_offer_fs"
// WEBRTC_CANDIDATE_FS ReqType = "webrtc_candidate_fs"
// )
type WebRTCFsMiddleware struct {
Manager *WebrtcFsManager
stream SignalingService_LinkClient
}
// type WebRTCFsMiddleware struct {
// Manager *WebrtcFsManager
// stream SignalingService_LinkClient
// }
func NewWebRTCFsMiddleware(manager *WebrtcFsManager) (webrtcFsMiddleware *WebRTCFsMiddleware) {
webrtcFsMiddleware = &WebRTCFsMiddleware{
Manager: manager,
}
return
}
// func NewWebRTCFsMiddleware(manager *WebrtcFsManager) (webrtcFsMiddleware *WebRTCFsMiddleware) {
// webrtcFsMiddleware = &WebRTCFsMiddleware{
// Manager: manager,
// }
// return
// }
func (wfm *WebRTCFsMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
bs, err := json.Marshal(map[string]string{
"from": "lolo_local_serv",
"to": to,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
})
if err != nil {
return
}
err = wfm.stream.Send(&SignalingMessage{
Type: string(WEBRTC_CANDIDATE_FS),
From: "lolo_local_serv",
Payload: bs,
})
return
}
// func (wfm *WebRTCFsMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
// bs, err := json.Marshal(map[string]string{
// "from": "lolo_local_serv",
// "to": to,
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// })
// if err != nil {
// return
// }
// err = wfm.stream.Send(&SignalingMessage{
// Type: string(WEBRTC_CANDIDATE_FS),
// From: "lolo_local_serv",
// Payload: bs,
// })
// return
// }
func (wfm *WebRTCFsMiddleware) Process(ctx context.Context, req *SignalingMessage, stream 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); err != nil {
errCh <- e
return
}
switch req.Type {
case string(INCOMING_PEER_FS):
logger.Println("quit squad called")
if from, ok := payload[FROM]; ok {
logger.Println(from)
//wfm.Manager.HandleLeavingMember(from)
done <- struct{}{}
}
case string(PEER_CONNECTION_REQUEST):
if err := validateRequest(payload, FROM, TO); err != nil {
errCh <- err
return
}
// if err := wfm.Manager.CreateOffer(ctx, payload[FROM], payload[TO], wfm.signalCandidate); err != nil {
// errCh <- err
// return
// }
done <- struct{}{}
case string(WEBRTC_OFFER_FS):
if err := validateRequest(payload, FROM, TO, SDP); err != nil {
errCh <- err
return
}
if err := wfm.Manager.HandleOffer(ctx, payload, wfm.signalCandidate); err != nil {
errCh <- err
return
}
done <- struct{}{}
case string(WEBRTC_ANSWER_FS):
if err := validateRequest(payload, FROM, TO, SDP); err != nil {
errCh <- err
return
}
if err := wfm.Manager.HandleAnswer(ctx, payload); err != nil {
errCh <- err
return
}
done <- struct{}{}
case string(WEBRTC_COUNTER_OFFER_FS):
if err := validateRequest(payload, FROM); err != nil {
errCh <- err
return
}
if err := wfm.Manager.HandleCounterOffer(ctx, payload); err != nil {
errCh <- err
return
}
done <- struct{}{}
case string(WEBRTC_RENNEGOTIATION_ANSWER_FS):
if err := validateRequest(payload, FROM, SDP); err != nil {
errCh <- err
return
}
if err := wfm.Manager.HandleRennegotiationAnswer(payload[FROM], "lolo_local_serv", payload[SDP]); err != nil {
errCh <- err
return
}
done <- struct{}{}
case string(WEBRTC_RENNEGOTIATION_OFFER_FS):
if err := validateRequest(payload, FROM, SDP); err != nil {
errCh <- err
return
}
if err := wfm.Manager.HandleRennegotiationOffer(payload[FROM], "", payload[SDP]); err != nil {
errCh <- err
return
}
done <- struct{}{}
case string(WEBRTC_CANDIDATE_FS):
if err := validateRequest(payload, FROM, "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 := wfm.Manager.AddCandidate(&webrtc.ICECandidateInit{
Candidate: payload["candidate"],
SDPMid: &sdpMid,
SDPMLineIndex: &SDPMLineIndex,
}, payload[FROM]); err != nil {
errCh <- err
return
}
done <- struct{}{}
default:
logger.Println("fs is correctly linked")
done <- struct{}{}
}
done <- struct{}{}
}()
select {
case <-ctx.Done():
err = ctx.Err()
return
case <-done:
return
case err = <-errCh:
return
}
}
// func (wfm *WebRTCFsMiddleware) Process(ctx context.Context, req *SignalingMessage, stream 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); err != nil {
// errCh <- e
// return
// }
// switch req.Type {
// case string(INCOMING_PEER_FS):
// logger.Println("quit squad called")
// if from, ok := payload[FROM]; ok {
// logger.Println(from)
// //wfm.Manager.HandleLeavingMember(from)
// done <- struct{}{}
// }
// case string(PEER_CONNECTION_REQUEST):
// if err := validateRequest(payload, FROM, TO); err != nil {
// errCh <- err
// return
// }
// // if err := wfm.Manager.CreateOffer(ctx, payload[FROM], payload[TO], wfm.signalCandidate); err != nil {
// // errCh <- err
// // return
// // }
// done <- struct{}{}
// case string(WEBRTC_OFFER_FS):
// if err := validateRequest(payload, FROM, TO, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wfm.Manager.HandleOffer(ctx, payload, wfm.signalCandidate); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// case string(WEBRTC_ANSWER_FS):
// if err := validateRequest(payload, FROM, TO, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wfm.Manager.HandleAnswer(ctx, payload); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// case string(WEBRTC_COUNTER_OFFER_FS):
// if err := validateRequest(payload, FROM); err != nil {
// errCh <- err
// return
// }
// if err := wfm.Manager.HandleCounterOffer(ctx, payload); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// case string(WEBRTC_RENNEGOTIATION_ANSWER_FS):
// if err := validateRequest(payload, FROM, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wfm.Manager.HandleRennegotiationAnswer(payload[FROM], "lolo_local_serv", payload[SDP]); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// case string(WEBRTC_RENNEGOTIATION_OFFER_FS):
// if err := validateRequest(payload, FROM, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wfm.Manager.HandleRennegotiationOffer(payload[FROM], "", payload[SDP]); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// case string(WEBRTC_CANDIDATE_FS):
// if err := validateRequest(payload, FROM, "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 := wfm.Manager.AddCandidate(&webrtc.ICECandidateInit{
// Candidate: payload["candidate"],
// SDPMid: &sdpMid,
// SDPMLineIndex: &SDPMLineIndex,
// }, payload[FROM]); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// default:
// logger.Println("fs is correctly linked")
// done <- struct{}{}
// }
// done <- struct{}{}
// }()
// select {
// case <-ctx.Done():
// err = ctx.Err()
// return
// case <-done:
// return
// case err = <-errCh:
// return
// }
// }

View File

@ -1,186 +1,186 @@
package localserver
import (
"context"
"encoding/json"
"strconv"
// import (
// "context"
// "encoding/json"
// "strconv"
"github.com/pion/webrtc/v3"
)
// "github.com/pion/webrtc/v3"
// )
type GrpcRequestType string
// type GrpcRequestType string
const (
PEER_CONNECTION_REQUEST GrpcRequestType = "peer_connection_request"
)
// const (
// PEER_CONNECTION_REQUEST GrpcRequestType = "peer_connection_request"
// )
const (
OFFER ReqType = "offer"
ANSWER ReqType = "answer"
COUNTER_OFFER ReqType = "webrtc_counter_offer"
JOIN_HOSTED_SQUAD ReqType = "join_hosted_squad"
HOSTED_SQUAD_ACCESS_DENIED ReqType = "hosted_squad_access_denied"
HOSTED_SQUAD_STOP_CALL ReqType = "hosted_squad_stop_call"
HOSTED_SQUAD_ACCESS_GRANTED ReqType = "hosted_squad_access_granted"
LEAVE_HOSTED_SQUAD ReqType = "leave_hosted_squad"
INCOMING_MEMBER_HOSTED ReqType = "incoming_member_hosted"
LEAVING_MEMBER_HOSTED ReqType = "leaving_member_hosted"
HOSTED_SQUAD_WEBRTC_OFFER ReqType = "hosted_squad_offer"
HOSTED_SQUAD_WEBRTC_ANSWER ReqType = "hosted_squad_answer"
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER ReqType = "hosted_squad_rennegotiation_offer"
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "hosted_squad_rennegotiation_answer"
HOSTED_SQUAD_WEBRTC_COUNTER_OFFER ReqType = "hosted_squad_webrtc_counter_offer"
HOSTED_SQUAD_WEBRTC_CANDIDATE ReqType = "hosted_squad_webrtc_candidate"
HOSTED_SQUAD_REMOVE_VIDEO ReqType = "hosted_squad_remove_video"
GET_HOSTED_SQUAD_TRACKS ReqType = "hosted_squad_get_tracks"
NEW_HOSTED_SQUAD = "new_hosted_squad"
)
// const (
// OFFER ReqType = "offer"
// ANSWER ReqType = "answer"
// COUNTER_OFFER ReqType = "webrtc_counter_offer"
// JOIN_HOSTED_SQUAD ReqType = "join_hosted_squad"
// HOSTED_SQUAD_ACCESS_DENIED ReqType = "hosted_squad_access_denied"
// HOSTED_SQUAD_STOP_CALL ReqType = "hosted_squad_stop_call"
// HOSTED_SQUAD_ACCESS_GRANTED ReqType = "hosted_squad_access_granted"
// LEAVE_HOSTED_SQUAD ReqType = "leave_hosted_squad"
// INCOMING_MEMBER_HOSTED ReqType = "incoming_member_hosted"
// LEAVING_MEMBER_HOSTED ReqType = "leaving_member_hosted"
// HOSTED_SQUAD_WEBRTC_OFFER ReqType = "hosted_squad_offer"
// HOSTED_SQUAD_WEBRTC_ANSWER ReqType = "hosted_squad_answer"
// HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER ReqType = "hosted_squad_rennegotiation_offer"
// HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "hosted_squad_rennegotiation_answer"
// HOSTED_SQUAD_WEBRTC_COUNTER_OFFER ReqType = "hosted_squad_webrtc_counter_offer"
// HOSTED_SQUAD_WEBRTC_CANDIDATE ReqType = "hosted_squad_webrtc_candidate"
// HOSTED_SQUAD_REMOVE_VIDEO ReqType = "hosted_squad_remove_video"
// GET_HOSTED_SQUAD_TRACKS ReqType = "hosted_squad_get_tracks"
// NEW_HOSTED_SQUAD = "new_hosted_squad"
// )
type WebRTCGrpcMiddleware struct {
Manager *WebRTCCallManager
stream SignalingService_LinkClient
}
// type WebRTCGrpcMiddleware struct {
// Manager *WebRTCCallManager
// stream SignalingService_LinkClient
// }
func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *WebRTCGrpcMiddleware) {
webrtcGrpcMiddleware = &WebRTCGrpcMiddleware{
Manager: manager,
}
return
}
// func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *WebRTCGrpcMiddleware) {
// webrtcGrpcMiddleware = &WebRTCGrpcMiddleware{
// Manager: manager,
// }
// return
// }
func (wgm *WebRTCGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
bs, err := json.Marshal(map[string]string{
"from": wgm.Manager.ID,
"to": to,
"candidate": candidate.ToJSON().Candidate,
"sdpMid": *candidate.ToJSON().SDPMid,
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
})
if err != nil {
return
}
err = wgm.stream.Send(&SignalingMessage{
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
From: wgm.Manager.ID,
To: to,
Payload: bs,
})
return
}
// func (wgm *WebRTCGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
// bs, err := json.Marshal(map[string]string{
// "from": wgm.Manager.ID,
// "to": to,
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// })
// if err != nil {
// return
// }
// err = wgm.stream.Send(&SignalingMessage{
// Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
// From: wgm.Manager.ID,
// To: to,
// Payload: bs,
// })
// return
// }
func (wgm *WebRTCGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
defer func() {
done <- struct{}{}
}()
var payload map[string]string
if e := json.Unmarshal(req.Payload, &payload); err != nil {
errCh <- e
return
}
switch req.Type {
case NEW_HOSTED_SQUAD:
if err := validateRequest(payload, "ID"); err != nil {
errCh <- err
return
}
logger.Println("new squad incoming")
wgm.Manager.SquadMapMux.Lock()
wgm.Manager.Squads[payload["ID"]] = &Squad{
ID: payload["ID"],
Members: []string{},
}
wgm.Manager.SquadMapMux.Unlock()
case string(HOSTED_SQUAD_STOP_CALL):
logger.Println("quit squad called")
if err := validateRequest(payload, "squadId"); err != nil {
errCh <- err
return
}
wgm.Manager.HandleLeavingMember(req.GetFrom(), payload["squadId"])
done <- struct{}{}
case string(PEER_CONNECTION_REQUEST):
logger.Println("creating offer for peer")
if err := wgm.Manager.CreateOffer(ctx, req.GetFrom(), req.GetTo(), wgm.signalCandidate); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_OFFER):
if err := validateRequest(payload, SDP, SQUAD_ID); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, wgm.signalCandidate); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_ANSWER):
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER):
if err := wgm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
logger.Println("received negotiation answer")
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
logger.Println("received negotiation offer")
if err := validateRequest(payload, SDP); err != nil {
errCh <- err
return
}
if err := wgm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
errCh <- err
return
}
case string(HOSTED_SQUAD_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 := wgm.Manager.AddCandidate(&webrtc.ICECandidateInit{
Candidate: payload["candidate"],
SDPMid: &sdpMid,
SDPMLineIndex: &SDPMLineIndex,
}, req.GetFrom()); err != nil {
errCh <- err
return
}
default:
}
}()
select {
case <-ctx.Done():
err = ctx.Err()
return
case <-done:
return
case err = <-errCh:
return
}
}
// func (wgm *WebRTCGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// defer func() {
// done <- struct{}{}
// }()
// var payload map[string]string
// if e := json.Unmarshal(req.Payload, &payload); err != nil {
// errCh <- e
// return
// }
// switch req.Type {
// case NEW_HOSTED_SQUAD:
// if err := validateRequest(payload, "ID"); err != nil {
// errCh <- err
// return
// }
// logger.Println("new squad incoming")
// wgm.Manager.SquadMapMux.Lock()
// wgm.Manager.Squads[payload["ID"]] = &Squad{
// ID: payload["ID"],
// Members: []string{},
// }
// wgm.Manager.SquadMapMux.Unlock()
// case string(HOSTED_SQUAD_STOP_CALL):
// logger.Println("quit squad called")
// if err := validateRequest(payload, "squadId"); err != nil {
// errCh <- err
// return
// }
// wgm.Manager.HandleLeavingMember(req.GetFrom(), payload["squadId"])
// done <- struct{}{}
// case string(PEER_CONNECTION_REQUEST):
// logger.Println("creating offer for peer")
// if err := wgm.Manager.CreateOffer(ctx, req.GetFrom(), req.GetTo(), wgm.signalCandidate); err != nil {
// errCh <- err
// return
// }
// case string(HOSTED_SQUAD_WEBRTC_OFFER):
// if err := validateRequest(payload, SDP, SQUAD_ID); err != nil {
// errCh <- err
// return
// }
// if err := wgm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, wgm.signalCandidate); err != nil {
// errCh <- err
// return
// }
// case string(HOSTED_SQUAD_WEBRTC_ANSWER):
// if err := validateRequest(payload, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wgm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
// errCh <- err
// return
// }
// case string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER):
// if err := wgm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
// errCh <- err
// return
// }
// case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
// logger.Println("received negotiation answer")
// if err := validateRequest(payload, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wgm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
// errCh <- err
// return
// }
// case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
// logger.Println("received negotiation offer")
// if err := validateRequest(payload, SDP); err != nil {
// errCh <- err
// return
// }
// if err := wgm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
// errCh <- err
// return
// }
// case string(HOSTED_SQUAD_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 := wgm.Manager.AddCandidate(&webrtc.ICECandidateInit{
// Candidate: payload["candidate"],
// SDPMid: &sdpMid,
// SDPMLineIndex: &SDPMLineIndex,
// }, req.GetFrom()); err != nil {
// errCh <- err
// return
// }
// default:
// }
// }()
// select {
// case <-ctx.Done():
// err = ctx.Err()
// return
// case <-done:
// return
// case err = <-errCh:
// return
// }
// }

View File

@ -1,66 +1,66 @@
package localserver
import (
"context"
"encoding/json"
"io"
"net/http"
)
// import (
// "context"
// "encoding/json"
// "io"
// "net/http"
// )
type (
WebRTCHttpMiddleware struct {
//menuItem *systray.MenuItem
}
)
// type (
// WebRTCHttpMiddleware struct {
// //menuItem *systray.MenuItem
// }
// )
const (
CREATE_HOSTED_SQUAD = "create_hosted_squad"
)
// const (
// CREATE_HOSTED_SQUAD = "create_hosted_squad"
// )
// func NewWebRTCHttpMiddleware(menuItem *systray.MenuItem) (webRTCHttpMiddleware *WebRTCHttpMiddleware) {
// webRTCHttpMiddleware = &WebRTCHttpMiddleware{
// menuItem: menuItem,
// // func NewWebRTCHttpMiddleware(menuItem *systray.MenuItem) (webRTCHttpMiddleware *WebRTCHttpMiddleware) {
// // webRTCHttpMiddleware = &WebRTCHttpMiddleware{
// // menuItem: menuItem,
// // }
// // return
// // }
// func (wm *WebRTCHttpMiddleware) Process(ctx context.Context, req *http.Request) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// localServerReq, err := wm.unmarshallBody(req)
// if err != nil {
// errCh <- err
// return
// }
// switch localServerReq.ReqType {
// case CREATE_HOSTED_SQUAD:
// default:
// }
// }()
// select {
// case <-done:
// return
// case err = <-errCh:
// return
// case <-ctx.Done():
// err = ctx.Err()
// return
// }
// }
// func (wm *WebRTCHttpMiddleware) unmarshallBody(req *http.Request) (localServerReq *LocalServerRequest, err error) {
// reqBody, err := req.GetBody()
// if err != nil {
// return
// }
// bs, err := io.ReadAll(reqBody)
// if err != nil {
// return
// }
// err = json.Unmarshal(bs, &localServerReq)
// if err != nil {
// return
// }
// return
// }
func (wm *WebRTCHttpMiddleware) Process(ctx context.Context, req *http.Request) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
localServerReq, err := wm.unmarshallBody(req)
if err != nil {
errCh <- err
return
}
switch localServerReq.ReqType {
case CREATE_HOSTED_SQUAD:
default:
}
}()
select {
case <-done:
return
case err = <-errCh:
return
case <-ctx.Done():
err = ctx.Err()
return
}
}
func (wm *WebRTCHttpMiddleware) unmarshallBody(req *http.Request) (localServerReq *LocalServerRequest, err error) {
reqBody, err := req.GetBody()
if err != nil {
return
}
bs, err := io.ReadAll(reqBody)
if err != nil {
return
}
err = json.Unmarshal(bs, &localServerReq)
if err != nil {
return
}
return
}

View File

@ -264,7 +264,7 @@ func (ac *AudioChannel) createPeerConnection(target string, from string, peerTyp
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478"},
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
@ -459,10 +459,10 @@ func (ac *AudioChannel) createPeerConnection(target string, from string, peerTyp
} else if localTrack.Kind() == webrtc.RTPCodecTypeVideo {
logger.Println("track of wrong type")
}
go func() {
go func(id string) {
<-time.After(time.Millisecond * 500)
connection.negotiate(id, sendDCMessage)
}()
}(id)
}
}
return

View File

@ -413,7 +413,7 @@ func (fs *ChatFSInstance) FileDownloadFailed(chatId, filename, userId string) (e
// config := webrtc.Configuration{
// ICEServers: []webrtc.ICEServer{
// {
// URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478"},
// URLs: []string{"stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302"},
// },
// },
// }

View File

@ -11,6 +11,7 @@ import (
)
type ChatFile struct {
ID uint64
ChatId string `json:"chatId"`
Owner string `json:"owner"`
Name string `json:"name"`

View File

@ -937,7 +937,7 @@ func (zch *ZoneChatsHandler[T]) AddChatMessage(userId, chatId, content string, i
ResponseOf: nil,
File: file,
Tags: make([]string, 0),
Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"),
Date: time.Now().Format(time.RFC3339),
}
var chatType string
var chatMembers []string

View File

@ -1109,8 +1109,8 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
Owner: req.Payload["userId"].(string),
Type: PRIVATE,
Folder: true,
ModTime: time.Now().Format(time.UnixDate),
CreationTime: time.Now().Format(time.UnixDate),
ModTime: time.Now().Format(time.RFC3339),
CreationTime: time.Now().Format(time.RFC3339),
Size: 0,
Members: map[string]*FSEntityAccessRights{
req.Payload["userId"].(string): {
@ -1148,8 +1148,8 @@ func (zfh *ZoneFileHandler[T]) handleZoneRequest(c context.Context, req *ZoneReq
Owner: req.Payload["userId"].(string),
Type: req.Payload["type"].(string),
Size: uint64(req.Payload["size"].(float64)),
ModTime: time.Now().Format(time.UnixDate),
CreationTime: time.Now().Format(time.UnixDate),
ModTime: time.Now().Format(time.RFC3339),
CreationTime: time.Now().Format(time.RFC3339),
Folder: false,
Members: map[string]*FSEntityAccessRights{
req.Payload["userId"].(string): {

View File

@ -416,7 +416,7 @@ func (fs *FSInstance) FileDownloadFailed(path, filename, userId string) (err err
// config := webrtc.Configuration{
// ICEServers: []webrtc.ICEServer{
// {
// URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478"},
// URLs: []string{"stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302"},
// },
// },
// SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,

View File

@ -3,6 +3,7 @@ package localserver
import (
"context"
"encoding/json"
"fmt"
"strconv"
"github.com/pion/webrtc/v3"
@ -62,6 +63,7 @@ func (zm *ZoneGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECa
func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
done, errCh := make(chan struct{}), make(chan error)
fmt.Println("got req", req.Type, string(req.Payload))
go func() {
var payload map[string]string
if e := json.Unmarshal(req.Payload, &payload); e != nil {
@ -92,16 +94,20 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
}
if err = atomicallyExecute(zm.Manager.zoneFlag, func() (err error) {
reqChan := make(chan *ZoneRequest)
if _, ok := zm.Manager.Zones[payload["zoneId"]]; !ok {
err = fmt.Errorf("no such zone")
return
}
done, e := zm.Manager.Zones[payload["zoneId"]].ZoneRequestScheduler.Schedule(reqChan)
go func() {
defer close(reqChan)
reqChan <- &ZoneRequest{
ReqType: string(REMOVE_USER),
From: payload["userId"],
Payload: map[string]interface{}{
"userId": payload["userId"],
},
}
// reqChan <- &ZoneRequest{
// ReqType: string(REMOVE_USER),
// From: payload["userId"],
// Payload: map[string]interface{}{
// "userId": payload["userId"],
// },
// }
reqChan <- &ZoneRequest{
ReqType: string(REMOVED_ZONE_AUTHORIZED_MEMBER),
From: payload["userId"],
@ -125,16 +131,13 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
}
if err = atomicallyExecute(zm.Manager.zoneFlag, func() (err error) {
reqChan := make(chan *ZoneRequest)
if _, ok := zm.Manager.Zones[payload["zoneId"]]; !ok {
err = fmt.Errorf("no such zone")
return
}
done, e := zm.Manager.Zones[payload["zoneId"]].ZoneRequestScheduler.Schedule(reqChan)
go func() {
defer close(reqChan)
reqChan <- &ZoneRequest{
ReqType: string(ADD_USER),
From: payload["userId"],
Payload: map[string]interface{}{
"userId": payload["userId"],
},
}
reqChan <- &ZoneRequest{
ReqType: string(NEW_AUTHORIZED_ZONE_MEMBER),
From: payload["userId"],
@ -142,6 +145,13 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage
"userId": payload["userId"],
},
}
// reqChan <- &ZoneRequest{
// ReqType: string(ADD_USER),
// From: payload["userId"],
// Payload: map[string]interface{}{
// "userId": payload["userId"],
// },
// }
}()
select {
case <-done:

View File

@ -400,7 +400,7 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302", "stun:stunserver.org:3478"},
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
SDPSemantics: webrtc.SDPSemanticsUnifiedPlan,

View File

@ -48,44 +48,6 @@ func NewZoneNotificationsHandler(_ string, zoneId string, owner string, authoriz
return
}
// func (znh *ZoneNotificationsHandler) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
// go func() {
// for _, rc := range znh.reqChans {
// rc <- &ZoneRequest{
// ReqType: reqType,
// From: from,
// Payload: payload,
// }
// }
// }()
// }
// func (znh *ZoneNotificationsHandler) 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(znh.Flag, func() (err error) {
// if _, ok := znh.DataChannels[to]; ok {
// bs, jsonErr := json.Marshal(&ZoneResponse{
// Type: reqType,
// From: from,
// To: to,
// Payload: payload,
// })
// if jsonErr != nil {
// return jsonErr
// }
// err = znh.DataChannels[to].DataChannel.SendText(string(bs))
// }
// return
// }); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// }()
// return done, errCh
// }
func (znh *ZoneNotificationsHandler) Init(ctx context.Context, authorizedMembers []string) (err error) {
//? initialization code here
return
@ -169,12 +131,6 @@ func (znh *ZoneNotificationsHandler) handleZoneRequest(ctx context.Context, req
err = fmt.Errorf(" field recipient in payload is wrong type")
return
}
// recipients := []string{}
// for _, recipient := range req.Payload["recipients"].([]any) {
// if r, ok := recipient.(string); ok {
// recipients = append(recipients, r)
// }
// }
err = znh.CreateNotification(req.Payload["type"].(string), req.Payload["title"].(string), req.Payload["body"].(string), req.Payload["payload"].(string), req.Payload["isPushed"].(bool), req.Payload["recipients"].([]string)...)
}

View File

@ -80,16 +80,16 @@ 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)
for req := range reqChan {
go func(r *ZoneRequest) {
for _, publisher := range zrs.handlersPublishers {
go func(p chan<- *ZoneRequest) {
p <- r
}(publisher)
}
}(req)
}
done <- struct{}{}
go func() {
for req := range reqChan {
go func(r *ZoneRequest) {
for _, publisher := range zrs.handlersPublishers {
publisher <- r
}
}(req)
}
done <- struct{}{}
}()
return
}

Some files were not shown because too many files have changed in this diff Show More