Skip to content

Commit

Permalink
Merge pull request #281 from strukturag/refactor-async-events
Browse files Browse the repository at this point in the history
Clustering support
  • Loading branch information
fancycode authored Jul 7, 2022
2 parents 042d447 + ad1dea2 commit d3f8876
Show file tree
Hide file tree
Showing 57 changed files with 6,906 additions and 1,205 deletions.
1 change: 1 addition & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:

- name: Install dependencies
run: |
sudo apt -y update && sudo apt -y install protobuf-compiler
make common
- name: lint
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ jobs:
path: ${{ steps.go-cache-paths.outputs.go-mod }}
key: ${{ runner.os }}-${{ steps.go-cache-paths.outputs.go-version }}-mod-${{ hashFiles('**/go.mod', '**/go.sum') }}

- name: Install dependencies
run: |
sudo apt -y update && sudo apt -y install protobuf-compiler
- name: Build applications
run: |
echo "Building with $(nproc) threads"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ vendor/

*_easyjson.go
*.pem
*.pb.go
*.prof
*.socket
*.tar.gz
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM golang:1.18 AS builder
WORKDIR /workdir

COPY . .
RUN apt -y update && apt -y install protobuf-compiler
RUN make build

FROM alpine:3.15
Expand Down
34 changes: 29 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ $(GOPATHBIN)/easyjson:
$(GO) get -u -d github.com/mailru/easyjson/...
$(GO) install github.com/mailru/easyjson/...

$(GOPATHBIN)/protoc-gen-go:
$(GO) get -u -d google.golang.org/protobuf/cmd/protoc-gen-go
$(GO) install google.golang.org/protobuf/cmd/protoc-gen-go

$(GOPATHBIN)/protoc-gen-go-grpc:
$(GO) get -u -d google.golang.org/grpc/cmd/protoc-gen-go-grpc
$(GO) install google.golang.org/grpc/cmd/protoc-gen-go-grpc

continentmap.go:
$(CURDIR)/scripts/get_continent_map.py $@

Expand All @@ -70,7 +78,7 @@ check-continentmap:
get:
$(GO) get $(PACKAGE)

fmt: hook
fmt: hook | common_proto
$(GOFMT) -s -w *.go client proxy server

vet: common
Expand All @@ -83,22 +91,37 @@ cover: vet common
rm -f cover.out && \
$(GO) test -v -timeout $(TIMEOUT) -coverprofile cover.out $(ALL_PACKAGES) && \
sed -i "/_easyjson/d" cover.out && \
sed -i "/\.pb\.go/d" cover.out && \
$(GO) tool cover -func=cover.out

coverhtml: vet common
rm -f cover.out && \
$(GO) test -v -timeout $(TIMEOUT) -coverprofile cover.out $(ALL_PACKAGES) && \
sed -i "/_easyjson/d" cover.out && \
sed -i "/\.pb\.go/d" cover.out && \
$(GO) tool cover -html=cover.out -o coverage.html

%_easyjson.go: %.go $(GOPATHBIN)/easyjson
%_easyjson.go: %.go $(GOPATHBIN)/easyjson | common_proto
PATH="$(GODIR)":$(PATH) "$(GOPATHBIN)/easyjson" -all $*.go

common: \
%.pb.go: %.proto $(GOPATHBIN)/protoc-gen-go $(GOPATHBIN)/protoc-gen-go-grpc
PATH="$(GODIR)":"$(GOPATHBIN)":$(PATH) protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
$*.proto

common: common_easyjson common_proto

common_easyjson: \
api_async_easyjson.go \
api_backend_easyjson.go \
api_grpc_easyjson.go \
api_proxy_easyjson.go \
api_signaling_easyjson.go \
natsclient_easyjson.go
api_signaling_easyjson.go

common_proto: \
grpc_internal.pb.go \
grpc_mcu.pb.go \
grpc_sessions.pb.go

$(BINDIR):
mkdir -p $(BINDIR)
Expand All @@ -115,6 +138,7 @@ proxy: common $(BINDIR)
clean:
rm -f *_easyjson.go
rm -f easyjson-bootstrap*.go
rm -f *.pb.go

build: server proxy

Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The following tools are required for building the signaling server.
- git
- go >= 1.17
- make
- protobuf-compiler >= 3

All other dependencies are fetched automatically while building.

Expand Down Expand Up @@ -156,6 +157,20 @@ proxy process gracefully after all clients have been disconnected. No new
publishers will be accepted in this case.


### Clustering

The signaling server supports a clustering mode where multiple running servers
can be interconnected to form a single "virtual" server. This can be used to
increase the capacity of the signaling server or provide a failover setup.

For that a central NATS server / cluster must be used by all instances. Each
instance must running a GRPC server (enable `listening` in section `grpc` and
optionally setup certificate, private key and CA). The list of other GRPC
targets must be configured as `targets` in section `grpc` or can be retrieved
from an etcd cluster. See `server.conf.in` in section `grpc` for configuration
details.


## Setup of frontend webserver

Usually the standalone signaling server is running behind a webserver that does
Expand Down
54 changes: 54 additions & 0 deletions api_async.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Standalone signaling server for the Nextcloud Spreed app.
* Copyright (C) 2022 struktur AG
*
* @author Joachim Bauch <[email protected]>
*
* @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 signaling

import "time"

type AsyncMessage struct {
SendTime time.Time `json:"sendtime"`

Type string `json:"type"`

Message *ServerMessage `json:"message,omitempty"`

Room *BackendServerRoomRequest `json:"room,omitempty"`

Permissions []Permission `json:"permissions,omitempty"`

AsyncRoom *AsyncRoomMessage `json:"asyncroom,omitempty"`

SendOffer *SendOfferMessage `json:"sendoffer,omitempty"`

Id string `json:"id"`
}

type AsyncRoomMessage struct {
Type string `json:"type"`

SessionId string `json:"sessionid,omitempty"`
}

type SendOfferMessage struct {
MessageId string `json:"messageid,omitempty"`
SessionId string `json:"sessionid"`
Data *MessageClientMessageData `json:"data"`
}
39 changes: 39 additions & 0 deletions api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import (
"crypto/subtle"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)

const (
Expand Down Expand Up @@ -321,3 +324,39 @@ type TurnCredentials struct {
TTL int64 `json:"ttl"`
URIs []string `json:"uris"`
}

// Information on a backend in the etcd cluster.

type BackendInformationEtcd struct {
parsedUrl *url.URL

Url string `json:"url"`
Secret string `json:"secret"`

MaxStreamBitrate int `json:"maxstreambitrate,omitempty"`
MaxScreenBitrate int `json:"maxscreenbitrate,omitempty"`

SessionLimit uint64 `json:"sessionlimit,omitempty"`
}

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 strings.Contains(parsedUrl.Host, ":") && hasStandardPort(parsedUrl) {
parsedUrl.Host = parsedUrl.Hostname()
p.Url = parsedUrl.String()
}

p.parsedUrl = parsedUrl
return nil
}
41 changes: 41 additions & 0 deletions api_grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Standalone signaling server for the Nextcloud Spreed app.
* Copyright (C) 2022 struktur AG
*
* @author Joachim Bauch <[email protected]>
*
* @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 signaling

import (
"fmt"
)

// Information on a GRPC target in the etcd cluster.

type GrpcTargetInformationEtcd struct {
Address string `json:"address"`
}

func (p *GrpcTargetInformationEtcd) CheckValid() error {
if l := len(p.Address); l == 0 {
return fmt.Errorf("address missing")
} else if p.Address[l-1] == '/' {
p.Address = p.Address[:l-1]
}
return nil
}
Loading

0 comments on commit d3f8876

Please sign in to comment.