Move Talk capabilities to talk package.

This commit is contained in:
Joachim Bauch 2025-12-10 21:07:32 +01:00
commit b7f8f83944
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
12 changed files with 94 additions and 48 deletions

View file

@ -62,6 +62,10 @@ component_management:
name: server
paths:
- server/**
- component_id: module_talk
name: talk
paths:
- talk/**
- component_id: module_test
name: test
paths:

View file

@ -19,7 +19,7 @@ PROTO_FILES := $(filter-out $(GRPC_PROTO_FILES),$(basename $(wildcard *.proto)))
PROTO_GO_FILES := $(addsuffix .pb.go,$(PROTO_FILES))
GRPC_PROTO_GO_FILES := $(addsuffix .pb.go,$(GRPC_PROTO_FILES)) $(addsuffix _grpc.pb.go,$(GRPC_PROTO_FILES))
TEST_GO_FILES := $(wildcard *_test.go))
EASYJSON_FILES := $(filter-out $(TEST_GO_FILES),$(wildcard api*.go))
EASYJSON_FILES := $(filter-out $(TEST_GO_FILES),$(wildcard api*.go talk/ocs.go))
EASYJSON_GO_FILES := $(patsubst %.go,%_easyjson.go,$(EASYJSON_FILES))
COMMON_GO_FILES := $(filter-out continentmap.go $(PROTO_GO_FILES) $(GRPC_PROTO_GO_FILES) $(EASYJSON_GO_FILES) $(TEST_GO_FILES),$(wildcard *.go))
CLIENT_TEST_GO_FILES := $(wildcard client/*_test.go))

View file

@ -418,24 +418,6 @@ func NewBackendClientSessionRequest(roomid string, action string, sessionid Publ
return request
}
type OcsMeta struct {
Status string `json:"status"`
StatusCode int `json:"statuscode"`
Message string `json:"message"`
}
type OcsBody struct {
Meta OcsMeta `json:"meta"`
Data json.RawMessage `json:"data"`
}
type OcsResponse struct {
json.Marshaler
json.Unmarshaler
Ocs *OcsBody `json:"ocs"`
}
// See https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
type TurnCredentials struct {
Username string `json:"username"`

View file

@ -35,6 +35,7 @@ import (
"github.com/strukturag/nextcloud-spreed-signaling/log"
"github.com/strukturag/nextcloud-spreed-signaling/pool"
"github.com/strukturag/nextcloud-spreed-signaling/talk"
)
var (
@ -54,7 +55,7 @@ type BackendClient struct {
backends *BackendConfiguration
pool *pool.HttpClientPool
capabilities *Capabilities
capabilities *talk.Capabilities
buffers pool.BufferPool
}
@ -75,7 +76,7 @@ func NewBackendClient(ctx context.Context, config *goconf.ConfigFile, maxConcurr
return nil, err
}
capabilities, err := NewCapabilities(version, pool)
capabilities, err := talk.NewCapabilities(version, pool)
if err != nil {
return nil, err
}
@ -113,10 +114,6 @@ func (b *BackendClient) IsUrlAllowed(u *url.URL) bool {
return b.backends.IsUrlAllowed(u)
}
func isOcsRequest(u *url.URL) bool {
return strings.Contains(u.Path, "/ocs/v2.php") || strings.Contains(u.Path, "/ocs/v1.php")
}
// PerformJSONRequest sends a JSON POST request to the given url and decodes
// the result into "response".
func (b *BackendClient) PerformJSONRequest(ctx context.Context, u *url.URL, request any, response any) error {
@ -131,7 +128,7 @@ func (b *BackendClient) PerformJSONRequest(ctx context.Context, u *url.URL, requ
}
var requestUrl *url.URL
if b.capabilities.HasCapabilityFeature(ctx, u, FeatureSignalingV3Api) {
if b.capabilities.HasCapabilityFeature(ctx, u, talk.FeatureSignalingV3Api) {
newUrl := *u
newUrl.Path = strings.ReplaceAll(newUrl.Path, "/spreed/api/v1/signaling/", "/spreed/api/v3/signaling/")
newUrl.Path = strings.ReplaceAll(newUrl.Path, "/spreed/api/v2/signaling/", "/spreed/api/v3/signaling/")
@ -205,7 +202,7 @@ func (b *BackendClient) PerformJSONRequest(ctx context.Context, u *url.URL, requ
defer b.buffers.Put(body)
if isOcsRequest(u) || req.Header.Get("OCS-APIRequest") != "" {
if talk.IsOcsRequest(u) || req.Header.Get("OCS-APIRequest") != "" {
// OCS response are wrapped in an OCS container that needs to be parsed
// to get the actual contents:
// {
@ -214,7 +211,7 @@ func (b *BackendClient) PerformJSONRequest(ctx context.Context, u *url.URL, requ
// "data": { ... }
// }
// }
var ocs OcsResponse
var ocs talk.OcsResponse
if err := json.Unmarshal(body.Bytes(), &ocs); err != nil {
logger.Printf("Could not decode OCS response %s from %s: %s", body.String(), req.URL, err)
statsBackendClientError.WithLabelValues(backend.Id(), "error_decoding_ocs").Inc()

View file

@ -37,12 +37,13 @@ import (
"github.com/strukturag/nextcloud-spreed-signaling/log"
"github.com/strukturag/nextcloud-spreed-signaling/pool"
"github.com/strukturag/nextcloud-spreed-signaling/talk"
)
func returnOCS(t *testing.T, w http.ResponseWriter, body []byte) {
response := OcsResponse{
Ocs: &OcsBody{
Meta: OcsMeta{
response := talk.OcsResponse{
Ocs: &talk.OcsBody{
Meta: talk.OcsMeta{
Status: "OK",
StatusCode: http.StatusOK,
Message: "OK",
@ -51,7 +52,7 @@ func returnOCS(t *testing.T, w http.ResponseWriter, body []byte) {
},
}
if strings.Contains(t.Name(), "Throttled") {
response.Ocs.Meta = OcsMeta{
response.Ocs.Meta = talk.OcsMeta{
Status: "failure",
StatusCode: 429,
Message: "Reached maximum delay",

View file

@ -49,6 +49,7 @@ import (
signaling "github.com/strukturag/nextcloud-spreed-signaling"
"github.com/strukturag/nextcloud-spreed-signaling/internal"
"github.com/strukturag/nextcloud-spreed-signaling/talk"
)
var (
@ -458,9 +459,9 @@ func registerAuthHandler(router *mux.Router) {
}
rawdata := json.RawMessage(data)
payload := &signaling.OcsResponse{
Ocs: &signaling.OcsBody{
Meta: signaling.OcsMeta{
payload := &talk.OcsResponse{
Ocs: &talk.OcsBody{
Meta: talk.OcsMeta{
Status: "ok",
StatusCode: http.StatusOK,
Message: http.StatusText(http.StatusOK),

3
hub.go
View file

@ -56,6 +56,7 @@ import (
"github.com/strukturag/nextcloud-spreed-signaling/container"
"github.com/strukturag/nextcloud-spreed-signaling/internal"
"github.com/strukturag/nextcloud-spreed-signaling/log"
"github.com/strukturag/nextcloud-spreed-signaling/talk"
)
var (
@ -1403,7 +1404,7 @@ func (h *Hub) processHelloV2(ctx context.Context, client HandlerClient, message
tokenString = message.Hello.Auth.helloV2Params.Token
tokenClaims = &HelloV2TokenClaims{}
case HelloClientTypeFederation:
if !h.backend.capabilities.HasCapabilityFeature(ctx, url, FeatureFederationV2) {
if !h.backend.capabilities.HasCapabilityFeature(ctx, url, talk.FeatureFederationV2) {
return nil, nil, ErrFederationNotSupported
}

View file

@ -58,6 +58,7 @@ import (
"github.com/strukturag/nextcloud-spreed-signaling/internal"
"github.com/strukturag/nextcloud-spreed-signaling/log"
"github.com/strukturag/nextcloud-spreed-signaling/nats"
"github.com/strukturag/nextcloud-spreed-signaling/talk"
"github.com/strukturag/nextcloud-spreed-signaling/test"
)
@ -374,9 +375,9 @@ func validateBackendChecksum(t *testing.T, f func(http.ResponseWriter, *http.Req
assert.NoError(err)
if r.Header.Get("OCS-APIRequest") != "" {
var ocs OcsResponse
ocs.Ocs = &OcsBody{
Meta: OcsMeta{
var ocs talk.OcsResponse
ocs.Ocs = &talk.OcsBody{
Meta: talk.OcsMeta{
Status: "ok",
StatusCode: http.StatusOK,
Message: http.StatusText(http.StatusOK),
@ -778,8 +779,8 @@ func registerBackendHandlerUrl(t *testing.T, router *mux.Router, url string) {
"config": config,
})
assert.NoError(t, err)
response := &CapabilitiesResponse{
Version: CapabilitiesVersion{
response := &talk.CapabilitiesResponse{
Version: talk.CapabilitiesVersion{
Major: 20,
},
Capabilities: map[string]json.RawMessage{
@ -790,9 +791,9 @@ func registerBackendHandlerUrl(t *testing.T, router *mux.Router, url string) {
data, err := json.Marshal(response)
assert.NoError(t, err, "Could not marshal %+v", response)
var ocs OcsResponse
ocs.Ocs = &OcsBody{
Meta: OcsMeta{
var ocs talk.OcsResponse
ocs.Ocs = &talk.OcsBody{
Meta: talk.OcsMeta{
Status: "ok",
StatusCode: http.StatusOK,
Message: http.StatusText(http.StatusOK),

View file

@ -30,6 +30,7 @@ import (
"github.com/strukturag/nextcloud-spreed-signaling/internal"
"github.com/strukturag/nextcloud-spreed-signaling/log"
"github.com/strukturag/nextcloud-spreed-signaling/talk"
)
type pingEntries struct {
@ -70,13 +71,13 @@ type RoomPing struct {
closer *internal.Closer
backend *BackendClient
capabilities *Capabilities
capabilities *talk.Capabilities
// +checklocks:mu
entries map[string]*pingEntries
}
func NewRoomPing(backend *BackendClient, capabilities *Capabilities) (*RoomPing, error) {
func NewRoomPing(backend *BackendClient, capabilities *talk.Capabilities) (*RoomPing, error) {
result := &RoomPing{
closer: internal.NewCloser(),
backend: backend,

View file

@ -19,7 +19,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package signaling
package talk
import (
"context"
@ -59,6 +59,10 @@ const (
var (
ErrUnexpectedHttpStatus = errors.New("unexpected_http_status") // +checklocksignore: Global readonly variable.
ErrUnsupportedContentType = errors.New("unsupported_content_type") // +checklocksignore: Global readonly variable.
ErrIncompleteResponse = errors.New("incomplete OCS response") // +checklocksignore: Global readonly variable.
)
type capabilitiesEntry struct {

View file

@ -19,7 +19,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package signaling
package talk
import (
"context"
@ -46,6 +46,10 @@ import (
"github.com/strukturag/nextcloud-spreed-signaling/pool"
)
const (
testTimeout = 10 * time.Second
)
func NewCapabilitiesForTestWithCallback(t *testing.T, callback func(*CapabilitiesResponse, http.ResponseWriter) error) (*url.URL, *Capabilities) {
require := require.New(t)
assert := assert.New(t)

50
talk/ocs.go Normal file
View file

@ -0,0 +1,50 @@
/**
* Standalone signaling server for the Nextcloud Spreed app.
* Copyright (C) 2025 struktur AG
*
* @author Joachim Bauch <bauch@struktur.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package talk
import (
"encoding/json"
"net/url"
"strings"
)
type OcsMeta struct {
Status string `json:"status"`
StatusCode int `json:"statuscode"`
Message string `json:"message"`
}
type OcsBody struct {
Meta OcsMeta `json:"meta"`
Data json.RawMessage `json:"data"`
}
type OcsResponse struct {
json.Marshaler
json.Unmarshaler
Ocs *OcsBody `json:"ocs"`
}
func IsOcsRequest(u *url.URL) bool {
return strings.Contains(u.Path, "/ocs/v2.php") || strings.Contains(u.Path, "/ocs/v1.php")
}