Skip to content

Commit

Permalink
Add support for multiple URLs per backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
fancycode committed Dec 19, 2024
1 parent e7de895 commit 39580fc
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 91 deletions.
48 changes: 34 additions & 14 deletions api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"net/http"
"net/url"
"regexp"
"slices"
"strings"
"time"
)
Expand Down Expand Up @@ -432,10 +433,12 @@ type TurnCredentials struct {
// Information on a backend in the etcd cluster.

type BackendInformationEtcd struct {
parsedUrl *url.URL
// Compat setting.
Url string `json:"url,omitempty"`

Url string `json:"url"`
Secret string `json:"secret"`
Urls []string `json:"urls,omitempty"`
parsedUrls []*url.URL
Secret string `json:"secret"`

MaxStreamBitrate int `json:"maxstreambitrate,omitempty"`
MaxScreenBitrate int `json:"maxscreenbitrate,omitempty"`
Expand All @@ -444,23 +447,40 @@ type BackendInformationEtcd struct {
}

func (p *BackendInformationEtcd) CheckValid() error {
if p.Url == "" {
return fmt.Errorf("url missing")
}
if p.Secret == "" {
return fmt.Errorf("secret missing")
}

parsedUrl, err := url.Parse(p.Url)
if err != nil {
return fmt.Errorf("invalid url: %w", err)
}
if len(p.Urls) > 0 {
slices.Sort(p.Urls)
p.Urls = slices.Compact(p.Urls)
for idx, u := range p.Urls {
parsedUrl, err := url.Parse(u)
if err != nil {
return fmt.Errorf("invalid url %s: %w", u, err)
}
if strings.Contains(parsedUrl.Host, ":") && hasStandardPort(parsedUrl) {
parsedUrl.Host = parsedUrl.Hostname()
p.Urls[idx] = parsedUrl.String()
}

p.parsedUrls = append(p.parsedUrls, parsedUrl)
}
} else if p.Url != "" {
parsedUrl, err := url.Parse(p.Url)
if err != nil {
return fmt.Errorf("invalid url: %w", err)
}
if strings.Contains(parsedUrl.Host, ":") && hasStandardPort(parsedUrl) {
parsedUrl.Host = parsedUrl.Hostname()
p.Url = parsedUrl.String()
}

if strings.Contains(parsedUrl.Host, ":") && hasStandardPort(parsedUrl) {
parsedUrl.Host = parsedUrl.Hostname()
p.Url = parsedUrl.String()
p.Urls = append(p.Urls, p.Url)
p.parsedUrls = append(p.parsedUrls, parsedUrl)
} else {
return fmt.Errorf("urls missing")
}

p.parsedUrl = parsedUrl
return nil
}
4 changes: 4 additions & 0 deletions api_signaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,10 @@ func (m *HelloClientMessage) CheckValid() error {
if m.Auth.Url[len(m.Auth.Url)-1] != '/' {
m.Auth.Url += "/"
}
if pos := strings.Index(m.Auth.Url, "ocs/v2.php/apps/spreed/"); pos != -1 {
m.Auth.Url = m.Auth.Url[:pos]
}

if u, err := url.ParseRequestURI(m.Auth.Url); err != nil {
return err
} else {
Expand Down
18 changes: 18 additions & 0 deletions backend_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
package signaling

import (
"bytes"
"fmt"
"net/url"
"slices"
"strings"
"sync"

Expand Down Expand Up @@ -68,6 +70,22 @@ func (b *Backend) IsCompat() bool {
return len(b.urls) == 0
}

func (b *Backend) Equal(other *Backend) bool {
if b == other {
return true
} else if b == nil || other == nil {
return false
}

return b.id == other.id &&
b.allowHttp == other.allowHttp &&
b.maxStreamBitrate == other.maxStreamBitrate &&
b.maxScreenBitrate == other.maxScreenBitrate &&
b.sessionLimit == other.sessionLimit &&
bytes.Equal(b.secret, other.secret) &&
slices.Equal(b.urls, other.urls)
}

func (b *Backend) IsUrlAllowed(u *url.URL) bool {
switch u.Scheme {
case "https":
Expand Down
2 changes: 1 addition & 1 deletion backend_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ func mustParse(s string) *url.URL {
return p
}

func TestBackendConfiguration_Etcd(t *testing.T) {
func TestBackendConfiguration_EtcdCompat(t *testing.T) {
t.Parallel()
CatchLogForTest(t)
require := require.New(t)
Expand Down
107 changes: 59 additions & 48 deletions backend_storage_etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,53 +178,62 @@ func (s *backendStorageEtcd) EtcdKeyUpdated(client *EtcdClient, key string, data
return
}

allowHttp := false
for _, u := range info.parsedUrls {
if u.Scheme == "http" {
allowHttp = true
break
}
}

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

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

maxStreamBitrate: info.MaxStreamBitrate,
maxScreenBitrate: info.MaxScreenBitrate,
sessionLimit: info.SessionLimit,
}

host := info.parsedUrl.Host

s.mu.Lock()
defer s.mu.Unlock()

s.keyInfos[key] = &info
entries, found := s.backends[host]
if !found {
// Simple case, first backend for this host
log.Printf("Added backend %s (from %s)", info.Url, key)
s.backends[host] = []*Backend{backend}
updateBackendStats(backend)
statsBackendsCurrent.Inc()
s.wakeupForTesting()
return
}

// Was the backend changed?
replaced := false
for idx, entry := range entries {
if entry.id == key {
log.Printf("Updated backend %s (from %s)", info.Url, key)
for idx, u := range info.parsedUrls {
host := u.Host
entries, found := s.backends[host]
if !found {
// Simple case, first backend for this host
log.Printf("Added backend %s (from %s)", info.Urls[idx], key)
s.backends[host] = []*Backend{backend}
updateBackendStats(backend)
entries[idx] = backend
replaced = true
break
statsBackendsCurrent.Inc()
s.wakeupForTesting()
continue
}
}

if !replaced {
// New backend, add to list.
log.Printf("Added backend %s (from %s)", info.Url, key)
s.backends[host] = append(entries, backend)
updateBackendStats(backend)
statsBackendsCurrent.Inc()
// Was the backend changed?
replaced := false
for idx, entry := range entries {
if entry.id == key {
log.Printf("Updated backend %s (from %s)", info.Urls[idx], key)
updateBackendStats(backend)
entries[idx] = backend
replaced = true
break
}
}

if !replaced {
// New backend, add to list.
log.Printf("Added backend %s (from %s)", info.Urls[idx], key)
s.backends[host] = append(entries, backend)
updateBackendStats(backend)
statsBackendsCurrent.Inc()
}
}
s.wakeupForTesting()
}
Expand All @@ -239,27 +248,29 @@ func (s *backendStorageEtcd) EtcdKeyDeleted(client *EtcdClient, key string, prev
}

delete(s.keyInfos, key)
host := info.parsedUrl.Host
entries, found := s.backends[host]
if !found {
return
}

log.Printf("Removing backend %s (from %s)", info.Url, key)
newEntries := make([]*Backend, 0, len(entries)-1)
for _, entry := range entries {
if entry.id == key {
updateBackendStats(entry)
statsBackendsCurrent.Dec()
for idx, u := range info.parsedUrls {
host := u.Host
entries, found := s.backends[host]
if !found {
continue
}

newEntries = append(newEntries, entry)
}
if len(newEntries) > 0 {
s.backends[host] = newEntries
} else {
delete(s.backends, host)
log.Printf("Removing backend %s (from %s)", info.Urls[idx], key)
newEntries := make([]*Backend, 0, len(entries)-1)
for _, entry := range entries {
if entry.id == key {
updateBackendStats(entry)
statsBackendsCurrent.Dec()
continue
}

newEntries = append(newEntries, entry)
}
if len(newEntries) > 0 {
s.backends[host] = newEntries
} else {
delete(s.backends, host)
}
}
s.wakeupForTesting()
}
Expand Down
Loading

0 comments on commit 39580fc

Please sign in to comment.