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 Dec 19, 2024
1 parent b4c46ef commit e7de895
Show file tree
Hide file tree
Showing 17 changed files with 267 additions and 201 deletions.
16 changes: 14 additions & 2 deletions api_signaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,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 @@ -475,11 +481,17 @@ func (m *HelloClientMessage) CheckValid() error {
case HelloClientTypeFederation:
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
20 changes: 10 additions & 10 deletions backend_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
require.NoError(storage.WaitForInitialized(ctx))

if backends := sortBackends(cfg.GetBackends()); assert.Len(backends, 1) &&
assert.Equal(url1, backends[0].url) &&
assert.Equal([]string{url1}, backends[0].urls) &&
assert.Equal(initialSecret1, string(backends[0].secret)) {
if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
assert.Fail("Expected backend %+v, got %+v", backends[0], backend)
Expand All @@ -502,7 +502,7 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
SetEtcdValue(etcd, "/backends/1_one", []byte("{\"url\":\""+url1+"\",\"secret\":\""+secret1+"\"}"))
<-ch
if backends := sortBackends(cfg.GetBackends()); assert.Len(backends, 1) &&
assert.Equal(url1, backends[0].url) &&
assert.Equal([]string{url1}, backends[0].urls) &&
assert.Equal(secret1, string(backends[0].secret)) {
if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
assert.Fail("Expected backend %+v, got %+v", backends[0], backend)
Expand All @@ -516,9 +516,9 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
SetEtcdValue(etcd, "/backends/2_two", []byte("{\"url\":\""+url2+"\",\"secret\":\""+secret2+"\"}"))
<-ch
if backends := sortBackends(cfg.GetBackends()); assert.Len(backends, 2) &&
assert.Equal(url1, backends[0].url) &&
assert.Equal([]string{url1}, backends[0].urls) &&
assert.Equal(secret1, string(backends[0].secret)) &&
assert.Equal(url2, backends[1].url) &&
assert.Equal([]string{url2}, backends[1].urls) &&
assert.Equal(secret2, string(backends[1].secret)) {
if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
assert.Fail("Expected backend %+v, got %+v", backends[0], backend)
Expand All @@ -534,11 +534,11 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
SetEtcdValue(etcd, "/backends/3_three", []byte("{\"url\":\""+url3+"\",\"secret\":\""+secret3+"\"}"))
<-ch
if backends := sortBackends(cfg.GetBackends()); assert.Len(backends, 3) &&
assert.Equal(url1, backends[0].url) &&
assert.Equal([]string{url1}, backends[0].urls) &&
assert.Equal(secret1, string(backends[0].secret)) &&
assert.Equal(url2, backends[1].url) &&
assert.Equal([]string{url2}, backends[1].urls) &&
assert.Equal(secret2, string(backends[1].secret)) &&
assert.Equal(url3, backends[2].url) &&
assert.Equal([]string{url3}, backends[2].urls) &&
assert.Equal(secret3, string(backends[2].secret)) {
if backend := cfg.GetBackend(mustParse(url1)); backend != backends[0] {
assert.Fail("Expected backend %+v, got %+v", backends[0], backend)
Expand All @@ -553,17 +553,17 @@ func TestBackendConfiguration_Etcd(t *testing.T) {
DeleteEtcdValue(etcd, "/backends/1_one")
<-ch
if backends := sortBackends(cfg.GetBackends()); assert.Len(backends, 2) {
assert.Equal(url2, backends[0].url)
assert.Equal([]string{url2}, backends[0].urls)
assert.Equal(secret2, string(backends[0].secret))
assert.Equal(url3, backends[1].url)
assert.Equal([]string{url3}, backends[1].urls)
assert.Equal(secret3, string(backends[1].secret))
}

drainWakeupChannel(ch)
DeleteEtcdValue(etcd, "/backends/2_two")
<-ch
if backends := sortBackends(cfg.GetBackends()); assert.Len(backends, 1) {
assert.Equal(url3, backends[0].url)
assert.Equal([]string{url3}, backends[0].urls)
assert.Equal(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 @@ -70,7 +69,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, ", "))
updateBackendStats(be)
}
numBackends += len(configuredBackends)
Expand All @@ -95,7 +94,6 @@ func NewBackendStorageStatic(config *goconf.ConfigFile) (BackendStorage, error)
compatBackend = &Backend{
id: "compat",
secret: []byte(commonSecret),
compat: true,

allowHttp: allowHttp,

Expand Down Expand Up @@ -140,7 +138,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, ", "))
deleteBackendStats(backend)
}
statsBackendsCurrent.Sub(float64(len(oldBackends)))
Expand All @@ -161,15 +159,15 @@ 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, ", "))
updateBackendStats(newBackend)
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:]...)
deleteBackendStats(removed)
statsBackendsCurrent.Dec()
Expand All @@ -178,7 +176,7 @@ func (s *backendStorageStatic) UpsertHost(host string, backends []*Backend) {

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, ", "))
updateBackendStats(added)
}
statsBackendsCurrent.Add(float64(len(backends)))
Expand Down Expand Up @@ -254,10 +252,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
26 changes: 7 additions & 19 deletions clientsession.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,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 @@ -130,24 +132,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 @@ -307,6 +291,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 @@ -563,7 +551,7 @@ func (s *ClientSession) doUnsubscribeRoomEvents(notify bool) {
request.Room.UpdateFromSession(s)
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
3 changes: 3 additions & 0 deletions federation.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func getCloudUrl(s string) string {
}
if pos := strings.Index(s, "/ocs/v"); pos != -1 {
s = s[:pos]
} else {
s = strings.TrimSuffix(s, "/")
}
return s
}
Expand Down Expand Up @@ -602,6 +604,7 @@ func (c *FederationClient) updateEventUsers(users []map[string]interface{}, loca
localCloudUrlLen := len(localCloudUrl)
remoteCloudUrl := "@" + getCloudUrl(c.federation.Load().NextcloudUrl)
checkSessionId := true
log.Printf("XXX local=%s remote=%s", localCloudUrl, remoteCloudUrl)
for _, u := range users {
if actorType, found := getStringMapEntry[string](u, "actorType"); found {
if actorId, found := getStringMapEntry[string](u, "actorId"); found {
Expand Down
Loading

0 comments on commit e7de895

Please sign in to comment.