diff --git a/Makefile b/Makefile index 80ddc34..b5843dd 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,6 @@ VENDORDIR := "$(CURDIR)/vendor" VERSION := $(shell "$(CURDIR)/scripts/get-version.sh") TARVERSION := $(shell "$(CURDIR)/scripts/get-version.sh" --tar) PACKAGENAME := github.com/strukturag/nextcloud-spreed-signaling -ALL_PACKAGES := $(PACKAGENAME) $(PACKAGENAME)/client $(PACKAGENAME)/proxy $(PACKAGENAME)/server GRPC_PROTO_FILES := $(basename $(wildcard grpc_*.proto)) PROTOBUF_VERSION := $(shell grep google.golang.org/protobuf go.mod | xargs | cut -d ' ' -f 2) PROTO_FILES := $(filter-out $(GRPC_PROTO_FILES),$(basename $(wildcard *.proto))) @@ -104,18 +103,18 @@ fmt: hook | $(PROTO_GO_FILES) $(GOFMT) -s -w *.go client proxy server vet: - GOEXPERIMENT=synctest $(GO) vet $(ALL_PACKAGES) + GOEXPERIMENT=synctest $(GO) vet ./... test: vet - GOEXPERIMENT=synctest $(GO) test -timeout $(TIMEOUT) $(TESTARGS) $(ALL_PACKAGES) + GOEXPERIMENT=synctest $(GO) test -timeout $(TIMEOUT) $(TESTARGS) ./... cover: vet rm -f cover.out && \ - GOEXPERIMENT=synctest $(GO) test -timeout $(TIMEOUT) -coverprofile cover.out $(ALL_PACKAGES) + GOEXPERIMENT=synctest $(GO) test -timeout $(TIMEOUT) -coverprofile cover.out ./... coverhtml: vet rm -f cover.out && \ - GOEXPERIMENT=synctest $(GO) test -timeout $(TIMEOUT) -coverprofile cover.out $(ALL_PACKAGES) && \ + GOEXPERIMENT=synctest $(GO) test -timeout $(TIMEOUT) -coverprofile cover.out ./... && \ sed -i "/_easyjson/d" cover.out && \ sed -i "/\.pb\.go/d" cover.out && \ $(GO) tool cover -html=cover.out -o coverage.html diff --git a/stringmap.go b/api/stringmap.go similarity index 90% rename from stringmap.go rename to api/stringmap.go index ef4d3fb..d4f7a73 100644 --- a/stringmap.go +++ b/api/stringmap.go @@ -19,7 +19,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package signaling +package api // StringMap maps string keys to arbitrary values. type StringMap map[string]any @@ -29,15 +29,14 @@ func ConvertStringMap(ob any) (StringMap, bool) { return nil, true } - if m, ok := ob.(map[string]any); ok { - return StringMap(m), true + switch ob := ob.(type) { + case map[string]any: + return StringMap(ob), true + case StringMap: + return ob, true + default: + return nil, false } - - if m, ok := ob.(StringMap); ok { - return m, true - } - - return nil, false } // GetStringMapEntry returns an entry from a string map in a given type. diff --git a/stringmap_test.go b/api/stringmap_test.go similarity index 99% rename from stringmap_test.go rename to api/stringmap_test.go index d0a5ebb..1d45a20 100644 --- a/stringmap_test.go +++ b/api/stringmap_test.go @@ -19,7 +19,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package signaling +package api import ( "testing" diff --git a/api_backend.go b/api_backend.go index b8bccb8..dc853e7 100644 --- a/api_backend.go +++ b/api_backend.go @@ -35,6 +35,8 @@ import ( "slices" "strings" "time" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -145,13 +147,13 @@ type BackendRoomInCallRequest struct { // TODO(jojo): Change "InCall" to "int" when #914 has landed in NC Talk. InCall json.RawMessage `json:"incall,omitempty"` All bool `json:"all,omitempty"` - Changed []StringMap `json:"changed,omitempty"` - Users []StringMap `json:"users,omitempty"` + Changed []api.StringMap `json:"changed,omitempty"` + Users []api.StringMap `json:"users,omitempty"` } type BackendRoomParticipantsRequest struct { - Changed []StringMap `json:"changed,omitempty"` - Users []StringMap `json:"users,omitempty"` + Changed []api.StringMap `json:"changed,omitempty"` + Users []api.StringMap `json:"users,omitempty"` } type BackendRoomMessageRequest struct { @@ -318,8 +320,8 @@ func (r *BackendClientRoomRequest) UpdateFromSession(s Session) { if s.ClientType() == HelloClientTypeFederation { // Need to send additional data for requests of federated users. if u, err := s.ParsedUserData(); err == nil && len(u) > 0 { - if actorType, found := GetStringMapEntry[string](u, "actorType"); found { - if actorId, found := GetStringMapEntry[string](u, "actorId"); found { + if actorType, found := api.GetStringMapEntry[string](u, "actorType"); found { + if actorId, found := api.GetStringMapEntry[string](u, "actorId"); found { r.ActorId = actorId r.ActorType = actorType } diff --git a/api_backend_easyjson.go b/api_backend_easyjson.go index d898e1a..fe51e3b 100644 --- a/api_backend_easyjson.go +++ b/api_backend_easyjson.go @@ -7,6 +7,7 @@ import ( easyjson "github.com/mailru/easyjson" jlexer "github.com/mailru/easyjson/jlexer" jwriter "github.com/mailru/easyjson/jwriter" + api "github.com/strukturag/nextcloud-spreed-signaling/api" time "time" ) @@ -2644,21 +2645,21 @@ func easyjson4354c623DecodeGithubComStrukturagNextcloudSpreedSignaling19(in *jle in.Delim('[') if out.Changed == nil { if !in.IsDelim(']') { - out.Changed = make([]StringMap, 0, 8) + out.Changed = make([]api.StringMap, 0, 8) } else { - out.Changed = []StringMap{} + out.Changed = []api.StringMap{} } } else { out.Changed = (out.Changed)[:0] } for !in.IsDelim(']') { - var v36 StringMap + var v36 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v36 = make(StringMap) + v36 = make(api.StringMap) } else { v36 = nil } @@ -2691,21 +2692,21 @@ func easyjson4354c623DecodeGithubComStrukturagNextcloudSpreedSignaling19(in *jle in.Delim('[') if out.Users == nil { if !in.IsDelim(']') { - out.Users = make([]StringMap, 0, 8) + out.Users = make([]api.StringMap, 0, 8) } else { - out.Users = []StringMap{} + out.Users = []api.StringMap{} } } else { out.Users = (out.Users)[:0] } for !in.IsDelim(']') { - var v38 StringMap + var v38 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v38 = make(StringMap) + v38 = make(api.StringMap) } else { v38 = nil } @@ -3112,21 +3113,21 @@ func easyjson4354c623DecodeGithubComStrukturagNextcloudSpreedSignaling22(in *jle in.Delim('[') if out.Changed == nil { if !in.IsDelim(']') { - out.Changed = make([]StringMap, 0, 8) + out.Changed = make([]api.StringMap, 0, 8) } else { - out.Changed = []StringMap{} + out.Changed = []api.StringMap{} } } else { out.Changed = (out.Changed)[:0] } for !in.IsDelim(']') { - var v52 StringMap + var v52 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v52 = make(StringMap) + v52 = make(api.StringMap) } else { v52 = nil } @@ -3159,21 +3160,21 @@ func easyjson4354c623DecodeGithubComStrukturagNextcloudSpreedSignaling22(in *jle in.Delim('[') if out.Users == nil { if !in.IsDelim(']') { - out.Users = make([]StringMap, 0, 8) + out.Users = make([]api.StringMap, 0, 8) } else { - out.Users = []StringMap{} + out.Users = []api.StringMap{} } } else { out.Users = (out.Users)[:0] } for !in.IsDelim(']') { - var v54 StringMap + var v54 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v54 = make(StringMap) + v54 = make(api.StringMap) } else { v54 = nil } diff --git a/api_proxy.go b/api_proxy.go index 5f7a70a..ac51760 100644 --- a/api_proxy.go +++ b/api_proxy.go @@ -27,6 +27,8 @@ import ( "net/url" "github.com/golang-jwt/jwt/v5" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type ProxyClientMessage struct { @@ -277,9 +279,9 @@ type CommandProxyServerMessage struct { type PayloadProxyClientMessage struct { Type string `json:"type"` - ClientId string `json:"clientId"` - Sid string `json:"sid,omitempty"` - Payload StringMap `json:"payload,omitempty"` + ClientId string `json:"clientId"` + Sid string `json:"sid,omitempty"` + Payload api.StringMap `json:"payload,omitempty"` } func (m *PayloadProxyClientMessage) CheckValid() error { @@ -308,8 +310,8 @@ func (m *PayloadProxyClientMessage) CheckValid() error { type PayloadProxyServerMessage struct { Type string `json:"type"` - ClientId string `json:"clientId"` - Payload StringMap `json:"payload"` + ClientId string `json:"clientId"` + Payload api.StringMap `json:"payload"` } // Type "event" diff --git a/api_proxy_easyjson.go b/api_proxy_easyjson.go index 4211cde..2eb6996 100644 --- a/api_proxy_easyjson.go +++ b/api_proxy_easyjson.go @@ -8,6 +8,7 @@ import ( easyjson "github.com/mailru/easyjson" jlexer "github.com/mailru/easyjson/jlexer" jwriter "github.com/mailru/easyjson/jwriter" + api "github.com/strukturag/nextcloud-spreed-signaling/api" ) // suppress unused package warning @@ -662,7 +663,7 @@ func easyjson1c8542dbDecodeGithubComStrukturagNextcloudSpreedSignaling4(in *jlex in.Skip() } else { in.Delim('{') - out.Payload = make(StringMap) + out.Payload = make(api.StringMap) for !in.IsDelim('}') { key := string(in.String()) in.WantColon() @@ -794,7 +795,7 @@ func easyjson1c8542dbDecodeGithubComStrukturagNextcloudSpreedSignaling5(in *jlex } else { in.Delim('{') if !in.IsDelim('}') { - out.Payload = make(StringMap) + out.Payload = make(api.StringMap) } else { out.Payload = nil } diff --git a/api_signaling.go b/api_signaling.go index 863880d..75b81e6 100644 --- a/api_signaling.go +++ b/api_signaling.go @@ -35,6 +35,8 @@ import ( "github.com/golang-jwt/jwt/v5" "github.com/pion/ice/v4" "github.com/pion/sdp/v3" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -724,10 +726,10 @@ type MessageClientMessage struct { } type MessageClientMessageData struct { - Type string `json:"type"` - Sid string `json:"sid"` - RoomType string `json:"roomType"` - Payload StringMap `json:"payload"` + Type string `json:"type"` + Sid string `json:"sid"` + RoomType string `json:"roomType"` + Payload api.StringMap `json:"payload"` // Only supported if Type == "offer" Bitrate int `json:"bitrate,omitempty"` @@ -752,7 +754,7 @@ func (m *MessageClientMessageData) String() string { func parseSDP(s string) (*sdp.SessionDescription, error) { var sdp sdp.SessionDescription if err := sdp.UnmarshalString(s); err != nil { - return nil, NewErrorDetail("invalid_sdp", "Error parsing SDP from payload.", StringMap{ + return nil, NewErrorDetail("invalid_sdp", "Error parsing SDP from payload.", api.StringMap{ "error": err.Error(), }) } @@ -764,7 +766,7 @@ func parseSDP(s string) (*sdp.SessionDescription, error) { } if _, err := ice.UnmarshalCandidate(a.Value); err != nil { - return nil, NewErrorDetail("invalid_sdp", "Error parsing candidate from media description.", StringMap{ + return nil, NewErrorDetail("invalid_sdp", "Error parsing candidate from media description.", api.StringMap{ "media": m.MediaName.Media, "idx": idx, "error": err.Error(), @@ -786,7 +788,7 @@ func (m *MessageClientMessageData) CheckValid() error { } switch m.Type { case "offer", "answer": - sdpText, ok := GetStringMapEntry[string](m.Payload, "sdp") + sdpText, ok := api.GetStringMapEntry[string](m.Payload, "sdp") if !ok { return ErrInvalidSdp } @@ -807,11 +809,11 @@ func (m *MessageClientMessageData) CheckValid() error { if !found { return ErrNoCandidate } - candItem, ok := ConvertStringMap(candValue) + candItem, ok := api.ConvertStringMap(candValue) if !ok { return ErrInvalidCandidate } - candText, ok := GetStringMapEntry[string](candItem, "candidate") + candText, ok := api.GetStringMapEntry[string](candItem, "candidate") if !ok { return ErrInvalidCandidate } @@ -821,7 +823,7 @@ func (m *MessageClientMessageData) CheckValid() error { } else { cand, err := ice.UnmarshalCandidate(candText) if err != nil { - return NewErrorDetail("invalid_candidate", "Error parsing candidate from payload.", StringMap{ + return NewErrorDetail("invalid_candidate", "Error parsing candidate from payload.", api.StringMap{ "error": err.Error(), }) } @@ -1131,8 +1133,8 @@ type RoomEventServerMessage struct { Properties json.RawMessage `json:"properties,omitempty"` // TODO(jojo): Change "InCall" to "int" when #914 has landed in NC Talk. InCall json.RawMessage `json:"incall,omitempty"` - Changed []StringMap `json:"changed,omitempty"` - Users []StringMap `json:"users,omitempty"` + Changed []api.StringMap `json:"changed,omitempty"` + Users []api.StringMap `json:"users,omitempty"` All bool `json:"all,omitempty"` } @@ -1167,7 +1169,7 @@ type RoomFlagsServerMessage struct { Flags uint32 `json:"flags"` } -type ChatComment StringMap +type ChatComment api.StringMap type RoomEventMessageDataChat struct { Comment *ChatComment `json:"comment,omitempty"` @@ -1240,7 +1242,7 @@ type AnswerOfferMessage struct { From PublicSessionId `json:"from"` Type string `json:"type"` RoomType string `json:"roomType"` - Payload StringMap `json:"payload"` + Payload api.StringMap `json:"payload"` Sid string `json:"sid,omitempty"` } @@ -1272,8 +1274,8 @@ func (m *TransientDataClientMessage) CheckValid() error { type TransientDataServerMessage struct { Type string `json:"type"` - Key string `json:"key,omitempty"` - OldValue any `json:"oldvalue,omitempty"` - Value any `json:"value,omitempty"` - Data StringMap `json:"data,omitempty"` + Key string `json:"key,omitempty"` + OldValue any `json:"oldvalue,omitempty"` + Value any `json:"value,omitempty"` + Data api.StringMap `json:"data,omitempty"` } diff --git a/api_signaling_easyjson.go b/api_signaling_easyjson.go index 6250c50..9f0f67b 100644 --- a/api_signaling_easyjson.go +++ b/api_signaling_easyjson.go @@ -8,6 +8,7 @@ import ( easyjson "github.com/mailru/easyjson" jlexer "github.com/mailru/easyjson/jlexer" jwriter "github.com/mailru/easyjson/jwriter" + api "github.com/strukturag/nextcloud-spreed-signaling/api" time "time" ) @@ -309,7 +310,7 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling2(in *jlex } else { in.Delim('{') if !in.IsDelim('}') { - out.Data = make(StringMap) + out.Data = make(api.StringMap) } else { out.Data = nil } @@ -1124,21 +1125,21 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling8(in *jlex in.Delim('[') if out.Changed == nil { if !in.IsDelim(']') { - out.Changed = make([]StringMap, 0, 8) + out.Changed = make([]api.StringMap, 0, 8) } else { - out.Changed = []StringMap{} + out.Changed = []api.StringMap{} } } else { out.Changed = (out.Changed)[:0] } for !in.IsDelim(']') { - var v6 StringMap + var v6 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v6 = make(StringMap) + v6 = make(api.StringMap) } else { v6 = nil } @@ -1171,21 +1172,21 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling8(in *jlex in.Delim('[') if out.Users == nil { if !in.IsDelim(']') { - out.Users = make([]StringMap, 0, 8) + out.Users = make([]api.StringMap, 0, 8) } else { - out.Users = []StringMap{} + out.Users = []api.StringMap{} } } else { out.Users = (out.Users)[:0] } for !in.IsDelim(']') { - var v8 StringMap + var v8 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v8 = make(StringMap) + v8 = make(api.StringMap) } else { v8 = nil } @@ -1753,21 +1754,21 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling13(in *jle in.Delim('[') if out.Changed == nil { if !in.IsDelim(']') { - out.Changed = make([]StringMap, 0, 8) + out.Changed = make([]api.StringMap, 0, 8) } else { - out.Changed = []StringMap{} + out.Changed = []api.StringMap{} } } else { out.Changed = (out.Changed)[:0] } for !in.IsDelim(']') { - var v18 StringMap + var v18 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v18 = make(StringMap) + v18 = make(api.StringMap) } else { v18 = nil } @@ -1800,21 +1801,21 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling13(in *jle in.Delim('[') if out.Users == nil { if !in.IsDelim(']') { - out.Users = make([]StringMap, 0, 8) + out.Users = make([]api.StringMap, 0, 8) } else { - out.Users = []StringMap{} + out.Users = []api.StringMap{} } } else { out.Users = (out.Users)[:0] } for !in.IsDelim(']') { - var v20 StringMap + var v20 api.StringMap if in.IsNull() { in.Skip() } else { in.Delim('{') if !in.IsDelim('}') { - v20 = make(StringMap) + v20 = make(api.StringMap) } else { v20 = nil } @@ -2639,7 +2640,7 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling21(in *jle in.Skip() } else { in.Delim('{') - out.Payload = make(StringMap) + out.Payload = make(api.StringMap) for !in.IsDelim('}') { key := string(in.String()) in.WantColon() @@ -5806,7 +5807,7 @@ func easyjson29f189fbDecodeGithubComStrukturagNextcloudSpreedSignaling47(in *jle in.Skip() } else { in.Delim('{') - out.Payload = make(StringMap) + out.Payload = make(api.StringMap) for !in.IsDelim('}') { key := string(in.String()) in.WantColon() diff --git a/backend_server.go b/backend_server.go index 4c0927e..53672c7 100644 --- a/backend_server.go +++ b/backend_server.go @@ -46,6 +46,8 @@ import ( "github.com/dlintw/goconf" "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus/promhttp" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -421,14 +423,14 @@ func (b *BackendServer) lookupByRoomSessionId(ctx context.Context, roomSessionId return sid, nil } -func (b *BackendServer) fixupUserSessions(ctx context.Context, cache *ConcurrentMap[RoomSessionId, PublicSessionId], users []StringMap) []StringMap { +func (b *BackendServer) fixupUserSessions(ctx context.Context, cache *ConcurrentMap[RoomSessionId, PublicSessionId], users []api.StringMap) []api.StringMap { if len(users) == 0 { return users } var wg sync.WaitGroup for _, user := range users { - roomSessionId, found := GetStringMapString[RoomSessionId](user, "sessionId") + roomSessionId, found := api.GetStringMapString[RoomSessionId](user, "sessionId") if !found { log.Printf("User %+v has invalid room session id, ignoring", user) delete(user, "sessionId") @@ -442,7 +444,7 @@ func (b *BackendServer) fixupUserSessions(ctx context.Context, cache *Concurrent } wg.Add(1) - go func(roomSessionId RoomSessionId, u StringMap) { + go func(roomSessionId RoomSessionId, u api.StringMap) { defer wg.Done() if sessionId, err := b.lookupByRoomSessionId(ctx, roomSessionId, cache); err != nil { log.Printf("Could not lookup by room session %s: %s", roomSessionId, err) @@ -457,7 +459,7 @@ func (b *BackendServer) fixupUserSessions(ctx context.Context, cache *Concurrent } wg.Wait() - result := make([]StringMap, 0, len(users)) + result := make([]api.StringMap, 0, len(users)) for _, user := range users { if _, found := user["sessionId"]; found { result = append(result, user) @@ -512,7 +514,7 @@ loop: continue } - sessionId, found := GetStringMapString[PublicSessionId](user, "sessionId") + sessionId, found := api.GetStringMapString[PublicSessionId](user, "sessionId") if !found { log.Printf("User entry has no session id: %+v", user) continue diff --git a/backend_server_test.go b/backend_server_test.go index c21d84b..7e9f828 100644 --- a/backend_server_test.go +++ b/backend_server_test.go @@ -45,6 +45,8 @@ import ( "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) var ( @@ -789,7 +791,7 @@ func TestBackendServer_ParticipantsUpdatePermissions(t *testing.T) { msg := &BackendServerRoomRequest{ Type: "participants", Participants: &BackendRoomParticipantsRequest{ - Changed: []StringMap{ + Changed: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello1.Hello.SessionId), "permissions": []Permission{PERMISSION_MAY_PUBLISH_MEDIA}, @@ -799,7 +801,7 @@ func TestBackendServer_ParticipantsUpdatePermissions(t *testing.T) { "permissions": []Permission{PERMISSION_MAY_PUBLISH_SCREEN}, }, }, - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello1.Hello.SessionId), "permissions": []Permission{PERMISSION_MAY_PUBLISH_MEDIA}, @@ -865,13 +867,13 @@ func TestBackendServer_ParticipantsUpdateEmptyPermissions(t *testing.T) { msg := &BackendServerRoomRequest{ Type: "participants", Participants: &BackendRoomParticipantsRequest{ - Changed: []StringMap{ + Changed: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello.Hello.SessionId), "permissions": []Permission{}, }, }, - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello.Hello.SessionId), "permissions": []Permission{}, @@ -931,7 +933,7 @@ func TestBackendServer_ParticipantsUpdateTimeout(t *testing.T) { Type: "incall", InCall: &BackendRoomInCallRequest{ InCall: json.RawMessage("7"), - Changed: []StringMap{ + Changed: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello1.Hello.SessionId), "inCall": 7, @@ -941,7 +943,7 @@ func TestBackendServer_ParticipantsUpdateTimeout(t *testing.T) { "inCall": 3, }, }, - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello1.Hello.SessionId), "inCall": 7, @@ -978,7 +980,7 @@ func TestBackendServer_ParticipantsUpdateTimeout(t *testing.T) { Type: "incall", InCall: &BackendRoomInCallRequest{ InCall: json.RawMessage("7"), - Changed: []StringMap{ + Changed: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello1.Hello.SessionId), "inCall": 7, @@ -988,7 +990,7 @@ func TestBackendServer_ParticipantsUpdateTimeout(t *testing.T) { "inCall": 3, }, }, - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello1.Hello.SessionId), "inCall": 7, diff --git a/capabilities.go b/capabilities.go index 4cc8d57..7f16344 100644 --- a/capabilities.go +++ b/capabilities.go @@ -33,6 +33,8 @@ import ( "time" "github.com/pquerna/cachecontrol/cacheobject" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -64,7 +66,7 @@ type capabilitiesEntry struct { nextUpdate time.Time etag string mustRevalidate bool - capabilities StringMap + capabilities api.StringMap } func newCapabilitiesEntry(c *Capabilities) *capabilitiesEntry { @@ -211,7 +213,7 @@ func (e *capabilitiesEntry) update(ctx context.Context, u *url.URL, now time.Tim return false, nil } - var capa StringMap + var capa api.StringMap if err := json.Unmarshal(capaObj, &capa); err != nil { log.Printf("Unsupported capabilities received for app spreed from %s: %+v", url, capaResponse) e.capabilities = nil @@ -223,7 +225,7 @@ func (e *capabilitiesEntry) update(ctx context.Context, u *url.URL, now time.Tim return true, nil } -func (e *capabilitiesEntry) GetCapabilities() StringMap { +func (e *capabilitiesEntry) GetCapabilities() api.StringMap { e.mu.RLock() defer e.mu.RUnlock() @@ -322,7 +324,7 @@ func (c *Capabilities) getKeyForUrl(u *url.URL) string { return key } -func (c *Capabilities) loadCapabilities(ctx context.Context, u *url.URL) (StringMap, bool, error) { +func (c *Capabilities) loadCapabilities(ctx context.Context, u *url.URL) (api.StringMap, bool, error) { key := c.getKeyForUrl(u) entry, valid := c.getCapabilities(key) if valid { @@ -363,7 +365,7 @@ func (c *Capabilities) HasCapabilityFeature(ctx context.Context, u *url.URL, fea return false } -func (c *Capabilities) getConfigGroup(ctx context.Context, u *url.URL, group string) (StringMap, bool, bool) { +func (c *Capabilities) getConfigGroup(ctx context.Context, u *url.URL, group string) (api.StringMap, bool, bool) { caps, cached, err := c.loadCapabilities(ctx, u) if err != nil { log.Printf("Could not get capabilities for %s: %s", u, err) @@ -375,7 +377,7 @@ func (c *Capabilities) getConfigGroup(ctx context.Context, u *url.URL, group str return nil, cached, false } - config, ok := ConvertStringMap(configInterface) + config, ok := api.ConvertStringMap(configInterface) if !ok { log.Printf("Invalid config mapping received from %s: %+v", u, configInterface) return nil, cached, false @@ -386,7 +388,7 @@ func (c *Capabilities) getConfigGroup(ctx context.Context, u *url.URL, group str return nil, cached, false } - groupConfig, ok := ConvertStringMap(groupInterface) + groupConfig, ok := api.ConvertStringMap(groupInterface) if !ok { log.Printf("Invalid group mapping \"%s\" received from %s: %+v", group, u, groupInterface) return nil, cached, false diff --git a/capabilities_test.go b/capabilities_test.go index e74e732..72a7f00 100644 --- a/capabilities_test.go +++ b/capabilities_test.go @@ -40,6 +40,8 @@ import ( "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) func NewCapabilitiesForTestWithCallback(t *testing.T, callback func(*CapabilitiesResponse, http.ResponseWriter) error) (*url.URL, *Capabilities) { @@ -66,14 +68,14 @@ func NewCapabilitiesForTestWithCallback(t *testing.T, callback func(*Capabilitie if strings.Contains(t.Name(), "V3Api") { features = append(features, "signaling-v3") } - signaling := StringMap{ + signaling := api.StringMap{ "foo": "bar", "baz": 42, } - config := StringMap{ + config := api.StringMap{ "signaling": signaling, } - spreedCapa, _ := json.Marshal(StringMap{ + spreedCapa, _ := json.Marshal(api.StringMap{ "features": features, "config": config, }) diff --git a/clientsession.go b/clientsession.go index 67e5fec..0f5f420 100644 --- a/clientsession.go +++ b/clientsession.go @@ -34,6 +34,8 @@ import ( "time" "github.com/pion/sdp/v3" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) var ( @@ -66,7 +68,7 @@ type ClientSession struct { userId string userData json.RawMessage - parseUserData func() (StringMap, error) + parseUserData func() (api.StringMap, error) inCall Flags supportsPermissions bool @@ -288,7 +290,7 @@ func (s *ClientSession) UserData() json.RawMessage { return s.userData } -func (s *ClientSession) ParsedUserData() (StringMap, error) { +func (s *ClientSession) ParsedUserData() (api.StringMap, error) { return s.parseUserData() } @@ -523,7 +525,7 @@ func (s *ClientSession) doUnsubscribeRoomEvents(notify bool) { request := NewBackendClientRoomRequest(room.Id(), s.userId, sid) request.Room.UpdateFromSession(s) request.Room.Action = "leave" - var response StringMap + var response api.StringMap if err := s.hub.backend.PerformJSONRequest(ctx, s.ParsedBackendOcsUrl(), request, &response); err != nil { log.Printf("Could not notify about room session %s left room %s: %s", sid, room.Id(), err) } else { @@ -587,7 +589,7 @@ func (s *ClientSession) SetClient(client HandlerClient) HandlerClient { return prev } -func (s *ClientSession) sendOffer(client McuClient, sender PublicSessionId, streamType StreamType, offer StringMap) { +func (s *ClientSession) sendOffer(client McuClient, sender PublicSessionId, streamType StreamType, offer api.StringMap) { offer_message := &AnswerOfferMessage{ To: s.PublicId(), From: sender, @@ -621,7 +623,7 @@ func (s *ClientSession) sendCandidate(client McuClient, sender PublicSessionId, From: sender, Type: "candidate", RoomType: string(streamType), - Payload: StringMap{ + Payload: api.StringMap{ "candidate": candidate, }, Sid: client.Sid(), @@ -686,7 +688,7 @@ func (s *ClientSession) SendMessages(messages []*ServerMessage) bool { return true } -func (s *ClientSession) OnUpdateOffer(client McuClient, offer StringMap) { +func (s *ClientSession) OnUpdateOffer(client McuClient, offer api.StringMap) { s.mu.Lock() defer s.mu.Unlock() @@ -1081,7 +1083,7 @@ func (s *ClientSession) processAsyncMessage(message *AsyncMessage) { return } - mc.SendMessage(s.Context(), nil, message.SendOffer.Data, func(err error, response StringMap) { + mc.SendMessage(s.Context(), nil, message.SendOffer.Data, func(err error, response api.StringMap) { if err != nil { log.Printf("Could not send MCU message %+v for session %s to %s: %s", message.SendOffer.Data, message.SendOffer.SessionId, s.PublicId(), err) if err := s.events.PublishSessionMessage(message.SendOffer.SessionId, s.backend, &AsyncMessage{ @@ -1144,7 +1146,7 @@ func filterDisplayNames(events []*EventServerMessageSessionEntry) []*EventServer continue } - var userdata StringMap + var userdata api.StringMap if err := json.Unmarshal(event.User, &userdata); err != nil { result = append(result, event) continue diff --git a/clientsession_test.go b/clientsession_test.go index daf98cc..ea10196 100644 --- a/clientsession_test.go +++ b/clientsession_test.go @@ -28,6 +28,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) func TestBandwidth_Client(t *testing.T) { @@ -67,7 +69,7 @@ func TestBandwidth_Client(t *testing.T) { Sid: "54321", RoomType: "video", Bitrate: bitrate, - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -139,7 +141,7 @@ func TestBandwidth_Backend(t *testing.T) { Sid: "54321", RoomType: string(streamType), Bitrate: bitrate, - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) diff --git a/federation.go b/federation.go index a4f5a0f..1f9747d 100644 --- a/federation.go +++ b/federation.go @@ -36,7 +36,9 @@ import ( "time" "github.com/gorilla/websocket" - easyjson "github.com/mailru/easyjson" + "github.com/mailru/easyjson" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -602,14 +604,14 @@ func (c *FederationClient) joinRoom() error { }) } -func (c *FederationClient) updateEventUsers(users []StringMap, localSessionId PublicSessionId, remoteSessionId PublicSessionId) { +func (c *FederationClient) updateEventUsers(users []api.StringMap, localSessionId PublicSessionId, remoteSessionId PublicSessionId) { localCloudUrl := "@" + getCloudUrl(c.session.BackendUrl()) localCloudUrlLen := len(localCloudUrl) remoteCloudUrl := "@" + getCloudUrl(c.federation.Load().NextcloudUrl) checkSessionId := true for _, u := range users { - if actorType, found := GetStringMapEntry[string](u, "actorType"); found { - if actorId, found := GetStringMapEntry[string](u, "actorId"); found { + if actorType, found := api.GetStringMapEntry[string](u, "actorType"); found { + if actorId, found := api.GetStringMapEntry[string](u, "actorId"); found { switch actorType { case ActorTypeFederatedUsers: if strings.HasSuffix(actorId, localCloudUrl) { @@ -625,10 +627,10 @@ func (c *FederationClient) updateEventUsers(users []StringMap, localSessionId Pu if checkSessionId { key := "sessionId" - sid, found := GetStringMapString[PublicSessionId](u, key) + sid, found := api.GetStringMapString[PublicSessionId](u, key) if !found { key := "sessionid" - sid, found = GetStringMapString[PublicSessionId](u, key) + sid, found = api.GetStringMapString[PublicSessionId](u, key) } if found && sid == remoteSessionId { u[key] = localSessionId @@ -667,10 +669,10 @@ func (c *FederationClient) processMessage(msg *ServerMessage) { c.updateSessionSender(msg.Control.Sender, localSessionId, remoteSessionId) // Special handling for "forceMute" event. if len(msg.Control.Data) > 0 && msg.Control.Data[0] == '{' { - var data StringMap + var data api.StringMap if err := json.Unmarshal(msg.Control.Data, &data); err == nil { if action, found := data["action"]; found && action == "forceMute" { - if peerId, found := GetStringMapString[PublicSessionId](data, "peerId"); found && peerId == remoteSessionId { + if peerId, found := api.GetStringMapString[PublicSessionId](data, "peerId"); found && peerId == remoteSessionId { data["peerId"] = localSessionId if d, err := json.Marshal(data); err == nil { msg.Control.Data = d diff --git a/federation_test.go b/federation_test.go index 5594ab5..726b998 100644 --- a/federation_test.go +++ b/federation_test.go @@ -31,6 +31,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) func Test_FederationInvalidToken(t *testing.T) { @@ -107,7 +109,7 @@ func Test_Federation(t *testing.T) { require.NotNil(room) now := time.Now() - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Federated user", "actorType": "federated_users", "actorId": "the-federated-user-id", @@ -307,7 +309,7 @@ func Test_Federation(t *testing.T) { } // Special handling for the "forceMute" control event. - forceMute := StringMap{ + forceMute := api.StringMap{ "action": "forceMute", "peerId": remoteSessionId, } @@ -315,7 +317,7 @@ func Test_Federation(t *testing.T) { Type: "session", SessionId: remoteSessionId, }, forceMute)) { - var payload StringMap + var payload api.StringMap if checkReceiveClientControl(ctx, t, client2, "session", hello1.Hello, &payload) { // The sessionId in "peerId" will be replaced with the local one. forceMute["peerId"] = string(hello2.Hello.SessionId) @@ -347,7 +349,7 @@ func Test_Federation(t *testing.T) { } // Simulate request from the backend that a federated user joined the call. - users := []StringMap{ + users := []api.StringMap{ { "sessionId": remoteSessionId, "inCall": 1, @@ -373,7 +375,7 @@ func Test_Federation(t *testing.T) { } // Simulate request from the backend that a local user joined the call. - users = []StringMap{ + users = []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -425,7 +427,7 @@ func Test_Federation(t *testing.T) { hello4 := MustSucceed1(t, client4.RunUntilHello, ctx) - userdata = StringMap{ + userdata = api.StringMap{ "displayname": "Federated user 2", "actorType": "federated_users", "actorId": "the-other-federated-user-id", @@ -517,7 +519,7 @@ func Test_FederationJoinRoomTwice(t *testing.T) { client1.RunUntilJoined(ctx, hello1.Hello) now := time.Now() - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Federated user", "actorType": "federated_users", "actorId": "the-federated-user-id", @@ -624,7 +626,7 @@ func Test_FederationChangeRoom(t *testing.T) { client1.RunUntilJoined(ctx, hello1.Hello) now := time.Now() - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Federated user", "actorType": "federated_users", "actorId": "the-federated-user-id", @@ -747,7 +749,7 @@ func Test_FederationMedia(t *testing.T) { client1.RunUntilJoined(ctx, hello1.Hello) now := time.Now() - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Federated user", "actorType": "federated_users", "actorId": "the-federated-user-id", @@ -798,7 +800,7 @@ func Test_FederationMedia(t *testing.T) { Type: "offer", Sid: "12345", RoomType: "screen", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -840,7 +842,7 @@ func Test_FederationResume(t *testing.T) { client1.RunUntilJoined(ctx, hello1.Hello) now := time.Now() - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Federated user", "actorType": "federated_users", "actorId": "the-federated-user-id", @@ -961,7 +963,7 @@ func Test_FederationResumeNewSession(t *testing.T) { client1.RunUntilJoined(ctx, hello1.Hello) now := time.Now() - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Federated user", "actorType": "federated_users", "actorId": "the-federated-user-id", diff --git a/hub.go b/hub.go index 32c22d2..97f8de9 100644 --- a/hub.go +++ b/hub.go @@ -51,6 +51,8 @@ import ( "github.com/gorilla/mux" "github.com/gorilla/websocket" "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) var ( @@ -2169,7 +2171,7 @@ func (h *Hub) processMessageMsg(sess Session, message *ClientMessage) { return } - mc.SendMessage(session.Context(), msg, clientData, func(err error, response StringMap) { + mc.SendMessage(session.Context(), msg, clientData, func(err error, response api.StringMap) { if err != nil { log.Printf("Could not send MCU message %+v for session %s to %s: %s", clientData, session.PublicId(), recipient.PublicId(), err) sendMcuProcessingFailed(session, message) @@ -2763,7 +2765,7 @@ func (h *Hub) processMcuMessage(session *ClientSession, client_message *ClientMe return } - mc.SendMessage(session.Context(), message, data, func(err error, response StringMap) { + mc.SendMessage(session.Context(), message, data, func(err error, response api.StringMap) { if err != nil { if !errors.Is(err, ErrCandidateFiltered) { log.Printf("Could not send MCU message %+v for session %s to %s: %s", data, session.PublicId(), message.Recipient.SessionId, err) @@ -2779,7 +2781,7 @@ func (h *Hub) processMcuMessage(session *ClientSession, client_message *ClientMe }) } -func (h *Hub) sendMcuMessageResponse(session *ClientSession, mcuClient McuClient, message *MessageClientMessage, data *MessageClientMessageData, response StringMap) { +func (h *Hub) sendMcuMessageResponse(session *ClientSession, mcuClient McuClient, message *MessageClientMessage, data *MessageClientMessageData, response api.StringMap) { var response_message *ServerMessage switch response["type"] { case "answer": @@ -2894,8 +2896,8 @@ func (h *Hub) processRoomParticipants(message *BackendServerRoomRequest) { room.PublishUsersChanged(message.Participants.Changed, message.Participants.Users) } -func (h *Hub) GetStats() StringMap { - result := make(StringMap) +func (h *Hub) GetStats() api.StringMap { + result := make(api.StringMap) h.ru.RLock() result["rooms"] = len(h.rooms) h.ru.RUnlock() diff --git a/hub_test.go b/hub_test.go index 58e632d..604844d 100644 --- a/hub_test.go +++ b/hub_test.go @@ -51,6 +51,8 @@ import ( "github.com/nats-io/nats-server/v2/server" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -699,11 +701,11 @@ func registerBackendHandlerUrl(t *testing.T, router *mux.Router, url string) { if strings.Contains(t.Name(), "Federation") { features = append(features, "federation-v2") } - signaling := StringMap{ + signaling := api.StringMap{ "foo": "bar", "baz": 42, } - config := StringMap{ + config := api.StringMap{ "signaling": signaling, } if strings.Contains(t.Name(), "MultiRoom") { @@ -735,7 +737,7 @@ func registerBackendHandlerUrl(t *testing.T, router *mux.Router, url string) { signaling[ConfigKeyHelloV2TokenKey] = string(public) } } - spreedCapa, _ := json.Marshal(StringMap{ + spreedCapa, _ := json.Marshal(api.StringMap{ "features": features, "config": config, }) @@ -1716,7 +1718,7 @@ func TestClientHelloResumeProxy(t *testing.T) { room2 := hub2.getRoom(roomId) require.Nil(room2, "Should not have gotten room %s", roomId) - users := []StringMap{ + users := []api.StringMap{ { "sessionId": "the-session-id", "inCall": 1, @@ -1928,7 +1930,7 @@ func TestClientMessageToSessionId(t *testing.T) { SessionId: hello2.Hello.SessionId, } - data1 := StringMap{ + data1 := api.StringMap{ "type": "test", "message": "from-1-to-2", } @@ -1940,7 +1942,7 @@ func TestClientMessageToSessionId(t *testing.T) { if checkReceiveClientMessage(ctx, t, client1, "session", hello2.Hello, &payload1) { assert.Equal(data2, payload1) } - var payload2 StringMap + var payload2 api.StringMap if checkReceiveClientMessage(ctx, t, client2, "session", hello1.Hello, &payload2) { assert.Equal(data1, payload2) } @@ -2344,7 +2346,7 @@ func TestClientMessageToCall(t *testing.T) { WaitForUsersJoined(ctx, t, client1, hello1, client2, hello2) // Simulate request from the backend that somebody joined the call. - users := []StringMap{ + users := []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -2377,7 +2379,7 @@ func TestClientMessageToCall(t *testing.T) { client2.RunUntilErrorIs(ctx2, ErrNoMessageReceived, context.DeadlineExceeded) // Simulate request from the backend that somebody joined the call. - users = []StringMap{ + users = []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -2449,7 +2451,7 @@ func TestClientControlToCall(t *testing.T) { WaitForUsersJoined(ctx, t, client1, hello1, client2, hello2) // Simulate request from the backend that somebody joined the call. - users := []StringMap{ + users := []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -2482,7 +2484,7 @@ func TestClientControlToCall(t *testing.T) { client2.RunUntilErrorIs(ctx2, ErrNoMessageReceived, context.DeadlineExceeded) // Simulate request from the backend that somebody joined the call. - users = []StringMap{ + users = []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -3146,7 +3148,7 @@ func TestClientMessageToSessionIdWhileDisconnected(t *testing.T) { // The two chat messages should get combined into one when receiving pending messages. chat_refresh := "{\"type\":\"chat\",\"chat\":{\"refresh\":true}}" - var data1 StringMap + var data1 api.StringMap require.NoError(json.Unmarshal([]byte(chat_refresh), &data1)) client1.SendMessage(recipient2, data1) // nolint client1.SendMessage(recipient2, data1) // nolint @@ -3163,7 +3165,7 @@ func TestClientMessageToSessionIdWhileDisconnected(t *testing.T) { assert.Equal(hello2.Hello.ResumeId, hello3.Hello.ResumeId, "%+v", hello3.Hello) } - var payload StringMap + var payload api.StringMap if checkReceiveClientMessage(ctx, t, client2, "session", hello1.Hello, &payload) { assert.Equal(data1, payload) } @@ -3202,7 +3204,7 @@ func TestRoomParticipantsListUpdateWhileDisconnected(t *testing.T) { WaitForUsersJoined(ctx, t, client1, hello1, client2, hello2) // Simulate request from the backend that somebody joined the call. - users := []StringMap{ + users := []api.StringMap{ { "sessionId": "the-session-id", "inCall": 1, @@ -3227,7 +3229,7 @@ func TestRoomParticipantsListUpdateWhileDisconnected(t *testing.T) { } chat_refresh := "{\"type\":\"chat\",\"chat\":{\"refresh\":true}}" - var data1 StringMap + var data1 api.StringMap require.NoError(json.Unmarshal([]byte(chat_refresh), &data1)) client1.SendMessage(recipient2, data1) // nolint @@ -3244,7 +3246,7 @@ func TestRoomParticipantsListUpdateWhileDisconnected(t *testing.T) { // TODO(jojo): Check contents of message and try with multiple users. checkReceiveClientEvent(ctx, t, client2, "update", nil) - var payload StringMap + var payload api.StringMap if checkReceiveClientMessage(ctx, t, client2, "session", hello1.Hello, &payload) { assert.Equal(data1, payload) } @@ -3404,7 +3406,7 @@ func TestClientSendOfferPermissions(t *testing.T) { Type: "offer", Sid: "12345", RoomType: "screen", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -3470,7 +3472,7 @@ func TestClientSendOfferPermissionsAudioOnly(t *testing.T) { Type: "offer", Sid: "54321", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -3486,7 +3488,7 @@ func TestClientSendOfferPermissionsAudioOnly(t *testing.T) { Type: "offer", Sid: "54321", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioOnly, }, })) @@ -3533,7 +3535,7 @@ func TestClientSendOfferPermissionsAudioVideo(t *testing.T) { Type: "offer", Sid: "54321", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -3544,13 +3546,13 @@ func TestClientSendOfferPermissionsAudioVideo(t *testing.T) { msg := &BackendServerRoomRequest{ Type: "participants", Participants: &BackendRoomParticipantsRequest{ - Changed: []StringMap{ + Changed: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello.Hello.SessionId), "permissions": []Permission{PERMISSION_MAY_PUBLISH_AUDIO}, }, }, - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello.Hello.SessionId), "permissions": []Permission{PERMISSION_MAY_PUBLISH_AUDIO}, @@ -3632,7 +3634,7 @@ func TestClientSendOfferPermissionsAudioVideoMedia(t *testing.T) { Type: "offer", Sid: "54321", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -3643,13 +3645,13 @@ func TestClientSendOfferPermissionsAudioVideoMedia(t *testing.T) { msg := &BackendServerRoomRequest{ Type: "participants", Participants: &BackendRoomParticipantsRequest{ - Changed: []StringMap{ + Changed: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello.Hello.SessionId), "permissions": []Permission{PERMISSION_MAY_PUBLISH_MEDIA, PERMISSION_MAY_CONTROL}, }, }, - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": fmt.Sprintf("%s-%s", roomId, hello.Hello.SessionId), "permissions": []Permission{PERMISSION_MAY_PUBLISH_MEDIA, PERMISSION_MAY_CONTROL}, @@ -3741,7 +3743,7 @@ func TestClientRequestOfferNotInRoom(t *testing.T) { Type: "offer", Sid: "54321", RoomType: "screen", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -3782,7 +3784,7 @@ func TestClientRequestOfferNotInRoom(t *testing.T) { require.True(checkMessageError(t, msg, "not_allowed")) // Simulate request from the backend that somebody joined the call. - users1 := []StringMap{ + users1 := []api.StringMap{ { "sessionId": hello2.Hello.SessionId, "inCall": 1, @@ -3808,7 +3810,7 @@ func TestClientRequestOfferNotInRoom(t *testing.T) { require.True(checkMessageError(t, msg, "not_allowed")) // Simulate request from the backend that somebody joined the call. - users2 := []StringMap{ + users2 := []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -3839,7 +3841,7 @@ func TestClientRequestOfferNotInRoom(t *testing.T) { Type: "answer", Sid: "12345", RoomType: "screen", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpAnswerAudioAndVideo, }, })) @@ -4150,7 +4152,7 @@ func TestClientSendOffer(t *testing.T) { Type: "offer", Sid: "12345", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -4212,7 +4214,7 @@ func TestClientUnshareScreen(t *testing.T) { Type: "offer", Sid: "54321", RoomType: "screen", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioOnly, }, })) @@ -4644,7 +4646,7 @@ func TestDuplicateVirtualSessions(t *testing.T) { Type: "incall", InCall: &BackendRoomInCallRequest{ InCall: []byte("0"), - Users: []StringMap{ + Users: []api.StringMap{ { "sessionId": virtualSession.PublicId(), "participantPermissions": 246, @@ -4758,7 +4760,7 @@ func TestDuplicateVirtualSessions(t *testing.T) { } } -func DoTestSwitchToOne(t *testing.T, details StringMap) { +func DoTestSwitchToOne(t *testing.T, details api.StringMap) { CatchLogForTest(t) for _, subtest := range clusteredTests { t.Run(subtest, func(t *testing.T) { @@ -4846,7 +4848,7 @@ func DoTestSwitchToOne(t *testing.T, details StringMap) { } func TestSwitchToOneMap(t *testing.T) { - DoTestSwitchToOne(t, StringMap{ + DoTestSwitchToOne(t, api.StringMap{ "foo": "bar", }) } @@ -4855,7 +4857,7 @@ func TestSwitchToOneList(t *testing.T) { DoTestSwitchToOne(t, nil) } -func DoTestSwitchToMultiple(t *testing.T, details1 StringMap, details2 StringMap) { +func DoTestSwitchToMultiple(t *testing.T, details1 api.StringMap, details2 api.StringMap) { CatchLogForTest(t) for _, subtest := range clusteredTests { t.Run(subtest, func(t *testing.T) { @@ -4945,9 +4947,9 @@ func DoTestSwitchToMultiple(t *testing.T, details1 StringMap, details2 StringMap } func TestSwitchToMultipleMap(t *testing.T) { - DoTestSwitchToMultiple(t, StringMap{ + DoTestSwitchToMultiple(t, api.StringMap{ "foo": "bar", - }, StringMap{ + }, api.StringMap{ "bar": "baz", }) } @@ -4957,7 +4959,7 @@ func TestSwitchToMultipleList(t *testing.T) { } func TestSwitchToMultipleMixed(t *testing.T) { - DoTestSwitchToMultiple(t, StringMap{ + DoTestSwitchToMultiple(t, api.StringMap{ "foo": "bar", }, nil) } @@ -5079,7 +5081,7 @@ func TestDialoutStatus(t *testing.T) { key := "callstatus_" + callId if msg, ok := client.RunUntilMessage(ctx); ok { - checkMessageTransientSet(t, msg, key, StringMap{ + checkMessageTransientSet(t, msg, key, api.StringMap{ "callid": callId, "status": "accepted", }, nil) @@ -5095,10 +5097,10 @@ func TestDialoutStatus(t *testing.T) { })) if msg, ok := client.RunUntilMessage(ctx); ok { - checkMessageTransientSet(t, msg, key, StringMap{ + checkMessageTransientSet(t, msg, key, api.StringMap{ "callid": callId, "status": "ringing", - }, StringMap{ + }, api.StringMap{ "callid": callId, "status": "accepted", }) @@ -5122,11 +5124,11 @@ func TestDialoutStatus(t *testing.T) { })) if msg, ok := client.RunUntilMessage(ctx); ok { - checkMessageTransientSet(t, msg, key, StringMap{ + checkMessageTransientSet(t, msg, key, api.StringMap{ "callid": callId, "status": "cleared", "cause": clearedCause, - }, StringMap{ + }, api.StringMap{ "callid": callId, "status": "ringing", }) @@ -5136,7 +5138,7 @@ func TestDialoutStatus(t *testing.T) { defer cancel() if msg, ok := client.RunUntilMessage(ctx2); ok { - checkMessageTransientRemove(t, msg, key, StringMap{ + checkMessageTransientRemove(t, msg, key, api.StringMap{ "callid": callId, "status": "cleared", "cause": clearedCause, diff --git a/janus_client.go b/janus_client.go index fbc568a..3aa8f6f 100644 --- a/janus_client.go +++ b/janus_client.go @@ -42,6 +42,8 @@ import ( "github.com/gorilla/websocket" "github.com/notedit/janus-go" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -204,8 +206,8 @@ func newTransaction() *transaction { return t } -func newRequest(method string) (StringMap, *transaction) { - req := make(StringMap, 8) +func newRequest(method string) (api.StringMap, *transaction) { + req := make(api.StringMap, 8) req["janus"] = method return req, newTransaction() } @@ -225,7 +227,7 @@ type JanusGatewayInterface interface { Create(context.Context) (*JanusSession, error) Close() error - send(StringMap, *transaction) (uint64, error) + send(api.StringMap, *transaction) (uint64, error) removeTransaction(uint64) removeSession(*JanusSession) @@ -338,7 +340,7 @@ func (gateway *JanusGateway) removeTransaction(id uint64) { } } -func (gateway *JanusGateway) send(msg StringMap, t *transaction) (uint64, error) { +func (gateway *JanusGateway) send(msg api.StringMap, t *transaction) (uint64, error) { id := gateway.nextTransaction.Add(1) msg["transaction"] = strconv.FormatUint(id, 10) data, err := json.Marshal(msg) @@ -599,7 +601,7 @@ type JanusSession struct { gateway JanusGatewayInterface } -func (session *JanusSession) send(msg StringMap, t *transaction) (uint64, error) { +func (session *JanusSession) send(msg api.StringMap, t *transaction) (uint64, error) { msg["session_id"] = session.Id return session.gateway.send(msg, t) } @@ -711,7 +713,7 @@ type JanusHandle struct { session *JanusSession } -func (handle *JanusHandle) send(msg StringMap, t *transaction) (uint64, error) { +func (handle *JanusHandle) send(msg api.StringMap, t *transaction) (uint64, error) { msg["handle_id"] = handle.Id return handle.session.send(msg, t) } diff --git a/mcu_common.go b/mcu_common.go index f8e39cc..5f77f7e 100644 --- a/mcu_common.go +++ b/mcu_common.go @@ -29,6 +29,8 @@ import ( "time" "github.com/dlintw/goconf" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -56,7 +58,7 @@ const ( type McuListener interface { PublicId() PublicSessionId - OnUpdateOffer(client McuClient, offer StringMap) + OnUpdateOffer(client McuClient, offer api.StringMap) OnIceCandidate(client McuClient, candidate any) OnIceCompleted(client McuClient) @@ -205,7 +207,7 @@ type McuClient interface { Close(ctx context.Context) - SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) + SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) } type McuPublisher interface { diff --git a/mcu_common_test.go b/mcu_common_test.go index a54434b..7632f92 100644 --- a/mcu_common_test.go +++ b/mcu_common_test.go @@ -23,6 +23,8 @@ package signaling import ( "testing" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) func TestCommonMcuStats(t *testing.T) { @@ -37,7 +39,7 @@ func (m *MockMcuListener) PublicId() PublicSessionId { return m.publicId } -func (m *MockMcuListener) OnUpdateOffer(client McuClient, offer StringMap) { +func (m *MockMcuListener) OnUpdateOffer(client McuClient, offer api.StringMap) { } diff --git a/mcu_janus.go b/mcu_janus.go index 526ddf0..d8229a7 100644 --- a/mcu_janus.go +++ b/mcu_janus.go @@ -34,6 +34,8 @@ import ( "github.com/dlintw/goconf" "github.com/notedit/janus-go" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -567,7 +569,7 @@ func (m *mcuJanus) SubscriberDisconnected(id string, publisher PublicSessionId, } func (m *mcuJanus) createPublisherRoom(ctx context.Context, handle *JanusHandle, id PublicSessionId, streamType StreamType, settings NewPublisherSettings) (uint64, int, error) { - create_msg := StringMap{ + create_msg := api.StringMap{ "request": "create", "description": getStreamId(id, streamType), // We publish every stream in its own Janus room. @@ -641,7 +643,7 @@ func (m *mcuJanus) getOrCreatePublisherHandle(ctx context.Context, id PublicSess return nil, 0, 0, 0, err } - msg := StringMap{ + msg := api.StringMap{ "request": "join", "ptype": "publisher", "room": roomId, @@ -833,7 +835,7 @@ func (m *mcuJanus) getOrCreateRemotePublisher(ctx context.Context, controller Re return nil, err } - response, err := handle.Request(ctx, StringMap{ + response, err := handle.Request(ctx, api.StringMap{ "request": "add_remote_publisher", "room": roomId, "id": streamTypeUserIds[streamType], diff --git a/mcu_janus_client.go b/mcu_janus_client.go index 8d7ae8f..2165509 100644 --- a/mcu_janus_client.go +++ b/mcu_janus_client.go @@ -29,6 +29,8 @@ import ( "sync" "github.com/notedit/janus-go" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type mcuJanusClient struct { @@ -75,7 +77,7 @@ func (c *mcuJanusClient) MaxBitrate() int { func (c *mcuJanusClient) Close(ctx context.Context) { } -func (c *mcuJanusClient) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (c *mcuJanusClient) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { } func (c *mcuJanusClient) closeClient(ctx context.Context) bool { @@ -124,14 +126,14 @@ loop: } } -func (c *mcuJanusClient) sendOffer(ctx context.Context, offer StringMap, callback func(error, StringMap)) { +func (c *mcuJanusClient) sendOffer(ctx context.Context, offer api.StringMap, callback func(error, api.StringMap)) { handle := c.handle if handle == nil { callback(ErrNotConnected, nil) return } - configure_msg := StringMap{ + configure_msg := api.StringMap{ "request": "configure", "audio": true, "video": true, @@ -146,14 +148,14 @@ func (c *mcuJanusClient) sendOffer(ctx context.Context, offer StringMap, callbac callback(nil, answer_msg.Jsep) } -func (c *mcuJanusClient) sendAnswer(ctx context.Context, answer StringMap, callback func(error, StringMap)) { +func (c *mcuJanusClient) sendAnswer(ctx context.Context, answer api.StringMap, callback func(error, api.StringMap)) { handle := c.handle if handle == nil { callback(ErrNotConnected, nil) return } - start_msg := StringMap{ + start_msg := api.StringMap{ "request": "start", "room": c.roomId, } @@ -166,7 +168,7 @@ func (c *mcuJanusClient) sendAnswer(ctx context.Context, answer StringMap, callb callback(nil, nil) } -func (c *mcuJanusClient) sendCandidate(ctx context.Context, candidate any, callback func(error, StringMap)) { +func (c *mcuJanusClient) sendCandidate(ctx context.Context, candidate any, callback func(error, api.StringMap)) { handle := c.handle if handle == nil { callback(ErrNotConnected, nil) @@ -188,7 +190,7 @@ func (c *mcuJanusClient) handleTrickle(event *TrickleMsg) { } } -func (c *mcuJanusClient) selectStream(ctx context.Context, stream *streamSelection, callback func(error, StringMap)) { +func (c *mcuJanusClient) selectStream(ctx context.Context, stream *streamSelection, callback func(error, api.StringMap)) { handle := c.handle if handle == nil { callback(ErrNotConnected, nil) @@ -200,7 +202,7 @@ func (c *mcuJanusClient) selectStream(ctx context.Context, stream *streamSelecti return } - configure_msg := StringMap{ + configure_msg := api.StringMap{ "request": "configure", } if stream != nil { diff --git a/mcu_janus_publisher.go b/mcu_janus_publisher.go index d57ae24..c4b7e7f 100644 --- a/mcu_janus_publisher.go +++ b/mcu_janus_publisher.go @@ -32,6 +32,8 @@ import ( "github.com/notedit/janus-go" "github.com/pion/sdp/v3" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -139,7 +141,7 @@ func (p *mcuJanusPublisher) Close(ctx context.Context) { notify := false p.mu.Lock() if handle := p.handle; handle != nil && p.roomId != 0 { - destroy_msg := StringMap{ + destroy_msg := api.StringMap{ "request": "destroy", "room": p.roomId, } @@ -167,7 +169,7 @@ func (p *mcuJanusPublisher) Close(ctx context.Context) { p.mcuJanusClient.Close(ctx) } -func (p *mcuJanusPublisher) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (p *mcuJanusPublisher) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { statsMcuMessagesTotal.WithLabelValues(data.Type).Inc() jsep_msg := data.Payload switch data.Type { @@ -201,13 +203,13 @@ func (p *mcuJanusPublisher) SendMessage(ctx context.Context, message *MessageCli msgctx, cancel := context.WithTimeout(context.Background(), p.mcu.settings.Timeout()) defer cancel() - p.sendOffer(msgctx, jsep_msg, func(err error, jsep StringMap) { + p.sendOffer(msgctx, jsep_msg, func(err error, jsep api.StringMap) { if err != nil { callback(err, jsep) return } - sdpString, found := GetStringMapEntry[string](jsep, "sdp") + sdpString, found := api.GetStringMapEntry[string](jsep, "sdp") if !found { log.Printf("No/invalid sdp found in answer %+v", jsep) } else if answerSdp, err := parseSDP(sdpString); err != nil { @@ -397,7 +399,7 @@ func getPublisherRemoteId(id PublicSessionId, remoteId PublicSessionId, hostname } func (p *mcuJanusPublisher) PublishRemote(ctx context.Context, remoteId PublicSessionId, hostname string, port int, rtcpPort int) error { - msg := StringMap{ + msg := api.StringMap{ "request": "publish_remotely", "room": p.roomId, "publisher_id": streamTypeUserIds[p.streamType], @@ -434,7 +436,7 @@ func (p *mcuJanusPublisher) PublishRemote(ctx context.Context, remoteId PublicSe } func (p *mcuJanusPublisher) UnpublishRemote(ctx context.Context, remoteId PublicSessionId, hostname string, port int, rtcpPort int) error { - msg := StringMap{ + msg := api.StringMap{ "request": "unpublish_remotely", "room": p.roomId, "publisher_id": streamTypeUserIds[p.streamType], diff --git a/mcu_janus_remote_publisher.go b/mcu_janus_remote_publisher.go index e3430ab..f2bafe6 100644 --- a/mcu_janus_remote_publisher.go +++ b/mcu_janus_remote_publisher.go @@ -27,6 +27,8 @@ import ( "sync/atomic" "github.com/notedit/janus-go" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type mcuJanusRemotePublisher struct { @@ -124,7 +126,7 @@ func (p *mcuJanusRemotePublisher) Close(ctx context.Context) { p.mu.Lock() if handle := p.handle; handle != nil { - response, err := p.handle.Request(ctx, StringMap{ + response, err := p.handle.Request(ctx, api.StringMap{ "request": "remove_remote_publisher", "room": p.roomId, "id": streamTypeUserIds[p.streamType], @@ -135,7 +137,7 @@ func (p *mcuJanusRemotePublisher) Close(ctx context.Context) { log.Printf("Removed remote publisher: %+v", response) } if p.roomId != 0 { - destroy_msg := StringMap{ + destroy_msg := api.StringMap{ "request": "destroy", "room": p.roomId, } diff --git a/mcu_janus_stream_selection.go b/mcu_janus_stream_selection.go index 2787d85..0458909 100644 --- a/mcu_janus_stream_selection.go +++ b/mcu_janus_stream_selection.go @@ -24,6 +24,8 @@ package signaling import ( "database/sql" "fmt" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type streamSelection struct { @@ -37,7 +39,7 @@ func (s *streamSelection) HasValues() bool { return s.substream.Valid || s.temporal.Valid || s.audio.Valid || s.video.Valid } -func (s *streamSelection) AddToMessage(message StringMap) { +func (s *streamSelection) AddToMessage(message api.StringMap) { if s.substream.Valid { message["substream"] = s.substream.Int16 } @@ -52,7 +54,7 @@ func (s *streamSelection) AddToMessage(message StringMap) { } } -func parseStreamSelection(payload StringMap) (*streamSelection, error) { +func parseStreamSelection(payload api.StringMap) (*streamSelection, error) { var stream streamSelection if value, found := payload["substream"]; found { switch value := value.(type) { diff --git a/mcu_janus_subscriber.go b/mcu_janus_subscriber.go index 885ce45..9699cef 100644 --- a/mcu_janus_subscriber.go +++ b/mcu_janus_subscriber.go @@ -28,6 +28,8 @@ import ( "strconv" "github.com/notedit/janus-go" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type mcuJanusSubscriber struct { @@ -55,7 +57,7 @@ func (p *mcuJanusSubscriber) handleEvent(event *janus.EventMsg) { } for _, stream := range streams { - if stream, ok := ConvertStringMap(stream); ok { + if stream, ok := api.ConvertStringMap(stream); ok { if (stream["type"] == "audio" || stream["type"] == "video") && stream["active"] != false { return } @@ -149,7 +151,7 @@ func (p *mcuJanusSubscriber) Close(ctx context.Context) { p.mcuJanusClient.Close(ctx) } -func (p *mcuJanusSubscriber) joinRoom(ctx context.Context, stream *streamSelection, callback func(error, StringMap)) { +func (p *mcuJanusSubscriber) joinRoom(ctx context.Context, stream *streamSelection, callback func(error, api.StringMap)) { handle := p.handle if handle == nil { callback(ErrNotConnected, nil) @@ -161,13 +163,13 @@ func (p *mcuJanusSubscriber) joinRoom(ctx context.Context, stream *streamSelecti loggedNotPublishingYet := false retry: - join_msg := StringMap{ + join_msg := api.StringMap{ "request": "join", "ptype": "subscriber", "room": p.roomId, } if p.mcu.isMultistream() { - join_msg["streams"] = []StringMap{ + join_msg["streams"] = []api.StringMap{ { "feed": streamTypeUserIds[p.streamType], }, @@ -255,14 +257,14 @@ retry: callback(nil, join_response.Jsep) } -func (p *mcuJanusSubscriber) update(ctx context.Context, stream *streamSelection, callback func(error, StringMap)) { +func (p *mcuJanusSubscriber) update(ctx context.Context, stream *streamSelection, callback func(error, api.StringMap)) { handle := p.handle if handle == nil { callback(ErrNotConnected, nil) return } - configure_msg := StringMap{ + configure_msg := api.StringMap{ "request": "configure", "update": true, } @@ -278,7 +280,7 @@ func (p *mcuJanusSubscriber) update(ctx context.Context, stream *streamSelection callback(nil, configure_response.Jsep) } -func (p *mcuJanusSubscriber) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (p *mcuJanusSubscriber) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { statsMcuMessagesTotal.WithLabelValues(data.Type).Inc() jsep_msg := data.Payload switch data.Type { diff --git a/mcu_janus_test.go b/mcu_janus_test.go index 6d4a4f1..1bfa955 100644 --- a/mcu_janus_test.go +++ b/mcu_janus_test.go @@ -35,6 +35,8 @@ import ( "github.com/notedit/janus-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type TestJanusHandle struct { @@ -49,7 +51,7 @@ type TestJanusRoom struct { publisher atomic.Pointer[TestJanusHandle] } -type TestJanusHandler func(room *TestJanusRoom, body StringMap, jsep StringMap) (any, *janus.ErrorMsg) +type TestJanusHandler func(room *TestJanusRoom, body api.StringMap, jsep api.StringMap) (any, *janus.ErrorMsg) type TestJanusGateway struct { t *testing.T @@ -140,7 +142,7 @@ func (g *TestJanusGateway) Close() error { return nil } -func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJanusHandle, body StringMap, jsep StringMap) any { +func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJanusHandle, body api.StringMap, jsep api.StringMap) any { request := body["request"].(string) switch request { case "create": @@ -152,7 +154,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan return &janus.SuccessMsg{ PluginData: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "room": room.id, }, }, @@ -180,7 +182,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan return &janus.EventMsg{ Plugindata: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "error_code": error_code, }, }, @@ -191,7 +193,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan return &janus.EventMsg{ Plugindata: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "error_code": JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM, }, }, @@ -215,7 +217,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan Handle: handle.id, Plugindata: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "room": room.id, }, }, @@ -226,7 +228,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan return &janus.EventMsg{ Plugindata: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "error_code": JANUS_VIDEOROOM_ERROR_NO_SUCH_FEED, }, }, @@ -235,7 +237,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan sdp := publisher.sdp.Load() return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "type": "offer", "sdp": sdp.(string), }, @@ -264,7 +266,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan return &janus.SuccessMsg{ PluginData: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{}, + Data: api.StringMap{}, }, } default: @@ -330,7 +332,7 @@ func (g *TestJanusGateway) processMessage(session *JanusSession, handle *TestJan return nil } -func (g *TestJanusGateway) processRequest(msg StringMap) any { +func (g *TestJanusGateway) processRequest(msg api.StringMap) any { method, found := msg["janus"] if !found { return nil @@ -407,10 +409,10 @@ func (g *TestJanusGateway) processRequest(msg StringMap) any { var result any switch method { case "message": - body, ok := ConvertStringMap(msg["body"]) + body, ok := api.ConvertStringMap(msg["body"]) assert.True(g.t, ok, "not a string map: %+v", msg["body"]) if jsepOb, found := msg["jsep"]; found { - if jsep, ok := ConvertStringMap(jsepOb); assert.True(g.t, ok, "not a string map: %+v", jsepOb) { + if jsep, ok := api.ConvertStringMap(jsepOb); assert.True(g.t, ok, "not a string map: %+v", jsepOb) { result = g.processMessage(session, handle, body, jsep) } } else { @@ -451,7 +453,7 @@ func (g *TestJanusGateway) processRequest(msg StringMap) any { return nil } -func (g *TestJanusGateway) send(msg StringMap, t *transaction) (uint64, error) { +func (g *TestJanusGateway) send(msg api.StringMap, t *transaction) (uint64, error) { tid := g.tid.Add(1) data, err := json.Marshal(msg) @@ -523,7 +525,7 @@ func (t *TestMcuListener) PublicId() PublicSessionId { return t.id } -func (t *TestMcuListener) OnUpdateOffer(client McuClient, offer StringMap) { +func (t *TestMcuListener) OnUpdateOffer(client McuClient, offer api.StringMap) { } @@ -593,7 +595,7 @@ func Test_JanusPublisherFilterOffer(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) if assert.NotNil(jsep) { // The SDP received by Janus will be filtered from blocked candidates. @@ -606,12 +608,12 @@ func Test_JanusPublisherFilterOffer(t *testing.T) { } return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "sdp": MockSdpAnswerAudioOnly, }, }, nil }, - "trickle": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "trickle": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) return &janus.AckMsg{}, nil }, @@ -637,7 +639,7 @@ func Test_JanusPublisherFilterOffer(t *testing.T) { // Send offer containing candidates that will be blocked / filtered. data := &MessageClientMessageData{ Type: "offer", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioOnly, }, } @@ -645,7 +647,7 @@ func Test_JanusPublisherFilterOffer(t *testing.T) { var wg sync.WaitGroup wg.Add(1) - pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer wg.Done() if assert.NoError(err) { @@ -661,15 +663,15 @@ func Test_JanusPublisherFilterOffer(t *testing.T) { data = &MessageClientMessageData{ Type: "candidate", - Payload: StringMap{ - "candidate": StringMap{ + Payload: api.StringMap{ + "candidate": api.StringMap{ "candidate": "candidate:1 1 UDP 1685987071 192.168.0.1 49203 typ srflx raddr 198.51.100.7 rport 51556", }, }, } require.NoError(data.CheckValid()) wg.Add(1) - pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer wg.Done() assert.ErrorContains(err, "filtered") @@ -679,15 +681,15 @@ func Test_JanusPublisherFilterOffer(t *testing.T) { data = &MessageClientMessageData{ Type: "candidate", - Payload: StringMap{ - "candidate": StringMap{ + Payload: api.StringMap{ + "candidate": api.StringMap{ "candidate": "candidate:0 1 UDP 2122194687 198.51.100.7 51556 typ host", }, }, } require.NoError(data.CheckValid()) wg.Add(1) - pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer wg.Done() assert.NoError(err) @@ -704,7 +706,7 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "start": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "start": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) if assert.NotNil(jsep) { // The SDP received by Janus will be filtered from blocked candidates. @@ -719,7 +721,7 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { return &janus.EventMsg{ Plugindata: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "room": room.id, "started": true, "videoroom": "event", @@ -727,7 +729,7 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { }, }, nil }, - "trickle": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "trickle": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) return &janus.AckMsg{}, nil }, @@ -764,7 +766,7 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { // Send answer containing candidates that will be blocked / filtered. data := &MessageClientMessageData{ Type: "answer", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpAnswerAudioOnly, }, } @@ -772,7 +774,7 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { var wg sync.WaitGroup wg.Add(1) - sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer wg.Done() if assert.NoError(err) { @@ -783,15 +785,15 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { data = &MessageClientMessageData{ Type: "candidate", - Payload: StringMap{ - "candidate": StringMap{ + Payload: api.StringMap{ + "candidate": api.StringMap{ "candidate": "candidate:1 1 UDP 1685987071 192.168.0.1 49203 typ srflx raddr 198.51.100.7 rport 51556", }, }, } require.NoError(data.CheckValid()) wg.Add(1) - sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer wg.Done() assert.ErrorContains(err, "filtered") @@ -801,15 +803,15 @@ func Test_JanusSubscriberFilterAnswer(t *testing.T) { data = &MessageClientMessageData{ Type: "candidate", - Payload: StringMap{ - "candidate": StringMap{ + Payload: api.StringMap{ + "candidate": api.StringMap{ "candidate": "candidate:0 1 UDP 2122194687 198.51.100.7 51556 typ host", }, }, } require.NoError(data.CheckValid()) wg.Add(1) - sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer wg.Done() assert.NoError(err) @@ -826,7 +828,7 @@ func Test_JanusPublisherGetStreamsAudioOnly(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) if assert.NotNil(jsep) { if sdpValue, found := jsep["sdp"]; assert.True(found) { @@ -838,7 +840,7 @@ func Test_JanusPublisherGetStreamsAudioOnly(t *testing.T) { } return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "sdp": MockSdpAnswerAudioOnly, }, }, nil @@ -864,14 +866,14 @@ func Test_JanusPublisherGetStreamsAudioOnly(t *testing.T) { data := &MessageClientMessageData{ Type: "offer", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioOnly, }, } require.NoError(data.CheckValid()) done := make(chan struct{}) - pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer close(done) if assert.NoError(err) { @@ -910,7 +912,7 @@ func Test_JanusPublisherGetStreamsAudioVideo(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) if assert.NotNil(jsep) { _, found := jsep["sdp"] @@ -918,7 +920,7 @@ func Test_JanusPublisherGetStreamsAudioVideo(t *testing.T) { } return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "sdp": MockSdpAnswerAudioAndVideo, }, }, nil @@ -944,7 +946,7 @@ func Test_JanusPublisherGetStreamsAudioVideo(t *testing.T) { data := &MessageClientMessageData{ Type: "offer", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, } @@ -953,7 +955,7 @@ func Test_JanusPublisherGetStreamsAudioVideo(t *testing.T) { // Defer sending of offer / answer so "GetStreams" will wait. go func() { done := make(chan struct{}) - pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer close(done) if assert.NoError(err) { @@ -1089,7 +1091,7 @@ func Test_JanusSubscriberRequestOffer(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) if assert.NotNil(jsep) { if sdp, found := jsep["sdp"]; assert.True(found) { @@ -1098,7 +1100,7 @@ func Test_JanusSubscriberRequestOffer(t *testing.T) { } return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "sdp": MockSdpAnswerAudioAndVideo, }, }, nil @@ -1136,14 +1138,14 @@ func Test_JanusSubscriberRequestOffer(t *testing.T) { go func() { data := &MessageClientMessageData{ Type: "offer", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, } require.NoError(data.CheckValid()) done := make(chan struct{}) - pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + pub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer close(done) if assert.NoError(err) { @@ -1164,7 +1166,7 @@ func Test_JanusSubscriberRequestOffer(t *testing.T) { require.NoError(data.CheckValid()) done := make(chan struct{}) - sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m StringMap) { + sub.SendMessage(ctx, &MessageClientMessage{}, data, func(err error, m api.StringMap) { defer close(done) if assert.NoError(err) { @@ -1192,11 +1194,11 @@ func Test_JanusRemotePublisher(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "add_remote_publisher": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "add_remote_publisher": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) assert.Nil(jsep) if streams := body["streams"].([]any); assert.Len(streams, 1) { - if stream, ok := ConvertStringMap(streams[0]); assert.True(ok, "not a string map: %+v", streams[0]) { + if stream, ok := api.ConvertStringMap(streams[0]); assert.True(ok, "not a string map: %+v", streams[0]) { assert.Equal("0", stream["mid"]) assert.EqualValues(0, stream["mindex"]) assert.Equal("audio", stream["type"]) @@ -1207,7 +1209,7 @@ func Test_JanusRemotePublisher(t *testing.T) { return &janus.SuccessMsg{ PluginData: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{ + Data: api.StringMap{ "id": 12345, "port": 10000, "rtcp_port": 10001, @@ -1215,14 +1217,14 @@ func Test_JanusRemotePublisher(t *testing.T) { }, }, nil }, - "remove_remote_publisher": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "remove_remote_publisher": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) assert.Nil(jsep) removed.Add(1) return &janus.SuccessMsg{ PluginData: janus.PluginData{ Plugin: pluginVideoRoom, - Data: StringMap{}, + Data: api.StringMap{}, }, }, nil }, @@ -1280,10 +1282,10 @@ func Test_JanusSubscriberNoSuchRoom(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "type": "answer", "sdp": MockSdpAnswerAudioAndVideo, }, @@ -1316,7 +1318,7 @@ func Test_JanusSubscriberNoSuchRoom(t *testing.T) { WaitForUsersJoined(ctx, t, client1, hello1, client2, hello2) // Simulate request from the backend that sessions joined the call. - users1 := []StringMap{ + users1 := []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -1338,7 +1340,7 @@ func Test_JanusSubscriberNoSuchRoom(t *testing.T) { }, MessageClientMessageData{ Type: "offer", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -1380,10 +1382,10 @@ func test_JanusSubscriberAlreadyJoined(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "type": "answer", "sdp": MockSdpAnswerAudioAndVideo, }, @@ -1416,7 +1418,7 @@ func test_JanusSubscriberAlreadyJoined(t *testing.T) { WaitForUsersJoined(ctx, t, client1, hello1, client2, hello2) // Simulate request from the backend that sessions joined the call. - users1 := []StringMap{ + users1 := []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -1438,7 +1440,7 @@ func test_JanusSubscriberAlreadyJoined(t *testing.T) { }, MessageClientMessageData{ Type: "offer", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) @@ -1490,10 +1492,10 @@ func Test_JanusSubscriberTimeout(t *testing.T) { mcu, gateway := newMcuJanusForTesting(t) gateway.registerHandlers(map[string]TestJanusHandler{ - "configure": func(room *TestJanusRoom, body, jsep StringMap) (any, *janus.ErrorMsg) { + "configure": func(room *TestJanusRoom, body, jsep api.StringMap) (any, *janus.ErrorMsg) { assert.EqualValues(1, room.id) return &janus.EventMsg{ - Jsep: StringMap{ + Jsep: api.StringMap{ "type": "answer", "sdp": MockSdpAnswerAudioAndVideo, }, @@ -1526,7 +1528,7 @@ func Test_JanusSubscriberTimeout(t *testing.T) { WaitForUsersJoined(ctx, t, client1, hello1, client2, hello2) // Simulate request from the backend that sessions joined the call. - users1 := []StringMap{ + users1 := []api.StringMap{ { "sessionId": hello1.Hello.SessionId, "inCall": 1, @@ -1548,7 +1550,7 @@ func Test_JanusSubscriberTimeout(t *testing.T) { }, MessageClientMessageData{ Type: "offer", RoomType: "video", - Payload: StringMap{ + Payload: api.StringMap{ "sdp": MockSdpOfferAudioAndVideo, }, })) diff --git a/mcu_proxy.go b/mcu_proxy.go index c19d3b7..ac8997d 100644 --- a/mcu_proxy.go +++ b/mcu_proxy.go @@ -45,6 +45,8 @@ import ( "github.com/dlintw/goconf" "github.com/golang-jwt/jwt/v5" "github.com/gorilla/websocket" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -101,7 +103,7 @@ func (c *mcuProxyPubSubCommon) MaxBitrate() int { return c.maxBitrate } -func (c *mcuProxyPubSubCommon) doSendMessage(ctx context.Context, msg *ProxyClientMessage, callback func(error, StringMap)) { +func (c *mcuProxyPubSubCommon) doSendMessage(ctx context.Context, msg *ProxyClientMessage, callback func(error, api.StringMap)) { c.conn.performAsyncRequest(ctx, msg, func(err error, response *ProxyServerMessage) { if err != nil { callback(err, nil) @@ -124,7 +126,7 @@ func (c *mcuProxyPubSubCommon) doSendMessage(ctx context.Context, msg *ProxyClie func (c *mcuProxyPubSubCommon) doProcessPayload(client McuClient, msg *PayloadProxyServerMessage) { switch msg.Type { case "offer": - offer, ok := ConvertStringMap(msg.Payload["offer"]) + offer, ok := api.ConvertStringMap(msg.Payload["offer"]) if !ok { log.Printf("Unsupported payload from %s: %+v", c.conn, msg) return @@ -201,7 +203,7 @@ func (p *mcuProxyPublisher) Close(ctx context.Context) { log.Printf("Deleted publisher %s at %s", p.proxyId, p.conn) } -func (p *mcuProxyPublisher) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (p *mcuProxyPublisher) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { msg := &ProxyClientMessage{ Type: "payload", Payload: &PayloadProxyClientMessage{ @@ -301,7 +303,7 @@ func (s *mcuProxySubscriber) Close(ctx context.Context) { } } -func (s *mcuProxySubscriber) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (s *mcuProxySubscriber) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { msg := &ProxyClientMessage{ Type: "payload", Payload: &PayloadProxyClientMessage{ diff --git a/mcu_test.go b/mcu_test.go index 4352a61..62f6d2a 100644 --- a/mcu_test.go +++ b/mcu_test.go @@ -31,6 +31,8 @@ import ( "sync/atomic" "github.com/dlintw/goconf" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -194,7 +196,7 @@ func (p *TestMCUPublisher) SetMedia(mt MediaType) { p.settings.MediaTypes = mt } -func (p *TestMCUPublisher) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (p *TestMCUPublisher) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { go func() { if p.isClosed() { callback(fmt.Errorf("Already closed"), nil) @@ -208,13 +210,13 @@ func (p *TestMCUPublisher) SendMessage(ctx context.Context, message *MessageClie p.sdp = sdp switch sdp { case MockSdpOfferAudioOnly: - callback(nil, StringMap{ + callback(nil, api.StringMap{ "type": "answer", "sdp": MockSdpAnswerAudioOnly, }) return case MockSdpOfferAudioAndVideo: - callback(nil, StringMap{ + callback(nil, api.StringMap{ "type": "answer", "sdp": MockSdpAnswerAudioAndVideo, }) @@ -250,7 +252,7 @@ func (s *TestMCUSubscriber) Publisher() PublicSessionId { return s.publisher.PublisherId() } -func (s *TestMCUSubscriber) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, StringMap)) { +func (s *TestMCUSubscriber) SendMessage(ctx context.Context, message *MessageClientMessage, data *MessageClientMessageData, callback func(error, api.StringMap)) { go func() { if s.isClosed() { callback(fmt.Errorf("Already closed"), nil) @@ -267,7 +269,7 @@ func (s *TestMCUSubscriber) SendMessage(ctx context.Context, message *MessageCli return } - callback(nil, StringMap{ + callback(nil, api.StringMap{ "type": "offer", "sdp": sdp, }) diff --git a/proxy/proxy_server.go b/proxy/proxy_server.go index 627a5ca..b7179c1 100644 --- a/proxy/proxy_server.go +++ b/proxy/proxy_server.go @@ -52,6 +52,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" signaling "github.com/strukturag/nextcloud-spreed-signaling" + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -1344,7 +1345,7 @@ func (s *ProxyServer) processPayload(ctx context.Context, client *ProxyClient, s ctx2, cancel := context.WithTimeout(ctx, s.mcuTimeout) defer cancel() - mcuClient.SendMessage(ctx2, nil, mcuData, func(err error, response signaling.StringMap) { + mcuClient.SendMessage(ctx2, nil, mcuData, func(err error, response api.StringMap) { var responseMsg *signaling.ProxyServerMessage if errors.Is(err, signaling.ErrCandidateFiltered) { // Silently ignore filtered candidates. @@ -1586,8 +1587,8 @@ func (s *ProxyServer) GetClientId(client signaling.McuClient) string { return s.clientIds[client.Id()] } -func (s *ProxyServer) getStats() signaling.StringMap { - result := signaling.StringMap{ +func (s *ProxyServer) getStats() api.StringMap { + result := api.StringMap{ "sessions": s.GetSessionsCount(), "load": s.load.Load(), "mcu": s.mcu.GetStats(), diff --git a/proxy/proxy_server_test.go b/proxy/proxy_server_test.go index 641d992..d4e0be5 100644 --- a/proxy/proxy_server_test.go +++ b/proxy/proxy_server_test.go @@ -43,7 +43,9 @@ import ( "github.com/gorilla/websocket" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + signaling "github.com/strukturag/nextcloud-spreed-signaling" + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -417,7 +419,7 @@ func (p *TestMCUPublisher) MaxBitrate() int { func (p *TestMCUPublisher) Close(ctx context.Context) { } -func (p *TestMCUPublisher) SendMessage(ctx context.Context, message *signaling.MessageClientMessage, data *signaling.MessageClientMessageData, callback func(error, signaling.StringMap)) { +func (p *TestMCUPublisher) SendMessage(ctx context.Context, message *signaling.MessageClientMessage, data *signaling.MessageClientMessageData, callback func(error, api.StringMap)) { callback(errors.New("not implemented"), nil) } @@ -670,7 +672,7 @@ func (p *TestRemotePublisher) Close(ctx context.Context) { } } -func (p *TestRemotePublisher) SendMessage(ctx context.Context, message *signaling.MessageClientMessage, data *signaling.MessageClientMessageData, callback func(error, signaling.StringMap)) { +func (p *TestRemotePublisher) SendMessage(ctx context.Context, message *signaling.MessageClientMessage, data *signaling.MessageClientMessageData, callback func(error, api.StringMap)) { callback(errors.New("not implemented"), nil) } @@ -726,7 +728,7 @@ func (s *TestRemoteSubscriber) Close(ctx context.Context) { s.closeFunc() } -func (s *TestRemoteSubscriber) SendMessage(ctx context.Context, message *signaling.MessageClientMessage, data *signaling.MessageClientMessageData, callback func(error, signaling.StringMap)) { +func (s *TestRemoteSubscriber) SendMessage(ctx context.Context, message *signaling.MessageClientMessage, data *signaling.MessageClientMessageData, callback func(error, api.StringMap)) { callback(errors.New("not implemented"), nil) } diff --git a/proxy/proxy_session.go b/proxy/proxy_session.go index 7479b7e..308708d 100644 --- a/proxy/proxy_session.go +++ b/proxy/proxy_session.go @@ -30,6 +30,7 @@ import ( "time" signaling "github.com/strukturag/nextcloud-spreed-signaling" + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -158,7 +159,7 @@ func (s *ProxySession) SetClient(client *ProxyClient) *ProxyClient { return prev } -func (s *ProxySession) OnUpdateOffer(client signaling.McuClient, offer signaling.StringMap) { +func (s *ProxySession) OnUpdateOffer(client signaling.McuClient, offer api.StringMap) { id := s.proxy.GetClientId(client) if id == "" { log.Printf("Received offer %+v from unknown %s client %s (%+v)", offer, client.StreamType(), client.Id(), client) @@ -170,7 +171,7 @@ func (s *ProxySession) OnUpdateOffer(client signaling.McuClient, offer signaling Payload: &signaling.PayloadProxyServerMessage{ Type: "offer", ClientId: id, - Payload: signaling.StringMap{ + Payload: api.StringMap{ "offer": offer, }, }, @@ -190,7 +191,7 @@ func (s *ProxySession) OnIceCandidate(client signaling.McuClient, candidate any) Payload: &signaling.PayloadProxyServerMessage{ Type: "candidate", ClientId: id, - Payload: signaling.StringMap{ + Payload: api.StringMap{ "candidate": candidate, }, }, diff --git a/room.go b/room.go index 8e533ec..7149f46 100644 --- a/room.go +++ b/room.go @@ -35,6 +35,8 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -81,7 +83,7 @@ type Room struct { statsRoomSessionsCurrent *prometheus.GaugeVec // Users currently in the room - users []StringMap + users []api.StringMap // Timestamps of last backend requests for the different types. lastRoomRequests map[string]int64 @@ -459,9 +461,9 @@ func (r *Room) RemoveSession(session Session) bool { if virtualSession, ok := session.(*VirtualSession); ok { delete(r.virtualSessions, virtualSession) // Handle case where virtual session was also sent by Nextcloud. - users := make([]StringMap, 0, len(r.users)) + users := make([]api.StringMap, 0, len(r.users)) for _, u := range r.users { - if value, found := GetStringMapString[PublicSessionId](u, "sessionId"); !found || value != sid { + if value, found := api.GetStringMapString[PublicSessionId](u, "sessionId"); !found || value != sid { users = append(users, u) } } @@ -628,7 +630,7 @@ func (r *Room) getClusteredInternalSessionsRLocked() (internal map[PublicSession return } -func (r *Room) addInternalSessions(users []StringMap) []StringMap { +func (r *Room) addInternalSessions(users []api.StringMap) []api.StringMap { now := time.Now().Unix() r.mu.RLock() defer r.mu.RUnlock() @@ -645,7 +647,7 @@ func (r *Room) addInternalSessions(users []StringMap) []StringMap { skipSession := make(map[PublicSessionId]bool) for _, user := range users { - sessionid, found := GetStringMapString[PublicSessionId](user, "sessionId") + sessionid, found := api.GetStringMapString[PublicSessionId](user, "sessionId") if !found || sessionid == "" { continue } @@ -670,7 +672,7 @@ func (r *Room) addInternalSessions(users []StringMap) []StringMap { } } for session := range r.internalSessions { - u := StringMap{ + u := api.StringMap{ "inCall": session.GetInCall(), "sessionId": session.PublicId(), "lastPing": now, @@ -682,7 +684,7 @@ func (r *Room) addInternalSessions(users []StringMap) []StringMap { users = append(users, u) } for _, session := range clusteredInternalSessions { - u := StringMap{ + u := api.StringMap{ "inCall": session.GetInCall(), "sessionId": session.GetSessionId(), "lastPing": now, @@ -699,7 +701,7 @@ func (r *Room) addInternalSessions(users []StringMap) []StringMap { continue } skipSession[sid] = true - users = append(users, StringMap{ + users = append(users, api.StringMap{ "inCall": session.GetInCall(), "sessionId": sid, "lastPing": now, @@ -711,7 +713,7 @@ func (r *Room) addInternalSessions(users []StringMap) []StringMap { continue } - users = append(users, StringMap{ + users = append(users, api.StringMap{ "inCall": session.GetInCall(), "sessionId": sid, "lastPing": now, @@ -721,7 +723,7 @@ func (r *Room) addInternalSessions(users []StringMap) []StringMap { return users } -func (r *Room) filterPermissions(users []StringMap) []StringMap { +func (r *Room) filterPermissions(users []api.StringMap) []api.StringMap { for _, user := range users { delete(user, "permissions") } @@ -748,7 +750,7 @@ func IsInCall(value any) (bool, bool) { } } -func (r *Room) PublishUsersInCallChanged(changed []StringMap, users []StringMap) { +func (r *Room) PublishUsersInCallChanged(changed []api.StringMap, users []api.StringMap) { r.users = users for _, user := range changed { inCallInterface, found := user["inCall"] @@ -760,9 +762,9 @@ func (r *Room) PublishUsersInCallChanged(changed []StringMap, users []StringMap) continue } - sessionId, found := GetStringMapString[PublicSessionId](user, "sessionId") + sessionId, found := api.GetStringMapString[PublicSessionId](user, "sessionId") if !found { - sessionId, found = GetStringMapString[PublicSessionId](user, "sessionid") + sessionId, found = api.GetStringMapString[PublicSessionId](user, "sessionid") if !found { continue } @@ -898,7 +900,7 @@ func (r *Room) PublishUsersInCallChangedAll(inCall int) { } } -func (r *Room) PublishUsersChanged(changed []StringMap, users []StringMap) { +func (r *Room) PublishUsersChanged(changed []api.StringMap, users []api.StringMap) { changed = r.filterPermissions(changed) users = r.filterPermissions(users) @@ -919,7 +921,7 @@ func (r *Room) PublishUsersChanged(changed []StringMap, users []StringMap) { } } -func (r *Room) getParticipantsUpdateMessage(users []StringMap) *ServerMessage { +func (r *Room) getParticipantsUpdateMessage(users []api.StringMap) *ServerMessage { users = r.filterPermissions(users) message := &ServerMessage{ diff --git a/roomsessions_test.go b/roomsessions_test.go index 50c1f18..a83e518 100644 --- a/roomsessions_test.go +++ b/roomsessions_test.go @@ -29,6 +29,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type DummySession struct { @@ -63,7 +65,7 @@ func (s *DummySession) UserData() json.RawMessage { return nil } -func (s *DummySession) ParsedUserData() (StringMap, error) { +func (s *DummySession) ParsedUserData() (api.StringMap, error) { return nil, nil } diff --git a/session.go b/session.go index 7cf40db..718b8ac 100644 --- a/session.go +++ b/session.go @@ -26,6 +26,8 @@ import ( "encoding/json" "net/url" "sync" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type Permission string @@ -56,7 +58,7 @@ type Session interface { UserId() string UserData() json.RawMessage - ParsedUserData() (StringMap, error) + ParsedUserData() (api.StringMap, error) Backend() *Backend BackendUrl() string @@ -74,13 +76,13 @@ type Session interface { SendMessage(message *ServerMessage) bool } -func parseUserData(data json.RawMessage) func() (StringMap, error) { - return sync.OnceValues(func() (StringMap, error) { +func parseUserData(data json.RawMessage) func() (api.StringMap, error) { + return sync.OnceValues(func() (api.StringMap, error) { if len(data) == 0 { return nil, nil } - var m StringMap + var m api.StringMap if err := json.Unmarshal(data, &m); err != nil { return nil, err } diff --git a/testclient_test.go b/testclient_test.go index ca31778..ec00fde 100644 --- a/testclient_test.go +++ b/testclient_test.go @@ -41,6 +41,8 @@ import ( "github.com/gorilla/websocket" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) var ( @@ -396,7 +398,7 @@ func (c *TestClient) SendHelloV2WithFeatures(userid string, features []string) e return c.SendHelloV2WithTimesAndFeatures(userid, now, now.Add(time.Minute), features) } -func (c *TestClient) CreateHelloV2TokenWithUserdata(userid string, issuedAt time.Time, expiresAt time.Time, userdata StringMap) (string, error) { +func (c *TestClient) CreateHelloV2TokenWithUserdata(userid string, issuedAt time.Time, expiresAt time.Time, userdata api.StringMap) (string, error) { data, err := json.Marshal(userdata) if err != nil { return "", err @@ -429,7 +431,7 @@ func (c *TestClient) CreateHelloV2TokenWithUserdata(userid string, issuedAt time } func (c *TestClient) CreateHelloV2Token(userid string, issuedAt time.Time, expiresAt time.Time) (string, error) { - userdata := StringMap{ + userdata := api.StringMap{ "displayname": "Displayname " + userid, } @@ -1013,24 +1015,24 @@ func (c *TestClient) RunUntilOffer(ctx context.Context, offer string) bool { return false } - var data StringMap + var data api.StringMap if err := json.Unmarshal(message.Message.Data, &data); !c.assert.NoError(err) { return false } - if dt, ok := GetStringMapEntry[string](data, "type"); !c.assert.True(ok, "no/invalid type in %+v", data) || + if dt, ok := api.GetStringMapEntry[string](data, "type"); !c.assert.True(ok, "no/invalid type in %+v", data) || !c.assert.Equal("offer", dt, "invalid data type in %+v", data) { return false } - if payload, ok := ConvertStringMap(data["payload"]); !c.assert.True(ok, "not a string map, got %+v", data["payload"]) { + if payload, ok := api.ConvertStringMap(data["payload"]); !c.assert.True(ok, "not a string map, got %+v", data["payload"]) { return false } else { - if pt, ok := GetStringMapEntry[string](payload, "type"); !c.assert.True(ok, "no/invalid type in payload %+v", payload) || + if pt, ok := api.GetStringMapEntry[string](payload, "type"); !c.assert.True(ok, "no/invalid type in payload %+v", payload) || !c.assert.Equal("offer", pt, "invalid payload type in %+v", payload) { return false } - if sdp, ok := GetStringMapEntry[string](payload, "sdp"); !c.assert.True(ok, "no/invalid sdp in payload %+v", payload) || + if sdp, ok := api.GetStringMapEntry[string](payload, "sdp"); !c.assert.True(ok, "no/invalid sdp in payload %+v", payload) || !c.assert.Equal(offer, sdp, "invalid payload offer") { return false } @@ -1058,24 +1060,24 @@ func (c *TestClient) RunUntilAnswerFromSender(ctx context.Context, answer string } } - var data StringMap + var data api.StringMap if err := json.Unmarshal(message.Message.Data, &data); !c.assert.NoError(err) { return false } - if dt, ok := GetStringMapEntry[string](data, "type"); !c.assert.True(ok, "no/invalid type in %+v", data) || + if dt, ok := api.GetStringMapEntry[string](data, "type"); !c.assert.True(ok, "no/invalid type in %+v", data) || !c.assert.Equal("answer", dt, "invalid data type in %+v", data) { return false } - if payload, ok := ConvertStringMap(data["payload"]); !c.assert.True(ok, "not a string map, got %+v", data["payload"]) { + if payload, ok := api.ConvertStringMap(data["payload"]); !c.assert.True(ok, "not a string map, got %+v", data["payload"]) { return false } else { - if pt, ok := GetStringMapEntry[string](payload, "type"); !c.assert.True(ok, "no/invalid type in payload %+v", payload) || + if pt, ok := api.GetStringMapEntry[string](payload, "type"); !c.assert.True(ok, "no/invalid type in payload %+v", payload) || !c.assert.Equal("answer", pt, "invalid payload type in %+v", payload) { return false } - if sdp, ok := GetStringMapEntry[string](payload, "sdp"); !c.assert.True(ok, "no/invalid sdp in payload %+v", payload) || + if sdp, ok := api.GetStringMapEntry[string](payload, "sdp"); !c.assert.True(ok, "no/invalid sdp in payload %+v", payload) || !c.assert.Equal(answer, sdp, "invalid payload answer") { return false } @@ -1101,7 +1103,7 @@ func checkMessageTransientRemove(t *testing.T, message *ServerMessage, key strin assert.EqualValues(oldValue, message.TransientData.OldValue, "invalid old value in %+v", message) } -func checkMessageTransientInitial(t *testing.T, message *ServerMessage, data StringMap) bool { +func checkMessageTransientInitial(t *testing.T, message *ServerMessage, data api.StringMap) bool { assert := assert.New(t) return checkMessageType(t, message, "transient") && assert.Equal("initial", message.TransientData.Type, "invalid message type in %+v", message) && diff --git a/transient_data.go b/transient_data.go index ac3ffb9..7e6f7d8 100644 --- a/transient_data.go +++ b/transient_data.go @@ -26,6 +26,8 @@ import ( "reflect" "sync" "time" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) type TransientListener interface { @@ -34,7 +36,7 @@ type TransientListener interface { type TransientData struct { mu sync.Mutex - data StringMap + data api.StringMap listeners map[TransientListener]bool timers map[string]*time.Timer ttlCh chan<- struct{} @@ -147,7 +149,7 @@ func (t *TransientData) removeAfterTTL(key string, value any, ttl time.Duration) func (t *TransientData) doSet(key string, value any, prev any, ttl time.Duration) { if t.data == nil { - t.data = make(StringMap) + t.data = make(api.StringMap) } t.data[key] = value t.notifySet(key, prev, value) @@ -252,11 +254,11 @@ func (t *TransientData) compareAndRemove(key string, old any) bool { } // GetData returns a copy of the internal data. -func (t *TransientData) GetData() StringMap { +func (t *TransientData) GetData() api.StringMap { t.mu.Lock() defer t.mu.Unlock() - result := make(StringMap) + result := make(api.StringMap) maps.Copy(result, t.data) return result } diff --git a/transient_data_test.go b/transient_data_test.go index b60aecb..feea5fb 100644 --- a/transient_data_test.go +++ b/transient_data_test.go @@ -29,6 +29,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) func (t *TransientData) SetTTLChannel(ch chan<- struct{}) { @@ -247,7 +249,7 @@ func Test_TransientMessages(t *testing.T) { require.LessOrEqual(len(ignored), 1, "Received too many messages: %+v", ignored) } - checkMessageTransientInitial(t, msg, StringMap{ + checkMessageTransientInitial(t, msg, api.StringMap{ "abc": data, }) diff --git a/virtualsession.go b/virtualsession.go index fb2be3c..4ec31cf 100644 --- a/virtualsession.go +++ b/virtualsession.go @@ -27,6 +27,8 @@ import ( "log" "net/url" "sync/atomic" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) const ( @@ -50,7 +52,7 @@ type VirtualSession struct { flags Flags options *AddSessionOptions - parseUserData func() (StringMap, error) + parseUserData func() (api.StringMap, error) } func GetVirtualSessionId(session Session, sessionId PublicSessionId) PublicSessionId { @@ -144,7 +146,7 @@ func (s *VirtualSession) UserData() json.RawMessage { return s.userData } -func (s *VirtualSession) ParsedUserData() (StringMap, error) { +func (s *VirtualSession) ParsedUserData() (api.StringMap, error) { return s.parseUserData() } @@ -290,7 +292,7 @@ func (s *VirtualSession) ProcessAsyncSessionMessage(message *AsyncMessage) { message.Message.Event.Disinvite != nil && message.Message.Event.Disinvite.RoomId == room.Id() { log.Printf("Virtual session %s was disinvited from room %s, hanging up", s.PublicId(), room.Id()) - payload := StringMap{ + payload := api.StringMap{ "type": "hangup", "hangup": map[string]string{ "reason": "disinvited", diff --git a/virtualsession_test.go b/virtualsession_test.go index 79477eb..2f741df 100644 --- a/virtualsession_test.go +++ b/virtualsession_test.go @@ -29,6 +29,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/strukturag/nextcloud-spreed-signaling/api" ) func TestVirtualSession(t *testing.T) { @@ -407,13 +409,13 @@ func checkHasEntryWithInCall(t *testing.T, message *RoomEventServerMessage, sess assert := assert.New(t) found := false for _, entry := range message.Users { - if sid, ok := GetStringMapString[PublicSessionId](entry, "sessionId"); ok && sid == sessionId { - if value, found := GetStringMapEntry[bool](entry, entryType); !assert.True(found, "entry %s not found or invalid in %+v", entryType, entry) || + if sid, ok := api.GetStringMapString[PublicSessionId](entry, "sessionId"); ok && sid == sessionId { + if value, found := api.GetStringMapEntry[bool](entry, entryType); !assert.True(found, "entry %s not found or invalid in %+v", entryType, entry) || !assert.True(value, "entry %s invalid in %+v", entryType, entry) { return false } - if value, found := GetStringMapEntry[float64](entry, "inCall"); !assert.True(found, "inCall not found or invalid in %+v", entry) || + if value, found := api.GetStringMapEntry[float64](entry, "inCall"); !assert.True(found, "inCall not found or invalid in %+v", entry) || !assert.EqualValues(value, inCall, "invalid inCall") { return false }