Skip to content

Commit

Permalink
Prepare internal APIs for multiple backend urls.
Browse files Browse the repository at this point in the history
  • Loading branch information
fancycode committed Jul 3, 2024
1 parent e582880 commit fba9eb3
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 108 deletions.
16 changes: 14 additions & 2 deletions api_signaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,17 @@ type ClientTypeInternalAuthParams struct {
func (p *ClientTypeInternalAuthParams) CheckValid() error {
if p.Backend == "" {
return fmt.Errorf("backend missing")
} else if u, err := url.Parse(p.Backend); err != nil {
}

if p.Backend[len(p.Backend)-1] != '/' {
p.Backend += "/"
}
if u, err := url.Parse(p.Backend); err != nil {
return err
} else {
if strings.Contains(u.Host, ":") && hasStandardPort(u) {
u.Host = u.Hostname()
p.Backend = u.String()
}

p.parsedBackend = u
Expand Down Expand Up @@ -411,11 +417,17 @@ func (m *HelloClientMessage) CheckValid() error {
case HelloClientTypeClient:
if m.Auth.Url == "" {
return fmt.Errorf("url missing")
} else if u, err := url.ParseRequestURI(m.Auth.Url); err != nil {
}

if m.Auth.Url[len(m.Auth.Url)-1] != '/' {
m.Auth.Url += "/"
}
if u, err := url.ParseRequestURI(m.Auth.Url); err != nil {
return err
} else {
if strings.Contains(u.Host, ":") && hasStandardPort(u) {
u.Host = u.Hostname()
m.Auth.Url = u.String()
}

m.Auth.parsedUrl = u
Expand Down
34 changes: 20 additions & 14 deletions backend_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ var (
)

type Backend struct {
id string
url string
parsedUrl *url.URL
secret []byte
compat bool
id string
urls []string
secret []byte

allowHttp bool

Expand All @@ -67,7 +65,7 @@ func (b *Backend) Secret() []byte {
}

func (b *Backend) IsCompat() bool {
return b.compat
return len(b.urls) == 0
}

func (b *Backend) IsUrlAllowed(u *url.URL) bool {
Expand All @@ -81,12 +79,23 @@ func (b *Backend) IsUrlAllowed(u *url.URL) bool {
}
}

func (b *Backend) Url() string {
return b.url
func (b *Backend) HasUrl(url string) bool {
if b.IsCompat() {
// Old-style configuration, only hosts are configured.
return true
}

for _, u := range b.urls {
if strings.HasPrefix(url, u) {
return true
}
}

return false
}

func (b *Backend) ParsedUrl() *url.URL {
return b.parsedUrl
func (b *Backend) Urls() []string {
return b.urls
}

func (b *Backend) Limit() int {
Expand Down Expand Up @@ -173,10 +182,7 @@ func (s *backendStorageCommon) getBackendLocked(u *url.URL) *Backend {
continue
}

if entry.url == "" {
// Old-style configuration, only hosts are configured.
return entry
} else if strings.HasPrefix(url, entry.url) {
if entry.HasUrl(url) {
return entry
}
}
Expand Down
41 changes: 21 additions & 20 deletions backend_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"context"
"net/url"
"reflect"
"slices"
"sort"
"testing"

Expand Down Expand Up @@ -530,8 +531,8 @@ func TestBackendConfiguration_Etcd(t *testing.T) {

if backends := sortBackends(cfg.GetBackends()); len(backends) != 1 {
t.Errorf("Expected one backend, got %+v", backends)
} else if backends[0].url != url1 {
t.Errorf("Expected backend url %s, got %s", url1, backends[0].url)
} else if !slices.Equal(backends[0].urls, []string{url1}) {
t.Errorf("Expected backend url %s, got %v", url1, backends[0].urls)
} else if string(backends[0].secret) != initialSecret1 {
t.Errorf("Expected backend secret %s, got %s", initialSecret1, string(backends[0].secret))
} else if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
Expand All @@ -543,8 +544,8 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
<-ch
if backends := sortBackends(cfg.GetBackends()); len(backends) != 1 {
t.Errorf("Expected one backend, got %+v", backends)
} else if backends[0].url != url1 {
t.Errorf("Expected backend url %s, got %s", url1, backends[0].url)
} else if !slices.Equal(backends[0].urls, []string{url1}) {
t.Errorf("Expected backend url %s, got %v", url1, backends[0].urls)
} else if string(backends[0].secret) != secret1 {
t.Errorf("Expected backend secret %s, got %s", secret1, string(backends[0].secret))
} else if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
Expand All @@ -559,12 +560,12 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
<-ch
if backends := sortBackends(cfg.GetBackends()); len(backends) != 2 {
t.Errorf("Expected two backends, got %+v", backends)
} else if backends[0].url != url1 {
t.Errorf("Expected backend url %s, got %s", url1, backends[0].url)
} else if !slices.Equal(backends[0].urls, []string{url1}) {
t.Errorf("Expected backend url %s, got %v", url1, backends[0].urls)
} else if string(backends[0].secret) != secret1 {
t.Errorf("Expected backend secret %s, got %s", secret1, string(backends[0].secret))
} else if backends[1].url != url2 {
t.Errorf("Expected backend url %s, got %s", url2, backends[1].url)
} else if !slices.Equal(backends[1].urls, []string{url2}) {
t.Errorf("Expected backend url %s, got %v", url2, backends[1].urls)
} else if string(backends[1].secret) != secret2 {
t.Errorf("Expected backend secret %s, got %s", secret2, string(backends[1].secret))
} else if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
Expand All @@ -581,16 +582,16 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
<-ch
if backends := sortBackends(cfg.GetBackends()); len(backends) != 3 {
t.Errorf("Expected three backends, got %+v", backends)
} else if backends[0].url != url1 {
t.Errorf("Expected backend url %s, got %s", url1, backends[0].url)
} else if !slices.Equal(backends[0].urls, []string{url1}) {
t.Errorf("Expected backend url %s, got %v", url1, backends[0].urls)
} else if string(backends[0].secret) != secret1 {
t.Errorf("Expected backend secret %s, got %s", secret1, string(backends[0].secret))
} else if backends[1].url != url2 {
t.Errorf("Expected backend url %s, got %s", url2, backends[1].url)
} else if !slices.Equal(backends[1].urls, []string{url2}) {
t.Errorf("Expected backend url %s, got %v", url2, backends[1].urls)
} else if string(backends[1].secret) != secret2 {
t.Errorf("Expected backend secret %s, got %s", secret2, string(backends[1].secret))
} else if backends[2].url != url3 {
t.Errorf("Expected backend url %s, got %s", url3, backends[2].url)
} else if !slices.Equal(backends[2].urls, []string{url3}) {
t.Errorf("Expected backend url %s, got %v", url3, backends[2].urls)
} else if string(backends[2].secret) != secret3 {
t.Errorf("Expected backend secret %s, got %s", secret3, string(backends[2].secret))
} else if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
Expand All @@ -606,12 +607,12 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
<-ch
if backends := sortBackends(cfg.GetBackends()); len(backends) != 2 {
t.Errorf("Expected two backends, got %+v", backends)
} else if backends[0].url != url2 {
t.Errorf("Expected backend url %s, got %s", url2, backends[0].url)
} else if !slices.Equal(backends[0].urls, []string{url2}) {
t.Errorf("Expected backend url %s, got %v", url2, backends[0].urls)
} else if string(backends[0].secret) != secret2 {
t.Errorf("Expected backend secret %s, got %s", secret2, string(backends[0].secret))
} else if backends[1].url != url3 {
t.Errorf("Expected backend url %s, got %s", url3, backends[1].url)
} else if !slices.Equal(backends[1].urls, []string{url3}) {
t.Errorf("Expected backend url %s, got %v", url3, backends[1].urls)
} else if string(backends[1].secret) != secret3 {
t.Errorf("Expected backend secret %s, got %s", secret3, string(backends[1].secret))
}
Expand All @@ -621,8 +622,8 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
<-ch
if backends := sortBackends(cfg.GetBackends()); len(backends) != 1 {
t.Errorf("Expected one backend, got %+v", backends)
} else if backends[0].url != url3 {
t.Errorf("Expected backend url %s, got %s", url3, backends[0].url)
} else if !slices.Equal(backends[0].urls, []string{url3}) {
t.Errorf("Expected backend url %s, got %v", url3, backends[0].urls)
} else if string(backends[0].secret) != secret3 {
t.Errorf("Expected backend secret %s, got %s", secret3, string(backends[0].secret))
}
Expand Down
22 changes: 16 additions & 6 deletions backend_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,12 +708,22 @@ func (b *BackendServer) startDialout(roomid string, backend *Backend, backendUrl
return returnDialoutError(http.StatusNotFound, NewError("no_client_available", "No available client found to trigger dialout."))
}

url := backend.Url()
if url == "" {
// Old-style compat backend, use client-provided URL.
url = backendUrl
if url != "" && url[len(url)-1] != '/' {
url += "/"
url := backendUrl
if url != "" && url[len(url)-1] != '/' {
url += "/"
}
if urls := backend.Urls(); len(urls) > 0 {
// Check if client-provided URL is registered for backend and use that.
found := false
for _, u := range urls {
if strings.HasPrefix(url, u) {
found = true
break
}
}

if !found {
url = urls[0]
}
}
id := newRandomString(32)
Expand Down
7 changes: 3 additions & 4 deletions backend_storage_etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,9 @@ func (s *backendStorageEtcd) EtcdKeyUpdated(client *EtcdClient, key string, data
}

backend := &Backend{
id: key,
url: info.Url,
parsedUrl: info.parsedUrl,
secret: []byte(info.Secret),
id: key,
urls: []string{info.Url},
secret: []byte(info.Secret),

allowHttp: info.parsedUrl.Scheme == "http",

Expand Down
19 changes: 8 additions & 11 deletions backend_storage_static.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ func NewBackendStorageStatic(config *goconf.ConfigFile) (BackendStorage, error)
compatBackend = &Backend{
id: "compat",
secret: []byte(commonSecret),
compat: true,

allowHttp: allowHttp,

Expand All @@ -69,7 +68,7 @@ func NewBackendStorageStatic(config *goconf.ConfigFile) (BackendStorage, error)
for host, configuredBackends := range getConfiguredHosts(backendIds, config, commonSecret) {
backends[host] = append(backends[host], configuredBackends...)
for _, be := range configuredBackends {
log.Printf("Backend %s added for %s", be.id, be.url)
log.Printf("Backend %s added for %s", be.id, strings.Join(be.urls, ", "))
}
numBackends += len(configuredBackends)
}
Expand All @@ -93,7 +92,6 @@ func NewBackendStorageStatic(config *goconf.ConfigFile) (BackendStorage, error)
compatBackend = &Backend{
id: "compat",
secret: []byte(commonSecret),
compat: true,

allowHttp: allowHttp,

Expand Down Expand Up @@ -137,7 +135,7 @@ func (s *backendStorageStatic) Close() {
func (s *backendStorageStatic) RemoveBackendsForHost(host string) {
if oldBackends := s.backends[host]; len(oldBackends) > 0 {
for _, backend := range oldBackends {
log.Printf("Backend %s removed for %s", backend.id, backend.url)
log.Printf("Backend %s removed for %s", backend.id, strings.Join(backend.urls, ", "))
}
statsBackendsCurrent.Sub(float64(len(oldBackends)))
}
Expand All @@ -157,22 +155,22 @@ func (s *backendStorageStatic) UpsertHost(host string, backends []*Backend) {
found = true
s.backends[host][existingIndex] = newBackend
backends = append(backends[:index], backends[index+1:]...)
log.Printf("Backend %s updated for %s", newBackend.id, newBackend.url)
log.Printf("Backend %s updated for %s", newBackend.id, strings.Join(newBackend.urls, ", "))
break
}
index++
}
if !found {
removed := s.backends[host][existingIndex]
log.Printf("Backend %s removed for %s", removed.id, removed.url)
log.Printf("Backend %s removed for %s", removed.id, strings.Join(removed.urls, ", "))
s.backends[host] = append(s.backends[host][:existingIndex], s.backends[host][existingIndex+1:]...)
statsBackendsCurrent.Dec()
}
}

s.backends[host] = append(s.backends[host], backends...)
for _, added := range backends {
log.Printf("Backend %s added for %s", added.id, added.url)
log.Printf("Backend %s added for %s", added.id, strings.Join(added.urls, ", "))
}
statsBackendsCurrent.Add(float64(len(backends)))
}
Expand Down Expand Up @@ -247,10 +245,9 @@ func getConfiguredHosts(backendIds string, config *goconf.ConfigFile, commonSecr
}

hosts[parsed.Host] = append(hosts[parsed.Host], &Backend{
id: id,
url: u,
parsedUrl: parsed,
secret: []byte(secret),
id: id,
urls: []string{u},
secret: []byte(secret),

allowHttp: parsed.Scheme == "http",

Expand Down
27 changes: 7 additions & 20 deletions clientsession.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"fmt"
"log"
"net/url"
"strings"
"sync"
"sync/atomic"
"time"
Expand All @@ -39,6 +38,8 @@ var (
// Warn if a session has 32 or more pending messages.
warnPendingMessagesCount = 32

// The "/api/v1/signaling/" URL will be changed to use "v3" as the "signaling-v3"
// feature is returned by the capabilities endpoint.
PathToOcsSignalingBackend = "ocs/v2.php/apps/spreed/api/v1/signaling/backend"
)

Expand Down Expand Up @@ -122,24 +123,6 @@ func NewClientSession(hub *Hub, privateId string, publicId string, data *Session
s.backendUrl = hello.Auth.Url
s.parsedBackendUrl = hello.Auth.parsedUrl
}
if !strings.Contains(s.backendUrl, "/ocs/v2.php/") {
backendUrl := s.backendUrl
if !strings.HasSuffix(backendUrl, "/") {
backendUrl += "/"
}
backendUrl += PathToOcsSignalingBackend
u, err := url.Parse(backendUrl)
if err != nil {
return nil, err
}

if strings.Contains(u.Host, ":") && hasStandardPort(u) {
u.Host = u.Hostname()
}

s.backendUrl = backendUrl
s.parsedBackendUrl = u
}

if err := s.SubscribeEvents(); err != nil {
return nil, err
Expand Down Expand Up @@ -299,6 +282,10 @@ func (s *ClientSession) ParsedBackendUrl() *url.URL {
return s.parsedBackendUrl
}

func (s *ClientSession) ParsedBackendOcsUrl() *url.URL {
return s.parsedBackendUrl.JoinPath(PathToOcsSignalingBackend)
}

func (s *ClientSession) AuthUserId() string {
return s.userId
}
Expand Down Expand Up @@ -505,7 +492,7 @@ func (s *ClientSession) doUnsubscribeRoomEvents(notify bool) {
request := NewBackendClientRoomRequest(room.Id(), s.userId, sid)
request.Room.Action = "leave"
var response map[string]interface{}
if err := s.hub.backend.PerformJSONRequest(ctx, s.ParsedBackendUrl(), request, &response); err != nil {
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 {
log.Printf("Removed room session %s: %+v", sid, response)
Expand Down
Loading

0 comments on commit fba9eb3

Please sign in to comment.