add chat tracking
This commit is contained in:
parent
5e95736e76
commit
a4ee2b4048
77
config.go
77
config.go
@ -6,6 +6,8 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -14,6 +16,8 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var NodeToken string
|
||||||
|
|
||||||
type LocalServerConfig struct {
|
type LocalServerConfig struct {
|
||||||
configFilePath string
|
configFilePath string
|
||||||
NodeId string `json:"nodeId"`
|
NodeId string `json:"nodeId"`
|
||||||
@ -29,9 +33,13 @@ func NewLocalServerConfig() (localServerConfig *LocalServerConfig, err error) {
|
|||||||
logger.SetOutput(logFile)
|
logger.SetOutput(logFile)
|
||||||
logger.SetFlags(log.Ldate | log.LUTC | log.Lshortfile | log.Ltime | log.LstdFlags | log.Lmsgprefix)
|
logger.SetFlags(log.Ldate | log.LUTC | log.Lshortfile | log.Ltime | log.LstdFlags | log.Lmsgprefix)
|
||||||
localServerConfig = &LocalServerConfig{
|
localServerConfig = &LocalServerConfig{
|
||||||
configFilePath: filepath.Join("config","node_config.json"),
|
configFilePath: filepath.Join("config", "node_config.json"),
|
||||||
}
|
}
|
||||||
err = localServerConfig.startup()
|
err = localServerConfig.startup()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = localServerConfig.authenticate()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +82,7 @@ func (l *LocalServerConfig) startup() (err error) {
|
|||||||
"from": id,
|
"from": id,
|
||||||
"to": "serv",
|
"to": "serv",
|
||||||
"token": "",
|
"token": "",
|
||||||
|
"peerType":"node",
|
||||||
"payload": map[string]string{
|
"payload": map[string]string{
|
||||||
"nodeId": id,
|
"nodeId": id,
|
||||||
"nodeKey": string(key),
|
"nodeKey": string(key),
|
||||||
@ -99,6 +108,70 @@ func (l *LocalServerConfig) startup() (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = json.NewDecoder(file).Decode(&l)
|
var config map[string]string
|
||||||
|
err = json.NewDecoder(file).Decode(&config)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Println(config)
|
||||||
|
l.NodeId = config["nodeId"]
|
||||||
|
l.PrivateKeyPath = config["privKeyPath"]
|
||||||
|
l.Token = config["token"]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LocalServerConfig) authenticate() (err error) {
|
||||||
|
f, err := os.Open(l.PrivateKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buff []byte
|
||||||
|
buff, err = io.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
em := NewEncryptionManager()
|
||||||
|
sig, err := em.SignRequest(string(buff), l.NodeId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := json.Marshal(map[string]interface{}{
|
||||||
|
"type": "login_key_node",
|
||||||
|
"from": l.NodeId,
|
||||||
|
"peerType":"node",
|
||||||
|
"payload": map[string]string{
|
||||||
|
"id": l.NodeId,
|
||||||
|
"signature": sig,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := http.Post("https://app.zippytal.com/req", "application/json", bytes.NewBuffer(body))
|
||||||
|
if err != nil {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
err = l.handleLoginResponse(payload)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LocalServerConfig) handleLoginResponse(res map[string]any) (err error) {
|
||||||
|
if _, ok := res["token"]; !ok {
|
||||||
|
err = fmt.Errorf("no field token in res")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := res["token"].(string); !ok {
|
||||||
|
err = fmt.Errorf("field token not string in res")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
NodeToken = res["token"].(string)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,13 @@ package localserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -110,3 +114,37 @@ func (em *EncryptionManager) LoadPrivKey(privKeyPath string, password string) (e
|
|||||||
em.PrivKey = privKey
|
em.PrivKey = privKey
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (em *EncryptionManager) ParsePrivKey(privateKey string) (privKey *rsa.PrivateKey, err error) {
|
||||||
|
key := []byte(privateKey)
|
||||||
|
block, _ := pem.Decode(key)
|
||||||
|
b := block.Bytes
|
||||||
|
privKey, err = x509.ParsePKCS1PrivateKey(b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (em *EncryptionManager) SignRequest(privKey, id string) (sig string, err error) {
|
||||||
|
key, err := em.ParsePrivKey(privKey)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := []byte(id)
|
||||||
|
hashed := sha256.Sum256(msg)
|
||||||
|
signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hashed[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sig = base64.StdEncoding.EncodeToString(signature)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (em *EncryptionManager) SignRequestHMAC(id string) string {
|
||||||
|
h := hmac.New(sha256.New, []byte(NodeToken))
|
||||||
|
h.Write([]byte(id))
|
||||||
|
sha := h.Sum(nil)
|
||||||
|
sig := base64.StdEncoding.EncodeToString(sha)
|
||||||
|
return sig
|
||||||
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -1,10 +1,9 @@
|
|||||||
module github.com/loisBN/zippytal_node/localserver
|
module github.com/loisBN/zippytal_node/localserver
|
||||||
|
|
||||||
go 1.17
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dgraph-io/badger/v3 v3.2103.2
|
github.com/dgraph-io/badger/v3 v3.2103.2
|
||||||
github.com/golang/protobuf v1.5.2
|
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/pion/rtcp v1.2.9
|
github.com/pion/rtcp v1.2.9
|
||||||
github.com/pion/webrtc/v3 v3.1.11
|
github.com/pion/webrtc/v3 v3.1.11
|
||||||
@ -20,6 +19,7 @@ require (
|
|||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.3 // indirect
|
github.com/golang/snappy v0.0.3 // indirect
|
||||||
github.com/google/flatbuffers v1.12.1 // indirect
|
github.com/google/flatbuffers v1.12.1 // indirect
|
||||||
github.com/klauspost/compress v1.12.3 // indirect
|
github.com/klauspost/compress v1.12.3 // indirect
|
||||||
|
|||||||
1958
grpc_manager.pb.go
1958
grpc_manager.pb.go
File diff suppressed because it is too large
Load Diff
@ -1,422 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
|
|
||||||
package localserver
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.32.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion7
|
|
||||||
|
|
||||||
// GrpcManagerClient is the client API for GrpcManager service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type GrpcManagerClient interface {
|
|
||||||
Link(ctx context.Context, opts ...grpc.CallOption) (GrpcManager_LinkClient, error)
|
|
||||||
RegisterPeer(ctx context.Context, in *PeerRegisterRequest, opts ...grpc.CallOption) (*PeerRegisterResponse, error)
|
|
||||||
ListPeers(ctx context.Context, in *PeerListRequest, opts ...grpc.CallOption) (*PeerListResponse, error)
|
|
||||||
CreateSquad(ctx context.Context, in *SquadCreateRequest, opts ...grpc.CallOption) (*SquadCreateResponse, error)
|
|
||||||
UpdateSquad(ctx context.Context, in *SquadUpdateRequest, opts ...grpc.CallOption) (*SquadUpdateResponse, error)
|
|
||||||
DeleteSquad(ctx context.Context, in *SquadDeleteRequest, opts ...grpc.CallOption) (*SquadDeleteResponse, error)
|
|
||||||
ListSquad(ctx context.Context, in *SquadListRequest, opts ...grpc.CallOption) (*SquadListResponse, error)
|
|
||||||
ConnectSquad(ctx context.Context, in *SquadConnectRequest, opts ...grpc.CallOption) (*SquadConnectResponse, error)
|
|
||||||
LeaveSquad(ctx context.Context, in *SquadLeaveRequest, opts ...grpc.CallOption) (*SquadLeaveResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type grpcManagerClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGrpcManagerClient(cc grpc.ClientConnInterface) GrpcManagerClient {
|
|
||||||
return &grpcManagerClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) Link(ctx context.Context, opts ...grpc.CallOption) (GrpcManager_LinkClient, error) {
|
|
||||||
stream, err := c.cc.NewStream(ctx, &GrpcManager_ServiceDesc.Streams[0], "/manager.GrpcManager/Link", opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &grpcManagerLinkClient{stream}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type GrpcManager_LinkClient interface {
|
|
||||||
Send(*Request) error
|
|
||||||
Recv() (*Response, error)
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type grpcManagerLinkClient struct {
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *grpcManagerLinkClient) Send(m *Request) error {
|
|
||||||
return x.ClientStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *grpcManagerLinkClient) Recv() (*Response, error) {
|
|
||||||
m := new(Response)
|
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) RegisterPeer(ctx context.Context, in *PeerRegisterRequest, opts ...grpc.CallOption) (*PeerRegisterResponse, error) {
|
|
||||||
out := new(PeerRegisterResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/RegisterPeer", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) ListPeers(ctx context.Context, in *PeerListRequest, opts ...grpc.CallOption) (*PeerListResponse, error) {
|
|
||||||
out := new(PeerListResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/ListPeers", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) CreateSquad(ctx context.Context, in *SquadCreateRequest, opts ...grpc.CallOption) (*SquadCreateResponse, error) {
|
|
||||||
out := new(SquadCreateResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/CreateSquad", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) UpdateSquad(ctx context.Context, in *SquadUpdateRequest, opts ...grpc.CallOption) (*SquadUpdateResponse, error) {
|
|
||||||
out := new(SquadUpdateResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/UpdateSquad", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) DeleteSquad(ctx context.Context, in *SquadDeleteRequest, opts ...grpc.CallOption) (*SquadDeleteResponse, error) {
|
|
||||||
out := new(SquadDeleteResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/DeleteSquad", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) ListSquad(ctx context.Context, in *SquadListRequest, opts ...grpc.CallOption) (*SquadListResponse, error) {
|
|
||||||
out := new(SquadListResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/ListSquad", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) ConnectSquad(ctx context.Context, in *SquadConnectRequest, opts ...grpc.CallOption) (*SquadConnectResponse, error) {
|
|
||||||
out := new(SquadConnectResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/ConnectSquad", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *grpcManagerClient) LeaveSquad(ctx context.Context, in *SquadLeaveRequest, opts ...grpc.CallOption) (*SquadLeaveResponse, error) {
|
|
||||||
out := new(SquadLeaveResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/manager.GrpcManager/LeaveSquad", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GrpcManagerServer is the server API for GrpcManager service.
|
|
||||||
// All implementations must embed UnimplementedGrpcManagerServer
|
|
||||||
// for forward compatibility
|
|
||||||
type GrpcManagerServer interface {
|
|
||||||
Link(GrpcManager_LinkServer) error
|
|
||||||
RegisterPeer(context.Context, *PeerRegisterRequest) (*PeerRegisterResponse, error)
|
|
||||||
ListPeers(context.Context, *PeerListRequest) (*PeerListResponse, error)
|
|
||||||
CreateSquad(context.Context, *SquadCreateRequest) (*SquadCreateResponse, error)
|
|
||||||
UpdateSquad(context.Context, *SquadUpdateRequest) (*SquadUpdateResponse, error)
|
|
||||||
DeleteSquad(context.Context, *SquadDeleteRequest) (*SquadDeleteResponse, error)
|
|
||||||
ListSquad(context.Context, *SquadListRequest) (*SquadListResponse, error)
|
|
||||||
ConnectSquad(context.Context, *SquadConnectRequest) (*SquadConnectResponse, error)
|
|
||||||
LeaveSquad(context.Context, *SquadLeaveRequest) (*SquadLeaveResponse, error)
|
|
||||||
mustEmbedUnimplementedGrpcManagerServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedGrpcManagerServer must be embedded to have forward compatible implementations.
|
|
||||||
type UnimplementedGrpcManagerServer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (UnimplementedGrpcManagerServer) Link(GrpcManager_LinkServer) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method Link not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) RegisterPeer(context.Context, *PeerRegisterRequest) (*PeerRegisterResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method RegisterPeer not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) ListPeers(context.Context, *PeerListRequest) (*PeerListResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListPeers not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) CreateSquad(context.Context, *SquadCreateRequest) (*SquadCreateResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method CreateSquad not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) UpdateSquad(context.Context, *SquadUpdateRequest) (*SquadUpdateResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateSquad not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) DeleteSquad(context.Context, *SquadDeleteRequest) (*SquadDeleteResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteSquad not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) ListSquad(context.Context, *SquadListRequest) (*SquadListResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListSquad not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) ConnectSquad(context.Context, *SquadConnectRequest) (*SquadConnectResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ConnectSquad not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) LeaveSquad(context.Context, *SquadLeaveRequest) (*SquadLeaveResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method LeaveSquad not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedGrpcManagerServer) mustEmbedUnimplementedGrpcManagerServer() {}
|
|
||||||
|
|
||||||
// UnsafeGrpcManagerServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to GrpcManagerServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeGrpcManagerServer interface {
|
|
||||||
mustEmbedUnimplementedGrpcManagerServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterGrpcManagerServer(s grpc.ServiceRegistrar, srv GrpcManagerServer) {
|
|
||||||
s.RegisterService(&GrpcManager_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_Link_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
return srv.(GrpcManagerServer).Link(&grpcManagerLinkServer{stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type GrpcManager_LinkServer interface {
|
|
||||||
Send(*Response) error
|
|
||||||
Recv() (*Request, error)
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type grpcManagerLinkServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *grpcManagerLinkServer) Send(m *Response) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *grpcManagerLinkServer) Recv() (*Request, error) {
|
|
||||||
m := new(Request)
|
|
||||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_RegisterPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(PeerRegisterRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).RegisterPeer(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/RegisterPeer",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).RegisterPeer(ctx, req.(*PeerRegisterRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_ListPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(PeerListRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).ListPeers(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/ListPeers",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).ListPeers(ctx, req.(*PeerListRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_CreateSquad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SquadCreateRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).CreateSquad(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/CreateSquad",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).CreateSquad(ctx, req.(*SquadCreateRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_UpdateSquad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SquadUpdateRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).UpdateSquad(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/UpdateSquad",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).UpdateSquad(ctx, req.(*SquadUpdateRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_DeleteSquad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SquadDeleteRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).DeleteSquad(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/DeleteSquad",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).DeleteSquad(ctx, req.(*SquadDeleteRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_ListSquad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SquadListRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).ListSquad(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/ListSquad",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).ListSquad(ctx, req.(*SquadListRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_ConnectSquad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SquadConnectRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).ConnectSquad(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/ConnectSquad",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).ConnectSquad(ctx, req.(*SquadConnectRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _GrpcManager_LeaveSquad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SquadLeaveRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(GrpcManagerServer).LeaveSquad(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/manager.GrpcManager/LeaveSquad",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(GrpcManagerServer).LeaveSquad(ctx, req.(*SquadLeaveRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GrpcManager_ServiceDesc is the grpc.ServiceDesc for GrpcManager service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var GrpcManager_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "manager.GrpcManager",
|
|
||||||
HandlerType: (*GrpcManagerServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{
|
|
||||||
{
|
|
||||||
MethodName: "RegisterPeer",
|
|
||||||
Handler: _GrpcManager_RegisterPeer_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "ListPeers",
|
|
||||||
Handler: _GrpcManager_ListPeers_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "CreateSquad",
|
|
||||||
Handler: _GrpcManager_CreateSquad_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "UpdateSquad",
|
|
||||||
Handler: _GrpcManager_UpdateSquad_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "DeleteSquad",
|
|
||||||
Handler: _GrpcManager_DeleteSquad_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "ListSquad",
|
|
||||||
Handler: _GrpcManager_ListSquad_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "ConnectSquad",
|
|
||||||
Handler: _GrpcManager_ConnectSquad_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "LeaveSquad",
|
|
||||||
Handler: _GrpcManager_LeaveSquad_Handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Streams: []grpc.StreamDesc{
|
|
||||||
{
|
|
||||||
StreamName: "Link",
|
|
||||||
Handler: _GrpcManager_Link_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
ClientStreams: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Metadata: "grpc_manager.proto",
|
|
||||||
}
|
|
||||||
1658
node.pb.go
Normal file
1658
node.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
357
node_grpc.pb.go
Normal file
357
node_grpc.pb.go
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
|
// - protoc v3.14.0
|
||||||
|
// source: node.proto
|
||||||
|
|
||||||
|
package localserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
|
// NodeServiceClient is the client API for NodeService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type NodeServiceClient interface {
|
||||||
|
CreateNode(ctx context.Context, in *CreateNodeRequest, opts ...grpc.CallOption) (*CreateNodeResponse, error)
|
||||||
|
GetNodes(ctx context.Context, in *GetNodesRequest, opts ...grpc.CallOption) (*GetNodesResponse, error)
|
||||||
|
GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error)
|
||||||
|
DeleteNode(ctx context.Context, in *DeleteNodeRequest, opts ...grpc.CallOption) (*DeleteNodeResponse, error)
|
||||||
|
NewPeerOperatorRequest(ctx context.Context, in *AddPeerOperatorRequest, opts ...grpc.CallOption) (*AddPeerOperatorResponse, error)
|
||||||
|
DeletePeerOperatorRequest(ctx context.Context, in *RejectPeerOperatorRequest, opts ...grpc.CallOption) (*RejectPeerOperatorResponse, error)
|
||||||
|
AcceptNewPeerOperator(ctx context.Context, in *AcceptPeerOperatorRequest, opts ...grpc.CallOption) (*AcceptPeerOperatorResponse, error)
|
||||||
|
RemovePeerOperator(ctx context.Context, in *RemovePeerOperatorRequest, opts ...grpc.CallOption) (*RemovePeerOperatorResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNodeServiceClient(cc grpc.ClientConnInterface) NodeServiceClient {
|
||||||
|
return &nodeServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) CreateNode(ctx context.Context, in *CreateNodeRequest, opts ...grpc.CallOption) (*CreateNodeResponse, error) {
|
||||||
|
out := new(CreateNodeResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/CreateNode", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) GetNodes(ctx context.Context, in *GetNodesRequest, opts ...grpc.CallOption) (*GetNodesResponse, error) {
|
||||||
|
out := new(GetNodesResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/GetNodes", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error) {
|
||||||
|
out := new(GetNodeResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/GetNode", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) DeleteNode(ctx context.Context, in *DeleteNodeRequest, opts ...grpc.CallOption) (*DeleteNodeResponse, error) {
|
||||||
|
out := new(DeleteNodeResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/DeleteNode", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) NewPeerOperatorRequest(ctx context.Context, in *AddPeerOperatorRequest, opts ...grpc.CallOption) (*AddPeerOperatorResponse, error) {
|
||||||
|
out := new(AddPeerOperatorResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/NewPeerOperatorRequest", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) DeletePeerOperatorRequest(ctx context.Context, in *RejectPeerOperatorRequest, opts ...grpc.CallOption) (*RejectPeerOperatorResponse, error) {
|
||||||
|
out := new(RejectPeerOperatorResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/DeletePeerOperatorRequest", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) AcceptNewPeerOperator(ctx context.Context, in *AcceptPeerOperatorRequest, opts ...grpc.CallOption) (*AcceptPeerOperatorResponse, error) {
|
||||||
|
out := new(AcceptPeerOperatorResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/AcceptNewPeerOperator", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeServiceClient) RemovePeerOperator(ctx context.Context, in *RemovePeerOperatorRequest, opts ...grpc.CallOption) (*RemovePeerOperatorResponse, error) {
|
||||||
|
out := new(RemovePeerOperatorResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/node.NodeService/RemovePeerOperator", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeServiceServer is the server API for NodeService service.
|
||||||
|
// All implementations must embed UnimplementedNodeServiceServer
|
||||||
|
// for forward compatibility
|
||||||
|
type NodeServiceServer interface {
|
||||||
|
CreateNode(context.Context, *CreateNodeRequest) (*CreateNodeResponse, error)
|
||||||
|
GetNodes(context.Context, *GetNodesRequest) (*GetNodesResponse, error)
|
||||||
|
GetNode(context.Context, *GetNodeRequest) (*GetNodeResponse, error)
|
||||||
|
DeleteNode(context.Context, *DeleteNodeRequest) (*DeleteNodeResponse, error)
|
||||||
|
NewPeerOperatorRequest(context.Context, *AddPeerOperatorRequest) (*AddPeerOperatorResponse, error)
|
||||||
|
DeletePeerOperatorRequest(context.Context, *RejectPeerOperatorRequest) (*RejectPeerOperatorResponse, error)
|
||||||
|
AcceptNewPeerOperator(context.Context, *AcceptPeerOperatorRequest) (*AcceptPeerOperatorResponse, error)
|
||||||
|
RemovePeerOperator(context.Context, *RemovePeerOperatorRequest) (*RemovePeerOperatorResponse, error)
|
||||||
|
mustEmbedUnimplementedNodeServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedNodeServiceServer must be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedNodeServiceServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedNodeServiceServer) CreateNode(context.Context, *CreateNodeRequest) (*CreateNodeResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CreateNode not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) GetNodes(context.Context, *GetNodesRequest) (*GetNodesResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetNodes not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) GetNode(context.Context, *GetNodeRequest) (*GetNodeResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetNode not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) DeleteNode(context.Context, *DeleteNodeRequest) (*DeleteNodeResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method DeleteNode not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) NewPeerOperatorRequest(context.Context, *AddPeerOperatorRequest) (*AddPeerOperatorResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method NewPeerOperatorRequest not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) DeletePeerOperatorRequest(context.Context, *RejectPeerOperatorRequest) (*RejectPeerOperatorResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method DeletePeerOperatorRequest not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) AcceptNewPeerOperator(context.Context, *AcceptPeerOperatorRequest) (*AcceptPeerOperatorResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method AcceptNewPeerOperator not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) RemovePeerOperator(context.Context, *RemovePeerOperatorRequest) (*RemovePeerOperatorResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method RemovePeerOperator not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {}
|
||||||
|
|
||||||
|
// UnsafeNodeServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to NodeServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeNodeServiceServer interface {
|
||||||
|
mustEmbedUnimplementedNodeServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterNodeServiceServer(s grpc.ServiceRegistrar, srv NodeServiceServer) {
|
||||||
|
s.RegisterService(&NodeService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_CreateNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CreateNodeRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).CreateNode(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/CreateNode",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).CreateNode(ctx, req.(*CreateNodeRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_GetNodes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetNodesRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).GetNodes(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/GetNodes",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).GetNodes(ctx, req.(*GetNodesRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_GetNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetNodeRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).GetNode(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/GetNode",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).GetNode(ctx, req.(*GetNodeRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_DeleteNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(DeleteNodeRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).DeleteNode(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/DeleteNode",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).DeleteNode(ctx, req.(*DeleteNodeRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_NewPeerOperatorRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(AddPeerOperatorRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).NewPeerOperatorRequest(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/NewPeerOperatorRequest",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).NewPeerOperatorRequest(ctx, req.(*AddPeerOperatorRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_DeletePeerOperatorRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(RejectPeerOperatorRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).DeletePeerOperatorRequest(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/DeletePeerOperatorRequest",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).DeletePeerOperatorRequest(ctx, req.(*RejectPeerOperatorRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_AcceptNewPeerOperator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(AcceptPeerOperatorRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).AcceptNewPeerOperator(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/AcceptNewPeerOperator",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).AcceptNewPeerOperator(ctx, req.(*AcceptPeerOperatorRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NodeService_RemovePeerOperator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(RemovePeerOperatorRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NodeServiceServer).RemovePeerOperator(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/node.NodeService/RemovePeerOperator",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NodeServiceServer).RemovePeerOperator(ctx, req.(*RemovePeerOperatorRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeService_ServiceDesc is the grpc.ServiceDesc for NodeService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var NodeService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "node.NodeService",
|
||||||
|
HandlerType: (*NodeServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "CreateNode",
|
||||||
|
Handler: _NodeService_CreateNode_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetNodes",
|
||||||
|
Handler: _NodeService_GetNodes_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetNode",
|
||||||
|
Handler: _NodeService_GetNode_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "DeleteNode",
|
||||||
|
Handler: _NodeService_DeleteNode_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "NewPeerOperatorRequest",
|
||||||
|
Handler: _NodeService_NewPeerOperatorRequest_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "DeletePeerOperatorRequest",
|
||||||
|
Handler: _NodeService_DeletePeerOperatorRequest_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "AcceptNewPeerOperator",
|
||||||
|
Handler: _NodeService_AcceptNewPeerOperator_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "RemovePeerOperator",
|
||||||
|
Handler: _NodeService_RemovePeerOperator_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "node.proto",
|
||||||
|
}
|
||||||
120
proto/node.proto
Normal file
120
proto/node.proto
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package node;
|
||||||
|
option go_package = ".;localserver";
|
||||||
|
|
||||||
|
enum NodeAuthType {
|
||||||
|
token = 0;
|
||||||
|
key = 1;
|
||||||
|
mac = 2;
|
||||||
|
none = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message NodeAuthParams {
|
||||||
|
string nodeId = 1;
|
||||||
|
string authKey = 2;
|
||||||
|
NodeAuthType authType = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OperatorAuthParams {
|
||||||
|
string operatorId = 1;
|
||||||
|
string authKey = 2;
|
||||||
|
NodeAuthType authType = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Node {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string pubKey = 3;
|
||||||
|
bool active = 4;
|
||||||
|
repeated string operators = 5;
|
||||||
|
repeated string operatorRequests = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateNodeRequest {
|
||||||
|
string nodeId = 1;
|
||||||
|
string nodeKey = 2;
|
||||||
|
string nodeUsername = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateNodeResponse {
|
||||||
|
bool success = 1;
|
||||||
|
string nodeId = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetNodesRequest {
|
||||||
|
OperatorAuthParams authParams = 1;
|
||||||
|
int64 lastIndex = 2;
|
||||||
|
int64 limit = 3;
|
||||||
|
}
|
||||||
|
message GetNodesResponse {
|
||||||
|
repeated Node nodes = 1;
|
||||||
|
bool success = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetNodeRequest {
|
||||||
|
string nodeId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetNodeResponse {
|
||||||
|
Node node = 1;
|
||||||
|
bool success = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteNodeRequest {
|
||||||
|
NodeAuthParams authParams = 1;
|
||||||
|
string nodeId = 2;
|
||||||
|
}
|
||||||
|
message DeleteNodeResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddPeerOperatorRequest {
|
||||||
|
OperatorAuthParams authParams = 1;
|
||||||
|
string nodeId = 2;
|
||||||
|
string operatorId = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddPeerOperatorResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RejectPeerOperatorRequest {
|
||||||
|
NodeAuthParams authParams = 1;
|
||||||
|
string nodeId = 2;
|
||||||
|
string operatorId = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RejectPeerOperatorResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AcceptPeerOperatorRequest {
|
||||||
|
NodeAuthParams authParams = 1;
|
||||||
|
string nodeId = 2;
|
||||||
|
string operatorId = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AcceptPeerOperatorResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RemovePeerOperatorRequest {
|
||||||
|
OperatorAuthParams authParams = 1;
|
||||||
|
string nodeId = 2;
|
||||||
|
string operatorId = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RemovePeerOperatorResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service NodeService {
|
||||||
|
rpc CreateNode (CreateNodeRequest) returns (CreateNodeResponse);
|
||||||
|
rpc GetNodes (GetNodesRequest) returns (GetNodesResponse);
|
||||||
|
rpc GetNode (GetNodeRequest) returns (GetNodeResponse);
|
||||||
|
rpc DeleteNode (DeleteNodeRequest) returns (DeleteNodeResponse);
|
||||||
|
rpc NewPeerOperatorRequest (AddPeerOperatorRequest) returns (AddPeerOperatorResponse);
|
||||||
|
rpc DeletePeerOperatorRequest (RejectPeerOperatorRequest) returns (RejectPeerOperatorResponse);
|
||||||
|
rpc AcceptNewPeerOperator (AcceptPeerOperatorRequest) returns (AcceptPeerOperatorResponse);
|
||||||
|
rpc RemovePeerOperator (RemovePeerOperatorRequest) returns (RemovePeerOperatorResponse);
|
||||||
|
}
|
||||||
26
proto/signaling.proto
Normal file
26
proto/signaling.proto
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package signaling;
|
||||||
|
option go_package = ".;localserver";
|
||||||
|
|
||||||
|
message NotifyRequest {
|
||||||
|
string from = 1;
|
||||||
|
string to = 2;
|
||||||
|
string type = 3;
|
||||||
|
bytes payload = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message NotifyResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignalingMessage {
|
||||||
|
string type = 1;
|
||||||
|
string from = 2;
|
||||||
|
string to = 3;
|
||||||
|
bytes payload = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
service SignalingService {
|
||||||
|
rpc Notify (NotifyRequest) returns (NotifyResponse);
|
||||||
|
rpc Link (stream SignalingMessage) returns (stream SignalingMessage);
|
||||||
|
}
|
||||||
83
server.go
83
server.go
@ -2,6 +2,8 @@ package localserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -41,8 +43,8 @@ type (
|
|||||||
Process(ctx context.Context, req *http.Request, w http.ResponseWriter) (err error)
|
Process(ctx context.Context, req *http.Request, w http.ResponseWriter) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
GrpcClientManagerMiddleware interface {
|
SignalingClientManagerMiddleware interface {
|
||||||
Process(ctx context.Context, req *Response, stream GrpcManager_LinkClient) (err error)
|
Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalServerHandler struct {
|
LocalServerHandler struct {
|
||||||
@ -51,14 +53,14 @@ type (
|
|||||||
|
|
||||||
LocalServer struct {
|
LocalServer struct {
|
||||||
ID string
|
ID string
|
||||||
GrpcClientManager *GrpcClientManager
|
GrpcClientManager *SignalingClientManager
|
||||||
}
|
}
|
||||||
|
|
||||||
GrpcClientManager struct {
|
SignalingClientManager struct {
|
||||||
GrpcConn grpc.ClientConnInterface
|
GrpcConn grpc.ClientConnInterface
|
||||||
GrpcManagerClient GrpcManagerClient
|
SignalingManagerClient SignalingServiceClient
|
||||||
GrpcLinkClient GrpcManager_LinkClient
|
GrpcLinkClient SignalingService_LinkClient
|
||||||
middlewares []GrpcClientManagerMiddleware
|
middlewares []SignalingClientManagerMiddleware
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomMenuItem struct {
|
CustomMenuItem struct {
|
||||||
@ -77,72 +79,89 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLocalServer(addr string, grpcAddr string, id string, token string) (localServer *LocalServer, err error) {
|
func NewLocalServer(_ string, grpcAddr string, id string, token string) (localServer *LocalServer, err error) {
|
||||||
webRTCCallManager, err := NewWebRTCCallManager(id, token, NewWebrtcCallSoundManager(), NewWebrtcCallChatManager(), NewWebrtcCallVideoManager(), NewWebrtcCallFileManager())
|
webRTCCallManager, err := NewWebRTCCallManager(id, token, NewWebrtcCallSoundManager(), NewWebrtcCallChatManager(), NewWebrtcCallVideoManager(), NewWebrtcCallFileManager())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error from call manager")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zoneManager, err := NewZoneManager(id, token)
|
zoneManager, err := NewZoneManager(id, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error from zone manager")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
webrtcFsManager, err := NewWebrtcFsManager(NewP2PFSDatachannelManager())
|
webrtcFsManager, err := NewWebrtcFsManager(NewP2PFSDatachannelManager())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error from fs manager")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
webrtcGrpcMiddleware := NewWebRTCGrpcMiddleware(webRTCCallManager)
|
webrtcGrpcMiddleware := NewWebRTCGrpcMiddleware(webRTCCallManager)
|
||||||
ZoneGrpcMiddleware := NewZoneGrpcMiddleware(zoneManager)
|
ZoneGrpcMiddleware := NewZoneGrpcMiddleware(zoneManager)
|
||||||
webrtcFsMiddleware := NewWebRTCFsMiddleware(webrtcFsManager)
|
webrtcFsMiddleware := NewWebRTCFsMiddleware(webrtcFsManager)
|
||||||
grpcClientManager, err := NewGrpcClientManager(grpcAddr, id, webrtcGrpcMiddleware, ZoneGrpcMiddleware)
|
signalingClientManager, err := NewGrpcClientManager(grpcAddr, id, webrtcGrpcMiddleware, ZoneGrpcMiddleware)
|
||||||
webrtcGrpcMiddleware.stream = grpcClientManager.GrpcLinkClient
|
if err != nil {
|
||||||
webRTCCallManager.stream = grpcClientManager.GrpcLinkClient
|
return
|
||||||
zoneManager.stream = grpcClientManager.GrpcLinkClient
|
}
|
||||||
webrtcFsMiddleware.stream = grpcClientManager.GrpcLinkClient
|
webrtcGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
|
||||||
webrtcFsManager.stream = grpcClientManager.GrpcLinkClient
|
webRTCCallManager.stream = signalingClientManager.GrpcLinkClient
|
||||||
ZoneGrpcMiddleware.stream = grpcClientManager.GrpcLinkClient
|
zoneManager.stream = signalingClientManager.GrpcLinkClient
|
||||||
|
webrtcFsMiddleware.stream = signalingClientManager.GrpcLinkClient
|
||||||
|
webrtcFsManager.stream = signalingClientManager.GrpcLinkClient
|
||||||
|
ZoneGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
|
||||||
localServer = &LocalServer{
|
localServer = &LocalServer{
|
||||||
ID: id,
|
ID: id,
|
||||||
GrpcClientManager: grpcClientManager,
|
GrpcClientManager: signalingClientManager,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcClientManager(addr string, id string, middleware ...GrpcClientManagerMiddleware) (grpcClientManager *GrpcClientManager, err error) {
|
func NewGrpcClientManager(addr string, id string, middleware ...SignalingClientManagerMiddleware) (signalingClientManager *SignalingClientManager, err error) {
|
||||||
conn, grpcClient, grpcLinkClient, err := NewGrpcConn(addr, id)
|
conn, signalingClient, signalingLinkClient, err := NewGrpcConn(addr, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
grpcClientManager = &GrpcClientManager{
|
signalingClientManager = &SignalingClientManager{
|
||||||
GrpcConn: conn,
|
GrpcConn: conn,
|
||||||
GrpcManagerClient: grpcClient,
|
SignalingManagerClient: signalingClient,
|
||||||
GrpcLinkClient: grpcLinkClient,
|
GrpcLinkClient: signalingLinkClient,
|
||||||
middlewares: middleware,
|
middlewares: middleware,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcConn(addr string, id string) (conn grpc.ClientConnInterface, grpcClient GrpcManagerClient, grpcLinkClient GrpcManager_LinkClient, err error) {
|
func NewGrpcConn(addr string, id string) (conn grpc.ClientConnInterface, signalingClient SignalingServiceClient, signalingLinkClient SignalingService_LinkClient, err error) {
|
||||||
var cert = filepath.Join("config", "cert.pem")
|
var cert = filepath.Join("config", "fullchain.pem")
|
||||||
creds, err := credentials.NewClientTLSFromFile(cert, "dev.zippytal.com")
|
creds, err := credentials.NewClientTLSFromFile(cert, "dev.zippytal.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("there")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var opts []grpc.DialOption = []grpc.DialOption{grpc.WithTransportCredentials(creds)}
|
var opts []grpc.DialOption = []grpc.DialOption{grpc.WithTransportCredentials(creds)}
|
||||||
conn, err = grpc.Dial(addr, opts...)
|
conn, err = grpc.Dial(addr, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("over there")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
grpcClient = NewGrpcManagerClient(conn)
|
signalingClient = NewSignalingServiceClient(conn)
|
||||||
grpcLinkClient, err = grpcClient.Link(context.Background())
|
signalingLinkClient, err = signalingClient.Link(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("really there")
|
||||||
|
logger.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payload := map[string]any{
|
||||||
|
"init": "init",
|
||||||
|
}
|
||||||
|
bs, err := json.Marshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = grpcLinkClient.Send(&Request{
|
if err = signalingLinkClient.Send(&SignalingMessage{
|
||||||
Type: "init",
|
Type: "init",
|
||||||
From: id,
|
From: id,
|
||||||
Payload: map[string]string{},
|
To: "server",
|
||||||
Token: "none",
|
Payload: bs,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -180,7 +199,7 @@ func (lsh *LocalServerHandler) ServeHTTP(w http.ResponseWriter, req *http.Reques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcm *GrpcClientManager) Handle(ctx context.Context) (err error) {
|
func (gcm *SignalingClientManager) Handle(ctx context.Context) (err error) {
|
||||||
done, errCh := make(chan struct{}), make(chan error)
|
done, errCh := make(chan struct{}), make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
@ -192,11 +211,11 @@ func (gcm *GrpcClientManager) Handle(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
for _, middleware := range gcm.middlewares {
|
for _, middleware := range gcm.middlewares {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(m GrpcClientManagerMiddleware) {
|
go func(m SignalingClientManagerMiddleware) {
|
||||||
|
defer wg.Done()
|
||||||
if err := m.Process(ctx, res, gcm.GrpcLinkClient); err != nil {
|
if err := m.Process(ctx, res, gcm.GrpcLinkClient); err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
}
|
}
|
||||||
wg.Done()
|
|
||||||
}(middleware)
|
}(middleware)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@ -212,8 +231,10 @@ func (gcm *GrpcClientManager) Handle(ctx context.Context) (err error) {
|
|||||||
err = ctx.Err()
|
err = ctx.Err()
|
||||||
return
|
return
|
||||||
case <-done:
|
case <-done:
|
||||||
|
logger.Println("done")
|
||||||
return
|
return
|
||||||
case err = <-errCh:
|
case err = <-errCh:
|
||||||
|
logger.Println("done with error")
|
||||||
if closeErr := gcm.GrpcLinkClient.CloseSend(); closeErr != nil {
|
if closeErr := gcm.GrpcLinkClient.CloseSend(); closeErr != nil {
|
||||||
return closeErr
|
return closeErr
|
||||||
}
|
}
|
||||||
|
|||||||
337
signaling.pb.go
Normal file
337
signaling.pb.go
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.28.0
|
||||||
|
// protoc v3.14.0
|
||||||
|
// source: signaling.proto
|
||||||
|
|
||||||
|
package localserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type NotifyRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"`
|
||||||
|
To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"`
|
||||||
|
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||||
|
Payload []byte `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) Reset() {
|
||||||
|
*x = NotifyRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_signaling_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NotifyRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_signaling_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NotifyRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*NotifyRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_signaling_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) GetFrom() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.From
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) GetTo() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.To
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyRequest) GetPayload() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Payload
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyResponse) Reset() {
|
||||||
|
*x = NotifyResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_signaling_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NotifyResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *NotifyResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_signaling_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NotifyResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*NotifyResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_signaling_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotifyResponse) GetSuccess() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Success
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignalingMessage struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||||
|
From string `protobuf:"bytes,2,opt,name=from,proto3" json:"from,omitempty"`
|
||||||
|
To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"`
|
||||||
|
Payload []byte `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) Reset() {
|
||||||
|
*x = SignalingMessage{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_signaling_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SignalingMessage) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_signaling_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SignalingMessage.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SignalingMessage) Descriptor() ([]byte, []int) {
|
||||||
|
return file_signaling_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) GetFrom() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.From
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) GetTo() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.To
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignalingMessage) GetPayload() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Payload
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_signaling_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_signaling_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x12, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x22, 0x61, 0x0a, 0x0d,
|
||||||
|
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
|
||||||
|
0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f,
|
||||||
|
0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74,
|
||||||
|
0x6f, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
|
||||||
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22,
|
||||||
|
0x2a, 0x0a, 0x0e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
|
0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x53,
|
||||||
|
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||||
|
0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
|
||||||
|
0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,
|
||||||
|
0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61,
|
||||||
|
0x64, 0x32, 0x97, 0x01, 0x0a, 0x10, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x53,
|
||||||
|
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
|
||||||
|
0x12, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x4e, 0x6f, 0x74,
|
||||||
|
0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x69, 0x67,
|
||||||
|
0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73,
|
||||||
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1b, 0x2e,
|
||||||
|
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c,
|
||||||
|
0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1b, 0x2e, 0x73, 0x69, 0x67,
|
||||||
|
0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x69, 0x6e, 0x67,
|
||||||
|
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x2e,
|
||||||
|
0x3b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_signaling_proto_rawDescOnce sync.Once
|
||||||
|
file_signaling_proto_rawDescData = file_signaling_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_signaling_proto_rawDescGZIP() []byte {
|
||||||
|
file_signaling_proto_rawDescOnce.Do(func() {
|
||||||
|
file_signaling_proto_rawDescData = protoimpl.X.CompressGZIP(file_signaling_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_signaling_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_signaling_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||||
|
var file_signaling_proto_goTypes = []interface{}{
|
||||||
|
(*NotifyRequest)(nil), // 0: signaling.NotifyRequest
|
||||||
|
(*NotifyResponse)(nil), // 1: signaling.NotifyResponse
|
||||||
|
(*SignalingMessage)(nil), // 2: signaling.SignalingMessage
|
||||||
|
}
|
||||||
|
var file_signaling_proto_depIdxs = []int32{
|
||||||
|
0, // 0: signaling.SignalingService.Notify:input_type -> signaling.NotifyRequest
|
||||||
|
2, // 1: signaling.SignalingService.Link:input_type -> signaling.SignalingMessage
|
||||||
|
1, // 2: signaling.SignalingService.Notify:output_type -> signaling.NotifyResponse
|
||||||
|
2, // 3: signaling.SignalingService.Link:output_type -> signaling.SignalingMessage
|
||||||
|
2, // [2:4] is the sub-list for method output_type
|
||||||
|
0, // [0:2] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_signaling_proto_init() }
|
||||||
|
func file_signaling_proto_init() {
|
||||||
|
if File_signaling_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_signaling_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NotifyRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_signaling_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NotifyResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_signaling_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*SignalingMessage); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_signaling_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 3,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_signaling_proto_goTypes,
|
||||||
|
DependencyIndexes: file_signaling_proto_depIdxs,
|
||||||
|
MessageInfos: file_signaling_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_signaling_proto = out.File
|
||||||
|
file_signaling_proto_rawDesc = nil
|
||||||
|
file_signaling_proto_goTypes = nil
|
||||||
|
file_signaling_proto_depIdxs = nil
|
||||||
|
}
|
||||||
174
signaling_grpc.pb.go
Normal file
174
signaling_grpc.pb.go
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
|
// - protoc v3.14.0
|
||||||
|
// source: signaling.proto
|
||||||
|
|
||||||
|
package localserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
|
// SignalingServiceClient is the client API for SignalingService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type SignalingServiceClient interface {
|
||||||
|
Notify(ctx context.Context, in *NotifyRequest, opts ...grpc.CallOption) (*NotifyResponse, error)
|
||||||
|
Link(ctx context.Context, opts ...grpc.CallOption) (SignalingService_LinkClient, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type signalingServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSignalingServiceClient(cc grpc.ClientConnInterface) SignalingServiceClient {
|
||||||
|
return &signalingServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *signalingServiceClient) Notify(ctx context.Context, in *NotifyRequest, opts ...grpc.CallOption) (*NotifyResponse, error) {
|
||||||
|
out := new(NotifyResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/signaling.SignalingService/Notify", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *signalingServiceClient) Link(ctx context.Context, opts ...grpc.CallOption) (SignalingService_LinkClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &SignalingService_ServiceDesc.Streams[0], "/signaling.SignalingService/Link", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &signalingServiceLinkClient{stream}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignalingService_LinkClient interface {
|
||||||
|
Send(*SignalingMessage) error
|
||||||
|
Recv() (*SignalingMessage, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type signalingServiceLinkClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *signalingServiceLinkClient) Send(m *SignalingMessage) error {
|
||||||
|
return x.ClientStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *signalingServiceLinkClient) Recv() (*SignalingMessage, error) {
|
||||||
|
m := new(SignalingMessage)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignalingServiceServer is the server API for SignalingService service.
|
||||||
|
// All implementations must embed UnimplementedSignalingServiceServer
|
||||||
|
// for forward compatibility
|
||||||
|
type SignalingServiceServer interface {
|
||||||
|
Notify(context.Context, *NotifyRequest) (*NotifyResponse, error)
|
||||||
|
Link(SignalingService_LinkServer) error
|
||||||
|
mustEmbedUnimplementedSignalingServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedSignalingServiceServer must be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedSignalingServiceServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedSignalingServiceServer) Notify(context.Context, *NotifyRequest) (*NotifyResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Notify not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedSignalingServiceServer) Link(SignalingService_LinkServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method Link not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedSignalingServiceServer) mustEmbedUnimplementedSignalingServiceServer() {}
|
||||||
|
|
||||||
|
// UnsafeSignalingServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to SignalingServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeSignalingServiceServer interface {
|
||||||
|
mustEmbedUnimplementedSignalingServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterSignalingServiceServer(s grpc.ServiceRegistrar, srv SignalingServiceServer) {
|
||||||
|
s.RegisterService(&SignalingService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SignalingService_Notify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(NotifyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(SignalingServiceServer).Notify(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/signaling.SignalingService/Notify",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(SignalingServiceServer).Notify(ctx, req.(*NotifyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SignalingService_Link_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
return srv.(SignalingServiceServer).Link(&signalingServiceLinkServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignalingService_LinkServer interface {
|
||||||
|
Send(*SignalingMessage) error
|
||||||
|
Recv() (*SignalingMessage, error)
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type signalingServiceLinkServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *signalingServiceLinkServer) Send(m *SignalingMessage) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *signalingServiceLinkServer) Recv() (*SignalingMessage, error) {
|
||||||
|
m := new(SignalingMessage)
|
||||||
|
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignalingService_ServiceDesc is the grpc.ServiceDesc for SignalingService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var SignalingService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "signaling.SignalingService",
|
||||||
|
HandlerType: (*SignalingServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Notify",
|
||||||
|
Handler: _SignalingService_Notify_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{
|
||||||
|
{
|
||||||
|
StreamName: "Link",
|
||||||
|
Handler: _SignalingService_Link_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
ClientStreams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metadata: "signaling.proto",
|
||||||
|
}
|
||||||
@ -36,7 +36,7 @@ type Squad struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WebRTCCallManager struct {
|
type WebRTCCallManager struct {
|
||||||
stream GrpcManager_LinkClient
|
stream SignalingService_LinkClient
|
||||||
middlewares []WebrtcCallEventManager
|
middlewares []WebrtcCallEventManager
|
||||||
ID string
|
ID string
|
||||||
LocalSD map[string]*webrtc.SessionDescription
|
LocalSD map[string]*webrtc.SessionDescription
|
||||||
@ -65,6 +65,7 @@ type IncomingCandidate struct {
|
|||||||
|
|
||||||
type RTCPeerConnection struct {
|
type RTCPeerConnection struct {
|
||||||
*webrtc.PeerConnection
|
*webrtc.PeerConnection
|
||||||
|
id string
|
||||||
makingOffer bool
|
makingOffer bool
|
||||||
negotiate func(string, string)
|
negotiate func(string, string)
|
||||||
makingOfferLock *sync.Mutex
|
makingOfferLock *sync.Mutex
|
||||||
@ -131,10 +132,13 @@ func NewWebRTCCallManager(id string, token string, eventHandlers ...WebrtcCallEv
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadHostedSquads(token string, hostId string) (squads []*Squad, err error) {
|
func loadHostedSquads(token string, hostId string) (squads []*Squad, err error) {
|
||||||
|
em := NewEncryptionManager()
|
||||||
|
sig := em.SignRequestHMAC(hostId)
|
||||||
body, err := json.Marshal(map[string]interface{}{
|
body, err := json.Marshal(map[string]interface{}{
|
||||||
"type": LIST_HOSTED_SQUADS_BY_HOST,
|
"type": LIST_HOSTED_SQUADS_BY_HOST,
|
||||||
"token": token,
|
"mac": sig,
|
||||||
"from": hostId,
|
"from": hostId,
|
||||||
|
"peerType":"node",
|
||||||
"payload": map[string]string{
|
"payload": map[string]string{
|
||||||
"host": hostId,
|
"host": hostId,
|
||||||
"lastIndex": "0",
|
"lastIndex": "0",
|
||||||
@ -143,7 +147,6 @@ func loadHostedSquads(token string, hostId string) (squads []*Squad, err error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := http.Post("https://app.zippytal.com/req", "application/json", bytes.NewBuffer(body))
|
res, err := http.Post("https://app.zippytal.com/req", "application/json", bytes.NewBuffer(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println("error come from there in webrtc call manager")
|
logger.Println("error come from there in webrtc call manager")
|
||||||
@ -153,7 +156,29 @@ func loadHostedSquads(token string, hostId string) (squads []*Squad, err error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(bs, &squads)
|
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 (wm *WebRTCCallManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
|
||||||
|
bs, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = wm.stream.Send(&SignalingMessage{
|
||||||
|
Type: messageType,
|
||||||
|
From: from,
|
||||||
|
To: to,
|
||||||
|
Payload: bs,
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,20 +204,15 @@ func (wm *WebRTCCallManager) CreateOffer(ctx context.Context, target string, fro
|
|||||||
negotiate: wm.negotiate,
|
negotiate: wm.negotiate,
|
||||||
}
|
}
|
||||||
wm.RTCPeerConnectionMapMux.Unlock()
|
wm.RTCPeerConnectionMapMux.Unlock()
|
||||||
err = wm.stream.Send(&Request{
|
err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_OFFER), wm.ID, target, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_OFFER),
|
|
||||||
From: wm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": target,
|
"to": target,
|
||||||
"from": wm.ID,
|
"from": wm.ID,
|
||||||
"sdp": rawOffer.SDP,
|
"sdp": rawOffer.SDP,
|
||||||
},
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *WebRTCCallManager) HandleOffer(ctx context.Context, req map[string]string, cb OnICECandidateFunc) (err error) {
|
func (wm *WebRTCCallManager) HandleOffer(ctx context.Context, from, to string, req map[string]string, cb OnICECandidateFunc) (err error) {
|
||||||
done, errCh := make(chan struct{}), make(chan error)
|
done, errCh := make(chan struct{}), make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
if _, ok := wm.Squads[req[SQUAD_ID]]; !ok {
|
if _, ok := wm.Squads[req[SQUAD_ID]]; !ok {
|
||||||
@ -200,13 +220,13 @@ func (wm *WebRTCCallManager) HandleOffer(ctx context.Context, req map[string]str
|
|||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peerConnection, err := wm.createPeerConnection(req[FROM], req[TO], req[SQUAD_ID], webrtc.SDPTypeAnswer, cb)
|
peerConnection, err := wm.createPeerConnection(from, to, req[SQUAD_ID], webrtc.SDPTypeAnswer, cb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wm.RTCPeerConnectionMapMux.Lock()
|
wm.RTCPeerConnectionMapMux.Lock()
|
||||||
wm.RTCPeerConnections[req[FROM]] = &RTCPeerConnection{
|
wm.RTCPeerConnections[from] = &RTCPeerConnection{
|
||||||
PeerConnection: peerConnection,
|
PeerConnection: peerConnection,
|
||||||
makingOffer: false,
|
makingOffer: false,
|
||||||
makingOfferLock: &sync.Mutex{},
|
makingOfferLock: &sync.Mutex{},
|
||||||
@ -227,20 +247,19 @@ func (wm *WebRTCCallManager) HandleOffer(ctx context.Context, req map[string]str
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
wm.LocalSDMapMux.Lock()
|
wm.LocalSDMapMux.Lock()
|
||||||
wm.LocalSD[req[FROM]] = &rawAnswer
|
wm.LocalSD[from] = &rawAnswer
|
||||||
wm.LocalSDMapMux.Unlock()
|
wm.LocalSDMapMux.Unlock()
|
||||||
|
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
wm.SquadMapMux.Lock()
|
wm.SquadMapMux.Lock()
|
||||||
wm.Squads[req[SQUAD_ID]].Members = append(wm.Squads[req[SQUAD_ID]].Members, req[FROM])
|
wm.Squads[req[SQUAD_ID]].Members = append(wm.Squads[req[SQUAD_ID]].Members, from)
|
||||||
wm.SquadMapMux.Unlock()
|
wm.SquadMapMux.Unlock()
|
||||||
if err = wm.stream.Send(&Request{
|
if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_ANSWER), wm.ID, from, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_ANSWER),
|
"to": from,
|
||||||
From: wm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": req[FROM],
|
|
||||||
"from": wm.ID,
|
"from": wm.ID,
|
||||||
"sdp": rawAnswer.SDP,
|
"sdp": rawAnswer.SDP,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
@ -258,7 +277,7 @@ func (wm *WebRTCCallManager) HandleOffer(ctx context.Context, req map[string]str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *WebRTCCallManager) HandleAnswer(ctx context.Context, req map[string]string) (err error) {
|
func (wm *WebRTCCallManager) HandleAnswer(ctx context.Context, from, to string, req map[string]string) (err error) {
|
||||||
wm.RTCPeerConnectionMapMux.Lock()
|
wm.RTCPeerConnectionMapMux.Lock()
|
||||||
defer wm.RTCPeerConnectionMapMux.Unlock()
|
defer wm.RTCPeerConnectionMapMux.Unlock()
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -266,11 +285,11 @@ func (wm *WebRTCCallManager) HandleAnswer(ctx context.Context, req map[string]st
|
|||||||
logger.Printf("recover from panic in handle answer : %v\n", r)
|
logger.Printf("recover from panic in handle answer : %v\n", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if _, ok := wm.RTCPeerConnections[req[FROM]]; !ok {
|
if _, ok := wm.RTCPeerConnections[from]; !ok {
|
||||||
err = fmt.Errorf("no corresponding peer connection for id : %s", req[FROM])
|
err = fmt.Errorf("no corresponding peer connection for id : %s", from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peerConnnection := wm.RTCPeerConnections[req[FROM]]
|
peerConnnection := wm.RTCPeerConnections[from]
|
||||||
logger.Println("---------------------")
|
logger.Println("---------------------")
|
||||||
logger.Println(req[SDP])
|
logger.Println(req[SDP])
|
||||||
logger.Println("---------------------")
|
logger.Println("---------------------")
|
||||||
@ -281,31 +300,21 @@ func (wm *WebRTCCallManager) HandleAnswer(ctx context.Context, req map[string]st
|
|||||||
logger.Println("error occured while setting remote description in handle answer")
|
logger.Println("error occured while setting remote description in handle answer")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = wm.stream.Send(&Request{
|
if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER), wm.ID, from, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER),
|
|
||||||
From: wm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": wm.ID,
|
"from": wm.ID,
|
||||||
"to": req[FROM],
|
"to": from,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wm.CandidateMux.Lock()
|
wm.CandidateMux.Lock()
|
||||||
for _, candidate := range wm.PendingCandidates[req[FROM]] {
|
for _, candidate := range wm.PendingCandidates[from] {
|
||||||
logger.Println("sending candidate from answer to", req[FROM])
|
logger.Println("sending candidate from answer to", from)
|
||||||
if err = wm.stream.Send(&Request{
|
if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_CANDIDATE), wm.ID, from, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
|
|
||||||
From: wm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": wm.ID,
|
"from": wm.ID,
|
||||||
"to": req[FROM],
|
"to": from,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
wm.CandidateMux.Unlock()
|
wm.CandidateMux.Unlock()
|
||||||
return
|
return
|
||||||
@ -313,53 +322,48 @@ func (wm *WebRTCCallManager) HandleAnswer(ctx context.Context, req map[string]st
|
|||||||
}
|
}
|
||||||
wm.CandidateMux.Unlock()
|
wm.CandidateMux.Unlock()
|
||||||
wm.CandidateMux.Lock()
|
wm.CandidateMux.Lock()
|
||||||
delete(wm.PendingCandidates, req[FROM])
|
delete(wm.PendingCandidates, from)
|
||||||
wm.CandidateMux.Unlock()
|
wm.CandidateMux.Unlock()
|
||||||
wm.LocalSDMapMux.Lock()
|
wm.LocalSDMapMux.Lock()
|
||||||
delete(wm.LocalSD, req[FROM])
|
delete(wm.LocalSD, from)
|
||||||
wm.LocalSDMapMux.Unlock()
|
wm.LocalSDMapMux.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *WebRTCCallManager) HandleCounterOffer(ctx context.Context, req map[string]string) (err error) {
|
func (wm *WebRTCCallManager) HandleCounterOffer(ctx context.Context, from, to string, req map[string]string) (err error) {
|
||||||
wm.RTCPeerConnectionMapMux.Lock()
|
wm.RTCPeerConnectionMapMux.Lock()
|
||||||
if _, ok := wm.RTCPeerConnections[req[FROM]]; !ok {
|
if _, ok := wm.RTCPeerConnections[from]; !ok {
|
||||||
err = fmt.Errorf("no field corresponding peer connection for id %s", req[FROM])
|
err = fmt.Errorf("no field corresponding peer connection for id %s", from)
|
||||||
wm.RTCPeerConnectionMapMux.Unlock()
|
wm.RTCPeerConnectionMapMux.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("handling counter offer")
|
logger.Println("handling counter offer")
|
||||||
connection := wm.RTCPeerConnections[req[FROM]]
|
//connection := wm.RTCPeerConnections[from]
|
||||||
wm.RTCPeerConnectionMapMux.Unlock()
|
wm.RTCPeerConnectionMapMux.Unlock()
|
||||||
wm.LocalSDMapMux.Lock()
|
// wm.LocalSDMapMux.Lock()
|
||||||
if err = connection.SetLocalDescription(*wm.LocalSD[req[FROM]]); err != nil {
|
// if err = connection.SetLocalDescription(*wm.LocalSD[from]); err != nil {
|
||||||
wm.LocalSDMapMux.Unlock()
|
// wm.LocalSDMapMux.Unlock()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
wm.LocalSDMapMux.Unlock()
|
// wm.LocalSDMapMux.Unlock()
|
||||||
wm.CandidateMux.Lock()
|
wm.CandidateMux.Lock()
|
||||||
for _, candidate := range wm.PendingCandidates[req[FROM]] {
|
for _, candidate := range wm.PendingCandidates[from] {
|
||||||
logger.Println("sending candidate to", req[FROM])
|
logger.Println("sending candidate to", from)
|
||||||
if err = wm.stream.Send(&Request{
|
if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_CANDIDATE), wm.ID, from, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
|
|
||||||
From: wm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": wm.ID,
|
"from": wm.ID,
|
||||||
"to": req[FROM],
|
"to": from,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
wm.CandidateMux.Unlock()
|
wm.CandidateMux.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(wm.PendingCandidates, req[FROM])
|
delete(wm.PendingCandidates, from)
|
||||||
wm.CandidateMux.Unlock()
|
wm.CandidateMux.Unlock()
|
||||||
wm.LocalSDMapMux.Lock()
|
wm.LocalSDMapMux.Lock()
|
||||||
delete(wm.LocalSD, req[FROM])
|
delete(wm.LocalSD, from)
|
||||||
wm.LocalSDMapMux.Unlock()
|
wm.LocalSDMapMux.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -645,14 +649,9 @@ func (wm *WebRTCCallManager) HandleRennegotiationOffer(from string, sdp string)
|
|||||||
if err = wm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
if err = wm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = wm.stream.Send(&Request{
|
if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER), wm.ID, from, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER),
|
|
||||||
From: wm.ID,
|
|
||||||
Token: "",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": from,
|
"to": from,
|
||||||
"sdp": localSd.SDP,
|
"sdp": localSd.SDP,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return
|
return
|
||||||
@ -828,14 +827,9 @@ func (wm *WebRTCCallManager) negotiate(target string, squadId string) {
|
|||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = wm.stream.Send(&Request{
|
if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER), wm.ID, id, map[string]interface{}{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER),
|
|
||||||
From: wm.ID,
|
|
||||||
Token: "",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": id,
|
"to": id,
|
||||||
"sdp": localSd.SDP,
|
"sdp": localSd.SDP,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -5,14 +5,13 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
|
||||||
sync "sync"
|
sync "sync"
|
||||||
|
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebrtcFsManager struct {
|
type WebrtcFsManager struct {
|
||||||
stream GrpcManager_LinkClient
|
stream SignalingService_LinkClient
|
||||||
DatachannelManager DataChannelManager
|
DatachannelManager DataChannelManager
|
||||||
LocalSD map[string]*webrtc.SessionDescription
|
LocalSD map[string]*webrtc.SessionDescription
|
||||||
RTCPeerConnections map[string]*webrtc.PeerConnection
|
RTCPeerConnections map[string]*webrtc.PeerConnection
|
||||||
@ -40,6 +39,20 @@ func NewWebrtcFsManager(dataChannelManager DataChannelManager) (webrtcFsManager
|
|||||||
return
|
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) {
|
func (wf *WebrtcFsManager) CreateOffer(ctx context.Context, target string, from string, cb OnICECandidateFunc) (err error) {
|
||||||
peerConnection, err := wf.createPeerConnection(target, from, webrtc.SDPTypeOffer, cb)
|
peerConnection, err := wf.createPeerConnection(target, from, webrtc.SDPTypeOffer, cb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -56,15 +69,10 @@ func (wf *WebrtcFsManager) CreateOffer(ctx context.Context, target string, from
|
|||||||
logger.Println("adding for target", target)
|
logger.Println("adding for target", target)
|
||||||
wf.RTCPeerConnections[target] = peerConnection
|
wf.RTCPeerConnections[target] = peerConnection
|
||||||
wf.RTCPeerConnectionMapMux.Unlock()
|
wf.RTCPeerConnectionMapMux.Unlock()
|
||||||
err = wf.stream.Send(&Request{
|
err = wf.sendSignalingMessage(string(WEBRTC_OFFER_FS), "lolo_local_serv", target, map[string]any{
|
||||||
Type: string(WEBRTC_OFFER_FS),
|
|
||||||
From: "lolo_local_serv",
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": target,
|
"to": target,
|
||||||
"from": "lolo_local_serv",
|
"from": "lolo_local_serv",
|
||||||
"sdp": rawOffer.SDP,
|
"sdp": rawOffer.SDP,
|
||||||
},
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -96,19 +104,19 @@ func (wf *WebrtcFsManager) HandleOffer(ctx context.Context, req map[string]strin
|
|||||||
wf.LocalSDMapMux.Lock()
|
wf.LocalSDMapMux.Lock()
|
||||||
wf.LocalSD[req[FROM]] = &rawAnswer
|
wf.LocalSD[req[FROM]] = &rawAnswer
|
||||||
wf.LocalSDMapMux.Unlock()
|
wf.LocalSDMapMux.Unlock()
|
||||||
if err = wf.stream.Send(&Request{
|
// if err = wf.stream.Send(&Request{
|
||||||
Type: string(WEBRTC_ANSWER_FS),
|
// Type: string(WEBRTC_ANSWER_FS),
|
||||||
From: "lolo_local_serv",
|
// From: "lolo_local_serv",
|
||||||
Token: "none",
|
// Token: "none",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"to": req[FROM],
|
// "to": req[FROM],
|
||||||
"from": "lolo_local_serv",
|
// "from": "lolo_local_serv",
|
||||||
"sdp": rawAnswer.SDP,
|
// "sdp": rawAnswer.SDP,
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
errCh <- err
|
// errCh <- err
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
@ -141,34 +149,34 @@ func (wf *WebrtcFsManager) HandleAnswer(ctx context.Context, req map[string]stri
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = wf.stream.Send(&Request{
|
// if err = wf.stream.Send(&Request{
|
||||||
Type: string(WEBRTC_COUNTER_OFFER_FS),
|
// Type: string(WEBRTC_COUNTER_OFFER_FS),
|
||||||
From: "lolo_local_serv",
|
// From: "lolo_local_serv",
|
||||||
Token: "none",
|
// Token: "none",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"from": "lolo_local_serv",
|
// "from": "lolo_local_serv",
|
||||||
"to": req[FROM],
|
// "to": req[FROM],
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
wf.CandidateMux.RLock()
|
wf.CandidateMux.RLock()
|
||||||
for _, candidate := range wf.PendingCandidates[req[FROM]] {
|
for range wf.PendingCandidates[req[FROM]] {
|
||||||
logger.Println("sending candidate to", req[FROM])
|
logger.Println("sending candidate to", req[FROM])
|
||||||
if err = wf.stream.Send(&Request{
|
// if err = wf.stream.Send(&Request{
|
||||||
Type: string(WEBRTC_CANDIDATE_FS),
|
// Type: string(WEBRTC_CANDIDATE_FS),
|
||||||
From: "lolo_local_serv",
|
// From: "lolo_local_serv",
|
||||||
Token: "none",
|
// Token: "none",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"from": "lolo_local_serv",
|
// "from": "lolo_local_serv",
|
||||||
"to": req[FROM],
|
// "to": req[FROM],
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
// "candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
// "sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
wf.CandidateMux.RUnlock()
|
wf.CandidateMux.RUnlock()
|
||||||
wf.CandidateMux.Lock()
|
wf.CandidateMux.Lock()
|
||||||
@ -194,22 +202,22 @@ func (wf *WebrtcFsManager) HandleCounterOffer(ctx context.Context, req map[strin
|
|||||||
}
|
}
|
||||||
wf.LocalSDMapMux.RUnlock()
|
wf.LocalSDMapMux.RUnlock()
|
||||||
wf.CandidateMux.RLock()
|
wf.CandidateMux.RLock()
|
||||||
for _, candidate := range wf.PendingCandidates[req[FROM]] {
|
for range wf.PendingCandidates[req[FROM]] {
|
||||||
logger.Println("sending candidate to", req[FROM])
|
// logger.Println("sending candidate to", req[FROM])
|
||||||
if err = wf.stream.Send(&Request{
|
// if err = wf.stream.Send(&Request{
|
||||||
Type: string(WEBRTC_CANDIDATE_FS),
|
// Type: string(WEBRTC_CANDIDATE_FS),
|
||||||
From: "lolo_local_serv",
|
// From: "lolo_local_serv",
|
||||||
Token: "none",
|
// Token: "none",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"from": "lolo_local_serv",
|
// "from": "lolo_local_serv",
|
||||||
"to": req[FROM],
|
// "to": req[FROM],
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
// "candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
// "sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
wf.CandidateMux.RUnlock()
|
wf.CandidateMux.RUnlock()
|
||||||
return
|
return
|
||||||
@ -356,7 +364,7 @@ func (wf *WebrtcFsManager) createPeerConnection(target string, from string, peer
|
|||||||
if peerConnection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && peerConnection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
|
if peerConnection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && peerConnection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
|
||||||
wf.RTCPeerConnectionMapMux.Lock()
|
wf.RTCPeerConnectionMapMux.Lock()
|
||||||
defer wf.RTCPeerConnectionMapMux.Unlock()
|
defer wf.RTCPeerConnectionMapMux.Unlock()
|
||||||
for id, connection := range wf.RTCPeerConnections {
|
for _, connection := range wf.RTCPeerConnections {
|
||||||
if connection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && connection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
|
if connection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && connection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer {
|
||||||
localSd, err := connection.CreateOffer(nil)
|
localSd, err := connection.CreateOffer(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -367,18 +375,18 @@ func (wf *WebrtcFsManager) createPeerConnection(target string, from string, peer
|
|||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = wf.stream.Send(&Request{
|
// if err = wf.stream.Send(&Request{
|
||||||
Type: string(WEBRTC_RENNEGOTIATION_OFFER_FS),
|
// Type: string(WEBRTC_RENNEGOTIATION_OFFER_FS),
|
||||||
From: "lolo_local_serv",
|
// From: "lolo_local_serv",
|
||||||
Token: "",
|
// Token: "",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"to": id,
|
// "to": id,
|
||||||
"sdp": localSd.SDP,
|
// "sdp": localSd.SDP,
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,18 +415,18 @@ func (wf *WebrtcFsManager) HandleRennegotiationOffer(from string, dst string, sd
|
|||||||
if err = wf.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
if err = wf.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = wf.stream.Send(&Request{
|
// if err = wf.stream.Send(&Request{
|
||||||
Type: string(WEBRTC_RENNEGOTIATION_ANSWER_FS),
|
// Type: string(WEBRTC_RENNEGOTIATION_ANSWER_FS),
|
||||||
From: "lolo_local_serv",
|
// From: "lolo_local_serv",
|
||||||
Token: "",
|
// Token: "",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"to": from,
|
// "to": from,
|
||||||
"sdp": localSd.SDP,
|
// "sdp": localSd.SDP,
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package localserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
@ -20,7 +21,7 @@ const (
|
|||||||
|
|
||||||
type WebRTCFsMiddleware struct {
|
type WebRTCFsMiddleware struct {
|
||||||
Manager *WebrtcFsManager
|
Manager *WebrtcFsManager
|
||||||
stream GrpcManager_LinkClient
|
stream SignalingService_LinkClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebRTCFsMiddleware(manager *WebrtcFsManager) (webrtcFsMiddleware *WebRTCFsMiddleware) {
|
func NewWebRTCFsMiddleware(manager *WebrtcFsManager) (webrtcFsMiddleware *WebRTCFsMiddleware) {
|
||||||
@ -31,111 +32,119 @@ func NewWebRTCFsMiddleware(manager *WebrtcFsManager) (webrtcFsMiddleware *WebRTC
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (wfm *WebRTCFsMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
func (wfm *WebRTCFsMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
||||||
err = wfm.stream.Send(&Request{
|
bs, err := json.Marshal(map[string]string{
|
||||||
Type: string(WEBRTC_CANDIDATE_FS),
|
|
||||||
From: "lolo_local_serv",
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": "lolo_local_serv",
|
"from": "lolo_local_serv",
|
||||||
"to": to,
|
"to": to,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wfm *WebRTCFsMiddleware) Process(ctx context.Context, req *Response, stream GrpcManager_LinkClient) (err error) {
|
func (wfm *WebRTCFsMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
|
||||||
done, errCh := make(chan struct{}), make(chan error)
|
done, errCh := make(chan struct{}), make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
|
var payload map[string]string
|
||||||
|
if e := json.Unmarshal(req.Payload, &payload); err != nil {
|
||||||
|
errCh <- e
|
||||||
|
return
|
||||||
|
}
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case string(INCOMING_PEER_FS):
|
case string(INCOMING_PEER_FS):
|
||||||
logger.Println("quit squad called")
|
logger.Println("quit squad called")
|
||||||
if from, ok := req.Payload[FROM]; ok {
|
if from, ok := payload[FROM]; ok {
|
||||||
logger.Println(from)
|
logger.Println(from)
|
||||||
//wfm.Manager.HandleLeavingMember(from)
|
//wfm.Manager.HandleLeavingMember(from)
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
}
|
}
|
||||||
case string(PEER_CONNECTION_REQUEST):
|
case string(PEER_CONNECTION_REQUEST):
|
||||||
if err := validateRequest(req.Payload, FROM, TO); err != nil {
|
if err := validateRequest(payload, FROM, TO); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// if err := wfm.Manager.CreateOffer(ctx, req.Payload[FROM], req.Payload[TO], wfm.signalCandidate); err != nil {
|
// if err := wfm.Manager.CreateOffer(ctx, payload[FROM], payload[TO], wfm.signalCandidate); err != nil {
|
||||||
// errCh <- err
|
// errCh <- err
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(WEBRTC_OFFER_FS):
|
case string(WEBRTC_OFFER_FS):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, TO, SDP); err != nil {
|
if err := validateRequest(payload, FROM, TO, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wfm.Manager.HandleOffer(ctx, req.GetPayload(), wfm.signalCandidate); err != nil {
|
if err := wfm.Manager.HandleOffer(ctx, payload, wfm.signalCandidate); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(WEBRTC_ANSWER_FS):
|
case string(WEBRTC_ANSWER_FS):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, TO, SDP); err != nil {
|
if err := validateRequest(payload, FROM, TO, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wfm.Manager.HandleAnswer(ctx, req.GetPayload()); err != nil {
|
if err := wfm.Manager.HandleAnswer(ctx, payload); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(WEBRTC_COUNTER_OFFER_FS):
|
case string(WEBRTC_COUNTER_OFFER_FS):
|
||||||
if err := validateRequest(req.GetPayload(), FROM); err != nil {
|
if err := validateRequest(payload, FROM); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wfm.Manager.HandleCounterOffer(ctx, req.Payload); err != nil {
|
if err := wfm.Manager.HandleCounterOffer(ctx, payload); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(WEBRTC_RENNEGOTIATION_ANSWER_FS):
|
case string(WEBRTC_RENNEGOTIATION_ANSWER_FS):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
|
if err := validateRequest(payload, FROM, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wfm.Manager.HandleRennegotiationAnswer(req.Payload[FROM], "lolo_local_serv", req.Payload[SDP]); err != nil {
|
if err := wfm.Manager.HandleRennegotiationAnswer(payload[FROM], "lolo_local_serv", payload[SDP]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(WEBRTC_RENNEGOTIATION_OFFER_FS):
|
case string(WEBRTC_RENNEGOTIATION_OFFER_FS):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
|
if err := validateRequest(payload, FROM, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wfm.Manager.HandleRennegotiationOffer(req.Payload[FROM], "", req.Payload[SDP]); err != nil {
|
if err := wfm.Manager.HandleRennegotiationOffer(payload[FROM], "", payload[SDP]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(WEBRTC_CANDIDATE_FS):
|
case string(WEBRTC_CANDIDATE_FS):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, "candidate", "sdpMlineIndex", "sdpMid"); err != nil {
|
if err := validateRequest(payload, FROM, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println(req.Payload)
|
logger.Println(payload)
|
||||||
i, err := strconv.Atoi(req.Payload["sdpMlineIndex"])
|
i, err := strconv.Atoi(payload["sdpMLineIndex"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sdpMlineIndex := uint16(i)
|
SDPMLineIndex := uint16(i)
|
||||||
sdpMid := req.Payload["sdpMid"]
|
sdpMid := payload["sdpMid"]
|
||||||
logger.Println(sdpMid, sdpMlineIndex)
|
logger.Println(sdpMid, SDPMLineIndex)
|
||||||
if err := wfm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
if err := wfm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
||||||
Candidate: req.Payload["candidate"],
|
Candidate: payload["candidate"],
|
||||||
SDPMid: &sdpMid,
|
SDPMid: &sdpMid,
|
||||||
SDPMLineIndex: &sdpMlineIndex,
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
}, req.Payload[FROM]); err != nil {
|
}, payload[FROM]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package localserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ const (
|
|||||||
|
|
||||||
type WebRTCGrpcMiddleware struct {
|
type WebRTCGrpcMiddleware struct {
|
||||||
Manager *WebRTCCallManager
|
Manager *WebRTCCallManager
|
||||||
stream GrpcManager_LinkClient
|
stream SignalingService_LinkClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *WebRTCGrpcMiddleware) {
|
func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *WebRTCGrpcMiddleware) {
|
||||||
@ -59,124 +60,125 @@ func validateRequest(req map[string]string, entries ...string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (wgm *WebRTCGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
func (wgm *WebRTCGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
||||||
err = wgm.stream.Send(&Request{
|
bs, err := json.Marshal(map[string]string{
|
||||||
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
|
|
||||||
From: wgm.Manager.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": wgm.Manager.ID,
|
"from": wgm.Manager.ID,
|
||||||
"to": to,
|
"to": to,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wgm *WebRTCGrpcMiddleware) Process(ctx context.Context, req *Response, stream GrpcManager_LinkClient) (err error) {
|
func (wgm *WebRTCGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
|
||||||
done, errCh := make(chan struct{}), make(chan error)
|
done, errCh := make(chan struct{}), make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
}()
|
}()
|
||||||
|
var payload map[string]string
|
||||||
|
if e := json.Unmarshal(req.Payload, &payload); err != nil {
|
||||||
|
errCh <- e
|
||||||
|
return
|
||||||
|
}
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case NEW_HOSTED_SQUAD:
|
case NEW_HOSTED_SQUAD:
|
||||||
if err := validateRequest(req.Payload, "ID"); err != nil {
|
if err := validateRequest(payload, "ID"); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("new squad incoming")
|
logger.Println("new squad incoming")
|
||||||
wgm.Manager.SquadMapMux.Lock()
|
wgm.Manager.SquadMapMux.Lock()
|
||||||
wgm.Manager.Squads[req.Payload["ID"]] = &Squad{
|
wgm.Manager.Squads[payload["ID"]] = &Squad{
|
||||||
ID: req.Payload["ID"],
|
ID: payload["ID"],
|
||||||
Members: []string{},
|
Members: []string{},
|
||||||
}
|
}
|
||||||
wgm.Manager.SquadMapMux.Unlock()
|
wgm.Manager.SquadMapMux.Unlock()
|
||||||
case string(HOSTED_SQUAD_STOP_CALL):
|
case string(HOSTED_SQUAD_STOP_CALL):
|
||||||
logger.Println("quit squad called")
|
logger.Println("quit squad called")
|
||||||
if err := validateRequest(req.Payload, FROM, "squadId"); err != nil {
|
if err := validateRequest(payload, "squadId"); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wgm.Manager.HandleLeavingMember(req.Payload[FROM], req.Payload["squadId"])
|
wgm.Manager.HandleLeavingMember(req.GetFrom(), payload["squadId"])
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
case string(PEER_CONNECTION_REQUEST):
|
case string(PEER_CONNECTION_REQUEST):
|
||||||
if err := validateRequest(req.Payload, FROM, TO); err != nil {
|
|
||||||
errCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.Println("creating offer for peer")
|
logger.Println("creating offer for peer")
|
||||||
if err := wgm.Manager.CreateOffer(ctx, req.Payload[FROM], req.Payload[TO], wgm.signalCandidate); err != nil {
|
if err := wgm.Manager.CreateOffer(ctx, req.GetFrom(), req.GetTo(), wgm.signalCandidate); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(HOSTED_SQUAD_WEBRTC_OFFER):
|
case string(HOSTED_SQUAD_WEBRTC_OFFER):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, TO, SDP, SQUAD_ID); err != nil {
|
if err := validateRequest(payload, SDP, SQUAD_ID); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wgm.Manager.HandleOffer(ctx, req.GetPayload(), wgm.signalCandidate); err != nil {
|
if err := wgm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, wgm.signalCandidate); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(HOSTED_SQUAD_WEBRTC_ANSWER):
|
case string(HOSTED_SQUAD_WEBRTC_ANSWER):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, TO, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wgm.Manager.HandleAnswer(ctx, req.GetPayload()); err != nil {
|
if err := wgm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER):
|
case string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER):
|
||||||
if err := validateRequest(req.GetPayload(), FROM); err != nil {
|
if err := wgm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
|
||||||
errCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := wgm.Manager.HandleCounterOffer(ctx, req.Payload); err != nil {
|
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
|
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
|
||||||
logger.Println("received negotiation answer")
|
logger.Println("received negotiation answer")
|
||||||
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wgm.Manager.HandleRennegotiationAnswer(req.Payload[FROM], req.Payload[SDP]); err != nil {
|
if err := wgm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
|
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
|
||||||
logger.Println("received negotiation offer")
|
logger.Println("received negotiation offer")
|
||||||
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := wgm.Manager.HandleRennegotiationOffer(req.Payload[FROM], req.Payload[SDP]); err != nil {
|
if err := wgm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(HOSTED_SQUAD_WEBRTC_CANDIDATE):
|
case string(HOSTED_SQUAD_WEBRTC_CANDIDATE):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, "candidate", "sdpMlineIndex", "sdpMid"); err != nil {
|
if err := validateRequest(payload, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println(req.Payload)
|
logger.Println(payload)
|
||||||
i, err := strconv.Atoi(req.Payload["sdpMlineIndex"])
|
i, err := strconv.Atoi(payload["sdpMLineIndex"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sdpMlineIndex := uint16(i)
|
SDPMLineIndex := uint16(i)
|
||||||
sdpMid := req.Payload["sdpMid"]
|
sdpMid := payload["sdpMid"]
|
||||||
logger.Println(sdpMid, sdpMlineIndex)
|
logger.Println(sdpMid, SDPMLineIndex)
|
||||||
if err := wgm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
if err := wgm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
||||||
Candidate: req.Payload["candidate"],
|
Candidate: payload["candidate"],
|
||||||
SDPMid: &sdpMid,
|
SDPMid: &sdpMid,
|
||||||
SDPMLineIndex: &sdpMlineIndex,
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
}, req.Payload[FROM]); err != nil {
|
}, req.GetFrom()); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -129,10 +129,10 @@ func (ac *AudioChannel) HandleOffer(ctx context.Context, channelId string, userI
|
|||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(ac.localSDMapFlag, func() (err error) {
|
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
|
||||||
ac.localSD[userId] = &rawAnswer
|
errCh <- err
|
||||||
return
|
return
|
||||||
})
|
}
|
||||||
_, _ = sendDCMessage(string(AUDIO_CHANNEL_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
_, _ = sendDCMessage(string(AUDIO_CHANNEL_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
||||||
"to": userId,
|
"to": userId,
|
||||||
"from": ac.ID,
|
"from": ac.ID,
|
||||||
@ -146,25 +146,25 @@ func (ac *AudioChannel) HandleOffer(ctx context.Context, channelId string, userI
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ac *AudioChannel) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
func (ac *AudioChannel) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
||||||
if err = atomicallyExecute(ac.rtcPeerConnectionMapFlag, func() (err error) {
|
// if err = atomicallyExecute(ac.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
if _, ok := ac.rtcPeerConnections[userId]; !ok {
|
// if _, ok := ac.rtcPeerConnections[userId]; !ok {
|
||||||
err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
// err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
logger.Println("handling counter offer")
|
// logger.Println("handling counter offer")
|
||||||
connection := ac.rtcPeerConnections[userId]
|
// connection := ac.rtcPeerConnections[userId]
|
||||||
err = atomicallyExecute(ac.localSDMapFlag, func() (err error) {
|
// err = atomicallyExecute(ac.localSDMapFlag, func() (err error) {
|
||||||
err = connection.SetLocalDescription(*ac.localSD[userId])
|
// err = connection.SetLocalDescription(*ac.localSD[userId])
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
_ = atomicallyExecute(ac.localSDMapFlag, func() (err error) {
|
// _ = atomicallyExecute(ac.localSDMapFlag, func() (err error) {
|
||||||
delete(ac.localSD, userId)
|
// delete(ac.localSD, userId)
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
if err = atomicallyExecute(ac.candidateFlag, func() (err error) {
|
if err = atomicallyExecute(ac.candidateFlag, func() (err error) {
|
||||||
for _, candidate := range ac.pendingCandidates[userId] {
|
for _, candidate := range ac.pendingCandidates[userId] {
|
||||||
logger.Println("sending candidate to", userId, candidate)
|
logger.Println("sending candidate to", userId, candidate)
|
||||||
@ -173,7 +173,7 @@ func (ac *AudioChannel) HandleCounterOffer(ctx context.Context, userId string, s
|
|||||||
"to": userId,
|
"to": userId,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-d:
|
case <-d:
|
||||||
@ -508,8 +508,8 @@ func (ac *AudioChannel) createPeerConnection(target string, from string, peerTyp
|
|||||||
return
|
return
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
peerConnection.OnNegotiationNeeded(func() {
|
//peerConnection.OnNegotiationNeeded(func() {
|
||||||
logger.Println("---------------- rennego is needed -----------")
|
//logger.Println("---------------- rennego is needed -----------")
|
||||||
// _ = atomicallyExecute(ac.rtcPeerConnectionMapFlag, func() (err error) {
|
// _ = atomicallyExecute(ac.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
// for _, id := range ac.CurrentMembersId {
|
// for _, id := range ac.CurrentMembersId {
|
||||||
// logger.Println("----------------- sending renego to peer with id", id)
|
// logger.Println("----------------- sending renego to peer with id", id)
|
||||||
@ -540,7 +540,7 @@ func (ac *AudioChannel) createPeerConnection(target string, from string, peerTyp
|
|||||||
// }
|
// }
|
||||||
// return
|
// return
|
||||||
// })
|
// })
|
||||||
})
|
//})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,12 @@ const (
|
|||||||
const (
|
const (
|
||||||
USER_JOINED_AUDIO_CHANNEL = "user_joined_audio_channel"
|
USER_JOINED_AUDIO_CHANNEL = "user_joined_audio_channel"
|
||||||
USER_LEFT_AUDIO_CHANNEL = "user_left_audio_channel"
|
USER_LEFT_AUDIO_CHANNEL = "user_left_audio_channel"
|
||||||
|
AUDIO_CHANNNEL_NAME_EDITED = "audio_channel_name_edited"
|
||||||
|
AUDIO_CHANNNEL_TYPE_EDITED = "audio_channel_type_edited"
|
||||||
|
AUDIO_CHANNEL_MEMBER_REMOVED = "audio_channel_member_removed"
|
||||||
|
AUDIO_CHANNEL_MEMBER_ADDED = "audio_channel_member_added"
|
||||||
|
ADDED_IN_AUDIO_CHANNEL = "added_in_audio_channel"
|
||||||
|
REMOVED_FROM_AUDIO_CHANNEL = "removed_from_audio_channel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AudioChannelMember struct {
|
type AudioChannelMember struct {
|
||||||
@ -195,7 +201,7 @@ func (zach *ZoneAudioChannelsHandler) signalCandidate(from string, to string, ca
|
|||||||
"to": to,
|
"to": to,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-d:
|
case <-d:
|
||||||
@ -270,15 +276,15 @@ func (zach *ZoneAudioChannelsHandler) AddNewAudioChannel(channelName string, own
|
|||||||
}
|
}
|
||||||
m := make([]string, 0, len(members))
|
m := make([]string, 0, len(members))
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
if _, ok := member.(string); ok {
|
if mbr, ok := member.(string); ok && mbr != owner {
|
||||||
m = append(m, member.(string))
|
m = append(m, mbr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
baseConfig := &AudioChannelConfig{
|
baseConfig := &AudioChannelConfig{
|
||||||
ID: channelName,
|
ID: channelName,
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
ChannelType: channelType,
|
ChannelType: channelType,
|
||||||
Members: m,
|
Members: append(m,owner),
|
||||||
}
|
}
|
||||||
bs, jsonErr := json.Marshal(baseConfig)
|
bs, jsonErr := json.Marshal(baseConfig)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
@ -344,7 +350,7 @@ func (zach *ZoneAudioChannelsHandler) DeleteAudioChannel(channelId string) (err
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zach.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(REMOVED_FROM_AUDIO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
"userId": member,
|
"userId": member,
|
||||||
})
|
})
|
||||||
@ -419,7 +425,7 @@ func (zach *ZoneAudioChannelsHandler) EditAudioChannelName(channelId string, new
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zach.sendDataChannelMessage(CHAT_NAME_EDITED, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(AUDIO_CHANNNEL_NAME_EDITED, "node", member, map[string]interface{}{
|
||||||
"formerAudioChannelId": channelId,
|
"formerAudioChannelId": channelId,
|
||||||
"newAudioChannelId": newAudioChannelId,
|
"newAudioChannelId": newAudioChannelId,
|
||||||
})
|
})
|
||||||
@ -449,7 +455,7 @@ func (zach *ZoneAudioChannelsHandler) EditAudioChannelType(channelId string, cha
|
|||||||
err = fmt.Errorf("no coresponding audioChannel")
|
err = fmt.Errorf("no coresponding audioChannel")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs, err := os.ReadFile(filepath.Join("data", "zones", zach.ZoneId, "audioChannels", channelId))
|
bs, err := os.ReadFile(filepath.Join("data", "zones", zach.ZoneId, "audioChannels", channelId, "audioChannelConfig.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -483,6 +489,10 @@ func (zach *ZoneAudioChannelsHandler) EditAudioChannelType(channelId string, cha
|
|||||||
if pubErr := zach.SetAudioChannelPublicForUser(channelId, member); pubErr != nil {
|
if pubErr := zach.SetAudioChannelPublicForUser(channelId, member); pubErr != nil {
|
||||||
logger.Println(pubErr)
|
logger.Println(pubErr)
|
||||||
}
|
}
|
||||||
|
zach.sendDataChannelMessage(AUDIO_CHANNNEL_TYPE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"channelId": channelId,
|
||||||
|
"channelType": channelType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case PRIVATE:
|
case PRIVATE:
|
||||||
var members = []string{}
|
var members = []string{}
|
||||||
@ -494,6 +504,10 @@ func (zach *ZoneAudioChannelsHandler) EditAudioChannelType(channelId string, cha
|
|||||||
if pubErr := zach.SetAudioChannelPrivateForUser(channelId, member); pubErr != nil {
|
if pubErr := zach.SetAudioChannelPrivateForUser(channelId, member); pubErr != nil {
|
||||||
logger.Println(pubErr)
|
logger.Println(pubErr)
|
||||||
}
|
}
|
||||||
|
zach.sendDataChannelMessage(AUDIO_CHANNNEL_TYPE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"channelId": channelId,
|
||||||
|
"channelType": channelType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
_ = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
||||||
@ -549,16 +563,14 @@ memberLoop:
|
|||||||
if _, err = f.Write(bs); err != nil {
|
if _, err = f.Write(bs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ac := NewAudioChannel(audioChannelConfig.ID, audioChannelConfig.Owner, audioChannelConfig.ChannelType, audioChannelConfig.Members, make([]string, 0), make(map[string]*AudioChannelMember))
|
|
||||||
_ = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
_ = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
||||||
zach.AudioChannels[channelId] = ac
|
zach.AudioChannels[channelId].Members = audioChannelConfig.Members
|
||||||
return
|
ac := zach.AudioChannels[channelId]
|
||||||
})
|
broadcastLoop:
|
||||||
broadcastLoop:
|
|
||||||
for _, member := range ac.Members {
|
for _, member := range ac.Members {
|
||||||
for _, m := range addedMembers {
|
for _, m := range addedMembers {
|
||||||
if member == m {
|
if member == m {
|
||||||
done, e := zach.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(ADDED_IN_AUDIO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"audioChannel": ac,
|
"audioChannel": ac,
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
@ -569,7 +581,7 @@ broadcastLoop:
|
|||||||
continue broadcastLoop
|
continue broadcastLoop
|
||||||
}
|
}
|
||||||
if _, ok := zach.DataChannels[member]; ok {
|
if _, ok := zach.DataChannels[member]; ok {
|
||||||
done, e := zach.sendDataChannelMessage(CHAT_MEMBER_ADDED, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(AUDIO_CHANNEL_MEMBER_ADDED, "node", member, map[string]interface{}{
|
||||||
"userId": m,
|
"userId": m,
|
||||||
"channelId": ac.ID,
|
"channelId": ac.ID,
|
||||||
})
|
})
|
||||||
@ -582,6 +594,8 @@ broadcastLoop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zach *ZoneAudioChannelsHandler) RemoveAudioChannelMember(channelId string, channelMember string) (err error) {
|
func (zach *ZoneAudioChannelsHandler) RemoveAudioChannelMember(channelId string, channelMember string) (err error) {
|
||||||
@ -633,31 +647,15 @@ func (zach *ZoneAudioChannelsHandler) RemoveAudioChannelMember(channelId string,
|
|||||||
if _, err = f.Write(bs); err != nil {
|
if _, err = f.Write(bs); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var ac *AudioChannel
|
|
||||||
_ = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
_ = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
||||||
ac := NewAudioChannel(audioChannelConfig.ID, audioChannelConfig.Owner, audioChannelConfig.ChannelType, audioChannelConfig.Members, make([]string, 0), make(map[string]*AudioChannelMember))
|
zach.AudioChannels[channelId].Members = audioChannelConfig.Members
|
||||||
zach.AudioChannels[channelId] = ac
|
ac := zach.AudioChannels[channelId]
|
||||||
return
|
broadcastLoop:
|
||||||
})
|
|
||||||
zach.sendZoneRequest(REMOVE_KNOWN_AUDIO_CHANNEL, "node", map[string]interface{}{
|
|
||||||
"userId": channelMember,
|
|
||||||
"channelId": channelId,
|
|
||||||
})
|
|
||||||
done, e := zach.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", channelMember, map[string]interface{}{
|
|
||||||
"channelId": channelId,
|
|
||||||
"userId": channelMember,
|
|
||||||
})
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case err = <-e:
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
broadcastLoop:
|
|
||||||
for _, member := range ac.Members {
|
for _, member := range ac.Members {
|
||||||
if member == channelMember {
|
if member == channelMember {
|
||||||
continue broadcastLoop
|
continue broadcastLoop
|
||||||
}
|
}
|
||||||
done, e := zach.sendDataChannelMessage(CHAT_MEMBER_REMOVED, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(AUDIO_CHANNEL_MEMBER_REMOVED, "node", member, map[string]interface{}{
|
||||||
"userId": channelMember,
|
"userId": channelMember,
|
||||||
"channelId": ac.ID,
|
"channelId": ac.ID,
|
||||||
})
|
})
|
||||||
@ -668,6 +666,21 @@ broadcastLoop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
})
|
||||||
|
zach.sendZoneRequest(REMOVE_KNOWN_AUDIO_CHANNEL, "node", map[string]interface{}{
|
||||||
|
"userId": channelMember,
|
||||||
|
"channelId": channelId,
|
||||||
|
})
|
||||||
|
done, e := zach.sendDataChannelMessage(REMOVED_FROM_AUDIO_CHANNEL, "node", channelMember, map[string]interface{}{
|
||||||
|
"channelId": channelId,
|
||||||
|
"userId": channelMember,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case err = <-e:
|
||||||
|
logger.Println(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zach *ZoneAudioChannelsHandler) SetAudioChannelPrivateForUser(channelId string, member string) (err error) {
|
func (zach *ZoneAudioChannelsHandler) SetAudioChannelPrivateForUser(channelId string, member string) (err error) {
|
||||||
@ -685,7 +698,7 @@ func (zach *ZoneAudioChannelsHandler) SetAudioChannelPrivateForUser(channelId st
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zach.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(REMOVED_FROM_AUDIO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
"userId": member,
|
"userId": member,
|
||||||
})
|
})
|
||||||
@ -715,7 +728,7 @@ func (zach *ZoneAudioChannelsHandler) SetAudioChannelPublicForUser(channelId str
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zach.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(ADDED_IN_AUDIO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"audioChannel": audioChannel,
|
"audioChannel": audioChannel,
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
@ -788,7 +801,7 @@ func (zach *ZoneAudioChannelsHandler) JoinAudioChannel(channelId string, userId
|
|||||||
audioChannel.CurrentMembersId = append(audioChannel.CurrentMembersId, userId)
|
audioChannel.CurrentMembersId = append(audioChannel.CurrentMembersId, userId)
|
||||||
audioChannel.CurrentMembers[userId] = &AudioChannelMember{}
|
audioChannel.CurrentMembers[userId] = &AudioChannelMember{}
|
||||||
signalMembers := func(members []string) {
|
signalMembers := func(members []string) {
|
||||||
for _, u := range audioChannel.Members {
|
for _, u := range members {
|
||||||
done, e := zach.sendDataChannelMessage(USER_JOINED_AUDIO_CHANNEL, "node", u, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(USER_JOINED_AUDIO_CHANNEL, "node", u, map[string]interface{}{
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
@ -842,7 +855,7 @@ func (zach *ZoneAudioChannelsHandler) LeaveAudioChannel(channelId string, userId
|
|||||||
}
|
}
|
||||||
delete(audioChannel.CurrentMembers, userId)
|
delete(audioChannel.CurrentMembers, userId)
|
||||||
signalMembers := func(members []string) {
|
signalMembers := func(members []string) {
|
||||||
for _, u := range audioChannel.Members {
|
for _, u := range members {
|
||||||
done, e := zach.sendDataChannelMessage(USER_LEFT_AUDIO_CHANNEL, "node", u, map[string]interface{}{
|
done, e := zach.sendDataChannelMessage(USER_LEFT_AUDIO_CHANNEL, "node", u, map[string]interface{}{
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
@ -1008,17 +1021,17 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
|
|||||||
case string(AUDIO_CHANNEL_WEBRTC_CANDIDATE):
|
case string(AUDIO_CHANNEL_WEBRTC_CANDIDATE):
|
||||||
logger.Println("handling audio channel webrtc candidate")
|
logger.Println("handling audio channel webrtc candidate")
|
||||||
logger.Println(req.Payload)
|
logger.Println(req.Payload)
|
||||||
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMlineIndex", "sdpMid", "channelId", "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println(req.Payload)
|
logger.Println(req.Payload)
|
||||||
i, convErr := strconv.Atoi(req.Payload["sdpMlineIndex"].(string))
|
i, convErr := strconv.Atoi(req.Payload["sdpMLineIndex"].(string))
|
||||||
if convErr != nil {
|
if convErr != nil {
|
||||||
return convErr
|
return convErr
|
||||||
}
|
}
|
||||||
sdpMlineIndex := uint16(i)
|
SDPMLineIndex := uint16(i)
|
||||||
sdpMid := req.Payload["sdpMid"].(string)
|
sdpMid := req.Payload["sdpMid"].(string)
|
||||||
logger.Println(sdpMid, sdpMlineIndex)
|
logger.Println(sdpMid, SDPMLineIndex)
|
||||||
err = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
err = atomicallyExecute(zach.AudioChannelsFlag, func() (err error) {
|
||||||
if _, ok := zach.AudioChannels[req.Payload["channelId"].(string)]; !ok {
|
if _, ok := zach.AudioChannels[req.Payload["channelId"].(string)]; !ok {
|
||||||
err = fmt.Errorf("no channel corresponging the one requested")
|
err = fmt.Errorf("no channel corresponging the one requested")
|
||||||
@ -1027,7 +1040,7 @@ func (zach *ZoneAudioChannelsHandler) handleZoneRequest(ctx context.Context, req
|
|||||||
err = zach.AudioChannels[req.Payload["channelId"].(string)].AddCandidate(&webrtc.ICECandidateInit{
|
err = zach.AudioChannels[req.Payload["channelId"].(string)].AddCandidate(&webrtc.ICECandidateInit{
|
||||||
Candidate: req.Payload["candidate"].(string),
|
Candidate: req.Payload["candidate"].(string),
|
||||||
SDPMid: &sdpMid,
|
SDPMid: &sdpMid,
|
||||||
SDPMLineIndex: &sdpMlineIndex,
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
}, req.Payload["userId"].(string))
|
}, req.Payload["userId"].(string))
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|||||||
707
zoneChatFileInstance.go
Normal file
707
zoneChatFileInstance.go
Normal file
@ -0,0 +1,707 @@
|
|||||||
|
package localserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
sync "sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ZONE_CHAT_WEBRTC_OFFER ReqType = "zone_chat_offer"
|
||||||
|
ZONE_CHAT_WEBRTC_ANSWER ReqType = "zone_chat_answer"
|
||||||
|
ZONE_CHAT_WEBRTC_RENNEGOTIATION_OFFER ReqType = "zone_chat_rennegotiation_offer"
|
||||||
|
ZONE_CHAT_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "zone_chat_rennegotiation_answer"
|
||||||
|
ZONE_CHAT_WEBRTC_COUNTER_OFFER ReqType = "zone_chat_webrtc_counter_offer"
|
||||||
|
ZONE_CHAT_WEBRTC_CANDIDATE ReqType = "zone_chat_webrtc_candidate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatFSInstance struct {
|
||||||
|
ZoneID string `json:"id"`
|
||||||
|
Owner string `json:"owner"`
|
||||||
|
Members []string `json:"members"`
|
||||||
|
OpenFiles map[string]*os.File `json:"-"`
|
||||||
|
OpenFilesForUser map[string][]string `json:"-"`
|
||||||
|
localSD map[string]*webrtc.SessionDescription `json:"-"`
|
||||||
|
rtcPeerConnections map[string]*ZoneRTCPeerConnection `json:"-"`
|
||||||
|
zoneFSDataChannels map[string]map[string]*DataChannel `json:"-"`
|
||||||
|
pendingCandidates map[string][]*webrtc.ICECandidate `json:"-"`
|
||||||
|
middlewares []interface{} `json:"-"`
|
||||||
|
candidateFlag *uint32 `json:"-"`
|
||||||
|
filesFlag *uint32 `json:"-"`
|
||||||
|
rtcPeerConnectionMapFlag *uint32 `json:"-"`
|
||||||
|
dataChannelMapFlag *uint32 `json:"-"`
|
||||||
|
localSDMapFlag *uint32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatFSInstanceOnICECandidateFunc = func(string, string, *webrtc.ICECandidate) error
|
||||||
|
|
||||||
|
func NewChatFSInstance(id, owner string, members []string) (audioChannel *ChatFSInstance) {
|
||||||
|
candidateFlag := uint32(0)
|
||||||
|
rtcPeerConnectionMapFlag := uint32(0)
|
||||||
|
dataChannelMapFlag := uint32(0)
|
||||||
|
filesFlag := uint32(0)
|
||||||
|
localSDMapFlag := uint32(0)
|
||||||
|
audioChannel = &ChatFSInstance{
|
||||||
|
ZoneID: id,
|
||||||
|
Owner: owner,
|
||||||
|
Members: members,
|
||||||
|
OpenFiles: make(map[string]*os.File),
|
||||||
|
OpenFilesForUser: make(map[string][]string),
|
||||||
|
localSD: make(map[string]*webrtc.SessionDescription),
|
||||||
|
rtcPeerConnections: make(map[string]*ZoneRTCPeerConnection),
|
||||||
|
zoneFSDataChannels: make(map[string]map[string]*DataChannel),
|
||||||
|
pendingCandidates: make(map[string][]*webrtc.ICECandidate),
|
||||||
|
middlewares: make([]interface{}, 0),
|
||||||
|
candidateFlag: &candidateFlag,
|
||||||
|
filesFlag: &filesFlag,
|
||||||
|
rtcPeerConnectionMapFlag: &rtcPeerConnectionMapFlag,
|
||||||
|
dataChannelMapFlag: &dataChannelMapFlag,
|
||||||
|
localSDMapFlag: &localSDMapFlag,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) SetupFileUpload(chatId, filename, userId string) (err error) {
|
||||||
|
concretePath := filepath.Join("data", "zones", fs.ZoneID, "chats", chatId, "__files__", filename)
|
||||||
|
if _, rErr := os.ReadDir(filepath.Join("data", "zones", fs.ZoneID, "chats", chatId, "__files__")); os.IsNotExist(rErr) {
|
||||||
|
if err = os.MkdirAll(filepath.Join("data", "zones", fs.ZoneID, "chats", chatId, "__files__"), 0700); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if rErr != nil {
|
||||||
|
return 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
|
||||||
|
}
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
fs.OpenFiles[fmt.Sprintf("%s/%s", filename, userId)] = file
|
||||||
|
if _, ok := fs.OpenFilesForUser[userId]; !ok {
|
||||||
|
fs.OpenFilesForUser[userId] = []string{}
|
||||||
|
}
|
||||||
|
fs.OpenFilesForUser[userId] = append(fs.OpenFilesForUser[userId], fmt.Sprintf("%s/%s", filename, userId))
|
||||||
|
return
|
||||||
|
})
|
||||||
|
var dc *webrtc.DataChannel
|
||||||
|
if err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
if pc, ok := fs.rtcPeerConnections[userId]; ok {
|
||||||
|
maxRetransmits := uint16(100)
|
||||||
|
dc, err = pc.CreateDataChannel(filename, &webrtc.DataChannelInit{
|
||||||
|
MaxRetransmits: &maxRetransmits,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("no peerconnection for id %s", userId)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
dc.SetBufferedAmountLowThreshold(15000000)
|
||||||
|
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||||
|
logger.Println(msg.Data)
|
||||||
|
_, _ = file.Write(msg.Data)
|
||||||
|
})
|
||||||
|
dc.OnOpen(func() {
|
||||||
|
|
||||||
|
logger.Println("updated")
|
||||||
|
err = dc.SendText("yooooo man this channel is open you should be able to send stuff")
|
||||||
|
logger.Println("!-----------------------------!")
|
||||||
|
logger.Printf("datachannel with id %s is now open\n", dc.Label())
|
||||||
|
logger.Println(*dc.ID())
|
||||||
|
logger.Println(err)
|
||||||
|
logger.Println("!-----------------------------!")
|
||||||
|
|
||||||
|
})
|
||||||
|
dc.OnClose(func() {
|
||||||
|
logger.Println("channel closed")
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
if f, ok := fs.OpenFiles[fmt.Sprintf("%s/%s", filename, userId)]; ok {
|
||||||
|
err = f.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
|
||||||
|
})
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
delete(fs.zoneFSDataChannels[userId], fmt.Sprintf("%s/%s", filename, userId))
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; !ok {
|
||||||
|
fs.zoneFSDataChannels[userId] = make(map[string]*DataChannel)
|
||||||
|
}
|
||||||
|
l := int32(0)
|
||||||
|
fs.zoneFSDataChannels[userId][dc.Label()] = &DataChannel{
|
||||||
|
DataChannel: dc,
|
||||||
|
l: &l,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) FileUploadDone(chatId, filename, userId string) (err error) {
|
||||||
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
if dc, ok := fs.zoneFSDataChannels[userId][filename]; ok {
|
||||||
|
err = dc.DataChannel.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) FileUploadFailed(chatId, filename, userId string) (err error) {
|
||||||
|
concretePath := filepath.Join("data", "zones", fs.ZoneID, "chats", chatId, "__files__", filename)
|
||||||
|
if err = os.Remove(concretePath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
if dc, ok := fs.zoneFSDataChannels[userId][filename]; ok {
|
||||||
|
err = dc.DataChannel.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) SetupFileDownload(chatId, filename, userId string) (err error) {
|
||||||
|
concretePath := filepath.Join("data", "zones", fs.ZoneID, "chats", chatId, "__files__", filename)
|
||||||
|
file, err := os.OpenFile(concretePath, os.O_RDONLY, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
fs.OpenFiles[fmt.Sprintf("%s/%s", filename, userId)] = file
|
||||||
|
if _, ok := fs.OpenFilesForUser[userId]; !ok {
|
||||||
|
fs.OpenFilesForUser[userId] = []string{}
|
||||||
|
}
|
||||||
|
fs.OpenFilesForUser[userId] = append(fs.OpenFilesForUser[userId], fmt.Sprintf("%s/%s", filename, userId))
|
||||||
|
return
|
||||||
|
})
|
||||||
|
var dc *webrtc.DataChannel
|
||||||
|
if err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
if pc, ok := fs.rtcPeerConnections[userId]; ok {
|
||||||
|
maxRetransmits := uint16(100)
|
||||||
|
dc, err = pc.CreateDataChannel(filename, &webrtc.DataChannelInit{
|
||||||
|
MaxRetransmits: &maxRetransmits,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("no peerconnection for id %s", userId)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if dc != nil {
|
||||||
|
dc.SetBufferedAmountLowThreshold(15000000)
|
||||||
|
bufferedAmountLock := make(chan struct{})
|
||||||
|
dc.OnOpen(func() {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
close(bufferedAmountLock)
|
||||||
|
bufferedAmountLock = nil
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
if f, ok := fs.OpenFiles[fmt.Sprintf("%s/%s", filename, userId)]; ok {
|
||||||
|
err = f.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
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
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")
|
||||||
|
<-time.After(time.Second * 4)
|
||||||
|
if err = dc.SendText("done"); err != nil {
|
||||||
|
logger.Println(err)
|
||||||
|
}
|
||||||
|
dc.Close()
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
delete(fs.zoneFSDataChannels[userId], dc.Label())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
logger.Println("done 2")
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
dc.OnBufferedAmountLow(func() {
|
||||||
|
if bufferedAmountLock != nil {
|
||||||
|
bufferedAmountLock <- struct{}{}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dc.OnClose(func() {
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
delete(fs.zoneFSDataChannels[userId], dc.Label())
|
||||||
|
//fs.HandleLeavingMember(target)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
})
|
||||||
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; !ok {
|
||||||
|
fs.zoneFSDataChannels[userId] = make(map[string]*DataChannel)
|
||||||
|
}
|
||||||
|
l := int32(0)
|
||||||
|
fs.zoneFSDataChannels[userId][dc.Label()] = &DataChannel{
|
||||||
|
DataChannel: dc,
|
||||||
|
l: &l,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
} 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 *ChatFSInstance) HandleOffer(ctx context.Context, channelId, userId, sdp, hostId string, sendDCMessage SendDCMessageFunc, cb ChatFSInstanceOnICECandidateFunc) (done chan struct{}, errCh chan error) {
|
||||||
|
done, errCh = make(chan struct{}), make(chan error)
|
||||||
|
go func() {
|
||||||
|
peerConnection, err := fs.createPeerConnection(userId, fs.ZoneID, webrtc.SDPTypeAnswer, cb, sendDCMessage)
|
||||||
|
if err != nil {
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
fs.rtcPeerConnections[userId] = &ZoneRTCPeerConnection{
|
||||||
|
PeerConnection: peerConnection,
|
||||||
|
makingOffer: false,
|
||||||
|
makingOfferLock: &sync.Mutex{},
|
||||||
|
}
|
||||||
|
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(ZONE_CHAT_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
||||||
|
"to": userId,
|
||||||
|
"from": fs.ZoneID,
|
||||||
|
"channelId": channelId,
|
||||||
|
"sdp": rawAnswer.SDP,
|
||||||
|
})
|
||||||
|
done <- struct{}{}
|
||||||
|
logger.Println("handle offer done")
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
||||||
|
// if err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
// if _, ok := fs.rtcPeerConnections[userId]; !ok {
|
||||||
|
// err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// logger.Println("handling counter offer")
|
||||||
|
// connection := fs.rtcPeerConnections[userId]
|
||||||
|
// err = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
||||||
|
// err = connection.SetLocalDescription(*fs.localSD[userId])
|
||||||
|
// return
|
||||||
|
// })
|
||||||
|
// return
|
||||||
|
// }); err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// _ = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
||||||
|
// delete(fs.localSD, userId)
|
||||||
|
// return
|
||||||
|
// })
|
||||||
|
if err = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
||||||
|
for _, candidate := range fs.pendingCandidates[userId] {
|
||||||
|
logger.Println("sending candidate to", userId, candidate)
|
||||||
|
d, e := sendDCMessage(string(ZONE_CHAT_WEBRTC_CANDIDATE), "", userId, map[string]interface{}{
|
||||||
|
"from": fs.ZoneID,
|
||||||
|
"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(fs.pendingCandidates, userId)
|
||||||
|
return
|
||||||
|
}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) HandleRennegotiationOffer(from, sdp string, sendDCMessage SendDCMessageFunc) (err error) {
|
||||||
|
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.rtcPeerConnections[from]; !ok {
|
||||||
|
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//fs.rtcPeerConnections[from].makingOfferLock.Lock()
|
||||||
|
if fs.rtcPeerConnections[from].makingOffer {
|
||||||
|
//fs.rtcPeerConnections[from].makingOfferLock.Unlock()
|
||||||
|
return fmt.Errorf("already making an offer or state is stable")
|
||||||
|
}
|
||||||
|
//fs.rtcPeerConnections[from].makingOfferLock.Unlock()
|
||||||
|
if err = fs.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
localSd, err := fs.rtcPeerConnections[from].CreateAnswer(nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = fs.rtcPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d, e := sendDCMessage(string(ZONE_CHAT_WEBRTC_RENNEGOTIATION_ANSWER), fs.ZoneID, from, map[string]interface{}{
|
||||||
|
"from": fs.ZoneID,
|
||||||
|
"to": from,
|
||||||
|
"sdp": localSd.SDP,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case err = <-e:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) HandleRennegotiationAnswer(from, sdp string) (err error) {
|
||||||
|
logger.Println("---------------------handling rennego answer")
|
||||||
|
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
err = fs.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
|
||||||
|
logger.Println("adding ice candidate", candidate)
|
||||||
|
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.rtcPeerConnections[from]; ok && candidate != nil {
|
||||||
|
err = fs.rtcPeerConnections[from].AddICECandidate(*candidate)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) createPeerConnection(target, from string, peerType webrtc.SDPType, cb ChatFSInstanceOnICECandidateFunc, 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:stunserver.org:3478"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
peerConnection, err = webrtc.NewPeerConnection(config)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Println("---------------------------------------------------")
|
||||||
|
if peerType == webrtc.SDPTypeAnswer {
|
||||||
|
maxRetransmits := uint16(1)
|
||||||
|
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) {
|
||||||
|
var event CallEvent
|
||||||
|
if err := json.Unmarshal(msg.Data, &event); err != nil {
|
||||||
|
logger.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if e := fs.HandleDataChannelEvents(event.From, event.EventId, event.Payload); e != nil {
|
||||||
|
logger.Println("*-------------- datachannel error: ", e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
logger.Println("new channel for target : ", target)
|
||||||
|
channel.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
|
||||||
|
channel.OnBufferedAmountLow(func() {
|
||||||
|
|
||||||
|
})
|
||||||
|
channel.OnClose(func() {
|
||||||
|
|
||||||
|
})
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
logger.Println(target)
|
||||||
|
l := int32(0)
|
||||||
|
if _, ok := fs.zoneFSDataChannels[target]; !ok {
|
||||||
|
fs.zoneFSDataChannels[target] = make(map[string]*DataChannel)
|
||||||
|
}
|
||||||
|
fs.zoneFSDataChannels[target][channel.Label()] = &DataChannel{
|
||||||
|
DataChannel: channel,
|
||||||
|
l: &l,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
l := int32(0)
|
||||||
|
if _, ok := fs.zoneFSDataChannels[target]; !ok {
|
||||||
|
fs.zoneFSDataChannels[target] = make(map[string]*DataChannel)
|
||||||
|
}
|
||||||
|
fs.zoneFSDataChannels[target][dc.Label()] = &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 := fs.HandleDataChannelEvents(event.From, event.EventId, event.Payload); e != nil {
|
||||||
|
logger.Println("*-------------- datachannel error: ", e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dc.OnClose(func() {
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[target]; ok {
|
||||||
|
delete(fs.zoneFSDataChannels[target], dc.Label())
|
||||||
|
fs.HandleLeavingMember(target)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
})
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
logger.Println(target)
|
||||||
|
l := int32(0)
|
||||||
|
if _, ok := fs.zoneFSDataChannels[target]; !ok {
|
||||||
|
fs.zoneFSDataChannels[target] = make(map[string]*DataChannel)
|
||||||
|
}
|
||||||
|
fs.zoneFSDataChannels[target][dc.Label()] = &DataChannel{
|
||||||
|
DataChannel: dc,
|
||||||
|
l: &l,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
|
||||||
|
if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
|
||||||
|
logger.Println(pcs)
|
||||||
|
fs.HandleLeavingMember(target)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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)
|
||||||
|
fs.HandleLeavingMember(target)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
|
||||||
|
if i == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
||||||
|
desc := peerConnection.RemoteDescription()
|
||||||
|
if desc == nil {
|
||||||
|
logger.Println("generated candidate appended to list : ", i)
|
||||||
|
fs.pendingCandidates[target] = append(fs.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(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
// logger.Println("----------------- sending renego to peer with id", target)
|
||||||
|
// 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(ZONE_CHAT_WEBRTC_RENNEGOTIATION_OFFER), fs.ZoneID, target, map[string]interface{}{
|
||||||
|
// "from": fs.ZoneID,
|
||||||
|
// "to": target,
|
||||||
|
// "sdp": localSd.SDP,
|
||||||
|
// })
|
||||||
|
// select {
|
||||||
|
// case <-d:
|
||||||
|
// case err = <-e:
|
||||||
|
// logger.Println(err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) HandleLeavingMember(id string) {
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[id]; ok {
|
||||||
|
for _, dc := range fs.zoneFSDataChannels[id] {
|
||||||
|
dc.DataChannel.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(fs.zoneFSDataChannels, id)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
logger.Println("chatfs datachannels cleaned")
|
||||||
|
_ = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
if pc, ok := fs.rtcPeerConnections[id]; ok {
|
||||||
|
if closeErr := pc.Close(); closeErr != nil {
|
||||||
|
err = closeErr
|
||||||
|
logger.Println("peer connection close error", closeErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(fs.rtcPeerConnections, id)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
logger.Println("chats perrconnections cleaned")
|
||||||
|
_ = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
||||||
|
delete(fs.pendingCandidates, id)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
for _, openFile := range fs.OpenFilesForUser[id] {
|
||||||
|
if f, ok := fs.OpenFiles[openFile]; ok {
|
||||||
|
_ = f.Close()
|
||||||
|
}
|
||||||
|
delete(fs.OpenFiles, openFile)
|
||||||
|
}
|
||||||
|
delete(fs.OpenFilesForUser, id)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *ChatFSInstance) HandleDataChannelEvents(from, eventId string, payload map[string]interface{}) (err error) {
|
||||||
|
switch eventId {
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
150
zoneChatTracking.go
Normal file
150
zoneChatTracking.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package localserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/dgraph-io/badger/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ZoneChatTrackingDB struct {
|
||||||
|
db func(cb func(*badger.DB) (err error)) (err error)
|
||||||
|
lock *sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewZoneChatTracking(zoneId,chatId string,members ...string) (*ZoneChatTrackingDB,error) {
|
||||||
|
if _,dirErr := os.ReadDir(filepath.Join("data", "zones", zoneId, "chats", chatId,"__tracking__")); os.IsNotExist(dirErr) {
|
||||||
|
_ = os.MkdirAll(filepath.Join("data", "zones", zoneId, "chats", chatId,"__tracking__"),0700)
|
||||||
|
}
|
||||||
|
db := func(f func(*badger.DB) (err error)) (err error) {
|
||||||
|
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zoneId, "chats", chatId,"__tracking__")).WithLogger(dbLogger))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
err = f(db)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lock := new(sync.RWMutex)
|
||||||
|
if err := db(func(d *badger.DB) (err error) {
|
||||||
|
err = d.Update(func(txn *badger.Txn) error {
|
||||||
|
b := make([]byte,bufferSize)
|
||||||
|
binary.BigEndian.PutUint64(b,0)
|
||||||
|
for _, member := range 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 &ZoneChatTrackingDB{db,lock},nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zctdb *ZoneChatTrackingDB) Initialize(lastIndex uint64,users ...string) (err error) {
|
||||||
|
for _, user := range users {
|
||||||
|
if err = zctdb.SetUserLastIndex(user,lastIndex);err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zctdb *ZoneChatTrackingDB) 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 *ZoneChatTrackingDB) 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 *ZoneChatTrackingDB) 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 *ZoneChatTrackingDB) 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
|
||||||
|
}
|
||||||
@ -3,22 +3,26 @@ package localserver
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/dgraph-io/badger/v3"
|
"github.com/dgraph-io/badger/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChatFile struct {
|
type ChatFile struct {
|
||||||
Path string `json:"path"`
|
ChatId string `json:"chatId"`
|
||||||
|
Owner string `json:"owner"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Size int `json:"size"`
|
Size int `json:"size"`
|
||||||
UploadTime string `json:"uploadTime`
|
UploadTime string `json:"uploadTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatMessage struct {
|
type ChatMessage struct {
|
||||||
ID uint64 `json:"id"`
|
ID uint64 `json:"id"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
ResponseOf *ChatMessage `json:"ResponseOf"`
|
IsResponse bool `json:"isResponse"`
|
||||||
|
ResponseOf *ChatMessage `json:"responseOf"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Date string `json:"date"`
|
Date string `json:"date"`
|
||||||
@ -29,9 +33,13 @@ type ZoneChatDBHandler struct {
|
|||||||
ChatID string
|
ChatID string
|
||||||
ZoneID string
|
ZoneID string
|
||||||
PreviousId uint64
|
PreviousId uint64
|
||||||
|
ItemCount uint64
|
||||||
db func(func(*badger.DB) (err error)) (err error)
|
db func(func(*badger.DB) (err error)) (err error)
|
||||||
|
lock *sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bufferSize = 8
|
||||||
|
|
||||||
func NewZoneChatDBHandler(zoneId string, chatID string) (zoneChatDBHandler *ZoneChatDBHandler, err error) {
|
func NewZoneChatDBHandler(zoneId string, chatID string) (zoneChatDBHandler *ZoneChatDBHandler, err error) {
|
||||||
zoneChatDBHandler = &ZoneChatDBHandler{
|
zoneChatDBHandler = &ZoneChatDBHandler{
|
||||||
db: func(f func(*badger.DB) (err error)) (err error) {
|
db: func(f func(*badger.DB) (err error)) (err error) {
|
||||||
@ -45,18 +53,95 @@ func NewZoneChatDBHandler(zoneId string, chatID string) (zoneChatDBHandler *Zone
|
|||||||
},
|
},
|
||||||
ChatID: chatID,
|
ChatID: chatID,
|
||||||
ZoneID: zoneId,
|
ZoneID: zoneId,
|
||||||
|
lock: new(sync.RWMutex),
|
||||||
}
|
}
|
||||||
err = zoneChatDBHandler.db(func(d *badger.DB) (err error) {
|
err = zoneChatDBHandler.db(func(d *badger.DB) (err error) {
|
||||||
err = d.View(func(txn *badger.Txn) error {
|
err = d.View(func(txn *badger.Txn) error {
|
||||||
opt := badger.DefaultIteratorOptions
|
opt := badger.DefaultIteratorOptions
|
||||||
it := txn.NewIterator(opt)
|
it := txn.NewIterator(opt)
|
||||||
defer it.Close()
|
defer it.Close()
|
||||||
counter := 0
|
var counter uint64 = 1
|
||||||
|
var itemCounter uint64 = 0
|
||||||
for it.Rewind(); it.Valid(); it.Next() {
|
for it.Rewind(); it.Valid(); it.Next() {
|
||||||
counter++
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zoneChatDBHandler.PreviousId = counter
|
||||||
|
zoneChatDBHandler.ItemCount = itemCounter
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zcdbh *ZoneChatDBHandler) 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)
|
||||||
|
for it.Seek(b); 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
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
return
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
count--
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zcdbh *ZoneChatDBHandler) revertPreviousId() (err error) {
|
||||||
|
zcdbh.lock.Lock()
|
||||||
|
defer zcdbh.lock.Unlock()
|
||||||
|
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
|
||||||
}
|
}
|
||||||
logger.Println(counter)
|
|
||||||
zoneChatDBHandler.PreviousId = uint64(counter)
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -77,10 +162,12 @@ func (zcdbh *ZoneChatDBHandler) updateDbCallbackFolder(newChatId string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) {
|
func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) {
|
||||||
b := make([]byte, 100)
|
zcdbh.lock.Lock()
|
||||||
binary.LittleEndian.PutUint64(b, zcdbh.PreviousId+1)
|
defer zcdbh.lock.Unlock()
|
||||||
chatMessage.ID = zcdbh.PreviousId
|
b := make([]byte, bufferSize)
|
||||||
zcdbh.PreviousId++
|
zcdbh.PreviousId++
|
||||||
|
binary.BigEndian.PutUint64(b, zcdbh.PreviousId)
|
||||||
|
chatMessage.ID = zcdbh.PreviousId
|
||||||
bs, err := json.Marshal(chatMessage)
|
bs, err := json.Marshal(chatMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -100,34 +187,54 @@ func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (zcdbh *ZoneChatDBHandler) DeleteChatMessage(key uint64) (err error) {
|
func (zcdbh *ZoneChatDBHandler) DeleteChatMessage(key uint64) (err error) {
|
||||||
|
if err = zcdbh.db(func(d *badger.DB) (err error) {
|
||||||
|
zcdbh.lock.Lock()
|
||||||
|
defer zcdbh.lock.Unlock()
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chatMessages []*ChatMessage, l int, err error) {
|
func (zcdbh *ZoneChatDBHandler) DeleteChatFile(filename string, key uint64) (err error) {
|
||||||
|
zcdbh.lock.Lock()
|
||||||
|
defer zcdbh.lock.Unlock()
|
||||||
|
if err = zcdbh.DeleteChatMessage(key); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.Remove(filepath.Join("data", "zones", zcdbh.ZoneID, "chats", zcdbh.ChatID, "__files__", filename))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chatMessages []*ChatMessage, l int, done bool, err error) {
|
||||||
|
zcdbh.lock.RLock()
|
||||||
|
defer zcdbh.lock.RUnlock()
|
||||||
err = zcdbh.db(func(d *badger.DB) (err error) {
|
err = zcdbh.db(func(d *badger.DB) (err error) {
|
||||||
err = d.View(func(txn *badger.Txn) (err error) {
|
err = d.View(func(txn *badger.Txn) (err error) {
|
||||||
opt := badger.DefaultIteratorOptions
|
opt := badger.DefaultIteratorOptions
|
||||||
opt.Reverse = true
|
opt.Reverse = true
|
||||||
it := txn.NewIterator(opt)
|
it := txn.NewIterator(opt)
|
||||||
b := make([]byte, 100)
|
b := make([]byte, bufferSize)
|
||||||
if lastIndex <= 0 {
|
if lastIndex <= 0 {
|
||||||
binary.LittleEndian.PutUint64(b, uint64(zcdbh.PreviousId))
|
binary.BigEndian.PutUint64(b, uint64(zcdbh.PreviousId))
|
||||||
} else {
|
} else {
|
||||||
binary.LittleEndian.PutUint64(b, uint64(lastIndex))
|
binary.BigEndian.PutUint64(b, uint64(lastIndex))
|
||||||
}
|
}
|
||||||
x := 0
|
x := 0
|
||||||
defer it.Close()
|
defer it.Close()
|
||||||
defer func() {
|
defer func() {
|
||||||
if lastIndex > limit {
|
if x < limit {
|
||||||
l = lastIndex - limit - 1
|
done = true
|
||||||
} else if lastIndex == 0 {
|
|
||||||
if zcdbh.PreviousId > uint64(limit) {
|
|
||||||
l = int(zcdbh.PreviousId) - limit - 1
|
|
||||||
} else {
|
|
||||||
l = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
l = 0
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
chatMessages = make([]*ChatMessage, 0)
|
chatMessages = make([]*ChatMessage, 0)
|
||||||
@ -141,6 +248,7 @@ func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chat
|
|||||||
if err = json.Unmarshal(val, &chatMessage); err != nil {
|
if err = json.Unmarshal(val, &chatMessage); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
l = int(chatMessage.ID)
|
||||||
chatMessages = append(chatMessages, chatMessage)
|
chatMessages = append(chatMessages, chatMessage)
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -155,11 +263,75 @@ func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chat
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zcdbh *ZoneChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatMessage, err error) {
|
func (zcdbh *ZoneChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMessages []*ChatFile, l int, err error) {
|
||||||
|
zcdbh.lock.RLock()
|
||||||
|
defer zcdbh.lock.RUnlock()
|
||||||
err = zcdbh.db(func(d *badger.DB) (err error) {
|
err = zcdbh.db(func(d *badger.DB) (err error) {
|
||||||
err = d.View(func(txn *badger.Txn) (err error) {
|
err = d.View(func(txn *badger.Txn) (err error) {
|
||||||
b := make([]byte, 100)
|
opt := badger.DefaultIteratorOptions
|
||||||
binary.LittleEndian.PutUint64(b, uint64(zcdbh.PreviousId))
|
opt.Reverse = true
|
||||||
|
it := txn.NewIterator(opt)
|
||||||
|
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 *ZoneChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatMessage, err error) {
|
||||||
|
zcdbh.lock.RLock()
|
||||||
|
defer zcdbh.lock.RUnlock()
|
||||||
|
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)
|
item, err := txn.Get(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -174,6 +346,30 @@ func (zcdbh *ZoneChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatM
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zcdbh *ZoneChatDBHandler) ModifyChatMessage(id string, chatMessage *ChatMessage) (err error) {
|
func (zcdbh *ZoneChatDBHandler) ModifyChatMessage(key uint64, newContent string) (err error) {
|
||||||
|
zcdbh.lock.Lock()
|
||||||
|
defer zcdbh.lock.Unlock()
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,17 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dgraph-io/badger/v3"
|
"github.com/dgraph-io/badger/v3"
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LIST_LATEST_CHATS = "list_latest_chats"
|
LIST_LATEST_CHATS = "list_latest_chats"
|
||||||
|
READ_LATEST_MESSAGE = "read_latest_message"
|
||||||
|
LIST_LATEST_FILES = "list_latest_files"
|
||||||
LIST_CHATS = "list_chats"
|
LIST_CHATS = "list_chats"
|
||||||
GET_CHATS = "get_chats"
|
GET_CHATS = "get_chats"
|
||||||
GET_CHAT = "get_chat"
|
GET_CHAT = "get_chat"
|
||||||
@ -24,17 +28,29 @@ const (
|
|||||||
ADD_CHAT_MEMBERS = "add_chat_members"
|
ADD_CHAT_MEMBERS = "add_chat_members"
|
||||||
REMOVE_CHAT_MEMBER = "remove_chat_member"
|
REMOVE_CHAT_MEMBER = "remove_chat_member"
|
||||||
ADD_CHAT_MESSAGE = "add_chat_message"
|
ADD_CHAT_MESSAGE = "add_chat_message"
|
||||||
|
ZONE_UPLOAD_CHAT_FILE = "zone_upload_chat_file"
|
||||||
|
ZONE_DOWNLOAD_CHAT_FILE = "zone_download_chat_file"
|
||||||
|
DELETE_CHAT_FILE = "delete_chat_file"
|
||||||
|
DELETE_CHAT_MESSAGE = "delete_chat_message"
|
||||||
|
EDIT_CHAT_MESSAGE = "edit_chat_message"
|
||||||
|
ZONE_UPLOAD_CHAT_FILE_DONE = "zone_upload_chat_file_done"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CHAT_NAME_EDITED = "chat_name_edited"
|
CHAT_NAME_EDITED = "chat_name_edited"
|
||||||
CHAT_MEMBER_LIST = "chat_messages_list"
|
CHAT_TYPE_EDITED = "chat_type_edited"
|
||||||
|
CHAT_MESSAGE_LIST = "chat_messages_list"
|
||||||
|
CHAT_FILES_LIST = "chat_files_list"
|
||||||
CHAT_MEMBER_ADDED = "chat_member_added"
|
CHAT_MEMBER_ADDED = "chat_member_added"
|
||||||
CHAT_MEMBER_REMOVED = "chat_member_removed"
|
CHAT_MEMBER_REMOVED = "chat_member_removed"
|
||||||
REMOVED_FROM_CHAT = "removed_from_chat"
|
REMOVED_FROM_CHAT = "removed_from_chat"
|
||||||
ADDED_IN_CHAT = "added_in_chat"
|
ADDED_IN_CHAT = "added_in_chat"
|
||||||
GET_CHATS_RESPONSE = "get_chats_response"
|
GET_CHATS_RESPONSE = "get_chats_response"
|
||||||
NEW_CHAT_MESSAGE = "new_chat_message"
|
NEW_CHAT_MESSAGE = "new_chat_message"
|
||||||
|
CHAT_MESSAGE_DELETED = "chat_message_deleted"
|
||||||
|
CHAT_MESSAGE_EDITED = "chat_message_edited"
|
||||||
|
CHAT_FILE_DELETED = "chat_file_deleted"
|
||||||
|
NEW_CHAT_FILE = "new_chat_file"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -56,21 +72,27 @@ type Chat struct {
|
|||||||
ChatType string `json:"chatType"`
|
ChatType string `json:"chatType"`
|
||||||
Owner string `json:"owner"`
|
Owner string `json:"owner"`
|
||||||
Members []string `json:"members"`
|
Members []string `json:"members"`
|
||||||
|
LastReadIndex uint `json:"lastReadIndex"`
|
||||||
|
Unread uint `json:"unread"`
|
||||||
DB *ZoneChatDBHandler `json:"-"`
|
DB *ZoneChatDBHandler `json:"-"`
|
||||||
|
Tracking *ZoneChatTrackingDB `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZoneChatsHandler struct {
|
type ZoneChatsHandler struct {
|
||||||
ZoneId string
|
ZoneId string
|
||||||
|
HostId string
|
||||||
|
ChatFSInstance *ChatFSInstance
|
||||||
ZoneMembersId []string
|
ZoneMembersId []string
|
||||||
DataChannels map[string]*DataChannel
|
DataChannels map[string]*DataChannel
|
||||||
Flag *uint32
|
Flag *uint32
|
||||||
|
ChatFSInstanceFlag *uint32
|
||||||
ChatFlag *uint32
|
ChatFlag *uint32
|
||||||
Chats map[string]*Chat
|
Chats map[string]*Chat
|
||||||
reqChans []chan<- *ZoneRequest
|
reqChans []chan<- *ZoneRequest
|
||||||
init bool
|
init bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZoneChatsHandler(zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneChatsHandler *ZoneChatsHandler, err error) {
|
func NewZoneChatsHandler(hostId, zoneId, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneChatsHandler *ZoneChatsHandler, err error) {
|
||||||
var dirs []fs.DirEntry
|
var dirs []fs.DirEntry
|
||||||
dirs, err = os.ReadDir(filepath.Join("data", "zones", zoneId, "chats"))
|
dirs, err = os.ReadDir(filepath.Join("data", "zones", zoneId, "chats"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -112,6 +134,10 @@ func NewZoneChatsHandler(zoneId string, owner string, authorizedMembers []string
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
zoneChatTracking,err := NewZoneChatTracking(zoneId, chat.Name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var bs []byte
|
var bs []byte
|
||||||
bs, err = os.ReadFile(filepath.Join("data", "zones", zoneId, "chats", chat.Name(), "chatConfig.json"))
|
bs, err = os.ReadFile(filepath.Join("data", "zones", zoneId, "chats", chat.Name(), "chatConfig.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -122,12 +148,20 @@ func NewZoneChatsHandler(zoneId string, owner string, authorizedMembers []string
|
|||||||
if err = json.Unmarshal(bs, &c); err != nil {
|
if err = json.Unmarshal(bs, &c); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err = zoneChatTracking.Initialize(0,c.Members...); err != nil {
|
||||||
|
return nil,err
|
||||||
|
}
|
||||||
logger.Println("chats data :", c.ChatId, c.ChatType, c.Owner, c.Members)
|
logger.Println("chats data :", c.ChatId, c.ChatType, c.Owner, c.Members)
|
||||||
c.DB = zoneChatDBHandler
|
c.DB = zoneChatDBHandler
|
||||||
|
c.Tracking = zoneChatTracking
|
||||||
chats[c.ChatId] = &c
|
chats[c.ChatId] = &c
|
||||||
}
|
}
|
||||||
chatFlag := uint32(0)
|
chatFlag := uint32(0)
|
||||||
|
chatFSFlag := uint32(0)
|
||||||
zoneChatsHandler = &ZoneChatsHandler{
|
zoneChatsHandler = &ZoneChatsHandler{
|
||||||
|
HostId: hostId,
|
||||||
|
ChatFSInstance: NewChatFSInstance(zoneId, owner, authorizedMembers),
|
||||||
|
ChatFSInstanceFlag: &chatFSFlag,
|
||||||
ZoneId: zoneId,
|
ZoneId: zoneId,
|
||||||
ZoneMembersId: authorizedMembers,
|
ZoneMembersId: authorizedMembers,
|
||||||
DataChannels: dataChannels,
|
DataChannels: dataChannels,
|
||||||
@ -206,6 +240,21 @@ func (zch *ZoneChatsHandler) Subscribe(ctx context.Context, publisher <-chan *Zo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) signalCandidate(from string, to string, candidate *webrtc.ICECandidate) (err error) {
|
||||||
|
d, e := zch.sendDataChannelMessage(string(ZONE_CHAT_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 (zch *ZoneChatsHandler) GetChats(userId string, chatsId ...interface{}) (err error) {
|
func (zch *ZoneChatsHandler) GetChats(userId string, chatsId ...interface{}) (err error) {
|
||||||
chats := make([]*Chat, 0, len(chatsId))
|
chats := make([]*Chat, 0, len(chatsId))
|
||||||
for _, id := range chatsId {
|
for _, id := range chatsId {
|
||||||
@ -213,7 +262,7 @@ func (zch *ZoneChatsHandler) GetChats(userId string, chatsId ...interface{}) (er
|
|||||||
err = fmt.Errorf("id of wrong type")
|
err = fmt.Errorf("id of wrong type")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("chat from get chats", id.(string))
|
fmt.Println("chat from get chats", id.(string))
|
||||||
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
if _, ok := zch.Chats[id.(string)]; ok {
|
if _, ok := zch.Chats[id.(string)]; ok {
|
||||||
logger.Println(zch.Chats[id.(string)])
|
logger.Println(zch.Chats[id.(string)])
|
||||||
@ -222,27 +271,36 @@ func (zch *ZoneChatsHandler) GetChats(userId string, chatsId ...interface{}) (er
|
|||||||
return
|
return
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
answer := &ZoneResponse{
|
fmt.Println("first loop done")
|
||||||
Type: GET_CHATS_RESPONSE,
|
for _, chat := range chats {
|
||||||
From: "",
|
fmt.Println(chat.ChatId)
|
||||||
To: "",
|
index,err := chat.Tracking.GetUserLastIndex(userId)
|
||||||
Payload: map[string]interface{}{
|
|
||||||
"chats": chats,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
bs, jsonErr := json.Marshal(answer)
|
|
||||||
if jsonErr != nil {
|
|
||||||
return jsonErr
|
|
||||||
}
|
|
||||||
_ = atomicallyExecute(zch.Flag, func() (err error) {
|
|
||||||
if _, ok := zch.DataChannels[userId]; ok {
|
|
||||||
err = zch.DataChannels[userId].DataChannel.SendText(string(bs))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
fmt.Println("there")
|
||||||
|
fmt.Println(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
chat.DB.lock.RLock()
|
||||||
|
defer chat.DB.lock.RUnlock()
|
||||||
|
unread,err := chat.DB.calculateNewChatCount(uint64(index))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("over there")
|
||||||
|
fmt.Println(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return
|
chat.LastReadIndex = index
|
||||||
|
chat.Unread = unread
|
||||||
|
}
|
||||||
|
fmt.Println(chats)
|
||||||
|
done,e := zch.sendDataChannelMessage(GET_CHATS_RESPONSE,"node",userId,map[string]interface{}{
|
||||||
|
"chats": chats,
|
||||||
})
|
})
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
fmt.Println("done")
|
||||||
|
case terr :=<-e:
|
||||||
|
fmt.Println(terr)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,21 +324,25 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
|
|||||||
if mkdirErr != nil {
|
if mkdirErr != nil {
|
||||||
return mkdirErr
|
return mkdirErr
|
||||||
}
|
}
|
||||||
|
mkdirErr = os.Mkdir(filepath.Join("data", "zones", zch.ZoneId, "chats", chatName,"__tracking__"), 0700)
|
||||||
|
if mkdirErr != nil {
|
||||||
|
return mkdirErr
|
||||||
|
}
|
||||||
file, ferr := os.Create(filepath.Join("data", "zones", zch.ZoneId, "chats", chatName, "chatConfig.json"))
|
file, ferr := os.Create(filepath.Join("data", "zones", zch.ZoneId, "chats", chatName, "chatConfig.json"))
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
m := make([]string, 0, len(members))
|
m := make([]string, 0, len(members))
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
if _, ok := member.(string); ok {
|
if mbr, ok := member.(string); ok && mbr != owner {
|
||||||
m = append(m, member.(string))
|
m = append(m, mbr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
baseConfig := &ChatConfig{
|
baseConfig := &ChatConfig{
|
||||||
ChatId: chatName,
|
ChatId: chatName,
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
ChatType: chatType,
|
ChatType: chatType,
|
||||||
Members: m,
|
Members: append(m,owner),
|
||||||
}
|
}
|
||||||
bs, jsonErr := json.Marshal(baseConfig)
|
bs, jsonErr := json.Marshal(baseConfig)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
@ -297,11 +359,19 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
zoneChatTrackingDB,err := NewZoneChatTracking(zch.ZoneId,chatName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = zoneChatTrackingDB.Initialize(1,baseConfig.Members...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
var c Chat
|
var c Chat
|
||||||
if err = json.Unmarshal(bs, &c); err != nil {
|
if err = json.Unmarshal(bs, &c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.DB = zoneChatDBHandler
|
c.DB = zoneChatDBHandler
|
||||||
|
c.Tracking = zoneChatTrackingDB
|
||||||
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
zch.Chats[c.ChatId] = &c
|
zch.Chats[c.ChatId] = &c
|
||||||
return
|
return
|
||||||
@ -396,10 +466,10 @@ func (zch *ZoneChatsHandler) EditChatName(chatId string, newChatId string) (err
|
|||||||
}
|
}
|
||||||
chatConfig.ChatId = newChatId
|
chatConfig.ChatId = newChatId
|
||||||
bs, err = json.Marshal(&chatConfig)
|
bs, err = json.Marshal(&chatConfig)
|
||||||
if err = os.Rename(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId), filepath.Join("data", "zones", zch.ZoneId, "chats", chatId)); err != nil {
|
if err = os.Rename(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId), filepath.Join("data", "zones", zch.ZoneId, "chats", newChatId)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f, err := os.OpenFile(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId, "chatConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
f, err := os.OpenFile(filepath.Join("data", "zones", zch.ZoneId, "chats", newChatId, "chatConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
}()
|
}()
|
||||||
@ -415,6 +485,7 @@ func (zch *ZoneChatsHandler) EditChatName(chatId string, newChatId string) (err
|
|||||||
ChatType: chatConfig.ChatType,
|
ChatType: chatConfig.ChatType,
|
||||||
Members: chatConfig.Members,
|
Members: chatConfig.Members,
|
||||||
DB: zch.Chats[chatId].DB,
|
DB: zch.Chats[chatId].DB,
|
||||||
|
Tracking:zch.Chats[chatId].Tracking,
|
||||||
}
|
}
|
||||||
chat.DB.updateDbCallbackFolder(newChatId)
|
chat.DB.updateDbCallbackFolder(newChatId)
|
||||||
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
@ -483,9 +554,10 @@ func (zch *ZoneChatsHandler) EditChatType(chatId string, chatType string) (err e
|
|||||||
chat := &Chat{
|
chat := &Chat{
|
||||||
Owner: chatConfig.Owner,
|
Owner: chatConfig.Owner,
|
||||||
ChatId: chatConfig.ChatId,
|
ChatId: chatConfig.ChatId,
|
||||||
ChatType: chatConfig.ChatType,
|
ChatType: chatType,
|
||||||
Members: chatConfig.Members,
|
Members: chatConfig.Members,
|
||||||
DB: zch.Chats[chatId].DB,
|
DB: zch.Chats[chatId].DB,
|
||||||
|
Tracking:zch.Chats[chatId].Tracking,
|
||||||
}
|
}
|
||||||
switch chatType {
|
switch chatType {
|
||||||
case BROADCAST:
|
case BROADCAST:
|
||||||
@ -500,6 +572,10 @@ func (zch *ZoneChatsHandler) EditChatType(chatId string, chatType string) (err e
|
|||||||
if pubErr := zch.SetChatPublicForUser(chatId, member); pubErr != nil {
|
if pubErr := zch.SetChatPublicForUser(chatId, member); pubErr != nil {
|
||||||
logger.Println(pubErr)
|
logger.Println(pubErr)
|
||||||
}
|
}
|
||||||
|
zch.sendDataChannelMessage(CHAT_TYPE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"chatType": chatType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case PRIVATE:
|
case PRIVATE:
|
||||||
var members = []string{}
|
var members = []string{}
|
||||||
@ -511,6 +587,10 @@ func (zch *ZoneChatsHandler) EditChatType(chatId string, chatType string) (err e
|
|||||||
if pubErr := zch.SetChatPrivateForUser(chatId, member); pubErr != nil {
|
if pubErr := zch.SetChatPrivateForUser(chatId, member); pubErr != nil {
|
||||||
logger.Println(pubErr)
|
logger.Println(pubErr)
|
||||||
}
|
}
|
||||||
|
zch.sendDataChannelMessage(CHAT_TYPE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"chatType": chatType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
@ -573,14 +653,27 @@ memberLoop:
|
|||||||
ChatType: chatConfig.ChatType,
|
ChatType: chatConfig.ChatType,
|
||||||
Members: chatConfig.Members,
|
Members: chatConfig.Members,
|
||||||
DB: zch.Chats[chatId].DB,
|
DB: zch.Chats[chatId].DB,
|
||||||
|
Tracking: zch.Chats[chatId].Tracking,
|
||||||
}
|
}
|
||||||
|
chat.DB.lock.Lock()
|
||||||
|
lastIndex := chat.DB.PreviousId
|
||||||
|
chat.DB.lock.Unlock()
|
||||||
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
zch.Chats[chatId] = chat
|
zch.Chats[chatId] = chat
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
var chmb []string
|
||||||
|
if chat.ChatType == PRIVATE {
|
||||||
|
chmb = chat.Members
|
||||||
|
} else {
|
||||||
|
chmb = zch.ZoneMembersId
|
||||||
|
}
|
||||||
broadcastLoop:
|
broadcastLoop:
|
||||||
for _, member := range chat.Members {
|
for _, member := range chmb {
|
||||||
for _, m := range addedMembers {
|
for _, m := range addedMembers {
|
||||||
|
if err = chat.Tracking.SetUserLastIndex(member,lastIndex); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if member == m {
|
if member == m {
|
||||||
done, e := zch.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
|
done, e := zch.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
|
||||||
"chat": chat,
|
"chat": chat,
|
||||||
@ -665,10 +758,14 @@ func (zch *ZoneChatsHandler) RemoveChatMember(chatId string, chatMember string)
|
|||||||
ChatType: chatConfig.ChatType,
|
ChatType: chatConfig.ChatType,
|
||||||
Members: chatConfig.Members,
|
Members: chatConfig.Members,
|
||||||
DB: zch.Chats[chatId].DB,
|
DB: zch.Chats[chatId].DB,
|
||||||
|
Tracking: zch.Chats[chatId].Tracking,
|
||||||
}
|
}
|
||||||
zch.Chats[chatId] = chat
|
zch.Chats[chatId] = chat
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
if err = chat.Tracking.DeleteUserTracking(chatMember); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
zch.sendZoneRequest(REMOVE_KNOWN_CHAT, "node", map[string]interface{}{
|
zch.sendZoneRequest(REMOVE_KNOWN_CHAT, "node", map[string]interface{}{
|
||||||
"userId": chatMember,
|
"userId": chatMember,
|
||||||
"chatId": chatId,
|
"chatId": chatId,
|
||||||
@ -682,8 +779,14 @@ func (zch *ZoneChatsHandler) RemoveChatMember(chatId string, chatMember string)
|
|||||||
case err = <-e:
|
case err = <-e:
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
}
|
}
|
||||||
|
var chmb []string
|
||||||
|
if chat.ChatType == PRIVATE {
|
||||||
|
chmb = chat.Members
|
||||||
|
} else {
|
||||||
|
chmb = zch.ZoneMembersId
|
||||||
|
}
|
||||||
broadcastLoop:
|
broadcastLoop:
|
||||||
for _, member := range chat.Members {
|
for _, member := range chmb {
|
||||||
if member == chatMember {
|
if member == chatMember {
|
||||||
continue broadcastLoop
|
continue broadcastLoop
|
||||||
}
|
}
|
||||||
@ -700,19 +803,58 @@ broadcastLoop:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zch *ZoneChatsHandler) ListLatestChatMessages(userId string, chatId string, lastIndex float64, limit float64) (err error) {
|
func(zch *ZoneChatsHandler) ReadLastMessage(userId,chatId string) (err error) {
|
||||||
|
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
|
if chat, ok := zch.Chats[chatId]; ok {
|
||||||
|
err = chat.Tracking.SetUserLastIndex(userId,chat.DB.PreviousId)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) ListLatestChatMessages(userId, chatId string, lastIndex, limit float64) (err error) {
|
||||||
var list []*ChatMessage
|
var list []*ChatMessage
|
||||||
var i int
|
var i int
|
||||||
|
var done bool
|
||||||
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
if _, ok := zch.Chats[chatId]; ok {
|
if chat, ok := zch.Chats[chatId]; ok {
|
||||||
list, i, err = zch.Chats[chatId].DB.ListChatMessages(int(lastIndex), int(limit))
|
list, i, done, err = zch.Chats[chatId].DB.ListChatMessages(int(lastIndex), int(limit))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = chat.Tracking.SetUserLastIndex(userId,chat.DB.PreviousId)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done, e := zch.sendDataChannelMessage(CHAT_MEMBER_LIST, "node", userId, map[string]interface{}{
|
success, e := zch.sendDataChannelMessage(CHAT_MESSAGE_LIST, "node", userId, map[string]interface{}{
|
||||||
"done": i == 0,
|
"done": done || i <= 0,
|
||||||
|
"lastIndex": i - 1,
|
||||||
|
"chatId": chatId,
|
||||||
|
"chatMessages": list,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-success:
|
||||||
|
case err = <-e:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) ListLatestChatFiles(userId, chatId string, lastIndex, limit float64) (err error) {
|
||||||
|
var list []*ChatFile
|
||||||
|
var i int
|
||||||
|
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
|
if _, ok := zch.Chats[chatId]; ok {
|
||||||
|
list, i, err = zch.Chats[chatId].DB.ListChatFiles(int(lastIndex), int(limit))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
done, e := zch.sendDataChannelMessage(CHAT_FILES_LIST, "node", userId, map[string]interface{}{
|
||||||
|
"done": i <= 0,
|
||||||
"lastIndex": i,
|
"lastIndex": i,
|
||||||
"chatId": chatId,
|
"chatId": chatId,
|
||||||
"chatMessages": list,
|
"chatMessages": list,
|
||||||
@ -724,27 +866,33 @@ func (zch *ZoneChatsHandler) ListLatestChatMessages(userId string, chatId string
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zch *ZoneChatsHandler) AddChatMessage(userId string, chatId string, content string, chatResponseId uint64, file *ChatFile) (err error) {
|
func (zch *ZoneChatsHandler) AddChatMessage(userId, chatId, content string, isResponse bool, chatResponseId uint64, file *ChatFile) (err error) {
|
||||||
chatMessage := &ChatMessage{
|
chatMessage := &ChatMessage{
|
||||||
Content: content,
|
Content: content,
|
||||||
From: userId,
|
From: userId,
|
||||||
|
IsResponse: isResponse,
|
||||||
ResponseOf: nil,
|
ResponseOf: nil,
|
||||||
File: file,
|
File: file,
|
||||||
Tags: make([]string, 0),
|
Tags: make([]string, 0),
|
||||||
Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"),
|
Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
if _, ok := zch.Chats[chatId]; ok {
|
if chat, ok := zch.Chats[chatId]; ok {
|
||||||
parentMessage, getErr := zch.Chats[chatId].DB.GetChatMessage(chatResponseId)
|
if isResponse {
|
||||||
|
parentMessage, getErr := chat.DB.GetChatMessage(chatResponseId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if getErr != badger.ErrKeyNotFound {
|
if getErr != badger.ErrKeyNotFound {
|
||||||
return getErr
|
return getErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chatMessage.ResponseOf = parentMessage
|
chatMessage.ResponseOf = parentMessage
|
||||||
|
}
|
||||||
if err = zch.Chats[chatId].DB.AddNewChatMessage(chatMessage); err != nil {
|
if err = zch.Chats[chatId].DB.AddNewChatMessage(chatMessage); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
chatMessage.ID = zch.Chats[chatId].DB.PreviousId
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("no corresponding chats")
|
err = fmt.Errorf("no corresponding chats")
|
||||||
}
|
}
|
||||||
@ -752,7 +900,6 @@ func (zch *ZoneChatsHandler) AddChatMessage(userId string, chatId string, conten
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chatMessage.ID = zch.Chats[chatId].DB.PreviousId
|
|
||||||
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
chat := zch.Chats[chatId]
|
chat := zch.Chats[chatId]
|
||||||
logger.Println(chat.ChatType)
|
logger.Println(chat.ChatType)
|
||||||
@ -896,9 +1043,166 @@ func (zch *ZoneChatsHandler) RemoveAllUserChat(userId string) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) ConnectToChatFSInstance(channelId string, userId string, sdp string) (err error) {
|
||||||
|
err = atomicallyExecute(zch.ChatFSInstanceFlag, func() (err error) {
|
||||||
|
d, e := zch.ChatFSInstance.HandleOffer(context.Background(), channelId, userId, sdp, zch.HostId, zch.sendDataChannelMessage, zch.signalCandidate)
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case err = <-e:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) LeaveChatFSInstance(
|
||||||
|
userId string) (err error) {
|
||||||
|
zch.ChatFSInstance.HandleLeavingMember(userId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) DeleteChatMessage(key uint64, chatId string) (err error) {
|
||||||
|
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
|
if _, ok := zch.Chats[chatId]; !ok {
|
||||||
|
err = fmt.Errorf("no file corresponding to id %s", chatId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = zch.Chats[chatId].DB.DeleteChatMessage(key); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if zch.Chats[chatId].ChatType == PRIVATE {
|
||||||
|
for _, member := range zch.Chats[chatId].Members {
|
||||||
|
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_DELETED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"messageId": key,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case tempErr := <-e:
|
||||||
|
logger.Println(tempErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, member := range zch.ZoneMembersId {
|
||||||
|
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_DELETED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"messageId": key,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case tempErr := <-e:
|
||||||
|
logger.Println(tempErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousId := zch.Chats[chatId].DB.PreviousId
|
||||||
|
if previousId == key {
|
||||||
|
if err = zch.Chats[chatId].DB.revertPreviousId(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
previousId = zch.Chats[chatId].DB.PreviousId
|
||||||
|
if previousId == 1 {
|
||||||
|
previousId = 0
|
||||||
|
}
|
||||||
|
if err = zch.Chats[chatId].Tracking.RevertTrackingLastIndex(previousId); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) UpdateChatMessage(key uint64, chatId, newContent string) (err error) {
|
||||||
|
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
|
if _, ok := zch.Chats[chatId]; !ok {
|
||||||
|
err = fmt.Errorf("no file corresponding to id %s", chatId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = zch.Chats[chatId].DB.ModifyChatMessage(key, newContent); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if zch.Chats[chatId].ChatType == PRIVATE {
|
||||||
|
for _, member := range zch.Chats[chatId].Members {
|
||||||
|
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"messageId": key,
|
||||||
|
"newContent": newContent,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case tempErr := <-e:
|
||||||
|
logger.Println(tempErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, member := range zch.ZoneMembersId {
|
||||||
|
d, e := zch.sendDataChannelMessage(CHAT_MESSAGE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"messageId": key,
|
||||||
|
"newContent": newContent,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case tempErr := <-e:
|
||||||
|
logger.Println(tempErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zch *ZoneChatsHandler) DeleteChatFile(key uint64, fileName, chatId string) (err error) {
|
||||||
|
err = atomicallyExecute(zch.ChatFlag, func() (err error) {
|
||||||
|
if _, ok := zch.Chats[chatId]; !ok {
|
||||||
|
err = fmt.Errorf("no file corresponding to id %s", chatId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = zch.Chats[chatId].DB.DeleteChatFile(fileName, key); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if zch.Chats[chatId].ChatType == PRIVATE {
|
||||||
|
for _, member := range zch.Chats[chatId].Members {
|
||||||
|
d, e := zch.sendDataChannelMessage(CHAT_FILE_DELETED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"fileId": key,
|
||||||
|
"fileName": fileName,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case tempErr := <-e:
|
||||||
|
logger.Println(tempErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, member := range zch.ZoneMembersId {
|
||||||
|
d, e := zch.sendDataChannelMessage(CHAT_FILE_DELETED, "node", member, map[string]interface{}{
|
||||||
|
"chatId": chatId,
|
||||||
|
"fileId": key,
|
||||||
|
"fileName": fileName,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case tempErr := <-e:
|
||||||
|
logger.Println(tempErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
|
func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
|
||||||
logger.Println("got request in zone chat handler", req)
|
logger.Println("got request in zone chat handler", req)
|
||||||
switch req.ReqType {
|
switch req.ReqType {
|
||||||
|
case LEAVE_ZONE:
|
||||||
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.LeaveChatFSInstance(req.Payload["userId"].(string))
|
||||||
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
|
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
|
||||||
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
return
|
return
|
||||||
@ -975,10 +1279,13 @@ func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
|
|||||||
}
|
}
|
||||||
err = zch.AddNewChat(req.Payload["chatId"].(string), req.Payload["owner"].(string), req.Payload["chatType"].(string), req.Payload["members"].([]interface{}))
|
err = zch.AddNewChat(req.Payload["chatId"].(string), req.Payload["owner"].(string), req.Payload["chatType"].(string), req.Payload["members"].([]interface{}))
|
||||||
case GET_CHATS:
|
case GET_CHATS:
|
||||||
|
fmt.Println("got a get chat req")
|
||||||
if err = verifyFieldsSliceInterface(req.Payload, "chatsId"); err != nil {
|
if err = verifyFieldsSliceInterface(req.Payload, "chatsId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Println("calling get chat")
|
||||||
err = zch.GetChats(req.From, req.Payload["chatsId"].([]interface{})...)
|
err = zch.GetChats(req.From, req.Payload["chatsId"].([]interface{})...)
|
||||||
|
fmt.Println("get chat done")
|
||||||
case LIST_LATEST_CHATS:
|
case LIST_LATEST_CHATS:
|
||||||
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
|
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
|
||||||
return
|
return
|
||||||
@ -988,16 +1295,37 @@ func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
|
|||||||
}
|
}
|
||||||
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
|
return
|
||||||
|
case LIST_LATEST_FILES:
|
||||||
|
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = verifyFieldsFloat64(req.Payload, "lastIndex", "limit"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.ListLatestChatFiles(req.From, req.Payload["chatId"].(string), req.Payload["lastIndex"].(float64), req.Payload["limit"].(float64))
|
||||||
|
return
|
||||||
|
case READ_LATEST_MESSAGE:
|
||||||
|
if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.ReadLastMessage(req.From,req.Payload["chatId"].(string))
|
||||||
case ADD_CHAT_MESSAGE:
|
case ADD_CHAT_MESSAGE:
|
||||||
logger.Println("got request in zone chat handler", req)
|
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
|
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 {
|
if err = verifyFieldsFloat64(req.Payload, "parentChatId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
parentChatId = uint64(req.Payload["parentChatId"].(float64))
|
||||||
|
}
|
||||||
var file *ChatFile = nil
|
var file *ChatFile = nil
|
||||||
if _,ok := req.Payload["file"]; ok {
|
if _, ok := req.Payload["file"]; ok {
|
||||||
bs, jsonErr := json.Marshal(req.Payload["file"])
|
bs, jsonErr := json.Marshal(req.Payload["file"])
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
return jsonErr
|
return jsonErr
|
||||||
@ -1009,7 +1337,114 @@ func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
|
|||||||
}
|
}
|
||||||
file = &f
|
file = &f
|
||||||
}
|
}
|
||||||
err = zch.AddChatMessage(req.From, req.Payload["chatId"].(string), req.Payload["content"].(string),uint64(req.Payload["parentChatId"].(float64)),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 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = verifyFieldsFloat64(req.Payload, "messageId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.DeleteChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatId"].(string))
|
||||||
|
case EDIT_CHAT_MESSAGE:
|
||||||
|
if err = verifyFieldsString(req.Payload, "chatId", "newContent"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = verifyFieldsFloat64(req.Payload, "messageId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.UpdateChatMessage(uint64(req.Payload["messageId"].(float64)), req.Payload["chatId"].(string), req.Payload["newContent"].(string))
|
||||||
|
case DELETE_CHAT_FILE:
|
||||||
|
if err = verifyFieldsString(req.Payload, "chatId", "fileName"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = verifyFieldsFloat64(req.Payload, "fileId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.DeleteChatFile(uint64(req.Payload["fileId"].(float64)), req.Payload["fileName"].(string), req.Payload["chatId"].(string))
|
||||||
|
case ZONE_UPLOAD_CHAT_FILE:
|
||||||
|
if err = verifyFieldsString(req.Payload, "chatId", "userId", "fileName"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.ChatFSInstance.SetupFileUpload(req.Payload["chatId"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))
|
||||||
|
case ZONE_DOWNLOAD_CHAT_FILE:
|
||||||
|
if err = verifyFieldsString(req.Payload, "chatId", "userId", "fileName"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.ChatFSInstance.SetupFileDownload(req.Payload["chatId"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string))
|
||||||
|
case ZONE_UPLOAD_CHAT_FILE_DONE:
|
||||||
|
if err = verifyFieldsBool(req.Payload, "failed"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = verifyFieldsFloat64(req.Payload, "size"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := req.Payload["chatFile"]; !ok {
|
||||||
|
err = fmt.Errorf("no field chatFile in request payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.Payload["failed"].(bool) {
|
||||||
|
logger.Println(zch.ChatFSInstance.FileUploadFailed(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)))
|
||||||
|
} else {
|
||||||
|
defer func() {
|
||||||
|
logger.Println(zch.ChatFSInstance.FileUploadDone(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
case string(ZONE_CHAT_WEBRTC_OFFER):
|
||||||
|
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zch.ConnectToChatFSInstance(req.Payload["channelId"].(string), req.Payload["userId"].(string), req.Payload["sdp"].(string))
|
||||||
|
case string(ZONE_CHAT_WEBRTC_COUNTER_OFFER):
|
||||||
|
logger.Println("handling fs instance counter offer")
|
||||||
|
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = atomicallyExecute(zch.ChatFSInstanceFlag, func() (err error) {
|
||||||
|
err = zch.ChatFSInstance.HandleCounterOffer(context.Background(), req.Payload["userId"].(string), zch.sendDataChannelMessage)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
case string(ZONE_CHAT_WEBRTC_RENNEGOTIATION_OFFER):
|
||||||
|
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = atomicallyExecute(zch.ChatFSInstanceFlag, func() (err error) {
|
||||||
|
err = zch.ChatFSInstance.HandleRennegotiationOffer(req.Payload["userId"].(string), req.Payload["sdp"].(string), zch.sendDataChannelMessage)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
case string(ZONE_CHAT_WEBRTC_RENNEGOTIATION_ANSWER):
|
||||||
|
if err = verifyFieldsString(req.Payload, "channelId", "userId", "sdp"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = atomicallyExecute(zch.ChatFSInstanceFlag, func() (err error) {
|
||||||
|
err = zch.ChatFSInstance.HandleRennegotiationAnswer(req.Payload["userId"].(string), req.Payload["sdp"].(string))
|
||||||
|
return
|
||||||
|
})
|
||||||
|
case string(ZONE_CHAT_WEBRTC_CANDIDATE):
|
||||||
|
logger.Println("handling fs instance 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(zch.ChatFSInstanceFlag, func() (err error) {
|
||||||
|
err = zch.ChatFSInstance.AddCandidate(&webrtc.ICECandidateInit{
|
||||||
|
Candidate: req.Payload["candidate"].(string),
|
||||||
|
SDPMid: &sdpMid,
|
||||||
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
|
}, req.Payload["userId"].(string))
|
||||||
|
return
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ type ZoneFSEntity struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewZoneFileHandler: factory function to create a zone file handler the name of the parameters are explicit, this is the only way to safely create a ZoneFSEntity
|
// NewZoneFileHandler: factory function to create a zone file handler the name of the parameters are explicit, this is the only way to safely create a ZoneFSEntity
|
||||||
func NewZoneFileHandler(hostId string, zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneFileHandler *ZoneFileHandler, err error) {
|
func NewZoneFileHandler(_ string, zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneFileHandler *ZoneFileHandler, err error) {
|
||||||
db, err := NewZoneFilesDBHandler(zoneId)
|
db, err := NewZoneFilesDBHandler(zoneId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -219,7 +219,7 @@ func (zfh *ZoneFileHandler) signalCandidate(from string, to string, candidate *w
|
|||||||
"to": to,
|
"to": to,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-d:
|
case <-d:
|
||||||
@ -560,6 +560,18 @@ func (zfh *ZoneFileHandler) RemoveFolderMember(userId string, path string, folde
|
|||||||
logger.Println(sendErr)
|
logger.Println(sendErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, member := range members {
|
||||||
|
if _, ok := member.(string); ok {
|
||||||
|
done, errCh := zfh.sendDataChannelMessage(REMOVE_FS_ENTITY_MEMBERS_DONE, "node", member.(string), map[string]interface{}{
|
||||||
|
"path": filepath.Join(path, folderName),
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case sendErr := <-errCh:
|
||||||
|
logger.Println(sendErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,6 +801,7 @@ func (zfh *ZoneFileHandler) CopyDir(src, dst string, init bool, fsEntity *ZoneFS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if fsEntity != nil {
|
||||||
for member := range fsEntity.Members {
|
for member := range fsEntity.Members {
|
||||||
done, errCh := zfh.sendDataChannelMessage(COPY_FOLDER_DONE, "node", member, map[string]interface{}{
|
done, errCh := zfh.sendDataChannelMessage(COPY_FOLDER_DONE, "node", member, map[string]interface{}{
|
||||||
"path": dst,
|
"path": dst,
|
||||||
@ -799,6 +812,7 @@ func (zfh *ZoneFileHandler) CopyDir(src, dst string, init bool, fsEntity *ZoneFS
|
|||||||
logger.Println(sendErr)
|
logger.Println(sendErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,6 +859,50 @@ func (zch *ZoneFileHandler) SetPublicRootFolders(user string) (err error) {
|
|||||||
|
|
||||||
func (zfh *ZoneFileHandler) handleZoneRequest(c context.Context, req *ZoneRequest) (err error) {
|
func (zfh *ZoneFileHandler) handleZoneRequest(c context.Context, req *ZoneRequest) (err error) {
|
||||||
switch req.ReqType {
|
switch req.ReqType {
|
||||||
|
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
|
||||||
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var index int
|
||||||
|
for i, m := range zfh.ZoneMembersId {
|
||||||
|
if m == req.Payload["userId"].(string) {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zfh.ZoneMembersId = append(zfh.ZoneMembersId[:index], zfh.ZoneMembersId[index+1:]...)
|
||||||
|
err = zfh.DeleteFolder("", req.Payload["userId"].(string))
|
||||||
|
case string(NEW_AUTHORIZED_ZONE_MEMBER):
|
||||||
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var contain bool
|
||||||
|
for _, m := range zfh.ZoneMembersId {
|
||||||
|
if m == req.Payload["userId"].(string) {
|
||||||
|
contain = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !contain {
|
||||||
|
zfh.ZoneMembersId = append(zfh.ZoneMembersId, req.Payload["userId"].(string))
|
||||||
|
}
|
||||||
|
err = zfh.DB.AddNewFSEntity("", &ZoneFSEntity{
|
||||||
|
Name: req.Payload["userId"].(string),
|
||||||
|
Owner: req.Payload["userId"].(string),
|
||||||
|
Type: PRIVATE,
|
||||||
|
Folder: true,
|
||||||
|
ModTime: time.Now().Format(time.UnixDate),
|
||||||
|
CreationTime: time.Now().Format(time.UnixDate),
|
||||||
|
Size: 0,
|
||||||
|
Members: map[string]*FSEntityAccessRights{
|
||||||
|
req.Payload["userId"].(string): {
|
||||||
|
Read: true,
|
||||||
|
Write: true,
|
||||||
|
Download: true,
|
||||||
|
Rename: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
case LEAVE_ZONE:
|
case LEAVE_ZONE:
|
||||||
logger.Println("*-----------------handling leaving zone---------------*")
|
logger.Println("*-----------------handling leaving zone---------------*")
|
||||||
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
@ -852,12 +910,21 @@ func (zfh *ZoneFileHandler) handleZoneRequest(c context.Context, req *ZoneReques
|
|||||||
}
|
}
|
||||||
err = zfh.LeaveFSInstance(req.Payload["userId"].(string))
|
err = zfh.LeaveFSInstance(req.Payload["userId"].(string))
|
||||||
case ZONE_UPLOAD_FILE_DONE:
|
case ZONE_UPLOAD_FILE_DONE:
|
||||||
|
if err = verifyFieldsBool(req.Payload, "failed"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if err = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
|
if err = verifyFieldsString(req.Payload, "path", "userId", "fileName", "type"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = verifyFieldsFloat64(req.Payload, "size"); err != nil {
|
if err = verifyFieldsFloat64(req.Payload, "size"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if req.Payload["failed"].(bool) {
|
||||||
|
logger.Println(zfh.FSInstance.FileUploadFailed(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)))
|
||||||
|
} else {
|
||||||
|
defer func() {
|
||||||
|
logger.Println(zfh.FSInstance.FileUploadDone(req.Payload["path"].(string), req.Payload["fileName"].(string), req.Payload["userId"].(string)))
|
||||||
|
}()
|
||||||
err = zfh.CreateFile(req.Payload["path"].(string), req.Payload["fileName"].(string), &ZoneFSEntity{
|
err = zfh.CreateFile(req.Payload["path"].(string), req.Payload["fileName"].(string), &ZoneFSEntity{
|
||||||
Name: req.Payload["fileName"].(string),
|
Name: req.Payload["fileName"].(string),
|
||||||
Owner: req.Payload["userId"].(string),
|
Owner: req.Payload["userId"].(string),
|
||||||
@ -875,6 +942,7 @@ func (zfh *ZoneFileHandler) handleZoneRequest(c context.Context, req *ZoneReques
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
case ZONE_UPLOAD_FILE:
|
case ZONE_UPLOAD_FILE:
|
||||||
if err = verifyFieldsString(req.Payload, "path", "userId", "fileName"); err != nil {
|
if err = verifyFieldsString(req.Payload, "path", "userId", "fileName"); err != nil {
|
||||||
return
|
return
|
||||||
@ -1087,22 +1155,22 @@ func (zfh *ZoneFileHandler) handleZoneRequest(c context.Context, req *ZoneReques
|
|||||||
case string(ZONE_FS_WEBRTC_CANDIDATE):
|
case string(ZONE_FS_WEBRTC_CANDIDATE):
|
||||||
logger.Println("handling fs instance webrtc candidate")
|
logger.Println("handling fs instance webrtc candidate")
|
||||||
logger.Println(req.Payload)
|
logger.Println(req.Payload)
|
||||||
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMlineIndex", "sdpMid", "channelId", "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println(req.Payload)
|
logger.Println(req.Payload)
|
||||||
i, convErr := strconv.Atoi(req.Payload["sdpMlineIndex"].(string))
|
i, convErr := strconv.Atoi(req.Payload["sdpMLineIndex"].(string))
|
||||||
if convErr != nil {
|
if convErr != nil {
|
||||||
return convErr
|
return convErr
|
||||||
}
|
}
|
||||||
sdpMlineIndex := uint16(i)
|
SDPMLineIndex := uint16(i)
|
||||||
sdpMid := req.Payload["sdpMid"].(string)
|
sdpMid := req.Payload["sdpMid"].(string)
|
||||||
logger.Println(sdpMid, sdpMlineIndex)
|
logger.Println(sdpMid, SDPMLineIndex)
|
||||||
err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
|
err = atomicallyExecute(zfh.FSInstanceFlag, func() (err error) {
|
||||||
err = zfh.FSInstance.AddCandidate(&webrtc.ICECandidateInit{
|
err = zfh.FSInstance.AddCandidate(&webrtc.ICECandidateInit{
|
||||||
Candidate: req.Payload["candidate"].(string),
|
Candidate: req.Payload["candidate"].(string),
|
||||||
SDPMid: &sdpMid,
|
SDPMid: &sdpMid,
|
||||||
SDPMLineIndex: &sdpMlineIndex,
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
}, req.Payload["userId"].(string))
|
}, req.Payload["userId"].(string))
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|||||||
@ -24,13 +24,12 @@ const (
|
|||||||
ZONE_FS_WEBRTC_CANDIDATE ReqType = "zone_fs_webrtc_candidate"
|
ZONE_FS_WEBRTC_CANDIDATE ReqType = "zone_fs_webrtc_candidate"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ()
|
|
||||||
|
|
||||||
type FSInstance struct {
|
type FSInstance struct {
|
||||||
ZoneID string `json:"id"`
|
ZoneID string `json:"id"`
|
||||||
Owner string `json:"owner"`
|
Owner string `json:"owner"`
|
||||||
Members []string `json:"members"`
|
Members []string `json:"members"`
|
||||||
OpenFiles map[string]*os.File `json:"-"`
|
OpenFiles map[string]*os.File `json:"-"`
|
||||||
|
OpenFilesForUser map[string][]string `json:"-"`
|
||||||
localSD map[string]*webrtc.SessionDescription `json:"-"`
|
localSD map[string]*webrtc.SessionDescription `json:"-"`
|
||||||
rtcPeerConnections map[string]*ZoneRTCPeerConnection `json:"-"`
|
rtcPeerConnections map[string]*ZoneRTCPeerConnection `json:"-"`
|
||||||
zoneFSDataChannels map[string]map[string]*DataChannel `json:"-"`
|
zoneFSDataChannels map[string]map[string]*DataChannel `json:"-"`
|
||||||
@ -56,6 +55,7 @@ func NewFSInstance(id, owner string, members []string) (audioChannel *FSInstance
|
|||||||
Owner: owner,
|
Owner: owner,
|
||||||
Members: members,
|
Members: members,
|
||||||
OpenFiles: make(map[string]*os.File),
|
OpenFiles: make(map[string]*os.File),
|
||||||
|
OpenFilesForUser: make(map[string][]string),
|
||||||
localSD: make(map[string]*webrtc.SessionDescription),
|
localSD: make(map[string]*webrtc.SessionDescription),
|
||||||
rtcPeerConnections: make(map[string]*ZoneRTCPeerConnection),
|
rtcPeerConnections: make(map[string]*ZoneRTCPeerConnection),
|
||||||
zoneFSDataChannels: make(map[string]map[string]*DataChannel),
|
zoneFSDataChannels: make(map[string]map[string]*DataChannel),
|
||||||
@ -79,6 +79,9 @@ func (fs *FSInstance) SetupFileUpload(path, filename, userId string) (err error)
|
|||||||
} else if rErr != nil {
|
} else if rErr != nil {
|
||||||
return rErr
|
return 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)
|
file, err := os.OpenFile(concretePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -87,11 +90,11 @@ func (fs *FSInstance) SetupFileUpload(path, filename, userId string) (err error)
|
|||||||
fs.OpenFiles[filename] = file
|
fs.OpenFiles[filename] = file
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
setupDataChan := func(id, fileName string) (err error) {
|
||||||
if pc, ok := fs.rtcPeerConnections[userId]; ok {
|
if pc, ok := fs.rtcPeerConnections[id]; ok {
|
||||||
maxRetransmits := uint16(100)
|
maxRetransmits := uint16(100)
|
||||||
var dc *webrtc.DataChannel
|
var dc *webrtc.DataChannel
|
||||||
dc, err = pc.CreateDataChannel(filename, &webrtc.DataChannelInit{
|
dc, err = pc.CreateDataChannel(fileName, &webrtc.DataChannelInit{
|
||||||
MaxRetransmits: &maxRetransmits,
|
MaxRetransmits: &maxRetransmits,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -100,34 +103,75 @@ func (fs *FSInstance) SetupFileUpload(path, filename, userId string) (err error)
|
|||||||
dc.OnOpen(func() {
|
dc.OnOpen(func() {
|
||||||
logger.Println("!-----------------------------!")
|
logger.Println("!-----------------------------!")
|
||||||
logger.Printf("datachannel with id %s is now open\n", dc.Label())
|
logger.Printf("datachannel with id %s is now open\n", dc.Label())
|
||||||
|
logger.Println("updated")
|
||||||
logger.Println("!-----------------------------!")
|
logger.Println("!-----------------------------!")
|
||||||
})
|
})
|
||||||
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||||
|
logger.Println(msg)
|
||||||
_, _ = file.Write(msg.Data)
|
_, _ = file.Write(msg.Data)
|
||||||
})
|
})
|
||||||
dc.OnClose(func() {
|
dc.OnClose(func() {
|
||||||
|
//fmt.Println("closing datachannel with id", dc.Label())
|
||||||
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
if f, ok := fs.OpenFiles[filename]; ok {
|
if f, ok := fs.OpenFiles[fileName]; ok {
|
||||||
err = f.Close()
|
err = f.Close()
|
||||||
}
|
}
|
||||||
delete(fs.OpenFiles, filename)
|
delete(fs.OpenFiles, fileName)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
delete(fs.zoneFSDataChannels[userId], fileName)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
dc.Close()
|
||||||
})
|
})
|
||||||
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
if _, ok := fs.zoneFSDataChannels[userId]; !ok {
|
if _, ok := fs.zoneFSDataChannels[id]; !ok {
|
||||||
err = fmt.Errorf("no corresponding map entry in zoneFSDataChannels for id %s", userId)
|
fs.zoneFSDataChannels[id] = make(map[string]*DataChannel)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
l := int32(0)
|
l := int32(0)
|
||||||
fs.zoneFSDataChannels[userId][dc.Label()] = &DataChannel{
|
fs.zoneFSDataChannels[id][dc.Label()] = &DataChannel{
|
||||||
DataChannel: dc,
|
DataChannel: dc,
|
||||||
l: &l,
|
l: &l,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("no peerconnection for id %s", userId)
|
err = fmt.Errorf("no peerconnection for id %s", id)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
err = setupDataChan(userId, filename)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FSInstance) FileUploadDone(path, filename, userId string) (err error) {
|
||||||
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
if dc, ok := fs.zoneFSDataChannels[userId][filename]; ok {
|
||||||
|
err = dc.DataChannel.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FSInstance) FileUploadFailed(path, filename, userId string) (err error) {
|
||||||
|
concretePath := filepath.Join("data", "zones", fs.ZoneID, "fs", path, "__files__", filename)
|
||||||
|
if err = os.Remove(concretePath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
if dc, ok := fs.zoneFSDataChannels[userId][filename]; ok {
|
||||||
|
err = dc.DataChannel.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
@ -142,28 +186,59 @@ func (fs *FSInstance) SetupFileDownload(path, filename, userId string) (err erro
|
|||||||
}
|
}
|
||||||
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
fs.OpenFiles[filename] = file
|
fs.OpenFiles[filename] = file
|
||||||
|
if _, ok := fs.OpenFilesForUser[userId]; !ok {
|
||||||
|
fs.OpenFilesForUser[userId] = []string{}
|
||||||
|
}
|
||||||
|
fs.OpenFilesForUser[userId] = append(fs.OpenFilesForUser[userId], filename)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
var dc *webrtc.DataChannel
|
||||||
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
if pc, ok := fs.rtcPeerConnections[userId]; ok {
|
if pc, ok := fs.rtcPeerConnections[userId]; ok {
|
||||||
maxRetransmits := uint16(100)
|
maxRetransmits := uint16(100)
|
||||||
var dc *webrtc.DataChannel
|
|
||||||
dc, err = pc.CreateDataChannel(filename, &webrtc.DataChannelInit{
|
dc, err = pc.CreateDataChannel(filename, &webrtc.DataChannelInit{
|
||||||
MaxRetransmits: &maxRetransmits,
|
MaxRetransmits: &maxRetransmits,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dc.SetBufferedAmountLowThreshold(16000000)
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
if dc != nil {
|
||||||
|
dc.SetBufferedAmountLowThreshold(15000000)
|
||||||
bufferedAmountLock := make(chan struct{})
|
bufferedAmountLock := make(chan struct{})
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
dc.OnOpen(func() {
|
dc.OnOpen(func() {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
close(bufferedAmountLock)
|
||||||
bufferedAmountLock = nil
|
bufferedAmountLock = nil
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
if f, ok := fs.OpenFiles[filename]; ok {
|
||||||
|
err = f.Close()
|
||||||
|
}
|
||||||
|
delete(fs.OpenFiles, filename)
|
||||||
|
if _, ok := fs.OpenFilesForUser[userId]; ok {
|
||||||
|
var index int
|
||||||
|
for i, v := range fs.OpenFilesForUser[userId] {
|
||||||
|
if v == filename {
|
||||||
|
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
|
||||||
|
})
|
||||||
}()
|
}()
|
||||||
r := bufio.NewReader(file)
|
r := bufio.NewReader(file)
|
||||||
buf := make([]byte, 0, 60000)
|
buf := make([]byte, 0, 15000)
|
||||||
|
sendingLoop:
|
||||||
for {
|
for {
|
||||||
n, readErr := r.Read(buf[:cap(buf)])
|
n, readErr := r.Read(buf[:cap(buf)])
|
||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
@ -179,7 +254,9 @@ func (fs *FSInstance) SetupFileDownload(path, filename, userId string) (err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = dc.Send(buf); err != nil {
|
if err = dc.Send(buf); err != nil {
|
||||||
|
dc.Close()
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
|
break sendingLoop
|
||||||
}
|
}
|
||||||
if dc.BufferedAmount() > dc.
|
if dc.BufferedAmount() > dc.
|
||||||
BufferedAmountLowThreshold() {
|
BufferedAmountLowThreshold() {
|
||||||
@ -187,13 +264,22 @@ func (fs *FSInstance) SetupFileDownload(path, filename, userId string) (err erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.Println("done")
|
logger.Println("done")
|
||||||
|
<-time.After(4*time.Second)
|
||||||
_ = dc.SendText("done")
|
_ = dc.SendText("done")
|
||||||
<-time.After(time.Second * 5)
|
<-time.After(time.Second)
|
||||||
_ = dc.Close()
|
_ = dc.Close()
|
||||||
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
|
if _, ok := fs.zoneFSDataChannels[userId]; ok {
|
||||||
|
delete(fs.zoneFSDataChannels[userId], dc.Label())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
dc.OnBufferedAmountLow(func() {
|
dc.OnBufferedAmountLow(func() {
|
||||||
|
if bufferedAmountLock != nil {
|
||||||
bufferedAmountLock <- struct{}{}
|
bufferedAmountLock <- struct{}{}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
dc.OnClose(func() {
|
dc.OnClose(func() {
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
@ -205,13 +291,28 @@ func (fs *FSInstance) SetupFileDownload(path, filename, userId string) (err erro
|
|||||||
delete(fs.OpenFiles, filename)
|
delete(fs.OpenFiles, filename)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
} else {
|
err = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
err = fmt.Errorf("no peerconnection for id %s", userId)
|
if _, ok := fs.zoneFSDataChannels[userId]; !ok {
|
||||||
|
fs.zoneFSDataChannels[userId] = make(map[string]*DataChannel)
|
||||||
|
}
|
||||||
|
l := int32(0)
|
||||||
|
fs.zoneFSDataChannels[userId][dc.Label()] = &DataChannel{
|
||||||
|
DataChannel: dc,
|
||||||
|
l: &l,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("datachannel not created")
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
if file, ok := fs.OpenFiles[filename]; ok {
|
||||||
|
file.Close()
|
||||||
|
}
|
||||||
|
delete(fs.OpenFiles, filename)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,10 +345,10 @@ func (fs *FSInstance) HandleOffer(ctx context.Context, channelId, userId, sdp, h
|
|||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
|
||||||
fs.localSD[userId] = &rawAnswer
|
errCh <- err
|
||||||
return
|
return
|
||||||
})
|
}
|
||||||
_, _ = sendDCMessage(string(ZONE_FS_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
_, _ = sendDCMessage(string(ZONE_FS_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
||||||
"to": userId,
|
"to": userId,
|
||||||
"from": fs.ZoneID,
|
"from": fs.ZoneID,
|
||||||
@ -261,25 +362,25 @@ func (fs *FSInstance) HandleOffer(ctx context.Context, channelId, userId, sdp, h
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FSInstance) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
func (fs *FSInstance) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
||||||
if err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
// if err = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
if _, ok := fs.rtcPeerConnections[userId]; !ok {
|
// if _, ok := fs.rtcPeerConnections[userId]; !ok {
|
||||||
err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
// err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
logger.Println("handling counter offer")
|
// logger.Println("handling counter offer")
|
||||||
connection := fs.rtcPeerConnections[userId]
|
// connection := fs.rtcPeerConnections[userId]
|
||||||
err = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
// err = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
||||||
err = connection.SetLocalDescription(*fs.localSD[userId])
|
// err = connection.SetLocalDescription(*fs.localSD[userId])
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
_ = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
// _ = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
||||||
delete(fs.localSD, userId)
|
// delete(fs.localSD, userId)
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
if err = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
if err = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
||||||
for _, candidate := range fs.pendingCandidates[userId] {
|
for _, candidate := range fs.pendingCandidates[userId] {
|
||||||
logger.Println("sending candidate to", userId, candidate)
|
logger.Println("sending candidate to", userId, candidate)
|
||||||
@ -288,7 +389,7 @@ func (fs *FSInstance) HandleCounterOffer(ctx context.Context, userId string, sen
|
|||||||
"to": userId,
|
"to": userId,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-d:
|
case <-d:
|
||||||
@ -310,12 +411,12 @@ func (fs *FSInstance) HandleRennegotiationOffer(from, sdp string, sendDCMessage
|
|||||||
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fs.rtcPeerConnections[from].makingOfferLock.Lock()
|
// fs.rtcPeerConnections[from].makingOfferLock.Lock()
|
||||||
if fs.rtcPeerConnections[from].makingOffer {
|
// if fs.rtcPeerConnections[from].makingOffer {
|
||||||
fs.rtcPeerConnections[from].makingOfferLock.Unlock()
|
// fs.rtcPeerConnections[from].makingOfferLock.Unlock()
|
||||||
return fmt.Errorf("already making an offer or state is stable")
|
// return fmt.Errorf("already making an offer or state is stable")
|
||||||
}
|
// }
|
||||||
fs.rtcPeerConnections[from].makingOfferLock.Unlock()
|
// fs.rtcPeerConnections[from].makingOfferLock.Unlock()
|
||||||
if err = fs.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
if err = fs.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -452,7 +553,7 @@ func (fs *FSInstance) createPeerConnection(target, from string, peerType webrtc.
|
|||||||
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
|
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
|
||||||
if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
|
if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
|
||||||
logger.Println(pcs)
|
logger.Println(pcs)
|
||||||
fs.HandleLeavingMember(target)
|
//fs.HandleLeavingMember(target)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
|
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
|
||||||
@ -479,60 +580,38 @@ func (fs *FSInstance) createPeerConnection(target, from string, peerType webrtc.
|
|||||||
return
|
return
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
peerConnection.OnNegotiationNeeded(func() {
|
// peerConnection.OnNegotiationNeeded(func() {
|
||||||
logger.Println("---------------- rennego is needed -----------")
|
// logger.Println("---------------- rennego is needed -----------")
|
||||||
_ = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
// _ = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
logger.Println("----------------- sending renego to peer with id", target)
|
// logger.Println("----------------- sending renego to peer with id", target)
|
||||||
if peerConnection.SignalingState() == webrtc.SignalingStateStable {
|
// if peerConnection.SignalingState() == webrtc.SignalingStateStable {
|
||||||
localSd, localSdErr := peerConnection.CreateOffer(nil)
|
// localSd, localSdErr := peerConnection.CreateOffer(nil)
|
||||||
if localSdErr != nil {
|
// if localSdErr != nil {
|
||||||
logger.Println(localSdErr)
|
// logger.Println(localSdErr)
|
||||||
return localSdErr
|
// return localSdErr
|
||||||
}
|
// }
|
||||||
if err = peerConnection.SetLocalDescription(localSd); err != nil {
|
// if err = peerConnection.SetLocalDescription(localSd); err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
d, e := sendDCMessage(string(ZONE_FS_WEBRTC_RENNEGOTIATION_OFFER), fs.ZoneID, target, map[string]interface{}{
|
// d, e := sendDCMessage(string(ZONE_FS_WEBRTC_RENNEGOTIATION_OFFER), fs.ZoneID, target, map[string]interface{}{
|
||||||
"from": fs.ZoneID,
|
// "from": fs.ZoneID,
|
||||||
"to": target,
|
// "to": target,
|
||||||
"sdp": localSd.SDP,
|
// "sdp": localSd.SDP,
|
||||||
})
|
// })
|
||||||
select {
|
// select {
|
||||||
case <-d:
|
// case <-d:
|
||||||
case err = <-e:
|
// case err = <-e:
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FSInstance) HandleLeavingMember(id string) {
|
func (fs *FSInstance) HandleLeavingMember(id string) {
|
||||||
if err := atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
|
||||||
if _, ok := fs.rtcPeerConnections[id]; !ok {
|
|
||||||
err = fmt.Errorf("no corresponding peerconnection for audio channel leaving member")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}); err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
} else {
|
|
||||||
defer func() {
|
|
||||||
_ = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
|
||||||
if _, ok := fs.rtcPeerConnections[id]; ok {
|
|
||||||
if closeErr := fs.rtcPeerConnections[id].Close(); closeErr != nil {
|
|
||||||
err = closeErr
|
|
||||||
logger.Println("peer connection close error", closeErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete(fs.rtcPeerConnections, id)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
logger.Printf("peer %s is leaving the squad\n", id)
|
|
||||||
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
_ = atomicallyExecute(fs.dataChannelMapFlag, func() (err error) {
|
||||||
if _, ok := fs.zoneFSDataChannels[id]; ok {
|
if _, ok := fs.zoneFSDataChannels[id]; ok {
|
||||||
for _, dc := range fs.zoneFSDataChannels[id] {
|
for _, dc := range fs.zoneFSDataChannels[id] {
|
||||||
@ -542,14 +621,32 @@ func (fs *FSInstance) HandleLeavingMember(id string) {
|
|||||||
delete(fs.zoneFSDataChannels, id)
|
delete(fs.zoneFSDataChannels, id)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
_ = atomicallyExecute(fs.localSDMapFlag, func() (err error) {
|
logger.Println("chatfs datachannels cleaned")
|
||||||
delete(fs.localSD, id)
|
_ = atomicallyExecute(fs.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
|
if pc, ok := fs.rtcPeerConnections[id]; ok {
|
||||||
|
if closeErr := pc.Close(); closeErr != nil {
|
||||||
|
err = closeErr
|
||||||
|
logger.Println("peer connection close error", closeErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(fs.rtcPeerConnections, id)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
logger.Println("chats perrconnections cleaned")
|
||||||
_ = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
_ = atomicallyExecute(fs.candidateFlag, func() (err error) {
|
||||||
delete(fs.pendingCandidates, id)
|
delete(fs.pendingCandidates, id)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
_ = atomicallyExecute(fs.filesFlag, func() (err error) {
|
||||||
|
for _, openFile := range fs.OpenFilesForUser[id] {
|
||||||
|
if f, ok := fs.OpenFiles[openFile]; ok {
|
||||||
|
_ = f.Close()
|
||||||
|
}
|
||||||
|
delete(fs.OpenFiles, openFile)
|
||||||
|
}
|
||||||
|
delete(fs.OpenFilesForUser, id)
|
||||||
|
return
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FSInstance) HandleDataChannelEvents(from, eventId string, payload map[string]interface{}) (err error) {
|
func (fs *FSInstance) HandleDataChannelEvents(from, eventId string, payload map[string]interface{}) (err error) {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package localserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
@ -23,11 +24,13 @@ const (
|
|||||||
NEW_ZONE ReqType = "new_zone"
|
NEW_ZONE ReqType = "new_zone"
|
||||||
NEW_AUTHORIZED_ZONE_MEMBER ReqType = "new_authorized_zone_member"
|
NEW_AUTHORIZED_ZONE_MEMBER ReqType = "new_authorized_zone_member"
|
||||||
REMOVED_ZONE_AUTHORIZED_MEMBER ReqType = "removed_zone_authorized_member"
|
REMOVED_ZONE_AUTHORIZED_MEMBER ReqType = "removed_zone_authorized_member"
|
||||||
|
DELETE_ZONE = "delete_zone"
|
||||||
|
DISCONNECT_ZONE_MEMBER = "disconnect_zone_member"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ZoneGrpcMiddleware struct {
|
type ZoneGrpcMiddleware struct {
|
||||||
Manager *ZoneManager
|
Manager *ZoneManager
|
||||||
stream GrpcManager_LinkClient
|
stream SignalingService_LinkClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZoneGrpcMiddleware(manager *ZoneManager) (zoneGrpcMiddleware *ZoneGrpcMiddleware) {
|
func NewZoneGrpcMiddleware(manager *ZoneManager) (zoneGrpcMiddleware *ZoneGrpcMiddleware) {
|
||||||
@ -38,55 +41,72 @@ func NewZoneGrpcMiddleware(manager *ZoneManager) (zoneGrpcMiddleware *ZoneGrpcMi
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
func (zm *ZoneGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
||||||
err = zm.stream.Send(&Request{
|
bs, err := json.Marshal(map[string]string{
|
||||||
Type: string(ZONE_WEBRTC_CANDIDATE),
|
|
||||||
From: zm.Manager.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": zm.Manager.ID,
|
"from": zm.Manager.ID,
|
||||||
"to": to,
|
"to": to,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zm.stream.Send(&SignalingMessage{
|
||||||
|
Type: string(ZONE_WEBRTC_CANDIDATE),
|
||||||
|
From: zm.Manager.ID,
|
||||||
|
To: to,
|
||||||
|
Payload: bs,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *Response, stream GrpcManager_LinkClient) (err error) {
|
func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
|
||||||
done, errCh := make(chan struct{}), make(chan error)
|
done, errCh := make(chan struct{}), make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
switch req.Type {
|
var payload map[string]string
|
||||||
case string(INCOMING_ZONE_MEMBER):
|
if e := json.Unmarshal(req.Payload, &payload); err != nil {
|
||||||
case string(LEAVING_ZONE_MEMBER):
|
errCh <- e
|
||||||
if err := validateRequest(req.GetPayload(), "zoneId", "userId"); err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := zm.Manager.HandleLeavingMember(req.Payload["userId"], req.Payload["zoneId"]); err != nil {
|
switch req.Type {
|
||||||
|
case string(INCOMING_ZONE_MEMBER):
|
||||||
|
case string(DELETE_ZONE):
|
||||||
|
if err := validateRequest(payload, "zoneId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := zm.Manager.DeleteZone(payload["zoneId"]); err != nil {
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case string(LEAVING_ZONE_MEMBER):
|
||||||
|
if err := validateRequest(payload, "zoneId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := zm.Manager.HandleLeavingMember(req.GetFrom(), payload["zoneId"]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
|
case string(REMOVED_ZONE_AUTHORIZED_MEMBER):
|
||||||
if err := validateRequest(req.GetPayload(), "zoneId", "userId"); err != nil {
|
if err := validateRequest(payload, "zoneId", "userId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = atomicallyExecute(zm.Manager.zoneFlag, func() (err error) {
|
if err = atomicallyExecute(zm.Manager.zoneFlag, func() (err error) {
|
||||||
reqChan := make(chan *ZoneRequest)
|
reqChan := make(chan *ZoneRequest)
|
||||||
done, e := zm.Manager.Zones[req.Payload["zoneId"]].ZoneRequestScheduler.Schedule(reqChan)
|
done, e := zm.Manager.Zones[payload["zoneId"]].ZoneRequestScheduler.Schedule(reqChan)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(reqChan)
|
defer close(reqChan)
|
||||||
reqChan <- &ZoneRequest{
|
reqChan <- &ZoneRequest{
|
||||||
ReqType: string(REMOVE_USER),
|
ReqType: string(REMOVE_USER),
|
||||||
From: req.Payload["userId"],
|
From: payload["userId"],
|
||||||
Payload: map[string]interface{}{
|
Payload: map[string]interface{}{
|
||||||
"userId": req.Payload["userId"],
|
"userId": payload["userId"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
reqChan <- &ZoneRequest{
|
reqChan <- &ZoneRequest{
|
||||||
ReqType: string(REMOVED_ZONE_AUTHORIZED_MEMBER),
|
ReqType: string(REMOVED_ZONE_AUTHORIZED_MEMBER),
|
||||||
From: req.Payload["userId"],
|
From: payload["userId"],
|
||||||
Payload: map[string]interface{}{
|
Payload: map[string]interface{}{
|
||||||
"userId": req.Payload["userId"],
|
"userId": payload["userId"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -100,26 +120,26 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *Response, stream
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(NEW_AUTHORIZED_ZONE_MEMBER):
|
case string(NEW_AUTHORIZED_ZONE_MEMBER):
|
||||||
if err := validateRequest(req.GetPayload(), "zoneId", "userId"); err != nil {
|
if err := validateRequest(payload, "zoneId", "userId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = atomicallyExecute(zm.Manager.zoneFlag, func() (err error) {
|
if err = atomicallyExecute(zm.Manager.zoneFlag, func() (err error) {
|
||||||
reqChan := make(chan *ZoneRequest)
|
reqChan := make(chan *ZoneRequest)
|
||||||
done, e := zm.Manager.Zones[req.Payload["zoneId"]].ZoneRequestScheduler.Schedule(reqChan)
|
done, e := zm.Manager.Zones[payload["zoneId"]].ZoneRequestScheduler.Schedule(reqChan)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(reqChan)
|
defer close(reqChan)
|
||||||
reqChan <- &ZoneRequest{
|
reqChan <- &ZoneRequest{
|
||||||
ReqType: string(ADD_USER),
|
ReqType: string(ADD_USER),
|
||||||
From: req.Payload["userId"],
|
From: payload["userId"],
|
||||||
Payload: map[string]interface{}{
|
Payload: map[string]interface{}{
|
||||||
"userId": req.Payload["userId"],
|
"userId": payload["userId"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
reqChan <- &ZoneRequest{
|
reqChan <- &ZoneRequest{
|
||||||
ReqType: string(NEW_AUTHORIZED_ZONE_MEMBER),
|
ReqType: string(NEW_AUTHORIZED_ZONE_MEMBER),
|
||||||
From: req.Payload["userId"],
|
From: payload["userId"],
|
||||||
Payload: map[string]interface{}{
|
Payload: map[string]interface{}{
|
||||||
"userId": req.Payload["userId"],
|
"userId": payload["userId"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -133,12 +153,12 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *Response, stream
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(NEW_ZONE):
|
case string(NEW_ZONE):
|
||||||
logger.Println(req.Payload)
|
logger.Println(payload)
|
||||||
if err := validateRequest(req.GetPayload(), "zoneId", "zoneName", "zoneImageURL", "zoneOwner", "zoneCreationDate"); err != nil {
|
if err := validateRequest(payload, "zoneId", "zoneName", "zoneImageURL", "zoneOwner", "zoneCreationDate"); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zone, err := NewZone(zm.Manager.ID, req.Payload["zoneId"], req.Payload["zoneName"], req.Payload["zoneImageURL"], req.Payload["zoneOwner"], req.Payload["zoneCreationDate"], true, []string{req.Payload["zoneOwner"]})
|
zone, err := NewZone(zm.Manager.ID, payload["zoneId"], payload["zoneName"], payload["zoneImageURL"], payload["zoneOwner"], payload["zoneCreationDate"], true, []string{payload["zoneOwner"]})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
@ -148,77 +168,73 @@ func (zm *ZoneGrpcMiddleware) Process(ctx context.Context, req *Response, stream
|
|||||||
return
|
return
|
||||||
})
|
})
|
||||||
case string(ZONE_OFFER):
|
case string(ZONE_OFFER):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, TO, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := zm.Manager.HandleOffer(ctx, req.GetPayload(), zm.signalCandidate); err != nil {
|
if err := zm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, zm.signalCandidate); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(ZONE_ANSWER):
|
case string(ZONE_ANSWER):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, TO, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := zm.Manager.HandleAnswer(ctx, req.GetPayload()); err != nil {
|
if err := zm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(ZONE_COUNTER_OFFER):
|
case string(ZONE_COUNTER_OFFER):
|
||||||
if err := validateRequest(req.GetPayload(), FROM); err != nil {
|
if err := zm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
|
||||||
errCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := zm.Manager.HandleCounterOffer(ctx, req.Payload); err != nil {
|
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(ZONE_WEBRTC_RENNEGOTIATION_OFFER):
|
case string(ZONE_WEBRTC_RENNEGOTIATION_OFFER):
|
||||||
logger.Println("received negotiation offer")
|
logger.Println("received negotiation offer")
|
||||||
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := zm.Manager.HandleRennegotiationOffer(req.Payload[FROM], req.Payload[SDP]); err != nil {
|
if err := zm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(ZONE_WEBRTC_RENNEGOTIATION_ANSWER):
|
case string(ZONE_WEBRTC_RENNEGOTIATION_ANSWER):
|
||||||
logger.Println("received negotiation answer")
|
logger.Println("received negotiation answer")
|
||||||
if err := validateRequest(req.GetPayload(), FROM, SDP); err != nil {
|
if err := validateRequest(payload, SDP); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := zm.Manager.HandleRennegotiationAnswer(req.Payload[FROM], req.Payload[SDP]); err != nil {
|
if err := zm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case string(ZONE_WEBRTC_CANDIDATE):
|
case string(ZONE_WEBRTC_CANDIDATE):
|
||||||
if err := validateRequest(req.GetPayload(), FROM, "candidate", "sdpMlineIndex", "sdpMid"); err != nil {
|
if err := validateRequest(payload, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println(req.Payload)
|
logger.Println(payload)
|
||||||
i, err := strconv.Atoi(req.Payload["sdpMlineIndex"])
|
i, err := strconv.Atoi(payload["sdpMLineIndex"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sdpMlineIndex := uint16(i)
|
SDPMLineIndex := uint16(i)
|
||||||
sdpMid := req.Payload["sdpMid"]
|
sdpMid := payload["sdpMid"]
|
||||||
logger.Println(sdpMid, sdpMlineIndex)
|
logger.Println(sdpMid, SDPMLineIndex)
|
||||||
if err := zm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
if err := zm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
||||||
Candidate: req.Payload["candidate"],
|
Candidate: payload["candidate"],
|
||||||
SDPMid: &sdpMid,
|
SDPMid: &sdpMid,
|
||||||
SDPMLineIndex: &sdpMlineIndex,
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
}, req.Payload[FROM]); err != nil {
|
}, req.GetFrom()); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logger.Println("no request for zon grpc middleware")
|
logger.Println("no request for zon grpc middleware")
|
||||||
logger.Println(req.GetPayload())
|
logger.Println(payload)
|
||||||
logger.Println(req.Type)
|
logger.Println(req.Type)
|
||||||
}
|
}
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
|
|||||||
359
zoneManager.go
359
zoneManager.go
@ -7,10 +7,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ type ZoneManager struct {
|
|||||||
RTCPeerConnections map[string]*RTCPeerConnection
|
RTCPeerConnections map[string]*RTCPeerConnection
|
||||||
DataChannels map[string]*DataChannel
|
DataChannels map[string]*DataChannel
|
||||||
PendingCandidates map[string][]*webrtc.ICECandidate
|
PendingCandidates map[string][]*webrtc.ICECandidate
|
||||||
stream GrpcManager_LinkClient
|
stream SignalingService_LinkClient
|
||||||
zoneFlag *uint32
|
zoneFlag *uint32
|
||||||
peerConnectionFlag *uint32
|
peerConnectionFlag *uint32
|
||||||
localSDFlag *uint32
|
localSDFlag *uint32
|
||||||
@ -49,7 +52,7 @@ type Zone struct {
|
|||||||
|
|
||||||
func NewZone(hostId string, zoneId string, zoneName string, imageUrl string, owner string, creationDate string, initialized bool, authorizedMembers []string) (zone *Zone, err error) {
|
func NewZone(hostId string, zoneId string, zoneName string, imageUrl string, owner string, creationDate string, initialized bool, authorizedMembers []string) (zone *Zone, err error) {
|
||||||
dataChannels, dataChannelFlag := make(map[string]*DataChannel), uint32(0)
|
dataChannels, dataChannelFlag := make(map[string]*DataChannel), uint32(0)
|
||||||
zoneChatHandler, err := NewZoneChatsHandler(zoneId, owner, authorizedMembers, dataChannels, &dataChannelFlag)
|
zoneChatHandler, err := NewZoneChatsHandler(hostId, zoneId, owner, authorizedMembers, dataChannels, &dataChannelFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -69,7 +72,7 @@ func NewZone(hostId string, zoneId string, zoneName string, imageUrl string, own
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zoneScheduler, e := NewZoneRequestScheduler(authorizedMembers, zoneUsersHandler, zoneChatHandler, zoneAudioChannelsHandler, zoneVideoChannelsHandler, zoneFileHandler)
|
zoneScheduler, e := NewZoneRequestScheduler(authorizedMembers, zoneUsersHandler, zoneAudioChannelsHandler, zoneVideoChannelsHandler, zoneFileHandler, zoneChatHandler)
|
||||||
go func() {
|
go func() {
|
||||||
for schedErr := range e {
|
for schedErr := range e {
|
||||||
logger.Println("from scheduler :", schedErr)
|
logger.Println("from scheduler :", schedErr)
|
||||||
@ -108,6 +111,10 @@ func NewZoneManager(id string, token string) (zoneManager *ZoneManager, err erro
|
|||||||
}
|
}
|
||||||
zoneMap[zone.ID] = z
|
zoneMap[zone.ID] = z
|
||||||
}
|
}
|
||||||
|
zonesFolder,err := os.ReadDir(filepath.Join("data", "zones"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
logger.Println(zoneMap)
|
logger.Println(zoneMap)
|
||||||
zoneManager = &ZoneManager{
|
zoneManager = &ZoneManager{
|
||||||
ID: id,
|
ID: id,
|
||||||
@ -122,6 +129,11 @@ func NewZoneManager(id string, token string) (zoneManager *ZoneManager, err erro
|
|||||||
dataChannelFlag: &dataChannelFlag,
|
dataChannelFlag: &dataChannelFlag,
|
||||||
candidateFlag: &candidateFlag,
|
candidateFlag: &candidateFlag,
|
||||||
}
|
}
|
||||||
|
for _, z := range zonesFolder {
|
||||||
|
if _,ok := zoneMap[z.Name()]; !ok {
|
||||||
|
logger.Println(zoneManager.DeleteZone(z.Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,13 +148,32 @@ func atomicallyExecute(flag *uint32, job func() (err error)) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneManager) DeleteZone(zoneId string) {}
|
func (zm *ZoneManager) 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 *ZoneManager) DeleteZone(zoneId string) error {
|
||||||
|
return os.RemoveAll(filepath.Join("data", "zones",zoneId))
|
||||||
|
}
|
||||||
|
|
||||||
func (zm *ZoneManager) fetchZones(nodeId string, token string) (zones []*Zone, err error) {
|
func (zm *ZoneManager) fetchZones(nodeId string, token string) (zones []*Zone, err error) {
|
||||||
|
em := NewEncryptionManager()
|
||||||
|
sig := em.SignRequestHMAC(nodeId)
|
||||||
body, err := json.Marshal(map[string]interface{}{
|
body, err := json.Marshal(map[string]interface{}{
|
||||||
"type": LIST_ZONES_BY_HOST,
|
"type": LIST_ZONES_BY_HOST,
|
||||||
"token": token,
|
"mac": sig,
|
||||||
"from": nodeId,
|
"from": nodeId,
|
||||||
|
"peerType":"node",
|
||||||
"payload": map[string]string{
|
"payload": map[string]string{
|
||||||
"host": nodeId,
|
"host": nodeId,
|
||||||
"lastIndex": "0",
|
"lastIndex": "0",
|
||||||
@ -160,7 +191,15 @@ func (zm *ZoneManager) fetchZones(nodeId string, token string) (zones []*Zone, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(bs, &zones)
|
var payload map[string]any
|
||||||
|
if err = json.Unmarshal(bs, &payload); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(payload["zones"])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(b, &zones)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,8 +217,10 @@ func (zm *ZoneManager) CreateOffer(ctx context.Context, target string, from stri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
||||||
|
id := uuid.New().String()
|
||||||
logger.Println("adding for target", target)
|
logger.Println("adding for target", target)
|
||||||
zm.RTCPeerConnections[target] = &RTCPeerConnection{
|
zm.RTCPeerConnections[target] = &RTCPeerConnection{
|
||||||
|
id: id,
|
||||||
PeerConnection: peerConnection,
|
PeerConnection: peerConnection,
|
||||||
makingOffer: true,
|
makingOffer: true,
|
||||||
makingOfferLock: &sync.Mutex{},
|
makingOfferLock: &sync.Mutex{},
|
||||||
@ -187,20 +228,15 @@ func (zm *ZoneManager) CreateOffer(ctx context.Context, target string, from stri
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
err = zm.stream.Send(&Request{
|
err = zm.sendSignalingMessage(string(ZONE_OFFER), zm.ID, target, map[string]any{
|
||||||
Type: string(ZONE_OFFER),
|
|
||||||
From: zm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": target,
|
"to": target,
|
||||||
"from": zm.ID,
|
"from": zm.ID,
|
||||||
"sdp": rawOffer.SDP,
|
"sdp": rawOffer.SDP,
|
||||||
},
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneManager) HandleOffer(ctx context.Context, req map[string]string, cb OnICECandidateFunc) (err error) {
|
func (zm *ZoneManager) HandleOffer(ctx context.Context, from string, to string, req map[string]string, cb OnICECandidateFunc) (err error) {
|
||||||
done, errCh := make(chan struct{}), make(chan error)
|
done, errCh := make(chan struct{}), make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
if _, ok := zm.Zones[req["zoneId"]]; !ok {
|
if _, ok := zm.Zones[req["zoneId"]]; !ok {
|
||||||
@ -209,21 +245,31 @@ func (zm *ZoneManager) HandleOffer(ctx context.Context, req map[string]string, c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("handling zone offer")
|
logger.Println("handling zone offer")
|
||||||
peerConnection, err := zm.createPeerConnection(req[FROM], req[TO], req["zoneId"], webrtc.SDPTypeAnswer, cb)
|
|
||||||
|
if _,ok := zm.RTCPeerConnections[from]; ok {
|
||||||
|
if e := zm.HandleLeavingMember(from,req["zoneId"]); e != nil {
|
||||||
|
logger.Println(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
peerConnection, err := zm.createPeerConnection(from, to, req["zoneId"], webrtc.SDPTypeAnswer, cb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("peer connection created")
|
logger.Println("peer connection created")
|
||||||
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
_ = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
||||||
zm.RTCPeerConnections[req[FROM]] = &RTCPeerConnection{
|
id := uuid.New().String()
|
||||||
|
zm.RTCPeerConnections[from] = &RTCPeerConnection{
|
||||||
PeerConnection: peerConnection,
|
PeerConnection: peerConnection,
|
||||||
|
id: id,
|
||||||
makingOffer: false,
|
makingOffer: false,
|
||||||
makingOfferLock: &sync.Mutex{},
|
makingOfferLock: &sync.Mutex{},
|
||||||
negotiate: zm.negotiate,
|
negotiate: zm.negotiate,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
logger.Println("peer connection added to map")
|
||||||
offer := webrtc.SessionDescription{
|
offer := webrtc.SessionDescription{
|
||||||
Type: webrtc.SDPTypeOffer,
|
Type: webrtc.SDPTypeOffer,
|
||||||
SDP: req[SDP],
|
SDP: req[SDP],
|
||||||
@ -238,23 +284,17 @@ func (zm *ZoneManager) HandleOffer(ctx context.Context, req map[string]string, c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
||||||
zm.LocalSD[req[FROM]] = &rawAnswer
|
zm.LocalSD[from] = &rawAnswer
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
|
||||||
_ = atomicallyExecute(zm.zoneFlag, func() (err error) {
|
errCh <- err
|
||||||
//zm.Zones[req[SQUAD_ID]].Members = append(zm.Squads[req[SQUAD_ID]].Members, req[FROM])
|
|
||||||
return
|
return
|
||||||
})
|
}
|
||||||
if err = zm.stream.Send(&Request{
|
if err = zm.sendSignalingMessage(string(ZONE_ANSWER), zm.ID, from, map[string]any{
|
||||||
Type: string(ZONE_ANSWER),
|
"to": from,
|
||||||
From: zm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": req[FROM],
|
|
||||||
"from": zm.ID,
|
"from": zm.ID,
|
||||||
"sdp": rawAnswer.SDP,
|
"sdp": rawAnswer.SDP,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
@ -272,18 +312,18 @@ func (zm *ZoneManager) HandleOffer(ctx context.Context, req map[string]string, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneManager) HandleAnswer(ctx context.Context, req map[string]string) (err error) {
|
func (zm *ZoneManager) HandleAnswer(ctx context.Context, from string, to string, req map[string]string) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); err != nil {
|
if r := recover(); err != nil {
|
||||||
logger.Printf("recover from panic in handle answer : %v\n", r)
|
logger.Printf("recover from panic in handle answer : %v\n", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
||||||
if _, ok := zm.RTCPeerConnections[req[FROM]]; !ok {
|
if _, ok := zm.RTCPeerConnections[from]; !ok {
|
||||||
err = fmt.Errorf("no corresponding peer connection for id : %s", req[FROM])
|
err = fmt.Errorf("no corresponding peer connection for id : %s", from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peerConnnection := zm.RTCPeerConnections[req[FROM]]
|
peerConnnection := zm.RTCPeerConnections[from]
|
||||||
logger.Println("---------------------")
|
logger.Println("---------------------")
|
||||||
logger.Println(req[SDP])
|
logger.Println(req[SDP])
|
||||||
logger.Println("---------------------")
|
logger.Println("---------------------")
|
||||||
@ -298,92 +338,77 @@ func (zm *ZoneManager) HandleAnswer(ctx context.Context, req map[string]string)
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = zm.stream.Send(&Request{
|
if err = zm.sendSignalingMessage(string(ZONE_COUNTER_OFFER), zm.ID, from, map[string]any{
|
||||||
Type: string(ZONE_COUNTER_OFFER),
|
|
||||||
From: zm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": zm.ID,
|
"from": zm.ID,
|
||||||
"to": req[FROM],
|
"to": from,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
|
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
|
||||||
for _, candidate := range zm.PendingCandidates[req[FROM]] {
|
for _, candidate := range zm.PendingCandidates[from] {
|
||||||
logger.Println("sending candidate from answer to", req[FROM])
|
logger.Println("sending candidate from answer to", from)
|
||||||
if err = zm.stream.Send(&Request{
|
if err = zm.sendSignalingMessage(string(ZONE_WEBRTC_CANDIDATE), zm.ID, from, map[string]any{
|
||||||
Type: string(ZONE_WEBRTC_CANDIDATE),
|
|
||||||
From: zm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": zm.ID,
|
"from": zm.ID,
|
||||||
"to": req[FROM],
|
"to": from,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(zm.PendingCandidates, req[FROM])
|
delete(zm.PendingCandidates, from)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
||||||
delete(zm.LocalSD, req[FROM])
|
delete(zm.LocalSD, from)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneManager) HandleCounterOffer(ctx context.Context, req map[string]string) (err error) {
|
func (zm *ZoneManager) HandleCounterOffer(ctx context.Context, from string, to string, req map[string]string) (err error) {
|
||||||
logger.Println("handling counter offer 1")
|
logger.Println("handling counter offer 1")
|
||||||
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
// if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
||||||
logger.Println("start job")
|
// logger.Println("start job")
|
||||||
if _, ok := zm.RTCPeerConnections[req[FROM]]; !ok {
|
// if _, ok := zm.RTCPeerConnections[from]; !ok {
|
||||||
logger.Println("error here")
|
// logger.Println("error here")
|
||||||
err = fmt.Errorf("no field corresponding peer connection for id %s", req[FROM])
|
// err = fmt.Errorf("no field corresponding peer connection for id %s", from)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
logger.Println("handling counter offer")
|
// logger.Println("handling counter offer")
|
||||||
connection := zm.RTCPeerConnections[req[FROM]]
|
// connection := zm.RTCPeerConnections[from]
|
||||||
err = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
// err = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
||||||
if err = connection.SetLocalDescription(*zm.LocalSD[req[FROM]]); err != nil {
|
// if err = connection.SetLocalDescription(*zm.LocalSD[from]); err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
logger.Println("handling counter offer 2")
|
logger.Println("handling counter offer 2")
|
||||||
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
|
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
|
||||||
for _, candidate := range zm.PendingCandidates[req[FROM]] {
|
for _, candidate := range zm.PendingCandidates[from] {
|
||||||
logger.Println("sending candidate to", req[FROM])
|
logger.Println("sending candidate to", from)
|
||||||
if err = zm.stream.Send(&Request{
|
if err = zm.sendSignalingMessage(string(ZONE_WEBRTC_CANDIDATE), zm.ID, from, map[string]any{
|
||||||
Type: string(ZONE_WEBRTC_CANDIDATE),
|
|
||||||
From: zm.ID,
|
|
||||||
Token: "none",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"from": zm.ID,
|
"from": zm.ID,
|
||||||
"to": req[FROM],
|
"to": from,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(zm.PendingCandidates, req[FROM])
|
delete(zm.PendingCandidates, from)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
_ = atomicallyExecute(zm.localSDFlag, func() (err error) {
|
||||||
delete(zm.LocalSD, req[FROM])
|
delete(zm.LocalSD, from)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -409,7 +434,7 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("---------------------------------------------------")
|
logger.Println("---------------------------------------------------")
|
||||||
if peerType == webrtc.SDPTypeAnswer {
|
if peerType == webrtc.SDPTypeOffer {
|
||||||
maxRetransmits := uint16(100)
|
maxRetransmits := uint16(100)
|
||||||
channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{
|
channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{
|
||||||
MaxRetransmits: &maxRetransmits,
|
MaxRetransmits: &maxRetransmits,
|
||||||
@ -446,13 +471,16 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
|
|||||||
logger.Println("error in open channel send", sendErr)
|
logger.Println("error in open channel send", sendErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
return
|
return
|
||||||
case <-err:
|
case e := <-err:
|
||||||
|
logger.Println("----- error from scheduler:", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
channel.OnClose(func() {
|
channel.OnClose(func() {
|
||||||
@ -494,11 +522,17 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
|
|||||||
if _, ok := zm.Zones[zoneId]; ok {
|
if _, ok := zm.Zones[zoneId]; ok {
|
||||||
logger.Println("this zone exist")
|
logger.Println("this zone exist")
|
||||||
_ = atomicallyExecute(zm.Zones[zoneId].DataChannelsFlag, func() (err error) {
|
_ = atomicallyExecute(zm.Zones[zoneId].DataChannelsFlag, func() (err error) {
|
||||||
|
logger.Println("adding dc to dc map")
|
||||||
x := int32(0)
|
x := int32(0)
|
||||||
zm.Zones[zoneId].DataChannels[target] = &DataChannel{DataChannel: dc, bufferedAmountLowThresholdReached: make(<-chan struct{}), l: &x}
|
zm.Zones[zoneId].DataChannels[target] = &DataChannel{DataChannel: dc, bufferedAmountLowThresholdReached: make(<-chan struct{}), l: &x}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
if _, ok := zm.Zones[zoneId]; !ok {
|
||||||
|
err = fmt.Errorf("no corresponding zones")
|
||||||
|
return
|
||||||
|
}
|
||||||
done, err := zm.Zones[zoneId].ZoneRequestScheduler.Schedule(reqChan)
|
done, err := zm.Zones[zoneId].ZoneRequestScheduler.Schedule(reqChan)
|
||||||
|
|
||||||
bs, jsonErr := json.Marshal(&ZoneResponse{
|
bs, jsonErr := json.Marshal(&ZoneResponse{
|
||||||
Type: "user_zone_init",
|
Type: "user_zone_init",
|
||||||
From: zoneId,
|
From: zoneId,
|
||||||
@ -513,6 +547,7 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
|
|||||||
logger.Println("error in open channel send", sendErr)
|
logger.Println("error in open channel send", sendErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
@ -520,11 +555,16 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
|
|||||||
case <-err:
|
case <-err:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
dc.OnClose(func() {
|
dc.OnClose(func() {
|
||||||
close(reqChan)
|
close(reqChan)
|
||||||
})
|
})
|
||||||
|
dc.OnError(func(err error) {
|
||||||
|
logger.Println("--------------- error in dc:", err)
|
||||||
|
close(reqChan)
|
||||||
|
})
|
||||||
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||||
var req ZoneRequest
|
var req ZoneRequest
|
||||||
if err := json.Unmarshal(msg.Data, &req); err != nil {
|
if err := json.Unmarshal(msg.Data, &req); err != nil {
|
||||||
@ -534,44 +574,53 @@ func (zm *ZoneManager) createPeerConnection(target string, from string, zoneId s
|
|||||||
logger.Println("incoming request", req)
|
logger.Println("incoming request", req)
|
||||||
reqChan <- &req
|
reqChan <- &req
|
||||||
})
|
})
|
||||||
|
_ = atomicallyExecute(zm.dataChannelFlag, func() (err error) {
|
||||||
|
l := int32(0)
|
||||||
|
zm.DataChannels[target] = &DataChannel{
|
||||||
|
DataChannel: dc,
|
||||||
|
bufferedAmountLowThresholdReached: make(<-chan struct{}),
|
||||||
|
l: &l,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
|
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
|
||||||
if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
|
if pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
|
||||||
logger.Println(pcs)
|
logger.Println(pcs)
|
||||||
if err = zm.HandleLeavingMember(target, zoneId); err != nil {
|
if err = zm.HandleLeavingMember(target, zoneId); err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
peerConnection.OnNegotiationNeeded(func() {
|
// peerConnection.OnNegotiationNeeded(func() {
|
||||||
logger.Println("------------------- negotiation is needed --------------------")
|
// logger.Println("------------------- negotiation is needed --------------------")
|
||||||
if pc, ok := zm.RTCPeerConnections[target]; ok {
|
// if pc, ok := zm.RTCPeerConnections[target]; ok {
|
||||||
if pc.SignalingState() == webrtc.ICETransportStateConnected {
|
// if pc.SignalingState() == webrtc.ICETransportStateConnected {
|
||||||
localSd, err := pc.CreateOffer(nil)
|
// localSd, err := pc.CreateOffer(nil)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
if err = pc.SetLocalDescription(localSd); err != nil {
|
// if err = pc.SetLocalDescription(localSd); err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
if err = zm.stream.Send(&Request{
|
// if err = zm.stream.Send(&Request{
|
||||||
Type: string(ZONE_WEBRTC_RENNEGOTIATION_OFFER),
|
// Type: string(ZONE_WEBRTC_RENNEGOTIATION_OFFER),
|
||||||
From: zm.ID,
|
// From: zm.ID,
|
||||||
Token: "",
|
// Token: "",
|
||||||
Payload: map[string]string{
|
// Payload: map[string]string{
|
||||||
"to": target,
|
// "to": target,
|
||||||
"sdp": localSd.SDP,
|
// "sdp": localSd.SDP,
|
||||||
},
|
// },
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
logger.Println(err)
|
// logger.Println(err)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
|
peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
|
||||||
logger.Printf("ICE connection state has changed %s\n", is.String())
|
logger.Printf("ICE connection state has changed %s\n", is.String())
|
||||||
if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
|
if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
|
||||||
@ -605,13 +654,13 @@ func (zm *ZoneManager) HandleRennegotiationOffer(from string, sdp string) (err e
|
|||||||
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zm.RTCPeerConnections[from].makingOfferLock.Lock()
|
//zm.RTCPeerConnections[from].makingOfferLock.Lock()
|
||||||
if zm.RTCPeerConnections[from].makingOffer {
|
// if zm.RTCPeerConnections[from].makingOffer {
|
||||||
zm.RTCPeerConnections[from].makingOfferLock.Unlock()
|
// //zm.RTCPeerConnections[from].makingOfferLock.Unlock()
|
||||||
err = fmt.Errorf("already making an offer or state is stable")
|
// err = fmt.Errorf("already making an offer or state is stable")
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
zm.RTCPeerConnections[from].makingOfferLock.Unlock()
|
//zm.RTCPeerConnections[from].makingOfferLock.Unlock()
|
||||||
if err = zm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
if err = zm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -622,14 +671,9 @@ func (zm *ZoneManager) HandleRennegotiationOffer(from string, sdp string) (err e
|
|||||||
if err = zm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
if err = zm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = zm.stream.Send(&Request{
|
if err = zm.sendSignalingMessage(string(ZONE_WEBRTC_RENNEGOTIATION_ANSWER), zm.ID, from, map[string]any{
|
||||||
Type: string(ZONE_WEBRTC_RENNEGOTIATION_ANSWER),
|
|
||||||
From: zm.ID,
|
|
||||||
Token: "",
|
|
||||||
Payload: map[string]string{
|
|
||||||
"to": from,
|
"to": from,
|
||||||
"sdp": localSd.SDP,
|
"sdp": localSd.SDP,
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return
|
return
|
||||||
@ -664,6 +708,10 @@ func (zm *ZoneManager) AddCandidate(candidate *webrtc.ICECandidateInit, from str
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error) {
|
func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error) {
|
||||||
|
defer func () {
|
||||||
|
logger.Println(zm.notifyLeavingMember(id,zoneId,zm.ID))
|
||||||
|
}()
|
||||||
|
logger.Println("---------------- handling leaving member", id)
|
||||||
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
||||||
if _, ok := zm.RTCPeerConnections[id]; !ok {
|
if _, ok := zm.RTCPeerConnections[id]; !ok {
|
||||||
err = fmt.Errorf("no correponding peerconnection for id %s", id)
|
err = fmt.Errorf("no correponding peerconnection for id %s", id)
|
||||||
@ -673,17 +721,21 @@ func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error)
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = atomicallyExecute(zm.zoneFlag, func() (err error) {
|
logger.Println(err)
|
||||||
|
err = atomicallyExecute(zm.zoneFlag, func() (err error) {
|
||||||
|
logger.Println("---------------- cleaning zone handlers", id)
|
||||||
if zone, ok := zm.Zones[zoneId]; ok {
|
if zone, ok := zm.Zones[zoneId]; ok {
|
||||||
|
go func() {
|
||||||
for _, handlersPublishers := range zone.ZoneRequestScheduler.handlersPublishers {
|
for _, handlersPublishers := range zone.ZoneRequestScheduler.handlersPublishers {
|
||||||
handlersPublishers <- &ZoneRequest{
|
handlersPublishers <- &ZoneRequest{
|
||||||
ReqType: LEAVE_ZONE,
|
ReqType: LEAVE_ZONE,
|
||||||
From: "node",
|
From: id,
|
||||||
Payload: map[string]interface{}{
|
Payload: map[string]interface{}{
|
||||||
"userId": id,
|
"userId": id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
if err = atomicallyExecute(zone.DataChannelsFlag, func() (err error) {
|
if err = atomicallyExecute(zone.DataChannelsFlag, func() (err error) {
|
||||||
defer delete(zone.DataChannels, id)
|
defer delete(zone.DataChannels, id)
|
||||||
if dataChannel, ok := zone.DataChannels[id]; ok {
|
if dataChannel, ok := zone.DataChannels[id]; ok {
|
||||||
@ -695,14 +747,14 @@ func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error)
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logger.Println("datachannels cleaned", id)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("no corresponding zone for zoneId %s", zoneId)
|
err = fmt.Errorf("no corresponding zone for zoneId %s", zoneId)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}); err != nil {
|
})
|
||||||
return
|
logger.Println(err)
|
||||||
}
|
err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
||||||
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
|
|
||||||
if _, ok := zm.RTCPeerConnections[id]; ok {
|
if _, ok := zm.RTCPeerConnections[id]; ok {
|
||||||
defer delete(zm.RTCPeerConnections, id)
|
defer delete(zm.RTCPeerConnections, id)
|
||||||
if err = zm.RTCPeerConnections[id].Close(); err != nil {
|
if err = zm.RTCPeerConnections[id].Close(); err != nil {
|
||||||
@ -710,7 +762,34 @@ func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}); err != nil {
|
})
|
||||||
|
logger.Println(err)
|
||||||
|
_ = atomicallyExecute(zm.candidateFlag, func() (err error) {
|
||||||
|
delete(zm.PendingCandidates, id)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zm *ZoneManager) notifyLeavingMember(userId,zoneId,hostId string) (err error) {
|
||||||
|
em := NewEncryptionManager()
|
||||||
|
sig := em.SignRequestHMAC(hostId)
|
||||||
|
body, err := json.Marshal(map[string]interface{}{
|
||||||
|
"type": DISCONNECT_ZONE_MEMBER,
|
||||||
|
"mac": sig,
|
||||||
|
"from": hostId,
|
||||||
|
"peerType":"node",
|
||||||
|
"payload": map[string]string{
|
||||||
|
"zoneId": zoneId,
|
||||||
|
"userId": userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = http.Post("https://app.zippytal.com/req", "application/json", bytes.NewBuffer(body))
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("error come from there in zone manager")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -721,13 +800,13 @@ func (zm *ZoneManager) negotiate(target string, zoneId string) {
|
|||||||
if _, ok := zm.RTCPeerConnections[target]; !ok {
|
if _, ok := zm.RTCPeerConnections[target]; !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zm.RTCPeerConnections[target].makingOfferLock.Lock()
|
//zm.RTCPeerConnections[target].makingOfferLock.Lock()
|
||||||
zm.RTCPeerConnections[target].makingOffer = true
|
//zm.RTCPeerConnections[target].makingOffer = true
|
||||||
zm.RTCPeerConnections[target].makingOfferLock.Unlock()
|
//zm.RTCPeerConnections[target].makingOfferLock.Unlock()
|
||||||
defer func() {
|
defer func() {
|
||||||
zm.RTCPeerConnections[target].makingOfferLock.Lock()
|
//zm.RTCPeerConnections[target].makingOfferLock.Lock()
|
||||||
zm.RTCPeerConnections[target].makingOffer = false
|
//zm.RTCPeerConnections[target].makingOffer = false
|
||||||
zm.RTCPeerConnections[target].makingOfferLock.Unlock()
|
//zm.RTCPeerConnections[target].makingOfferLock.Unlock()
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|||||||
10
zoneNotificationsHandler.go
Normal file
10
zoneNotificationsHandler.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package localserver
|
||||||
|
|
||||||
|
type ZoneNotificationsHandler struct {
|
||||||
|
ZoneId string
|
||||||
|
ZoneMembersId []string
|
||||||
|
DataChannels map[string]*DataChannel
|
||||||
|
Flag *uint32
|
||||||
|
Publishers []<-chan *ZoneRequest
|
||||||
|
reqChans []chan<- *ZoneRequest
|
||||||
|
}
|
||||||
@ -2,19 +2,45 @@ package localserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/dgraph-io/badger/v3"
|
"github.com/dgraph-io/badger/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type BasicRights struct {
|
||||||
|
Create bool `json:"create"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatRights struct {
|
||||||
|
*BasicRights
|
||||||
|
}
|
||||||
|
|
||||||
|
type AudioChannelRights struct {
|
||||||
|
*BasicRights
|
||||||
|
}
|
||||||
|
|
||||||
|
type VideoChannelRights struct {
|
||||||
|
*BasicRights
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaRights struct {
|
||||||
|
*BasicRights
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileRights struct {
|
||||||
|
*BasicRights
|
||||||
|
CreateAtRoot bool `json:"createAtRoot"`
|
||||||
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ChatRights string `json:"chatRights"`
|
ChatRights *ChatRights `json:"chatRights"`
|
||||||
AudioChannelRights string `json:"audioChannelRights"`
|
AudioChannelRights *AudioChannelRights `json:"audioChannelRights"`
|
||||||
VideoChannelRights string `json:"videoChannelRights"`
|
VideoChannelRights *VideoChannelRights `json:"videoChannelRights"`
|
||||||
MediaRights string `json:"mediaRights"`
|
MediaRights *MediaRights `json:"mediaRights"`
|
||||||
FileRights string `json:"fileRights"`
|
FileRights *FileRights `json:"fileRights"`
|
||||||
KnownChatsId []string `json:"knownChatsId"`
|
KnownChatsId []string `json:"knownChatsId"`
|
||||||
KnownAudioChannelsId []string `json:"knownAudioChannelsId"`
|
KnownAudioChannelsId []string `json:"knownAudioChannelsId"`
|
||||||
KnownVideoChannelsId []string `json:"knownVideoChannelsId"`
|
KnownVideoChannelsId []string `json:"knownVideoChannelsId"`
|
||||||
@ -29,6 +55,46 @@ type ZoneUsersDBHandler struct {
|
|||||||
db func(func(*badger.DB) (err error)) (err error)
|
db func(func(*badger.DB) (err error)) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewChatRights(create bool) *ChatRights {
|
||||||
|
return &ChatRights{
|
||||||
|
BasicRights: &BasicRights{
|
||||||
|
Create: create,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAudioChannelRights(create bool) *AudioChannelRights {
|
||||||
|
return &AudioChannelRights{
|
||||||
|
BasicRights: &BasicRights{
|
||||||
|
Create: create,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVideoChannelRights(create bool) *VideoChannelRights {
|
||||||
|
return &VideoChannelRights{
|
||||||
|
BasicRights: &BasicRights{
|
||||||
|
Create: create,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMediaRights(create bool) *MediaRights {
|
||||||
|
return &MediaRights{
|
||||||
|
BasicRights: &BasicRights{
|
||||||
|
Create: create,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFileRights(create bool) *FileRights {
|
||||||
|
return &FileRights{
|
||||||
|
BasicRights: &BasicRights{
|
||||||
|
Create: create,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewZoneUsersDBHandler(zoneId string, owner string, authorizedMembers []string, init bool) (zoneChatDBHandler *ZoneUsersDBHandler, err error) {
|
func NewZoneUsersDBHandler(zoneId string, owner string, authorizedMembers []string, init bool) (zoneChatDBHandler *ZoneUsersDBHandler, err error) {
|
||||||
db := func(f func(*badger.DB) (err error)) (err error) {
|
db := func(f func(*badger.DB) (err error)) (err error) {
|
||||||
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zoneId, "users")).WithLogger(dbLogger))
|
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zoneId, "users")).WithLogger(dbLogger))
|
||||||
@ -43,11 +109,11 @@ func NewZoneUsersDBHandler(zoneId string, owner string, authorizedMembers []stri
|
|||||||
admin := &User{
|
admin := &User{
|
||||||
ID: owner,
|
ID: owner,
|
||||||
Name: owner,
|
Name: owner,
|
||||||
ChatRights: "",
|
ChatRights: NewChatRights(true),
|
||||||
AudioChannelRights: "",
|
AudioChannelRights: NewAudioChannelRights(true),
|
||||||
VideoChannelRights: "",
|
VideoChannelRights: NewVideoChannelRights(true),
|
||||||
MediaRights: "",
|
MediaRights: NewMediaRights(true),
|
||||||
FileRights: "",
|
FileRights: NewFileRights(true),
|
||||||
KnownChatsId: []string{},
|
KnownChatsId: []string{},
|
||||||
KnownAudioChannelsId: []string{},
|
KnownAudioChannelsId: []string{},
|
||||||
KnownVideoChannelsId: []string{},
|
KnownVideoChannelsId: []string{},
|
||||||
@ -70,6 +136,14 @@ func NewZoneUsersDBHandler(zoneId string, owner string, authorizedMembers []stri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bs, err := os.ReadFile(filepath.Join("data", "zones", zoneId, "users", "usersConfig.json"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var baseUserConfig ZoneUserConfig
|
||||||
|
if err = json.Unmarshal(bs, &baseUserConfig); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if err = db(func(d *badger.DB) (err error) {
|
if err = db(func(d *badger.DB) (err error) {
|
||||||
err = d.Update(func(txn *badger.Txn) (err error) {
|
err = d.Update(func(txn *badger.Txn) (err error) {
|
||||||
for _, member := range authorizedMembers {
|
for _, member := range authorizedMembers {
|
||||||
@ -79,11 +153,11 @@ func NewZoneUsersDBHandler(zoneId string, owner string, authorizedMembers []stri
|
|||||||
user := &User{
|
user := &User{
|
||||||
ID: member,
|
ID: member,
|
||||||
Name: member,
|
Name: member,
|
||||||
ChatRights: "",
|
ChatRights: baseUserConfig.DefaultChatRights,
|
||||||
AudioChannelRights: "",
|
AudioChannelRights: baseUserConfig.DefaultAudioChannelRights,
|
||||||
VideoChannelRights: "",
|
VideoChannelRights: baseUserConfig.DefaultVideoChannelRights,
|
||||||
MediaRights: "",
|
MediaRights: baseUserConfig.DefaultMediaRights,
|
||||||
FileRights: "",
|
FileRights: baseUserConfig.DefaultFileRights,
|
||||||
KnownChatsId: []string{},
|
KnownChatsId: []string{},
|
||||||
KnownAudioChannelsId: []string{},
|
KnownAudioChannelsId: []string{},
|
||||||
KnownVideoChannelsId: []string{},
|
KnownVideoChannelsId: []string{},
|
||||||
@ -154,7 +228,7 @@ func (zcdbh *ZoneUsersDBHandler) ListUsers(lastIndex int, limit int) (users []*U
|
|||||||
opt.Reverse = true
|
opt.Reverse = true
|
||||||
it := txn.NewIterator(opt)
|
it := txn.NewIterator(opt)
|
||||||
defer it.Close()
|
defer it.Close()
|
||||||
users = make([]*User, 0)
|
users = []*User{}
|
||||||
for it.Rewind(); it.Valid(); it.Next() {
|
for it.Rewind(); it.Valid(); it.Next() {
|
||||||
item := it.Item()
|
item := it.Item()
|
||||||
if err = item.Value(func(val []byte) error {
|
if err = item.Value(func(val []byte) error {
|
||||||
|
|||||||
@ -9,9 +9,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
EDIT_DEFAULT_RIGHTS = "edit_default_rights"
|
||||||
|
EDIT_USERS_RIGHTS = "edit_users_rights"
|
||||||
LIST_ZONE_MEMBERS = "list_zone_members"
|
LIST_ZONE_MEMBERS = "list_zone_members"
|
||||||
LIST_ZONE_MEMBERS_RESPONSE = "list_zone_members_response"
|
LIST_ZONE_MEMBERS_RESPONSE = "list_zone_members_response"
|
||||||
GET_USER = "get_user"
|
GET_USER = "get_user"
|
||||||
|
GET_DEFAULT_RIGHTS = "get_default_rights"
|
||||||
MODIFY_USER_CHAT_RIGHTS = "modify_user_chat_rights"
|
MODIFY_USER_CHAT_RIGHTS = "modify_user_chat_rights"
|
||||||
ADD_KNOWN_CHAT = "add_known_chat"
|
ADD_KNOWN_CHAT = "add_known_chat"
|
||||||
REMOVE_KNOWN_CHAT = "remove_known_chat"
|
REMOVE_KNOWN_CHAT = "remove_known_chat"
|
||||||
@ -25,7 +28,11 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
NEW_ZONE_USER = "new_zone_user"
|
NEW_ZONE_USER = "new_zone_user"
|
||||||
|
GET_CURRENT_USER_RESPONSE = "get_current_user_response"
|
||||||
|
GET_USER_RESPONSE = "get_user_response"
|
||||||
REMOVED_ZONE_USER = "removed_zone_user"
|
REMOVED_ZONE_USER = "removed_zone_user"
|
||||||
|
DEFAULT_RIGHTS_EDITED = "default_rights_edited"
|
||||||
|
USER_RIGHTS_EDITED = "user_rights_edited"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ZoneUsersHandler struct {
|
type ZoneUsersHandler struct {
|
||||||
@ -38,13 +45,19 @@ type ZoneUsersHandler struct {
|
|||||||
reqChans []chan<- *ZoneRequest
|
reqChans []chan<- *ZoneRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ZoneMember struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Admin bool `json:"admin"`
|
||||||
|
Owner bool `json:"owner"`
|
||||||
|
Config *ZoneUserConfig `json:"config"`
|
||||||
|
}
|
||||||
|
|
||||||
type ZoneUserConfig struct {
|
type ZoneUserConfig struct {
|
||||||
DefaultChatsRights string `json:"defaultChatsRights"`
|
DefaultChatRights *ChatRights `json:"defaultChatsRights"`
|
||||||
DefaultAudioChannelsRights string `json:"defaultAudioChannelsRights"`
|
DefaultAudioChannelRights *AudioChannelRights `json:"defaultAudioChannelsRights"`
|
||||||
DefaultVideoChannelsRights string `json:"defaultVideoChannelsRights"`
|
DefaultVideoChannelRights *VideoChannelRights `json:"defaultVideoChannelsRights"`
|
||||||
DefaultMediaRights string `json:"defaultMediaRights"`
|
DefaultMediaRights *MediaRights `json:"defaultMediaRights"`
|
||||||
DefaultFileRights string `json:"defaultFileRights"`
|
DefaultFileRights *FileRights `json:"defaultFileRights"`
|
||||||
AdminRights string `json:"adminRights"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZoneUsersHandler(zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneUsersHandler *ZoneUsersHandler, err error) {
|
func NewZoneUsersHandler(zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneUsersHandler *ZoneUsersHandler, err error) {
|
||||||
@ -57,21 +70,16 @@ func NewZoneUsersHandler(zoneId string, owner string, authorizedMembers []string
|
|||||||
if mkdirErr != nil {
|
if mkdirErr != nil {
|
||||||
return nil, mkdirErr
|
return nil, mkdirErr
|
||||||
}
|
}
|
||||||
zoneUsersDBHandler, err = NewZoneUsersDBHandler(zoneId, owner, authorizedMembers, true)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file, ferr := os.Create(filepath.Join("data", "zones", zoneId, "users", "usersConfig.json"))
|
file, ferr := os.Create(filepath.Join("data", "zones", zoneId, "users", "usersConfig.json"))
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return nil, ferr
|
return nil, ferr
|
||||||
}
|
}
|
||||||
baseConfig := ZoneUserConfig{
|
baseConfig := ZoneUserConfig{
|
||||||
DefaultChatsRights: "",
|
DefaultChatRights: NewChatRights(true),
|
||||||
DefaultAudioChannelsRights: "",
|
DefaultAudioChannelRights: NewAudioChannelRights(true),
|
||||||
DefaultVideoChannelsRights: "",
|
DefaultVideoChannelRights: NewVideoChannelRights(true),
|
||||||
DefaultMediaRights: "",
|
DefaultMediaRights: NewMediaRights(true),
|
||||||
DefaultFileRights: "",
|
DefaultFileRights: NewFileRights(true),
|
||||||
AdminRights: "",
|
|
||||||
}
|
}
|
||||||
bs, jsonErr := json.Marshal(baseConfig)
|
bs, jsonErr := json.Marshal(baseConfig)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
@ -80,7 +88,11 @@ func NewZoneUsersHandler(zoneId string, owner string, authorizedMembers []string
|
|||||||
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
|
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
|
||||||
return nil, writeErr
|
return nil, writeErr
|
||||||
}
|
}
|
||||||
_ = file.Close()
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
zoneUsersDBHandler, err = NewZoneUsersDBHandler(zoneId, owner, authorizedMembers, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -139,6 +151,34 @@ func (zuh *ZoneUsersHandler) Init(ctx context.Context, authorizedMembers []strin
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (zuh *ZoneUsersHandler) sendDataChannelMessage(reqType string, from string, to string, payload map[string]interface{}) (<-chan struct{}, <-chan error) {
|
||||||
|
done, errCh := make(chan struct{}, 10), make(chan error, 10)
|
||||||
|
go func() {
|
||||||
|
if err := atomicallyExecute(zuh.Flag, func() (err error) {
|
||||||
|
if _, ok := zuh.DataChannels[to]; ok {
|
||||||
|
bs, jsonErr := json.Marshal(&ZoneResponse{
|
||||||
|
Type: reqType,
|
||||||
|
From: from,
|
||||||
|
To: to,
|
||||||
|
Payload: payload,
|
||||||
|
})
|
||||||
|
if jsonErr != nil {
|
||||||
|
return jsonErr
|
||||||
|
}
|
||||||
|
logger.Println(string(bs))
|
||||||
|
err = zuh.DataChannels[to].DataChannel.SendText(string(bs))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}); err != nil {
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
done <- struct{}{}
|
||||||
|
logger.Printf("sending %v done\n", payload)
|
||||||
|
}()
|
||||||
|
return done, errCh
|
||||||
|
}
|
||||||
|
|
||||||
func (zuh *ZoneUsersHandler) Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error) {
|
func (zuh *ZoneUsersHandler) Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error) {
|
||||||
reqChan, done, errCh = make(chan *ZoneRequest), make(chan struct{}), make(chan error)
|
reqChan, done, errCh = make(chan *ZoneRequest), make(chan struct{}), make(chan error)
|
||||||
zuh.reqChans = append(zuh.reqChans, reqChan)
|
zuh.reqChans = append(zuh.reqChans, reqChan)
|
||||||
@ -159,14 +199,22 @@ func (zuh *ZoneUsersHandler) Subscribe(ctx context.Context, publisher <-chan *Zo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (zuh *ZoneUsersHandler) AddUser(userId string) (err error) {
|
func (zuh *ZoneUsersHandler) AddUser(userId string) (err error) {
|
||||||
|
bs, err := os.ReadFile(filepath.Join("data", "zones", zuh.ZoneId, "users", "usersConfig.json"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var baseUserConfig ZoneUserConfig
|
||||||
|
if err = json.Unmarshal(bs, &baseUserConfig); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
newUser := &User{
|
newUser := &User{
|
||||||
ID: userId,
|
ID: userId,
|
||||||
Name: userId,
|
Name: userId,
|
||||||
ChatRights: "",
|
ChatRights: baseUserConfig.DefaultChatRights,
|
||||||
AudioChannelRights: "",
|
AudioChannelRights: baseUserConfig.DefaultAudioChannelRights,
|
||||||
VideoChannelRights: "",
|
VideoChannelRights: baseUserConfig.DefaultVideoChannelRights,
|
||||||
MediaRights: "",
|
MediaRights: baseUserConfig.DefaultMediaRights,
|
||||||
FileRights: "",
|
FileRights: baseUserConfig.DefaultFileRights,
|
||||||
KnownChatsId: []string{},
|
KnownChatsId: []string{},
|
||||||
KnownAudioChannelsId: []string{},
|
KnownAudioChannelsId: []string{},
|
||||||
KnownVideoChannelsId: make([]string, 0),
|
KnownVideoChannelsId: make([]string, 0),
|
||||||
@ -418,9 +466,137 @@ func (zuh *ZoneUsersHandler) RemoveKnownFolder(folderId string, userId string) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (zuh *ZoneUsersHandler) GetDefaultRights(userId string) (err error) {
|
||||||
|
bs, err := os.ReadFile(filepath.Join("data", "zones", zuh.ZoneId, "users", "usersConfig.json"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var defaultRights ZoneUserConfig
|
||||||
|
if err = json.Unmarshal(bs, &defaultRights); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d, e := zuh.sendDataChannelMessage(GET_DEFAULT_RIGHTS, "node", userId, map[string]interface{}{
|
||||||
|
"defaultRights": defaultRights,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case err = <-e:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zuh *ZoneUsersHandler) EditDefaultRights(defaultChatRights *ChatRights, defaultAudioChannelRights *AudioChannelRights, defaultVideoChannelRights *VideoChannelRights, defaultMediaRights *MediaRights, defaultFileRights *FileRights) (err error) {
|
||||||
|
bs, err := os.ReadFile(filepath.Join("data", "zones", zuh.ZoneId, "users", "usersConfig.json"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var baseUserConfig ZoneUserConfig
|
||||||
|
if err = json.Unmarshal(bs, &baseUserConfig); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
baseUserConfig.DefaultChatRights = defaultChatRights
|
||||||
|
baseUserConfig.DefaultAudioChannelRights = defaultAudioChannelRights
|
||||||
|
baseUserConfig.DefaultVideoChannelRights = defaultVideoChannelRights
|
||||||
|
baseUserConfig.DefaultMediaRights = defaultMediaRights
|
||||||
|
baseUserConfig.DefaultFileRights = defaultFileRights
|
||||||
|
bs, err = json.Marshal(baseUserConfig)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := os.OpenFile(filepath.Join("data", "zones", zuh.ZoneId, "users", "usersConfig.json"), os.O_WRONLY|os.O_TRUNC, os.ModeAppend)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err = file.WriteString(string(bs)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = file.Close()
|
||||||
|
for _, member := range zuh.ZoneMembersId {
|
||||||
|
done, err := zuh.sendDataChannelMessage(DEFAULT_RIGHTS_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"defaultRights": baseUserConfig,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case e := <-err:
|
||||||
|
logger.Println(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zuh *ZoneUsersHandler) EditUsersRights(users []interface{}, chatRights *ChatRights, audioChannelRights *AudioChannelRights, videoChannelRights *VideoChannelRights, mediaRights *MediaRights, fileRights *FileRights) (err error) {
|
||||||
|
for _, u := range users {
|
||||||
|
if user, ok := u.(string); ok {
|
||||||
|
if err = zuh.editUserRights(user, chatRights, audioChannelRights, videoChannelRights, mediaRights, fileRights); err != nil {
|
||||||
|
logger.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (zuh *ZoneUsersHandler) editUserRights(userId string, chatRights *ChatRights, audioChannelRights *AudioChannelRights, videoChannelRights *VideoChannelRights, mediaRights *MediaRights, fileRights *FileRights) (err error) {
|
||||||
|
user, err := zuh.DB.GetUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user.ChatRights = chatRights
|
||||||
|
user.AudioChannelRights = audioChannelRights
|
||||||
|
user.VideoChannelRights = videoChannelRights
|
||||||
|
user.MediaRights = mediaRights
|
||||||
|
user.FileRights = fileRights
|
||||||
|
if err = zuh.DB.ModifyUser(userId, user); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, id := range zuh.ZoneMembersId {
|
||||||
|
d, e := zuh.sendDataChannelMessage(USER_RIGHTS_EDITED, "node", userId, map[string]interface{}{
|
||||||
|
"userId": id,
|
||||||
|
"user": user,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-d:
|
||||||
|
case err = <-e:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
|
func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
|
||||||
logger.Println("got request in zone users handler", req)
|
logger.Println("got request in zone users handler", req)
|
||||||
switch req.ReqType {
|
switch req.ReqType {
|
||||||
|
case EDIT_DEFAULT_RIGHTS:
|
||||||
|
if _, ok := req.Payload["defaultRights"]; !ok {
|
||||||
|
err = fmt.Errorf("no field defaultRights in request payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bs, jsonErr := json.Marshal(req.Payload["defaultRights"])
|
||||||
|
if jsonErr != nil {
|
||||||
|
return jsonErr
|
||||||
|
}
|
||||||
|
var config ZoneUserConfig
|
||||||
|
if err = json.Unmarshal(bs, &config); err != nil {
|
||||||
|
err = fmt.Errorf("the defaultRights payload dont match ZoneFSEntity struct pattern : %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zuh.EditDefaultRights(config.DefaultChatRights, config.DefaultAudioChannelRights, config.DefaultVideoChannelRights, config.DefaultMediaRights, config.DefaultFileRights)
|
||||||
|
case EDIT_USERS_RIGHTS:
|
||||||
|
if err = verifyFieldsSliceInterface(req.Payload, "users"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := req.Payload["defaultRights"]; !ok {
|
||||||
|
err = fmt.Errorf("no field defaultRights in request payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bs, jsonErr := json.Marshal(req.Payload["defaultRights"])
|
||||||
|
if jsonErr != nil {
|
||||||
|
return jsonErr
|
||||||
|
}
|
||||||
|
var config ZoneUserConfig
|
||||||
|
if err = json.Unmarshal(bs, &config); err != nil {
|
||||||
|
err = fmt.Errorf("the defaultRights payload dont match ZoneFSEntity struct pattern : %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zuh.EditUsersRights(req.Payload["users"].([]interface{}), config.DefaultChatRights, config.DefaultAudioChannelRights, config.DefaultVideoChannelRights, config.DefaultMediaRights, config.DefaultFileRights)
|
||||||
case REMOVE_USER:
|
case REMOVE_USER:
|
||||||
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
return
|
return
|
||||||
@ -461,6 +637,11 @@ func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = zuh.AddKnownVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
|
err = zuh.AddKnownVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
|
||||||
|
case GET_DEFAULT_RIGHTS:
|
||||||
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = zuh.GetDefaultRights(req.Payload["userId"].(string))
|
||||||
case GET_USER:
|
case GET_USER:
|
||||||
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
|
||||||
return
|
return
|
||||||
@ -477,57 +658,58 @@ func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var answer *ZoneResponse
|
logger.Println("get user done")
|
||||||
|
|
||||||
if req.Payload["init"].(bool) {
|
if req.Payload["init"].(bool) {
|
||||||
answer = &ZoneResponse{
|
done, errCh := zuh.sendDataChannelMessage(GET_CURRENT_USER_RESPONSE, "node", req.Payload["userId"].(string), map[string]interface{}{
|
||||||
Type: "get_current_user_response",
|
|
||||||
To: "",
|
|
||||||
From: "",
|
|
||||||
Payload: map[string]interface{}{
|
|
||||||
"user": user,
|
"user": user,
|
||||||
},
|
})
|
||||||
}
|
select {
|
||||||
} else {
|
case <-done:
|
||||||
answer = &ZoneResponse{
|
case err = <-errCh:
|
||||||
Type: "get_user_response",
|
|
||||||
To: "",
|
|
||||||
From: "",
|
|
||||||
Payload: map[string]interface{}{
|
|
||||||
"user": user,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bs, err := json.Marshal(answer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Println(string(bs))
|
|
||||||
if _, ok := zuh.DataChannels[req.From]; ok {
|
} else {
|
||||||
if err = zuh.DataChannels[req.From].DataChannel.SendText(string(bs)); err != nil {
|
done, errCh := zuh.sendDataChannelMessage(GET_USER_RESPONSE, "node", req.Payload["userId"].(string), map[string]interface{}{
|
||||||
|
"user": user,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case err = <-errCh:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case LIST_ZONE_MEMBERS:
|
case LIST_ZONE_MEMBERS:
|
||||||
users, err := zuh.DB.ListUsers(0, 0)
|
users, err := zuh.DB.ListUsers(0, 1000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
bs, err := json.Marshal(&ZoneResponse{
|
usersIds := []*ZoneMember{}
|
||||||
Type: LIST_ZONE_MEMBERS_RESPONSE,
|
for _, user := range users {
|
||||||
To: "",
|
usersIds = append(usersIds, &ZoneMember{
|
||||||
From: "",
|
ID: user.ID,
|
||||||
Payload: map[string]interface{}{
|
Admin: user.Admin,
|
||||||
"users": users,
|
Owner: user.Owner,
|
||||||
|
Config: &ZoneUserConfig{
|
||||||
|
DefaultChatRights: user.ChatRights,
|
||||||
|
DefaultAudioChannelRights: user.AudioChannelRights,
|
||||||
|
DefaultVideoChannelRights: user.VideoChannelRights,
|
||||||
|
DefaultMediaRights: user.MediaRights,
|
||||||
|
DefaultFileRights: user.FileRights,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if _, ok := zuh.DataChannels[req.From]; ok {
|
logger.Println("get user done")
|
||||||
if err = zuh.DataChannels[req.From].DataChannel.SendText(string(bs)); err != nil {
|
done, errCh := zuh.sendDataChannelMessage(LIST_ZONE_MEMBERS_RESPONSE, zuh.ZoneId, req.From, map[string]interface{}{
|
||||||
|
"users": usersIds,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
logger.Println("send get user done")
|
||||||
|
case err = <-errCh:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case MODIFY_USER_CHAT_RIGHTS:
|
case MODIFY_USER_CHAT_RIGHTS:
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@ -129,10 +129,10 @@ func (vc *VideoChannel) HandleOffer(ctx context.Context, channelId string, userI
|
|||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
|
if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
|
||||||
vc.localSD[userId] = &rawAnswer
|
errCh <- err
|
||||||
return
|
return
|
||||||
})
|
}
|
||||||
_, _ = sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
_, _ = sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{
|
||||||
"to": userId,
|
"to": userId,
|
||||||
"from": vc.ID,
|
"from": vc.ID,
|
||||||
@ -146,25 +146,25 @@ func (vc *VideoChannel) HandleOffer(ctx context.Context, channelId string, userI
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (vc *VideoChannel) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
func (vc *VideoChannel) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) {
|
||||||
if err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
|
// if err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) {
|
||||||
if _, ok := vc.rtcPeerConnections[userId]; !ok {
|
// if _, ok := vc.rtcPeerConnections[userId]; !ok {
|
||||||
err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
// err = fmt.Errorf("no field corresponding peer connection for id %s", userId)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
logger.Println("handling counter offer")
|
// logger.Println("handling counter offer")
|
||||||
connection := vc.rtcPeerConnections[userId]
|
// connection := vc.rtcPeerConnections[userId]
|
||||||
err = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
|
// err = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
|
||||||
err = connection.SetLocalDescription(*vc.localSD[userId])
|
// err = connection.SetLocalDescription(*vc.localSD[userId])
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}); err != nil {
|
// }); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
_ = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
|
// _ = atomicallyExecute(vc.localSDMapFlag, func() (err error) {
|
||||||
delete(vc.localSD, userId)
|
// delete(vc.localSD, userId)
|
||||||
return
|
// return
|
||||||
})
|
// })
|
||||||
if err = atomicallyExecute(vc.candidateFlag, func() (err error) {
|
if err = atomicallyExecute(vc.candidateFlag, func() (err error) {
|
||||||
for _, candidate := range vc.pendingCandidates[userId] {
|
for _, candidate := range vc.pendingCandidates[userId] {
|
||||||
logger.Println("sending candidate to", userId, candidate)
|
logger.Println("sending candidate to", userId, candidate)
|
||||||
@ -173,7 +173,7 @@ func (vc *VideoChannel) HandleCounterOffer(ctx context.Context, userId string, s
|
|||||||
"to": userId,
|
"to": userId,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-d:
|
case <-d:
|
||||||
@ -195,12 +195,12 @@ func (vc *VideoChannel) HandleRennegotiationOffer(from string, sdp string, sendD
|
|||||||
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
err = fmt.Errorf("no corresponding peer connection for id %s", from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vc.rtcPeerConnections[from].makingOfferLock.Lock()
|
// vc.rtcPeerConnections[from].makingOfferLock.Lock()
|
||||||
if vc.rtcPeerConnections[from].makingOffer {
|
// if vc.rtcPeerConnections[from].makingOffer {
|
||||||
vc.rtcPeerConnections[from].makingOfferLock.Unlock()
|
// vc.rtcPeerConnections[from].makingOfferLock.Unlock()
|
||||||
return fmt.Errorf("already making an offer or state is stable")
|
// return fmt.Errorf("already making an offer or state is stable")
|
||||||
}
|
// }
|
||||||
vc.rtcPeerConnections[from].makingOfferLock.Unlock()
|
// vc.rtcPeerConnections[from].makingOfferLock.Unlock()
|
||||||
if err = vc.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
if err = vc.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -670,13 +670,13 @@ func (vc *VideoChannel) negotiate(target string, sendDCMessage SendDCMessageFunc
|
|||||||
if _, ok := vc.rtcPeerConnections[target]; !ok {
|
if _, ok := vc.rtcPeerConnections[target]; !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vc.rtcPeerConnections[target].makingOfferLock.Lock()
|
// vc.rtcPeerConnections[target].makingOfferLock.Lock()
|
||||||
vc.rtcPeerConnections[target].makingOffer = true
|
// vc.rtcPeerConnections[target].makingOffer = true
|
||||||
vc.rtcPeerConnections[target].makingOfferLock.Unlock()
|
// vc.rtcPeerConnections[target].makingOfferLock.Unlock()
|
||||||
defer func() {
|
defer func() {
|
||||||
vc.rtcPeerConnections[target].makingOfferLock.Lock()
|
// vc.rtcPeerConnections[target].makingOfferLock.Lock()
|
||||||
vc.rtcPeerConnections[target].makingOffer = false
|
// vc.rtcPeerConnections[target].makingOffer = false
|
||||||
vc.rtcPeerConnections[target].makingOfferLock.Unlock()
|
// vc.rtcPeerConnections[target].makingOfferLock.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for _, id := range vc.CurrentMembersId {
|
for _, id := range vc.CurrentMembersId {
|
||||||
|
|||||||
@ -29,6 +29,12 @@ const (
|
|||||||
const (
|
const (
|
||||||
USER_JOINED_VIDEO_CHANNEL = "user_joined_video_channel"
|
USER_JOINED_VIDEO_CHANNEL = "user_joined_video_channel"
|
||||||
USER_LEFT_VIDEO_CHANNEL = "user_left_video_channel"
|
USER_LEFT_VIDEO_CHANNEL = "user_left_video_channel"
|
||||||
|
VIDEO_CHANNNEL_NAME_EDITED = "video_channel_name_edited"
|
||||||
|
VIDEO_CHANNNEL_TYPE_EDITED = "video_channel_type_edited"
|
||||||
|
VIDEO_CHANNEL_MEMBER_REMOVED = "video_channel_member_removed"
|
||||||
|
VIDEO_CHANNEL_MEMBER_ADDED = "video_channel_member_added"
|
||||||
|
ADDED_IN_VIDEO_CHANNEL = "added_in_video_channel"
|
||||||
|
REMOVED_FROM_VIDEO_CHANNEL = "removed_from_video_channel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VideoChannelMember struct {
|
type VideoChannelMember struct {
|
||||||
@ -193,7 +199,7 @@ func (zvch *ZoneVideoChannelsHandler) signalCandidate(from string, to string, ca
|
|||||||
"to": to,
|
"to": to,
|
||||||
"candidate": candidate.ToJSON().Candidate,
|
"candidate": candidate.ToJSON().Candidate,
|
||||||
"sdpMid": *candidate.ToJSON().SDPMid,
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
||||||
"sdpMlineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-d:
|
case <-d:
|
||||||
@ -268,15 +274,15 @@ func (zvch *ZoneVideoChannelsHandler) AddNewVideoChannel(channelName string, own
|
|||||||
}
|
}
|
||||||
m := make([]string, 0, len(members))
|
m := make([]string, 0, len(members))
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
if _, ok := member.(string); ok {
|
if mbr, ok := member.(string); ok && mbr != owner {
|
||||||
m = append(m, member.(string))
|
m = append(m, mbr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
baseConfig := &VideoChannelConfig{
|
baseConfig := &VideoChannelConfig{
|
||||||
ID: channelName,
|
ID: channelName,
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
ChannelType: channelType,
|
ChannelType: channelType,
|
||||||
Members: m,
|
Members: append(m,owner),
|
||||||
}
|
}
|
||||||
bs, jsonErr := json.Marshal(baseConfig)
|
bs, jsonErr := json.Marshal(baseConfig)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
@ -343,7 +349,7 @@ func (zvch *ZoneVideoChannelsHandler) DeleteVideoChannel(channelId string) (err
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zvch.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(REMOVED_FROM_VIDEO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
"userId": member,
|
"userId": member,
|
||||||
})
|
})
|
||||||
@ -379,7 +385,7 @@ func (zvch *ZoneVideoChannelsHandler) EditVideoChannelName(channelId string, new
|
|||||||
err = fmt.Errorf("no coresponding videoChannel")
|
err = fmt.Errorf("no coresponding videoChannel")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs, err := os.ReadFile(filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", channelId))
|
bs, err := os.ReadFile(filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", channelId, "videoChannelConfig.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -392,7 +398,7 @@ func (zvch *ZoneVideoChannelsHandler) EditVideoChannelName(channelId string, new
|
|||||||
if err = os.Rename(filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", channelId), filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", newVideoChannelId)); err != nil {
|
if err = os.Rename(filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", channelId), filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", newVideoChannelId)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f, err := os.OpenFile(filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", newVideoChannelId), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
f, err := os.OpenFile(filepath.Join("data", "zones", zvch.ZoneId, "videoChannels", newVideoChannelId, "videoChannelConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
}()
|
}()
|
||||||
@ -416,7 +422,7 @@ func (zvch *ZoneVideoChannelsHandler) EditVideoChannelName(channelId string, new
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zvch.sendDataChannelMessage(CHAT_NAME_EDITED, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(VIDEO_CHANNNEL_NAME_EDITED, "node", member, map[string]interface{}{
|
||||||
"formerVideoChannelId": channelId,
|
"formerVideoChannelId": channelId,
|
||||||
"newVideoChannelId": newVideoChannelId,
|
"newVideoChannelId": newVideoChannelId,
|
||||||
})
|
})
|
||||||
@ -480,6 +486,10 @@ func (zvch *ZoneVideoChannelsHandler) EditVideoChannelType(channelId string, cha
|
|||||||
if pubErr := zvch.SetVideoChannelPublicForUser(channelId, member); pubErr != nil {
|
if pubErr := zvch.SetVideoChannelPublicForUser(channelId, member); pubErr != nil {
|
||||||
logger.Println(pubErr)
|
logger.Println(pubErr)
|
||||||
}
|
}
|
||||||
|
zvch.sendDataChannelMessage(VIDEO_CHANNNEL_TYPE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"channelId": channelId,
|
||||||
|
"channelType": channelType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case PRIVATE:
|
case PRIVATE:
|
||||||
var members = []string{}
|
var members = []string{}
|
||||||
@ -491,6 +501,10 @@ func (zvch *ZoneVideoChannelsHandler) EditVideoChannelType(channelId string, cha
|
|||||||
if pubErr := zvch.SetVideoChannelPrivateForUser(channelId, member); pubErr != nil {
|
if pubErr := zvch.SetVideoChannelPrivateForUser(channelId, member); pubErr != nil {
|
||||||
logger.Println(pubErr)
|
logger.Println(pubErr)
|
||||||
}
|
}
|
||||||
|
zvch.sendDataChannelMessage(VIDEO_CHANNNEL_TYPE_EDITED, "node", member, map[string]interface{}{
|
||||||
|
"channelId": channelId,
|
||||||
|
"channelType": channelType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
|
_ = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
|
||||||
@ -558,7 +572,7 @@ broadcastLoop:
|
|||||||
for _, member := range vc.Members {
|
for _, member := range vc.Members {
|
||||||
for _, m := range addedMembers {
|
for _, m := range addedMembers {
|
||||||
if member == m {
|
if member == m {
|
||||||
done, e := zvch.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(ADDED_IN_VIDEO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"videoChannel": vc,
|
"videoChannel": vc,
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
@ -569,7 +583,7 @@ broadcastLoop:
|
|||||||
continue broadcastLoop
|
continue broadcastLoop
|
||||||
}
|
}
|
||||||
if _, ok := zvch.DataChannels[member]; ok {
|
if _, ok := zvch.DataChannels[member]; ok {
|
||||||
done, e := zvch.sendDataChannelMessage(CHAT_MEMBER_ADDED, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(VIDEO_CHANNEL_MEMBER_ADDED, "node", member, map[string]interface{}{
|
||||||
"userId": m,
|
"userId": m,
|
||||||
"channelId": vc.ID,
|
"channelId": vc.ID,
|
||||||
})
|
})
|
||||||
@ -635,7 +649,7 @@ func (zvch *ZoneVideoChannelsHandler) RemoveVideoChannelMember(channelId string,
|
|||||||
}
|
}
|
||||||
var vc *VideoChannel
|
var vc *VideoChannel
|
||||||
_ = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
|
_ = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
|
||||||
vc := NewVideoChannel(videoChannelConfig.ID, videoChannelConfig.Owner, videoChannelConfig.ChannelType, videoChannelConfig.Members, make([]string, 0), make(map[string]*VideoChannelMember))
|
vc = NewVideoChannel(videoChannelConfig.ID, videoChannelConfig.Owner, videoChannelConfig.ChannelType, videoChannelConfig.Members, make([]string, 0), make(map[string]*VideoChannelMember))
|
||||||
zvch.VideoChannels[channelId] = vc
|
zvch.VideoChannels[channelId] = vc
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
@ -643,7 +657,7 @@ func (zvch *ZoneVideoChannelsHandler) RemoveVideoChannelMember(channelId string,
|
|||||||
"userId": channelMember,
|
"userId": channelMember,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zvch.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", channelMember, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(REMOVED_FROM_VIDEO_CHANNEL, "node", channelMember, map[string]interface{}{
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
"userId": channelMember,
|
"userId": channelMember,
|
||||||
})
|
})
|
||||||
@ -657,7 +671,7 @@ broadcastLoop:
|
|||||||
if member == channelMember {
|
if member == channelMember {
|
||||||
continue broadcastLoop
|
continue broadcastLoop
|
||||||
}
|
}
|
||||||
done, e := zvch.sendDataChannelMessage(CHAT_MEMBER_REMOVED, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(VIDEO_CHANNEL_MEMBER_REMOVED, "node", member, map[string]interface{}{
|
||||||
"userId": channelMember,
|
"userId": channelMember,
|
||||||
"channelId": vc.ID,
|
"channelId": vc.ID,
|
||||||
})
|
})
|
||||||
@ -685,7 +699,7 @@ func (zvch *ZoneVideoChannelsHandler) SetVideoChannelPrivateForUser(channelId st
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zvch.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(REMOVED_FROM_VIDEO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
"userId": member,
|
"userId": member,
|
||||||
})
|
})
|
||||||
@ -715,7 +729,7 @@ func (zvch *ZoneVideoChannelsHandler) SetVideoChannelPublicForUser(channelId str
|
|||||||
"userId": member,
|
"userId": member,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
})
|
})
|
||||||
done, e := zvch.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(ADDED_IN_VIDEO_CHANNEL, "node", member, map[string]interface{}{
|
||||||
"videoChannel": videoChannel,
|
"videoChannel": videoChannel,
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
@ -788,7 +802,7 @@ func (zvch *ZoneVideoChannelsHandler) JoinVideoChannel(channelId string, userId
|
|||||||
videoChannel.CurrentMembersId = append(videoChannel.CurrentMembersId, userId)
|
videoChannel.CurrentMembersId = append(videoChannel.CurrentMembersId, userId)
|
||||||
videoChannel.CurrentMembers[userId] = &VideoChannelMember{}
|
videoChannel.CurrentMembers[userId] = &VideoChannelMember{}
|
||||||
signalMembers := func(members []string) {
|
signalMembers := func(members []string) {
|
||||||
for _, u := range videoChannel.Members {
|
for _, u := range members {
|
||||||
done, e := zvch.sendDataChannelMessage(USER_JOINED_VIDEO_CHANNEL, "node", u, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(USER_JOINED_VIDEO_CHANNEL, "node", u, map[string]interface{}{
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
@ -842,7 +856,7 @@ func (zvch *ZoneVideoChannelsHandler) LeaveVideoChannel(channelId string, userId
|
|||||||
}
|
}
|
||||||
delete(videoChannel.CurrentMembers, userId)
|
delete(videoChannel.CurrentMembers, userId)
|
||||||
signalMembers := func(members []string) {
|
signalMembers := func(members []string) {
|
||||||
for _, u := range videoChannel.Members {
|
for _, u := range members {
|
||||||
done, e := zvch.sendDataChannelMessage(USER_LEFT_VIDEO_CHANNEL, "node", u, map[string]interface{}{
|
done, e := zvch.sendDataChannelMessage(USER_LEFT_VIDEO_CHANNEL, "node", u, map[string]interface{}{
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
"channelId": channelId,
|
"channelId": channelId,
|
||||||
@ -1008,17 +1022,17 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
|
|||||||
case string(VIDEO_CHANNEL_WEBRTC_CANDIDATE):
|
case string(VIDEO_CHANNEL_WEBRTC_CANDIDATE):
|
||||||
logger.Println("handling video channel webrtc candidate")
|
logger.Println("handling video channel webrtc candidate")
|
||||||
logger.Println(req.Payload)
|
logger.Println(req.Payload)
|
||||||
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMlineIndex", "sdpMid", "channelId", "userId"); err != nil {
|
if err = verifyFieldsString(req.Payload, FROM, "candidate", "sdpMLineIndex", "sdpMid", "channelId", "userId"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println(req.Payload)
|
logger.Println(req.Payload)
|
||||||
i, convErr := strconv.Atoi(req.Payload["sdpMlineIndex"].(string))
|
i, convErr := strconv.Atoi(req.Payload["sdpMLineIndex"].(string))
|
||||||
if convErr != nil {
|
if convErr != nil {
|
||||||
return convErr
|
return convErr
|
||||||
}
|
}
|
||||||
sdpMlineIndex := uint16(i)
|
SDPMLineIndex := uint16(i)
|
||||||
sdpMid := req.Payload["sdpMid"].(string)
|
sdpMid := req.Payload["sdpMid"].(string)
|
||||||
logger.Println(sdpMid, sdpMlineIndex)
|
logger.Println(sdpMid, SDPMLineIndex)
|
||||||
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
|
err = atomicallyExecute(zvch.VideoChannelsFlag, func() (err error) {
|
||||||
if _, ok := zvch.VideoChannels[req.Payload["channelId"].(string)]; !ok {
|
if _, ok := zvch.VideoChannels[req.Payload["channelId"].(string)]; !ok {
|
||||||
err = fmt.Errorf("no channel corresponging the one requested")
|
err = fmt.Errorf("no channel corresponging the one requested")
|
||||||
@ -1027,7 +1041,7 @@ func (zvch *ZoneVideoChannelsHandler) handleZoneRequest(ctx context.Context, req
|
|||||||
err = zvch.VideoChannels[req.Payload["channelId"].(string)].AddCandidate(&webrtc.ICECandidateInit{
|
err = zvch.VideoChannels[req.Payload["channelId"].(string)].AddCandidate(&webrtc.ICECandidateInit{
|
||||||
Candidate: req.Payload["candidate"].(string),
|
Candidate: req.Payload["candidate"].(string),
|
||||||
SDPMid: &sdpMid,
|
SDPMid: &sdpMid,
|
||||||
SDPMLineIndex: &sdpMlineIndex,
|
SDPMLineIndex: &SDPMLineIndex,
|
||||||
}, req.Payload["userId"].(string))
|
}, req.Payload["userId"].(string))
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user