diff --git a/.travis.yml b/.travis.yml
index 5f971be8..a0d6ba2a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,8 +10,7 @@ go:
- tip
env:
- - GEM_HOME=/var/lib/gems/1.9.1 USE_GODEPS=0
- - GEM_HOME=/var/lib/gems/1.9.1 USE_GODEPS=1
+ - GEM_HOME=/var/lib/gems/1.9.1
before_install:
- sudo add-apt-repository -y ppa:chris-lea/node.js
@@ -22,19 +21,17 @@ install:
- sudo gem1.9.1 install compass
- sudo gem1.9.1 install scss-lint
- npm install
- - if [ "$USE_GODEPS" = "1" ]; then wget https://raw.githubusercontent.com/pote/gpm/v1.3.2/bin/gpm && chmod +x gpm && sudo mv gpm /usr/local/bin; fi
script:
- ./autogen.sh
- ./configure
- - if [ "$USE_GODEPS" = "0" ]; then make get; fi
- - if [ "$USE_GODEPS" = "1" ]; then make gpm; fi
- make styleshint
# TODO(fancycode): enable styleslint once all styles have been fixed
# - make styleslint
- make styles
- make jshint
- make javascript
+ - make goget
- make test
- make binary
- make build-i18n
diff --git a/Godeps b/Godeps
deleted file mode 100644
index 887770cf..00000000
--- a/Godeps
+++ /dev/null
@@ -1,12 +0,0 @@
-github.com/gorilla/context 215affda49addc4c8ef7e2534915df2c8c35c6cd
-github.com/gorilla/mux ba336c9cfb43552c90de6cb2ceedd3271c747558
-github.com/gorilla/securecookie aeade84400a85c6875264ae51c7a56ecdcb61751
-github.com/gorilla/websocket 6eb6ad425a89d9da7a5549bc6da8f79ba5c17844
-github.com/longsleep/pkac 0.0.1
-github.com/satori/go.uuid afe1e2ddf0f05b7c29d388a3f8e76cb15c2231ca
-github.com/strukturag/goacceptlanguageparser goacceptlanguageparser_v100
-github.com/strukturag/httputils httputils_v012
-github.com/strukturag/phoenix phoenix_v100
-github.com/strukturag/sloth v0.9.2
-github.com/dlintw/goconf dcc070983490608a14480e3bf943bad464785df5
-github.com/nats-io/nats v1.1.6
diff --git a/Makefile.am b/Makefile.am
index 119b1f8e..1945da91 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,8 @@ AUTOMAKE_OPTIONS = -Wno-portability
ACLOCAL_AMFLAGS = -I m4
EXENAME := spreed-webrtc-server
+GOPKG := github.com/strukturag/spreed-webrtc
+GOPATH := "$(CURDIR)/vendor:$(CURDIR)"
CONFIG_FILE ?= spreed-webrtc-server.conf
CONFIG_PATH ?= /etc
@@ -47,24 +49,26 @@ build: get binary assets
gopath:
@echo GOPATH=$(GOPATH)
-if READONLY_VENDOR_GOPATH
-export GOPATH = $(DIST):$(CURDIR)
-get: $(DIST)
- ln -sf $(VENDOR_GOPATH)/src -t $(DIST)
-else
-export GOPATH = $(VENDOR_GOPATH):$(CURDIR)
-get:
-endif
- $(GO) get app/...
+goget:
+ if [ -z "$(DEB_BUILDING)" ]; then GOPATH=$(GOPATH) go get github.com/rogpeppe/godeps; fi
+ if [ -z "$(DEB_BUILDING)" ]; then GOPATH=$(GOPATH) $(CURDIR)/vendor/bin/godeps -u dependencies.tsv; fi
+ mkdir -p $(shell dirname "$(CURDIR)/vendor/src/$(GOPKG)")
+ rm -f $(CURDIR)/vendor/src/$(GOPKG)
+ ln -sfn $(PWD) $(CURDIR)/vendor/src/$(GOPKG)
-getupdate: vendorclean get
+get: goget
-gpm:
- @if [ "$(GPM)" = "" ]; then echo "Command 'gpm' not found"; exit 1; fi
- $(GPM) install
+gogetupdate: govendorclean goget
+
+dependencies.tsv:
+ set -e ;\
+ TMP=$$(mktemp -d) ;\
+ cp -r $(CURDIR)/vendor $$TMP ;\
+ GOPATH=$$TMP/vendor:$(CURDIR) $(CURDIR)/vendor/bin/godeps $(GOPKG)/src/app/spreed-webrtc-server ./go/... > $(CURDIR)/dependencies.tsv ;\
+ rm -rf $$TMP
binary:
- $(GO) build $(GOBUILDFLAGS) -o bin/$(EXENAME) -ldflags '$(INTERNALLDFLAGS)' app/$(EXENAME)
+ GOPATH=$(GOPATH) $(GO) build $(GOBUILDFLAGS) -o bin/$(EXENAME) -ldflags '$(INTERNALLDFLAGS)' app/$(EXENAME)
binaryrace: GOBUILDFLAGS := $(GOBUILDFLAGS) -race
binaryrace: binary
@@ -72,11 +76,13 @@ binaryrace: binary
binaryall: GOBUILDFLAGS := $(GOBUILDFLAGS) -a
binaryall: binary
-fmt:
- $(GO) fmt app/...
+gofmt:
+ GOPATH=$(GOPATH) $(GO) fmt app/... ./go/...
+
+fmt: gofmt
-test: get
- $(GO) test $(GOTESTFLAGS) app/...
+test:
+ GOPATH=$(GOPATH) $(GO) test -v $(GOTESTFLAGS) app/... ./go/...
assets: javascript fonts
@@ -166,7 +172,7 @@ clean:
distclean: clean
rm -rf $(DIST)
-vendorclean:
+govendorclean:
rm -rf vendor/*
pristine: distclean vendorclean
@@ -187,4 +193,4 @@ tarball: distclean release install
cp server.conf.in $(TARPATH)/loader
tar czf $(DIST)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)_$(BUILD_OS)_$(BUILD_ARCH).tar.gz -C $(DIST) $(PACKAGE_NAME)-$(PACKAGE_VERSION)
-.PHONY: clean distclean vendorclean pristine get getupdate build javascript fonts styles release releasetest dist_gopath install install-binary install-assets gopath binary binaryrace binaryall tarball assets
+.PHONY: clean distclean govendorclean pristine goget gogetupdate build javascript fonts styles release releasetest dist_gopath install install-binary install-assets gopath binary binaryrace binaryall tarball assets dependencies.tsv
diff --git a/dependencies.tsv b/dependencies.tsv
new file mode 100644
index 00000000..f886fd27
--- /dev/null
+++ b/dependencies.tsv
@@ -0,0 +1,12 @@
+github.com/dlintw/goconf git dcc070983490608a14480e3bf943bad464785df5 2012-02-28T08:26:10Z
+github.com/gorilla/context git 215affda49addc4c8ef7e2534915df2c8c35c6cd 2014-12-17T16:02:51Z
+github.com/gorilla/mux git ba336c9cfb43552c90de6cb2ceedd3271c747558 2015-07-17T15:03:03Z
+github.com/gorilla/securecookie git aeade84400a85c6875264ae51c7a56ecdcb61751 2015-07-16T23:32:44Z
+github.com/gorilla/websocket git 6eb6ad425a89d9da7a5549bc6da8f79ba5c17844 2015-07-14T14:06:27Z
+github.com/longsleep/pkac git 68bf8859f58dd84332ee41c07eba357fb3818ba3 2014-05-01T18:13:13Z
+github.com/nats-io/nats git 355b5b97e0842dc94f1106729aa88e33e06317ca 2015-12-09T21:13:14Z
+github.com/satori/go.uuid git afe1e2ddf0f05b7c29d388a3f8e76cb15c2231ca 2015-06-15T02:45:37Z
+github.com/strukturag/goacceptlanguageparser git 68066e68c2940059aadc6e19661610cf428b6647 2014-02-13T13:31:23Z
+github.com/strukturag/httputils git afbf05c71ac03ee7989c96d033a9571ba4ded468 2014-07-02T01:35:33Z
+github.com/strukturag/phoenix git c3429c4e93588d848606263a7f96f91c90e43178 2016-03-02T12:52:52Z
+github.com/strukturag/sloth git 74a8bcf67368de59baafe5d3e17aee9875564cfc 2015-04-22T08:59:42Z
diff --git a/src/app/spreed-webrtc-server/buffercache.go b/go/buffercache/buffercache.go
similarity index 98%
rename from src/app/spreed-webrtc-server/buffercache.go
rename to go/buffercache/buffercache.go
index d19ba72d..cc9d0793 100644
--- a/src/app/spreed-webrtc-server/buffercache.go
+++ b/go/buffercache/buffercache.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package buffercache
import (
"bytes"
@@ -161,7 +161,7 @@ func (cache *bufferCache) Wrap(data []byte) Buffer {
return &directBuffer{refcnt: 1, cache: cache, buf: bytes.NewBuffer(data)}
}
-func readAll(dest Buffer, r io.Reader) error {
+func ReadAll(dest Buffer, r io.Reader) error {
var err error
defer func() {
e := recover()
diff --git a/go/channelling/api.go b/go/channelling/api.go
new file mode 100644
index 00000000..5708e6ed
--- /dev/null
+++ b/go/channelling/api.go
@@ -0,0 +1,28 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type ChannellingAPI interface {
+ OnConnect(*Client, *Session) (interface{}, error)
+ OnDisconnect(*Client, *Session)
+ OnIncoming(Sender, *Session, *DataIncoming) (interface{}, error)
+}
diff --git a/go/channelling/api/api.go b/go/channelling/api/api.go
new file mode 100644
index 00000000..0c34ab9e
--- /dev/null
+++ b/go/channelling/api/api.go
@@ -0,0 +1,185 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "log"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+const (
+ maxConferenceSize = 100
+ apiVersion = 1.4 // Keep this in sync with CHANNELING-API docs.Hand
+)
+
+type channellingAPI struct {
+ RoomStatusManager channelling.RoomStatusManager
+ SessionEncoder channelling.SessionEncoder
+ SessionManager channelling.SessionManager
+ StatsCounter channelling.StatsCounter
+ ContactManager channelling.ContactManager
+ TurnDataCreator channelling.TurnDataCreator
+ Unicaster channelling.Unicaster
+ BusManager channelling.BusManager
+ config *channelling.Config
+}
+
+// New creates and initializes a new ChannellingAPI using
+// various other services for initialization. It is intended to handle
+// incoming and outgoing channeling API events from clients.
+func New(config *channelling.Config,
+ roomStatus channelling.RoomStatusManager,
+ sessionEncoder channelling.SessionEncoder,
+ sessionManager channelling.SessionManager,
+ statsCounter channelling.StatsCounter,
+ contactManager channelling.ContactManager,
+ turnDataCreator channelling.TurnDataCreator,
+ unicaster channelling.Unicaster,
+ busManager channelling.BusManager) channelling.ChannellingAPI {
+ return &channellingAPI{
+ roomStatus,
+ sessionEncoder,
+ sessionManager,
+ statsCounter,
+ contactManager,
+ turnDataCreator,
+ unicaster,
+ busManager,
+ config,
+ }
+}
+
+func (api *channellingAPI) OnConnect(client *channelling.Client, session *channelling.Session) (interface{}, error) {
+ api.Unicaster.OnConnect(client, session)
+ self, err := api.HandleSelf(session)
+ if err == nil {
+ api.BusManager.Trigger(channelling.BusManagerConnect, session.Id, "", nil)
+ }
+ return self, err
+}
+
+func (api *channellingAPI) OnDisconnect(client *channelling.Client, session *channelling.Session) {
+ api.Unicaster.OnDisconnect(client, session)
+ api.BusManager.Trigger(channelling.BusManagerDisconnect, session.Id, "", nil)
+}
+
+func (api *channellingAPI) OnIncoming(sender channelling.Sender, session *channelling.Session, msg *channelling.DataIncoming) (interface{}, error) {
+ switch msg.Type {
+ case "Self":
+ return api.HandleSelf(session)
+ case "Hello":
+ if msg.Hello == nil {
+ return nil, channelling.NewDataError("bad_request", "message did not contain Hello")
+ }
+
+ return api.HandleHello(session, msg.Hello, sender)
+ case "Offer":
+ if msg.Offer == nil || msg.Offer.Offer == nil {
+ log.Println("Received invalid offer message.", msg)
+ break
+ }
+ if _, ok := msg.Offer.Offer["_token"]; !ok {
+ // Trigger offer event when offer has no token, so this is
+ // not triggered for peerxfer and peerscreenshare offers.
+ api.BusManager.Trigger(channelling.BusManagerOffer, session.Id, msg.Offer.To, nil)
+ }
+
+ session.Unicast(msg.Offer.To, msg.Offer)
+ case "Candidate":
+ if msg.Candidate == nil || msg.Candidate.Candidate == nil {
+ log.Println("Received invalid candidate message.", msg)
+ break
+ }
+
+ session.Unicast(msg.Candidate.To, msg.Candidate)
+ case "Answer":
+ if msg.Answer == nil || msg.Answer.Answer == nil {
+ log.Println("Received invalid answer message.", msg)
+ break
+ }
+ if _, ok := msg.Answer.Answer["_token"]; !ok {
+ // Trigger answer event when answer has no token. so this is
+ // not triggered for peerxfer and peerscreenshare answers.
+ api.BusManager.Trigger(channelling.BusManagerAnswer, session.Id, msg.Answer.To, nil)
+ }
+
+ session.Unicast(msg.Answer.To, msg.Answer)
+ case "Users":
+ return api.HandleUsers(session)
+ case "Authentication":
+ if msg.Authentication == nil || msg.Authentication.Authentication == nil {
+ return nil, channelling.NewDataError("bad_request", "message did not contain Authentication")
+ }
+
+ return api.HandleAuthentication(session, msg.Authentication.Authentication)
+ case "Bye":
+ if msg.Bye == nil {
+ log.Println("Received invalid bye message.", msg)
+ break
+ }
+ api.BusManager.Trigger(channelling.BusManagerBye, session.Id, msg.Bye.To, nil)
+
+ session.Unicast(msg.Bye.To, msg.Bye)
+ case "Status":
+ if msg.Status == nil {
+ log.Println("Received invalid status message.", msg)
+ break
+ }
+
+ //log.Println("Status", msg.Status)
+ session.Update(&channelling.SessionUpdate{Types: []string{"Status"}, Status: msg.Status.Status})
+ session.BroadcastStatus()
+ case "Chat":
+ if msg.Chat == nil || msg.Chat.Chat == nil {
+ log.Println("Received invalid chat message.", msg)
+ break
+ }
+
+ api.HandleChat(session, msg.Chat)
+ case "Conference":
+ if msg.Conference == nil {
+ log.Println("Received invalid conference message.", msg)
+ break
+ }
+
+ api.HandleConference(session, msg.Conference)
+ case "Alive":
+ return msg.Alive, nil
+ case "Sessions":
+ if msg.Sessions == nil || msg.Sessions.Sessions == nil {
+ return nil, channelling.NewDataError("bad_request", "message did not contain Sessions")
+ }
+
+ return api.HandleSessions(session, msg.Sessions.Sessions)
+ case "Room":
+ if msg.Room == nil {
+ return nil, channelling.NewDataError("bad_request", "message did not contain Room")
+ }
+
+ return api.HandleRoom(session, msg.Room)
+ default:
+ log.Println("OnText unhandled message type", msg.Type)
+ }
+
+ return nil, nil
+}
diff --git a/src/app/spreed-webrtc-server/channelling_api_test.go b/go/channelling/api/api_test.go
similarity index 59%
rename from src/app/spreed-webrtc-server/channelling_api_test.go
rename to go/channelling/api/api_test.go
index 48a06179..7f3bea0d 100644
--- a/src/app/spreed-webrtc-server/channelling_api_test.go
+++ b/go/channelling/api/api_test.go
@@ -19,50 +19,55 @@
*
*/
-package main
+package api
import (
"errors"
"fmt"
"testing"
+
+ "github.com/gorilla/securecookie"
+
+ "github.com/strukturag/spreed-webrtc/go/buffercache"
+ "github.com/strukturag/spreed-webrtc/go/channelling"
)
type fakeClient struct {
}
-func (fake *fakeClient) Send(_ Buffer) {
+func (fake *fakeClient) Send(_ buffercache.Buffer) {
}
type fakeRoomManager struct {
joinedRoomID string
leftRoomID string
- roomUsers []*DataSession
+ roomUsers []*channelling.DataSession
joinedID string
joinError error
leftID string
broadcasts []interface{}
- updatedRoom *DataRoom
+ updatedRoom *channelling.DataRoom
updateError error
}
-func (fake *fakeRoomManager) RoomUsers(session *Session) []*DataSession {
+func (fake *fakeRoomManager) RoomUsers(session *channelling.Session) []*channelling.DataSession {
return fake.roomUsers
}
-func (fake *fakeRoomManager) JoinRoom(id, roomName, roomType string, _ *DataRoomCredentials, session *Session, sessionAuthenticated bool, _ Sender) (*DataRoom, error) {
+func (fake *fakeRoomManager) JoinRoom(id, roomName, roomType string, _ *channelling.DataRoomCredentials, session *channelling.Session, sessionAuthenticated bool, _ channelling.Sender) (*channelling.DataRoom, error) {
fake.joinedID = id
- return &DataRoom{Name: roomName, Type: roomType}, fake.joinError
+ return &channelling.DataRoom{Name: roomName, Type: roomType}, fake.joinError
}
func (fake *fakeRoomManager) LeaveRoom(roomID, sessionID string) {
fake.leftID = roomID
}
-func (fake *fakeRoomManager) Broadcast(_, _ string, outgoing *DataOutgoing) {
+func (fake *fakeRoomManager) Broadcast(_, _ string, outgoing *channelling.DataOutgoing) {
fake.broadcasts = append(fake.broadcasts, outgoing.Data)
}
-func (fake *fakeRoomManager) UpdateRoom(_ *Session, _ *DataRoom) (*DataRoom, error) {
+func (fake *fakeRoomManager) UpdateRoom(_ *channelling.Session, _ *channelling.DataRoom) (*channelling.DataRoom, error) {
return fake.updatedRoom, fake.updateError
}
@@ -73,23 +78,19 @@ func (fake *fakeRoomManager) MakeRoomID(roomName, roomType string) string {
return fmt.Sprintf("%s:%s", roomType, roomName)
}
-func NewTestChannellingAPI() (ChannellingAPI, *fakeClient, *Session, *fakeRoomManager) {
+func NewTestChannellingAPI() (channelling.ChannellingAPI, *fakeClient, *channelling.Session, *fakeRoomManager) {
client, roomManager := &fakeClient{}, &fakeRoomManager{}
- session := &Session{
- attestations: sessionNonces,
- Broadcaster: roomManager,
- RoomStatusManager: roomManager,
- }
- busManager := NewBusManager("", false, "")
- session.attestation = &SessionAttestation{s: session}
- return NewChannellingAPI(nil, roomManager, nil, nil, nil, nil, nil, nil, busManager), client, session, roomManager
+ sessionNonces := securecookie.New(securecookie.GenerateRandomKey(64), nil)
+ session := channelling.NewSession(nil, nil, roomManager, roomManager, nil, sessionNonces, "", "")
+ busManager := channelling.NewBusManager("", false, "")
+ return New(nil, roomManager, nil, nil, nil, nil, nil, nil, busManager), client, session, roomManager
}
func Test_ChannellingAPI_OnIncoming_HelloMessage_JoinsTheSelectedRoom(t *testing.T) {
roomID, roomName, ua := "Room:foobar", "foobar", "unit tests"
api, client, session, roomManager := NewTestChannellingAPI()
- api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName, Ua: ua}})
+ api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{Id: roomName, Ua: ua}})
if roomManager.joinedID != roomID {
t.Errorf("Expected to have joined room %v, but got %v", roomID, roomManager.joinedID)
@@ -99,7 +100,7 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_JoinsTheSelectedRoom(t *testing
t.Fatalf("Expected 1 broadcast, but got %d", broadcastCount)
}
- dataSession, ok := roomManager.broadcasts[0].(*DataSession)
+ dataSession, ok := roomManager.broadcasts[0].(*channelling.DataSession)
if !ok {
t.Fatal("Expected a session data broadcast")
}
@@ -113,8 +114,8 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_LeavesAnyPreviouslyJoinedRooms(
roomID, roomName := "Room:foobar", "foobar"
api, client, session, roomManager := NewTestChannellingAPI()
- api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName}})
- api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: "baz"}})
+ api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{Id: roomName}})
+ api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{Id: "baz"}})
if roomManager.leftID != roomID {
t.Errorf("Expected to have left room %v, but got %v", roomID, roomManager.leftID)
@@ -124,7 +125,7 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_LeavesAnyPreviouslyJoinedRooms(
t.Fatalf("Expected 3 broadcasts, but got %d", broadcastCount)
}
- dataSession, ok := roomManager.broadcasts[1].(*DataSession)
+ dataSession, ok := roomManager.broadcasts[1].(*channelling.DataSession)
if !ok {
t.Fatal("Expected a session data broadcast")
}
@@ -138,7 +139,7 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_DoesNotJoinIfNotPermitted(t *te
api, client, session, roomManager := NewTestChannellingAPI()
roomManager.joinError = errors.New("Can't enter this room")
- api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{}})
+ api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{}})
if broadcastCount := len(roomManager.broadcasts); broadcastCount != 0 {
t.Fatalf("Expected no broadcasts, but got %d", broadcastCount)
@@ -148,14 +149,14 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_DoesNotJoinIfNotPermitted(t *te
func Test_ChannellingAPI_OnIncoming_HelloMessage_RespondsWithAWelcome(t *testing.T) {
roomID := "a-room"
api, client, session, roomManager := NewTestChannellingAPI()
- roomManager.roomUsers = []*DataSession{&DataSession{}}
+ roomManager.roomUsers = []*channelling.DataSession{&channelling.DataSession{}}
- reply, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomID}})
+ reply, err := api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{Id: roomID}})
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
- welcome, ok := reply.(*DataWelcome)
+ welcome, ok := reply.(*channelling.DataWelcome)
if !ok {
t.Fatalf("Expected response %#v to be a Welcome", reply)
}
@@ -175,9 +176,9 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_RespondsWithAWelcome(t *testing
func Test_ChannellingAPI_OnIncoming_HelloMessage_RespondsWithAnErrorIfTheRoomCannotBeJoined(t *testing.T) {
api, client, session, roomManager := NewTestChannellingAPI()
- roomManager.joinError = NewDataError("bad_join", "")
+ roomManager.joinError = channelling.NewDataError("bad_join", "")
- _, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{}})
+ _, err := api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{}})
assertDataError(t, err, "bad_join")
}
@@ -185,19 +186,19 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_RespondsWithAnErrorIfTheRoomCan
func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAndBroadcastsTheUpdatedRoom(t *testing.T) {
roomName := "foo"
api, client, session, roomManager := NewTestChannellingAPI()
- roomManager.updatedRoom = &DataRoom{Name: "FOO"}
+ roomManager.updatedRoom = &channelling.DataRoom{Name: "FOO"}
- _, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName}})
+ _, err := api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{Id: roomName}})
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
- reply, err := api.OnIncoming(client, session, &DataIncoming{Type: "Room", Room: &DataRoom{Name: roomName}})
+ reply, err := api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Room", Room: &channelling.DataRoom{Name: roomName}})
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
- room, ok := reply.(*DataRoom)
+ room, ok := reply.(*channelling.DataRoom)
if !ok {
t.Fatalf("Expected response message to be a Room")
}
@@ -210,7 +211,7 @@ func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAndBroadcastsTheUpda
t.Fatalf("Expected 1 broadcasts, but got %d", broadcastCount)
}
- if _, ok := roomManager.broadcasts[1].(*DataRoom); !ok {
+ if _, ok := roomManager.broadcasts[1].(*channelling.DataRoom); !ok {
t.Fatal("Expected a room data broadcast")
}
}
@@ -218,13 +219,30 @@ func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAndBroadcastsTheUpda
func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAnErrorIfUpdatingTheRoomFails(t *testing.T) {
roomName := "foo"
api, client, session, roomManager := NewTestChannellingAPI()
- roomManager.updateError = NewDataError("a_room_error", "")
+ roomManager.updateError = channelling.NewDataError("a_room_error", "")
- _, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName}})
+ _, err := api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Hello", Hello: &channelling.DataHello{Id: roomName}})
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
- _, err = api.OnIncoming(client, session, &DataIncoming{Type: "Room", Room: &DataRoom{Name: roomName}})
+ _, err = api.OnIncoming(client, session, &channelling.DataIncoming{Type: "Room", Room: &channelling.DataRoom{Name: roomName}})
assertDataError(t, err, "a_room_error")
}
+
+func assertDataError(t *testing.T, err error, code string) {
+ if err == nil {
+ t.Error("Expected an error, but none was returned")
+ return
+ }
+
+ dataError, ok := err.(*channelling.DataError)
+ if !ok {
+ t.Errorf("Expected error %#v to be a *DataError", err)
+ return
+ }
+
+ if code != dataError.Code {
+ t.Errorf("Expected error code to be %v, but was %v", code, dataError.Code)
+ }
+}
diff --git a/go/channelling/api/handle_authentication.go b/go/channelling/api/handle_authentication.go
new file mode 100644
index 00000000..5487d05b
--- /dev/null
+++ b/go/channelling/api/handle_authentication.go
@@ -0,0 +1,43 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "log"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleAuthentication(session *channelling.Session, st *channelling.SessionToken) (*channelling.DataSelf, error) {
+ if err := api.SessionManager.Authenticate(session, st, ""); err != nil {
+ log.Println("Authentication failed", err, st.Userid, st.Nonce)
+ return nil, err
+ }
+
+ log.Println("Authentication success", session.Userid())
+ self, err := api.HandleSelf(session)
+ if err == nil {
+ session.BroadcastStatus()
+ }
+
+ return self, err
+}
diff --git a/go/channelling/api/handle_chat.go b/go/channelling/api/handle_chat.go
new file mode 100644
index 00000000..b1782cd8
--- /dev/null
+++ b/go/channelling/api/handle_chat.go
@@ -0,0 +1,68 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "log"
+ "time"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleChat(session *channelling.Session, chat *channelling.DataChat) {
+ // TODO(longsleep): Limit sent chat messages per incoming connection.
+ msg := chat.Chat
+ to := chat.To
+
+ if !msg.NoEcho {
+ session.Unicast(session.Id, chat)
+ }
+ msg.Time = time.Now().Format(time.RFC3339)
+ if to == "" {
+ // TODO(longsleep): Check if chat broadcast is allowed.
+ if session.Hello {
+ api.StatsCounter.CountBroadcastChat()
+ session.Broadcast(chat)
+ }
+ } else {
+ if msg.Status != nil {
+ if msg.Status.ContactRequest != nil {
+ if !api.config.WithModule("contacts") {
+ return
+ }
+ if err := api.ContactManager.ContactrequestHandler(session, to, msg.Status.ContactRequest); err != nil {
+ log.Println("Ignoring invalid contact request.", err)
+ return
+ }
+ msg.Status.ContactRequest.Userid = session.Userid()
+ }
+ } else {
+ api.StatsCounter.CountUnicastChat()
+ }
+
+ session.Unicast(to, chat)
+ if msg.Mid != "" {
+ // Send out delivery confirmation status chat message.
+ session.Unicast(session.Id, &channelling.DataChat{To: to, Type: "Chat", Chat: &channelling.DataChatMessage{Mid: msg.Mid, Status: &channelling.DataChatStatus{State: "sent"}}})
+ }
+ }
+}
diff --git a/go/channelling/api/handle_conference.go b/go/channelling/api/handle_conference.go
new file mode 100644
index 00000000..ed961dfb
--- /dev/null
+++ b/go/channelling/api/handle_conference.go
@@ -0,0 +1,43 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "log"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleConference(session *channelling.Session, conference *channelling.DataConference) {
+ // Check conference maximum size.
+ if len(conference.Conference) > maxConferenceSize {
+ log.Println("Refusing to create conference above limit.", len(conference.Conference))
+ return
+ }
+
+ // Send conference update to anyone.
+ for _, id := range conference.Conference {
+ if id != session.Id {
+ session.Unicast(id, conference)
+ }
+ }
+}
diff --git a/go/channelling/api/handle_hello.go b/go/channelling/api/handle_hello.go
new file mode 100644
index 00000000..aabd1307
--- /dev/null
+++ b/go/channelling/api/handle_hello.go
@@ -0,0 +1,48 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleHello(session *channelling.Session, hello *channelling.DataHello, sender channelling.Sender) (*channelling.DataWelcome, error) {
+ // TODO(longsleep): Filter room id and user agent.
+ session.Update(&channelling.SessionUpdate{Types: []string{"Ua"}, Ua: hello.Ua})
+
+ // Compatibily for old clients.
+ roomName := hello.Name
+ if roomName == "" {
+ roomName = hello.Id
+ }
+
+ room, err := session.JoinRoom(roomName, hello.Type, hello.Credentials, sender)
+ if err != nil {
+ return nil, err
+ }
+
+ return &channelling.DataWelcome{
+ Type: "Welcome",
+ Room: room,
+ Users: api.RoomStatusManager.RoomUsers(session),
+ }, nil
+}
diff --git a/go/channelling/api/handle_room.go b/go/channelling/api/handle_room.go
new file mode 100644
index 00000000..e09ec70b
--- /dev/null
+++ b/go/channelling/api/handle_room.go
@@ -0,0 +1,35 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleRoom(session *channelling.Session, room *channelling.DataRoom) (*channelling.DataRoom, error) {
+ room, err := api.RoomStatusManager.UpdateRoom(session, room)
+ if err == nil {
+ session.Broadcast(room)
+ }
+
+ return room, err
+}
diff --git a/go/channelling/api/handle_self.go b/go/channelling/api/handle_self.go
new file mode 100644
index 00000000..504e5557
--- /dev/null
+++ b/go/channelling/api/handle_self.go
@@ -0,0 +1,53 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "log"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleSelf(session *channelling.Session) (*channelling.DataSelf, error) {
+ token, err := api.SessionEncoder.EncodeSessionToken(session)
+ if err != nil {
+ log.Println("Error in OnRegister", err)
+ return nil, err
+ }
+
+ log.Println("Created new session token", len(token), token)
+ self := &channelling.DataSelf{
+ Type: "Self",
+ Id: session.Id,
+ Sid: session.Sid,
+ Userid: session.Userid(),
+ Suserid: api.SessionEncoder.EncodeSessionUserID(session),
+ Token: token,
+ Version: api.config.Version,
+ ApiVersion: apiVersion,
+ Turn: api.TurnDataCreator.CreateTurnData(session),
+ Stun: api.config.StunURIs,
+ }
+ api.BusManager.Trigger(channelling.BusManagerSession, session.Id, session.Userid(), nil)
+
+ return self, nil
+}
diff --git a/go/channelling/api/handle_sessions.go b/go/channelling/api/handle_sessions.go
new file mode 100644
index 00000000..7fab8f8e
--- /dev/null
+++ b/go/channelling/api/handle_sessions.go
@@ -0,0 +1,60 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleSessions(session *channelling.Session, sessions *channelling.DataSessionsRequest) (*channelling.DataSessions, error) {
+ switch sessions.Type {
+ case "contact":
+ if !api.config.WithModule("contacts") {
+ return nil, channelling.NewDataError("contacts_not_enabled", "incoming contacts session request with contacts disabled")
+ }
+ userID, err := api.ContactManager.GetContactID(session, sessions.Token)
+ if err != nil {
+ return nil, err
+ }
+ return &channelling.DataSessions{
+ Type: "Sessions",
+ Users: api.SessionManager.GetUserSessions(session, userID),
+ Sessions: sessions,
+ }, nil
+ case "session":
+ id, err := session.DecodeAttestation(sessions.Token)
+ if err != nil {
+ return nil, channelling.NewDataError("bad_attestation", err.Error())
+ }
+ session, ok := api.Unicaster.GetSession(id)
+ if !ok {
+ return nil, channelling.NewDataError("no_such_session", "cannot retrieve session")
+ }
+ return &channelling.DataSessions{
+ Type: "Sessions",
+ Users: []*channelling.DataSession{session.Data()},
+ Sessions: sessions,
+ }, nil
+ default:
+ return nil, channelling.NewDataError("bad_request", "unknown sessions request type")
+ }
+}
diff --git a/go/channelling/api/handle_users.go b/go/channelling/api/handle_users.go
new file mode 100644
index 00000000..ca8248c9
--- /dev/null
+++ b/go/channelling/api/handle_users.go
@@ -0,0 +1,36 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package api
+
+import (
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+)
+
+func (api *channellingAPI) HandleUsers(session *channelling.Session) (sessions *channelling.DataSessions, err error) {
+ if session.Hello {
+ sessions = &channelling.DataSessions{Type: "Users", Users: api.RoomStatusManager.RoomUsers(session)}
+ } else {
+ err = channelling.NewDataError("not_in_room", "Cannot list users without a current room")
+ }
+
+ return
+}
diff --git a/src/app/spreed-webrtc-server/bus_manager.go b/go/channelling/bus_manager.go
similarity index 99%
rename from src/app/spreed-webrtc-server/bus_manager.go
rename to go/channelling/bus_manager.go
index 367f9b08..1336976e 100644
--- a/src/app/spreed-webrtc-server/bus_manager.go
+++ b/go/channelling/bus_manager.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"errors"
@@ -114,6 +114,7 @@ func newNatsBus(id, prefix string) (*natsBus, error) {
triggerQueue := make(chan *busQueueEntry, 50)
// Start go routine to process outbount NATS publishing.
go chPublish(ec, triggerQueue)
+
return &natsBus{id, prefix, ec, triggerQueue}, nil
}
@@ -135,6 +136,7 @@ func (bus *natsBus) Trigger(name, from, payload string, data interface{}) (err e
err = errors.New("NATS trigger queue full")
}
}
+
return err
}
diff --git a/src/app/spreed-webrtc-server/client.go b/go/channelling/client.go
similarity index 71%
rename from src/app/spreed-webrtc-server/client.go
rename to go/channelling/client.go
index 7e6269f6..3310dcd3 100644
--- a/src/app/spreed-webrtc-server/client.go
+++ b/go/channelling/client.go
@@ -19,36 +19,34 @@
*
*/
-package main
+package channelling
import (
"log"
+
+ "github.com/strukturag/spreed-webrtc/go/buffercache"
)
type Sender interface {
- Send(Buffer)
-}
-
-type Client interface {
- Sender
- Session() *Session
- Index() uint64
- Close()
- ReplaceAndClose(Client)
+ Send(buffercache.Buffer)
}
-type client struct {
+type Client struct {
Codec
ChannellingAPI
Connection
session *Session
}
-func NewClient(codec Codec, api ChannellingAPI, session *Session) *client {
- return &client{codec, api, nil, session}
+func NewClient(codec Codec, api ChannellingAPI, session *Session) *Client {
+ return &Client{
+ Codec: codec,
+ ChannellingAPI: api,
+ session: session,
+ }
}
-func (client *client) OnConnect(conn Connection) {
+func (client *Client) OnConnect(conn Connection) {
client.Connection = conn
if reply, err := client.ChannellingAPI.OnConnect(client, client.session); err == nil {
client.reply("", reply)
@@ -57,38 +55,38 @@ func (client *client) OnConnect(conn Connection) {
}
}
-func (client *client) OnDisconnect() {
+func (client *Client) OnDisconnect() {
client.session.Close()
client.ChannellingAPI.OnDisconnect(client, client.session)
}
-func (client *client) OnText(b Buffer) {
- incoming, err := client.DecodeIncoming(b)
+func (client *Client) OnText(b buffercache.Buffer) {
+ incoming, err := client.Codec.DecodeIncoming(b)
if err != nil {
log.Println("OnText error while processing incoming message", err)
return
}
- if reply, err := client.OnIncoming(client, client.session, incoming); err != nil {
+ if reply, err := client.ChannellingAPI.OnIncoming(client, client.session, incoming); err != nil {
client.reply(incoming.Iid, err)
} else if reply != nil {
client.reply(incoming.Iid, reply)
}
}
-func (client *client) reply(iid string, m interface{}) {
+func (client *Client) reply(iid string, m interface{}) {
outgoing := &DataOutgoing{From: client.session.Id, Iid: iid, Data: m}
- if b, err := client.EncodeOutgoing(outgoing); err == nil {
- client.Send(b)
+ if b, err := client.Codec.EncodeOutgoing(outgoing); err == nil {
+ client.Connection.Send(b)
b.Decref()
}
}
-func (client *client) Session() *Session {
+func (client *Client) Session() *Session {
return client.session
}
-func (client *client) ReplaceAndClose(oldClient Client) {
+func (client *Client) ReplaceAndClose(oldClient *Client) {
oldSession := oldClient.Session()
client.session.Replace(oldSession)
go func() {
diff --git a/go/channelling/clientstats.go b/go/channelling/clientstats.go
new file mode 100644
index 00000000..b39b93cc
--- /dev/null
+++ b/go/channelling/clientstats.go
@@ -0,0 +1,26 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type ClientStats interface {
+ ClientInfo(details bool) (int, map[string]*DataSession, map[string]string)
+}
diff --git a/src/app/spreed-webrtc-server/incoming_codec.go b/go/channelling/codec.go
similarity index 74%
rename from src/app/spreed-webrtc-server/incoming_codec.go
rename to go/channelling/codec.go
index d3d0c3f0..55733797 100644
--- a/src/app/spreed-webrtc-server/incoming_codec.go
+++ b/go/channelling/codec.go
@@ -19,43 +19,45 @@
*
*/
-package main
+package channelling
import (
"bytes"
"encoding/json"
"errors"
"log"
+
+ "github.com/strukturag/spreed-webrtc/go/buffercache"
)
type IncomingDecoder interface {
- DecodeIncoming(Buffer) (*DataIncoming, error)
+ DecodeIncoming(buffercache.Buffer) (*DataIncoming, error)
}
type OutgoingEncoder interface {
- EncodeOutgoing(*DataOutgoing) (Buffer, error)
+ EncodeOutgoing(*DataOutgoing) (buffercache.Buffer, error)
}
type Codec interface {
- NewBuffer() Buffer
+ NewBuffer() buffercache.Buffer
IncomingDecoder
OutgoingEncoder
}
type incomingCodec struct {
- buffers BufferCache
+ buffers buffercache.BufferCache
incomingLimit int
}
func NewCodec(incomingLimit int) Codec {
- return &incomingCodec{NewBufferCache(1024, bytes.MinRead), incomingLimit}
+ return &incomingCodec{buffercache.NewBufferCache(1024, bytes.MinRead), incomingLimit}
}
-func (codec incomingCodec) NewBuffer() Buffer {
+func (codec incomingCodec) NewBuffer() buffercache.Buffer {
return codec.buffers.New()
}
-func (codec incomingCodec) DecodeIncoming(b Buffer) (*DataIncoming, error) {
+func (codec incomingCodec) DecodeIncoming(b buffercache.Buffer) (*DataIncoming, error) {
length := b.GetBuffer().Len()
if length > codec.incomingLimit {
return nil, errors.New("Incoming message size limit exceeded")
@@ -64,7 +66,7 @@ func (codec incomingCodec) DecodeIncoming(b Buffer) (*DataIncoming, error) {
return incoming, json.Unmarshal(b.Bytes(), incoming)
}
-func (codec incomingCodec) EncodeOutgoing(outgoing *DataOutgoing) (Buffer, error) {
+func (codec incomingCodec) EncodeOutgoing(outgoing *DataOutgoing) (buffercache.Buffer, error) {
b := codec.NewBuffer()
if err := json.NewEncoder(b).Encode(outgoing); err != nil {
log.Println("Error while encoding JSON", err)
diff --git a/src/app/spreed-webrtc-server/common_test.go b/go/channelling/common_test.go
similarity index 98%
rename from src/app/spreed-webrtc-server/common_test.go
rename to go/channelling/common_test.go
index 66bf4822..4ee11ced 100644
--- a/src/app/spreed-webrtc-server/common_test.go
+++ b/go/channelling/common_test.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"testing"
diff --git a/go/channelling/config.go b/go/channelling/config.go
new file mode 100644
index 00000000..c35b0b92
--- /dev/null
+++ b/go/channelling/config.go
@@ -0,0 +1,43 @@
+package channelling
+
+import (
+ "net/http"
+)
+
+type Config struct {
+ Title string // Title
+ Ver string `json:"-"` // Version (not exported to Javascript)
+ S string // Static URL prefix with version
+ B string // Base URL
+ Token string // Server token
+ Renegotiation bool // Renegotiation flag
+ StunURIs []string // STUN server URIs
+ TurnURIs []string // TURN server URIs
+ Tokens bool // True when we got a tokens file
+ Version string // Server version number
+ UsersEnabled bool // Flag if users are enabled
+ UsersAllowRegistration bool // Flag if users can register
+ UsersMode string // Users mode string
+ DefaultRoomEnabled bool // Flag if default room ("") is enabled
+ Plugin string // Plugin to load
+ AuthorizeRoomCreation bool // Whether a user account is required to create rooms
+ AuthorizeRoomJoin bool // Whether a user account is required to join rooms
+ Modules []string // List of enabled modules
+ ModulesTable map[string]bool `json:"-"` // Map of enabled modules
+ GlobalRoomID string `json:"-"` // Id of the global room (not exported to Javascript)
+ ContentSecurityPolicy string `json:"-"` // HTML content security policy
+ ContentSecurityPolicyReportOnly string `json:"-"` // HTML content security policy in report only mode
+ RoomTypeDefault string `json:"-"` // New rooms default to this type
+}
+
+func (config *Config) WithModule(m string) bool {
+ if val, ok := config.ModulesTable[m]; ok && val {
+ return true
+ }
+
+ return false
+}
+
+func (config *Config) Get(request *http.Request) (int, interface{}, http.Header) {
+ return 200, config, http.Header{"Content-Type": {"application/json; charset=utf-8"}}
+}
diff --git a/src/app/spreed-webrtc-server/connection.go b/go/channelling/connection.go
similarity index 92%
rename from src/app/spreed-webrtc-server/connection.go
rename to go/channelling/connection.go
index dc3fece1..d7f4cf0e 100644
--- a/src/app/spreed-webrtc-server/connection.go
+++ b/go/channelling/connection.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"container/list"
@@ -28,6 +28,8 @@ import (
"sync"
"time"
+ "github.com/strukturag/spreed-webrtc/go/buffercache"
+
"github.com/gorilla/websocket"
)
@@ -55,17 +57,17 @@ const (
type Connection interface {
Index() uint64
- Send(Buffer)
+ Send(buffercache.Buffer)
Close()
- readPump()
- writePump()
+ ReadPump()
+ WritePump()
}
type ConnectionHandler interface {
- NewBuffer() Buffer
+ NewBuffer() buffercache.Buffer
OnConnect(Connection)
OnDisconnect()
- OnText(Buffer)
+ OnText(buffercache.Buffer)
}
type connection struct {
@@ -116,7 +118,7 @@ func (c *connection) Close() {
break
}
c.queue.Remove(head)
- message := head.Value.(Buffer)
+ message := head.Value.(buffercache.Buffer)
message.Decref()
}
c.condition.Signal()
@@ -124,7 +126,7 @@ func (c *connection) Close() {
}
// readPump pumps messages from the websocket connection to the hub.
-func (c *connection) readPump() {
+func (c *connection) ReadPump() {
c.ws.SetReadLimit(maxMessageSize)
c.ws.SetReadDeadline(time.Now().Add(pongWait))
c.ws.SetPongHandler(func(string) error {
@@ -161,7 +163,7 @@ func (c *connection) readPump() {
times.PushBack(now)
message := c.handler.NewBuffer()
- err = readAll(message, r)
+ err = buffercache.ReadAll(message, r)
if err != nil {
message.Decref()
break
@@ -176,7 +178,7 @@ func (c *connection) readPump() {
}
// Write message to outbound queue.
-func (c *connection) Send(message Buffer) {
+func (c *connection) Send(message buffercache.Buffer) {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.isClosed {
@@ -190,11 +192,10 @@ func (c *connection) Send(message Buffer) {
message.Incref()
c.queue.PushBack(message)
c.condition.Signal()
-
}
// writePump pumps messages from the queue to the websocket connection.
-func (c *connection) writePump() {
+func (c *connection) WritePump() {
var timer *time.Timer
ping := false
@@ -232,7 +233,7 @@ func (c *connection) writePump() {
break
}
c.queue.Remove(head)
- message := head.Value.(Buffer)
+ message := head.Value.(buffercache.Buffer)
if ping {
// Send ping.
ping = false
diff --git a/src/app/spreed-webrtc-server/contact.go b/go/channelling/contact.go
similarity index 97%
rename from src/app/spreed-webrtc-server/contact.go
rename to go/channelling/contact.go
index 09588a33..f1fddbdf 100644
--- a/src/app/spreed-webrtc-server/contact.go
+++ b/go/channelling/contact.go
@@ -19,9 +19,7 @@
*
*/
-package main
-
-import ()
+package channelling
type Contact struct {
A string
diff --git a/go/channelling/contact_manager.go b/go/channelling/contact_manager.go
new file mode 100644
index 00000000..023056df
--- /dev/null
+++ b/go/channelling/contact_manager.go
@@ -0,0 +1,27 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type ContactManager interface {
+ ContactrequestHandler(*Session, string, *DataContactRequest) error
+ GetContactID(*Session, string) (string, error)
+}
diff --git a/src/app/spreed-webrtc-server/context.go b/go/channelling/context.go
similarity index 98%
rename from src/app/spreed-webrtc-server/context.go
rename to go/channelling/context.go
index 9df3b88c..1315e2f5 100644
--- a/src/app/spreed-webrtc-server/context.go
+++ b/go/channelling/context.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
type Context struct {
App string // Main client script
diff --git a/src/app/spreed-webrtc-server/channelling.go b/go/channelling/data.go
similarity index 99%
rename from src/app/spreed-webrtc-server/channelling.go
rename to go/channelling/data.go
index 78da0ad7..8456a839 100644
--- a/src/app/spreed-webrtc-server/channelling.go
+++ b/go/channelling/data.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
type DataError struct {
Type string
diff --git a/src/app/spreed-webrtc-server/hub.go b/go/channelling/hub.go
similarity index 84%
rename from src/app/spreed-webrtc-server/hub.go
rename to go/channelling/hub.go
index 6c4f9386..c06088cd 100644
--- a/src/app/spreed-webrtc-server/hub.go
+++ b/go/channelling/hub.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"crypto/aes"
@@ -36,35 +36,9 @@ import (
)
const (
- turnTTL = 3600 // XXX(longsleep): Add to config file.
- maxBroadcastPerSecond = 1000
- maxUsersLength = 5000
+ turnTTL = 3600 // XXX(longsleep): Add to config file.
)
-type SessionStore interface {
- GetSession(id string) (session *Session, ok bool)
-}
-
-type Unicaster interface {
- SessionStore
- OnConnect(Client, *Session)
- OnDisconnect(Client, *Session)
- Unicast(to string, outgoing *DataOutgoing)
-}
-
-type ContactManager interface {
- contactrequestHandler(*Session, string, *DataContactRequest) error
- getContactID(*Session, string) (string, error)
-}
-
-type TurnDataCreator interface {
- CreateTurnData(*Session) *DataTurn
-}
-
-type ClientStats interface {
- ClientInfo(details bool) (int, map[string]*DataSession, map[string]string)
-}
-
type Hub interface {
ClientStats
Unicaster
@@ -74,7 +48,7 @@ type Hub interface {
type hub struct {
OutgoingEncoder
- clients map[string]Client
+ clients map[string]*Client
config *Config
turnSecret []byte
mutex sync.RWMutex
@@ -82,10 +56,9 @@ type hub struct {
}
func NewHub(config *Config, sessionSecret, encryptionSecret, turnSecret []byte, encoder OutgoingEncoder) Hub {
-
h := &hub{
OutgoingEncoder: encoder,
- clients: make(map[string]Client),
+ clients: make(map[string]*Client),
config: config,
turnSecret: turnSecret,
}
@@ -94,8 +67,8 @@ func NewHub(config *Config, sessionSecret, encryptionSecret, turnSecret []byte,
h.contacts.MaxAge(0) // Forever
h.contacts.HashFunc(sha256.New)
h.contacts.BlockFunc(aes.NewCipher)
- return h
+ return h
}
func (h *hub) ClientInfo(details bool) (clientCount int, sessions map[string]*DataSession, connections map[string]string) {
@@ -119,7 +92,6 @@ func (h *hub) ClientInfo(details bool) (clientCount int, sessions map[string]*Da
}
func (h *hub) CreateTurnData(session *Session) *DataTurn {
-
// Create turn data credentials for shared secret auth with TURN
// server. See http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
// and https://code.google.com/p/rfc5766-turn-server/ REST API auth
@@ -136,20 +108,21 @@ func (h *hub) CreateTurnData(session *Session) *DataTurn {
user := fmt.Sprintf("%d:%s", expiration, id)
foo.Write([]byte(user))
password := base64.StdEncoding.EncodeToString(foo.Sum(nil))
- return &DataTurn{user, password, turnTTL, h.config.TurnURIs}
+ return &DataTurn{user, password, turnTTL, h.config.TurnURIs}
}
func (h *hub) GetSession(id string) (session *Session, ok bool) {
- var client Client
+ var client *Client
client, ok = h.GetClient(id)
if ok {
session = client.Session()
}
+
return
}
-func (h *hub) OnConnect(client Client, session *Session) {
+func (h *hub) OnConnect(client *Client, session *Session) {
h.mutex.Lock()
log.Printf("Created client %d with id %s\n", client.Index(), session.Id)
// Register connection or replace existing one.
@@ -161,7 +134,7 @@ func (h *hub) OnConnect(client Client, session *Session) {
h.mutex.Unlock()
}
-func (h *hub) OnDisconnect(client Client, session *Session) {
+func (h *hub) OnDisconnect(client *Client, session *Session) {
h.mutex.Lock()
if ec, ok := h.clients[session.Id]; ok {
if ec == client {
@@ -174,10 +147,11 @@ func (h *hub) OnDisconnect(client Client, session *Session) {
h.mutex.Unlock()
}
-func (h *hub) GetClient(sessionID string) (client Client, ok bool) {
+func (h *hub) GetClient(sessionID string) (client *Client, ok bool) {
h.mutex.RLock()
client, ok = h.clients[sessionID]
h.mutex.RUnlock()
+
return
}
@@ -193,7 +167,7 @@ func (h *hub) Unicast(to string, outgoing *DataOutgoing) {
}
}
-func (h *hub) getContactID(session *Session, token string) (userid string, err error) {
+func (h *hub) GetContactID(session *Session, token string) (userid string, err error) {
contact := &Contact{}
err = h.contacts.Decode("contact", token, contact)
if err != nil {
@@ -210,11 +184,11 @@ func (h *hub) getContactID(session *Session, token string) (userid string, err e
if userid == "" {
err = fmt.Errorf("Ignoring foreign contact token", contact.A, contact.B)
}
+
return
}
-func (h *hub) contactrequestHandler(session *Session, to string, cr *DataContactRequest) error {
-
+func (h *hub) ContactrequestHandler(session *Session, to string, cr *DataContactRequest) error {
var err error
if cr.Success {
@@ -274,5 +248,4 @@ func (h *hub) contactrequestHandler(session *Session, to string, cr *DataContact
}
return err
-
}
diff --git a/src/app/spreed-webrtc-server/images.go b/go/channelling/imagecache.go
similarity index 92%
rename from src/app/spreed-webrtc-server/images.go
rename to go/channelling/imagecache.go
index d18e4ce2..d2401c0f 100644
--- a/src/app/spreed-webrtc-server/images.go
+++ b/go/channelling/imagecache.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"bytes"
@@ -43,11 +43,25 @@ type Image struct {
data []byte
}
+func (img *Image) LastChangeID() string {
+ return img.lastChangeId
+}
+
+func (img *Image) LastChange() time.Time {
+ return img.lastChange
+}
+
+func (img *Image) MimeType() string {
+ return img.mimetype
+}
+
+func (img *Image) Reader() *bytes.Reader {
+ return bytes.NewReader(img.data)
+}
+
type ImageCache interface {
Update(sessionId string, image string) string
-
Get(imageId string) *Image
-
Delete(sessionId string)
}
@@ -136,6 +150,7 @@ func (self *imageCache) Update(sessionId string, image string) string {
if ok {
result += "/" + filename
}
+
return result
}
@@ -143,6 +158,7 @@ func (self *imageCache) Get(imageId string) *Image {
self.mutex.RLock()
image := self.images[imageId]
self.mutex.RUnlock()
+
return image
}
diff --git a/src/app/spreed-webrtc-server/nats.go b/go/channelling/nats.go
similarity index 99%
rename from src/app/spreed-webrtc-server/nats.go
rename to go/channelling/nats.go
index c8caa9b1..d06c4651 100644
--- a/src/app/spreed-webrtc-server/nats.go
+++ b/go/channelling/nats.go
@@ -1,4 +1,4 @@
-package main
+package channelling
import (
"errors"
diff --git a/src/app/spreed-webrtc-server/room_manager.go b/go/channelling/room_manager.go
similarity index 96%
rename from src/app/spreed-webrtc-server/room_manager.go
rename to go/channelling/room_manager.go
index 94ae53d2..c2063adc 100644
--- a/src/app/spreed-webrtc-server/room_manager.go
+++ b/go/channelling/room_manager.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"fmt"
@@ -65,8 +65,8 @@ func NewRoomManager(config *Config, encoder OutgoingEncoder) RoomManager {
OutgoingEncoder: encoder,
roomTable: make(map[string]RoomWorker),
}
- if config.globalRoomID != "" {
- rm.globalRoomID = rm.MakeRoomID(config.globalRoomID, "")
+ if config.GlobalRoomID != "" {
+ rm.globalRoomID = rm.MakeRoomID(config.GlobalRoomID, "")
}
rm.defaultRoomID = rm.MakeRoomID("", "")
return rm
@@ -111,7 +111,8 @@ func (rooms *roomManager) UpdateRoom(session *Session, room *DataRoom) (*DataRoo
return room, roomWorker.Update(room)
}
// Set default room type if room was not found.
- room.Type = rooms.roomTypeDefault
+ room.Type = rooms.RoomTypeDefault
+
// TODO(lcooper): We should almost certainly return an error in this case.
return room, nil
}
@@ -147,6 +148,7 @@ func (rooms *roomManager) RoomInfo(includeSessions bool) (count int, sessionInfo
sessionInfo[roomid] = room.SessionIDs()
}
}
+
return
}
@@ -154,6 +156,7 @@ func (rooms *roomManager) Get(roomID string) (room RoomWorker, ok bool) {
rooms.RLock()
room, ok = rooms.roomTable[roomID]
rooms.RUnlock()
+
return
}
@@ -211,7 +214,8 @@ func (rooms *roomManager) GlobalUsers() []*roomUser {
func (rooms *roomManager) MakeRoomID(roomName, roomType string) string {
if roomType == "" {
- roomType = rooms.roomTypeDefault
+ roomType = rooms.RoomTypeDefault
}
+
return fmt.Sprintf("%s:%s", roomType, roomName)
}
diff --git a/src/app/spreed-webrtc-server/room_manager_test.go b/go/channelling/room_manager_test.go
similarity index 98%
rename from src/app/spreed-webrtc-server/room_manager_test.go
rename to go/channelling/room_manager_test.go
index 5a2f5362..26a946c5 100644
--- a/src/app/spreed-webrtc-server/room_manager_test.go
+++ b/go/channelling/room_manager_test.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"testing"
@@ -27,7 +27,7 @@ import (
func NewTestRoomManager() (RoomManager, *Config) {
config := &Config{
- roomTypeDefault: "Room",
+ RoomTypeDefault: "Room",
}
return NewRoomManager(config, nil), config
}
diff --git a/src/app/spreed-webrtc-server/roomworker.go b/go/channelling/roomworker.go
similarity index 96%
rename from src/app/spreed-webrtc-server/roomworker.go
rename to go/channelling/roomworker.go
index 9302638d..8450f069 100644
--- a/src/app/spreed-webrtc-server/roomworker.go
+++ b/go/channelling/roomworker.go
@@ -19,18 +19,21 @@
*
*/
-package main
+package channelling
import (
"crypto/subtle"
"log"
"sync"
"time"
+
+ "github.com/strukturag/spreed-webrtc/go/buffercache"
)
const (
roomMaxWorkers = 10000
roomExpiryDuration = 60 * time.Second
+ maxUsersLength = 5000
)
type RoomWorker interface {
@@ -39,7 +42,7 @@ type RoomWorker interface {
Users() []*roomUser
Update(*DataRoom) error
GetUsers() []*DataSession
- Broadcast(sessionID string, buf Buffer)
+ Broadcast(sessionID string, buf buffercache.Buffer)
Join(*DataRoomCredentials, *Session, Sender) (*DataRoom, error)
Leave(sessionID string)
}
@@ -68,7 +71,6 @@ type roomUser struct {
}
func NewRoomWorker(manager *roomManager, roomID, roomName, roomType string, credentials *DataRoomCredentials) RoomWorker {
-
log.Printf("Creating worker for room '%s'\n", roomID)
r := &roomWorker{
@@ -91,11 +93,9 @@ func NewRoomWorker(manager *roomManager, roomID, roomName, roomType string, cred
})
return r
-
}
func (r *roomWorker) Start() {
-
// Main blocking worker.
L:
for {
@@ -122,7 +122,6 @@ L:
r.timer.Stop()
close(r.workers)
//fmt.Println("Exit worker", r.Id)
-
}
func (r *roomWorker) SessionIDs() []string {
@@ -132,23 +131,22 @@ func (r *roomWorker) SessionIDs() []string {
for id := range r.users {
sessions = append(sessions, id)
}
+
return sessions
}
func (r *roomWorker) Users() []*roomUser {
-
r.mutex.RLock()
defer r.mutex.RUnlock()
users := make([]*roomUser, 0, len(r.users))
for _, user := range r.users {
users = append(users, user)
}
- return users
+ return users
}
func (r *roomWorker) Run(f func()) bool {
-
select {
case r.workers <- f:
return true
@@ -156,7 +154,6 @@ func (r *roomWorker) Run(f func()) bool {
log.Printf("Room worker channel full or closed '%s'\n", r.id)
return false
}
-
}
func (r *roomWorker) Update(room *DataRoom) error {
@@ -178,6 +175,7 @@ func (r *roomWorker) Update(room *DataRoom) error {
fault <- nil
}
r.Run(worker)
+
return <-fault
}
@@ -223,8 +221,7 @@ func (r *roomWorker) GetUsers() []*DataSession {
return <-out
}
-func (r *roomWorker) Broadcast(sessionID string, message Buffer) {
-
+func (r *roomWorker) Broadcast(sessionID string, message buffercache.Buffer) {
worker := func() {
r.mutex.RLock()
for id, user := range r.users {
@@ -241,7 +238,6 @@ func (r *roomWorker) Broadcast(sessionID string, message Buffer) {
message.Incref()
r.Run(worker)
-
}
type joinResult struct {
@@ -280,6 +276,7 @@ func (r *roomWorker) Join(credentials *DataRoomCredentials, session *Session, se
}
r.Run(worker)
result := <-results
+
return result.DataRoom, result.error
}
diff --git a/src/app/spreed-webrtc-server/roomworker_test.go b/go/channelling/roomworker_test.go
similarity index 99%
rename from src/app/spreed-webrtc-server/roomworker_test.go
rename to go/channelling/roomworker_test.go
index 1ada20b3..e2d1d7e2 100644
--- a/src/app/spreed-webrtc-server/roomworker_test.go
+++ b/go/channelling/roomworker_test.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"testing"
diff --git a/src/app/spreed-webrtc-server/api.go b/go/channelling/server/api.go
similarity index 98%
rename from src/app/spreed-webrtc-server/api.go
rename to go/channelling/server/api.go
index 0fa83666..89297ca9 100644
--- a/src/app/spreed-webrtc-server/api.go
+++ b/go/channelling/server/api.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package server
import ()
diff --git a/src/app/spreed-webrtc-server/config.go b/go/channelling/server/config.go
similarity index 60%
rename from src/app/spreed-webrtc-server/config.go
rename to go/channelling/server/config.go
index 89a14c54..e35f0305 100644
--- a/src/app/spreed-webrtc-server/config.go
+++ b/go/channelling/server/config.go
@@ -19,44 +19,20 @@
*
*/
-package main
+package server
import (
"fmt"
- "github.com/strukturag/phoenix"
"log"
- "net/http"
"strings"
"time"
-)
-type Config struct {
- Title string // Title
- ver string // Version (not exported to Javascript)
- S string // Static URL prefix with version
- B string // Base URL
- Token string // Server token
- Renegotiation bool // Renegotiation flag
- StunURIs []string // STUN server URIs
- TurnURIs []string // TURN server URIs
- Tokens bool // True when we got a tokens file
- Version string // Server version number
- UsersEnabled bool // Flag if users are enabled
- UsersAllowRegistration bool // Flag if users can register
- UsersMode string // Users mode string
- DefaultRoomEnabled bool // Flag if default room ("") is enabled
- Plugin string // Plugin to load
- AuthorizeRoomCreation bool // Whether a user account is required to create rooms
- AuthorizeRoomJoin bool // Whether a user account is required to join rooms
- Modules []string // List of enabled modules
- modulesTable map[string]bool // Map of enabled modules
- globalRoomID string // Id of the global room (not exported to Javascript)
- contentSecurityPolicy string // HTML content security policy
- contentSecurityPolicyReportOnly string // HTML content security policy in report only mode
- roomTypeDefault string // New rooms default to this type
-}
+ "github.com/strukturag/spreed-webrtc/go/channelling"
-func NewConfig(container phoenix.Container, tokens bool) *Config {
+ "github.com/strukturag/phoenix"
+)
+
+func NewConfig(container phoenix.Container, tokens bool) *channelling.Config {
ver := container.GetStringDefault("app", "ver", "")
version := container.Version()
@@ -107,9 +83,9 @@ func NewConfig(container phoenix.Container, tokens bool) *Config {
}
log.Println("Enabled modules:", modules)
- return &Config{
+ return &channelling.Config{
Title: container.GetStringDefault("app", "title", "Spreed WebRTC"),
- ver: ver,
+ Ver: ver,
S: fmt.Sprintf("static/ver=%s", ver),
B: basePath,
Token: serverToken,
@@ -126,27 +102,14 @@ func NewConfig(container phoenix.Container, tokens bool) *Config {
AuthorizeRoomCreation: container.GetBoolDefault("app", "authorizeRoomCreation", false),
AuthorizeRoomJoin: container.GetBoolDefault("app", "authorizeRoomJoin", false),
Modules: modules,
- modulesTable: modulesTable,
- globalRoomID: container.GetStringDefault("app", "globalRoom", ""),
- contentSecurityPolicy: container.GetStringDefault("app", "contentSecurityPolicy", ""),
- contentSecurityPolicyReportOnly: container.GetStringDefault("app", "contentSecurityPolicyReportOnly", ""),
- roomTypeDefault: "Room",
+ ModulesTable: modulesTable,
+ GlobalRoomID: container.GetStringDefault("app", "globalRoom", ""),
+ ContentSecurityPolicy: container.GetStringDefault("app", "contentSecurityPolicy", ""),
+ ContentSecurityPolicyReportOnly: container.GetStringDefault("app", "contentSecurityPolicyReportOnly", ""),
+ RoomTypeDefault: "Room",
}
}
-func (config *Config) Get(request *http.Request) (int, interface{}, http.Header) {
- return 200, config, http.Header{"Content-Type": {"application/json; charset=utf-8"}}
-}
-
-func (config *Config) WithModule(m string) bool {
-
- if val, ok := config.modulesTable[m]; ok && val {
- return true
- }
- return false
-
-}
-
// Helper function to clean up string arrays.
func trimAndRemoveDuplicates(data *[]string) {
found := make(map[string]bool)
diff --git a/src/app/spreed-webrtc-server/rooms.go b/go/channelling/server/rooms.go
similarity index 90%
rename from src/app/spreed-webrtc-server/rooms.go
rename to go/channelling/server/rooms.go
index bea8b90d..4172ce8d 100644
--- a/src/app/spreed-webrtc-server/rooms.go
+++ b/go/channelling/server/rooms.go
@@ -19,11 +19,13 @@
*
*/
-package main
+package server
import (
"fmt"
"net/http"
+
+ "github.com/strukturag/spreed-webrtc/go/randomstring"
)
type Room struct {
@@ -36,7 +38,7 @@ type Rooms struct {
func (rooms *Rooms) Post(request *http.Request) (int, interface{}, http.Header) {
- name := NewRandomString(11)
+ name := randomstring.NewRandomString(11)
return 200, &Room{name, fmt.Sprintf("/%s", name)}, http.Header{"Content-Type": {"application/json"}}
}
diff --git a/src/app/spreed-webrtc-server/sessions.go b/go/channelling/server/sessions.go
similarity index 90%
rename from src/app/spreed-webrtc-server/sessions.go
rename to go/channelling/server/sessions.go
index 1c22c2ea..0b5af21b 100644
--- a/src/app/spreed-webrtc-server/sessions.go
+++ b/go/channelling/server/sessions.go
@@ -19,14 +19,17 @@
*
*/
-package main
+package server
import (
"encoding/json"
"errors"
- "github.com/gorilla/mux"
"log"
"net/http"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+
+ "github.com/gorilla/mux"
)
type SessionNonce struct {
@@ -43,9 +46,9 @@ type SessionNonceRequest struct {
}
type Sessions struct {
- SessionValidator
- SessionStore
- users *Users
+ channelling.SessionValidator
+ channelling.SessionStore
+ Users *Users
}
// Patch is used to add a userid to a given session (login).
@@ -87,8 +90,8 @@ func (sessions *Sessions) Patch(request *http.Request) (int, interface{}, http.H
var userid string
// Validate with users handler.
- if sessions.users.handler != nil {
- userid, err = sessions.users.handler.Validate(&snr, request)
+ if sessions.Users.handler != nil {
+ userid, err = sessions.Users.handler.Validate(&snr, request)
if err != nil {
error = true
log.Println("Session patch failed - users validation failed.", err)
@@ -107,7 +110,7 @@ func (sessions *Sessions) Patch(request *http.Request) (int, interface{}, http.H
if !error {
// FIXME(longsleep): Not running this might reveal error state with a timing attack.
if session, ok := sessions.GetSession(snr.Id); ok {
- nonce, err = session.Authorize(sessions.Realm(), &SessionToken{Id: snr.Id, Sid: snr.Sid, Userid: userid})
+ nonce, err = session.Authorize(sessions.Realm(), &channelling.SessionToken{Id: snr.Id, Sid: snr.Sid, Userid: userid})
} else {
err = errors.New("no such session")
}
diff --git a/src/app/spreed-webrtc-server/stats.go b/go/channelling/server/stats.go
similarity index 88%
rename from src/app/spreed-webrtc-server/stats.go
rename to go/channelling/server/stats.go
index 5318175c..5ad2bf64 100644
--- a/src/app/spreed-webrtc-server/stats.go
+++ b/go/channelling/server/stats.go
@@ -19,21 +19,23 @@
*
*/
-package main
+package server
import (
"net/http"
"runtime"
"time"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
)
type Stat struct {
details bool
- Runtime *RuntimeStat `json:"runtime"`
- Hub *HubStat `json:"hub"`
+ Runtime *RuntimeStat `json:"runtime"`
+ Hub *channelling.HubStat `json:"hub"`
}
-func NewStat(details bool, statsGenerator StatsGenerator) *Stat {
+func NewStat(details bool, statsGenerator channelling.StatsGenerator) *Stat {
stat := &Stat{
details: details,
Runtime: &RuntimeStat{},
@@ -69,7 +71,7 @@ func (stat *RuntimeStat) Read() {
}
type Stats struct {
- StatsGenerator
+ channelling.StatsGenerator
}
func (stats *Stats) Get(request *http.Request) (int, interface{}, http.Header) {
diff --git a/src/app/spreed-webrtc-server/tls.go b/go/channelling/server/tls.go
similarity index 99%
rename from src/app/spreed-webrtc-server/tls.go
rename to go/channelling/server/tls.go
index a431c72c..12791098 100644
--- a/src/app/spreed-webrtc-server/tls.go
+++ b/go/channelling/server/tls.go
@@ -32,7 +32,7 @@
*
*/
-package main
+package server
import (
"crypto"
diff --git a/src/app/spreed-webrtc-server/tokens.go b/go/channelling/server/tokens.go
similarity index 90%
rename from src/app/spreed-webrtc-server/tokens.go
rename to go/channelling/server/tokens.go
index d492d265..b7eff094 100644
--- a/src/app/spreed-webrtc-server/tokens.go
+++ b/go/channelling/server/tokens.go
@@ -19,12 +19,14 @@
*
*/
-package main
+package server
import (
"log"
"net/http"
"strings"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
)
type Token struct {
@@ -33,7 +35,7 @@ type Token struct {
}
type Tokens struct {
- provider TokenProvider
+ Provider channelling.TokenProvider
}
func (tokens Tokens) Post(request *http.Request) (int, interface{}, http.Header) {
@@ -44,7 +46,7 @@ func (tokens Tokens) Post(request *http.Request) (int, interface{}, http.Header)
return 413, NewApiError("auth_too_large", "Auth too large"), http.Header{"Content-Type": {"application/json"}}
}
- valid := tokens.provider(strings.ToLower(auth))
+ valid := tokens.Provider(strings.ToLower(auth))
if valid != "" {
log.Printf("Good incoming token request: %s\n", auth)
diff --git a/src/app/spreed-webrtc-server/users.go b/go/channelling/server/users.go
similarity index 96%
rename from src/app/spreed-webrtc-server/users.go
rename to go/channelling/server/users.go
index 6dac32bb..3898808e 100644
--- a/src/app/spreed-webrtc-server/users.go
+++ b/go/channelling/server/users.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package server
import (
"crypto"
@@ -34,15 +34,18 @@ import (
"encoding/pem"
"errors"
"fmt"
- "github.com/longsleep/pkac"
- "github.com/satori/go.uuid"
- "github.com/strukturag/phoenix"
"log"
"math/big"
"net/http"
"strconv"
"strings"
"time"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+
+ "github.com/longsleep/pkac"
+ "github.com/satori/go.uuid"
+ "github.com/strukturag/phoenix"
)
var (
@@ -290,14 +293,14 @@ func (un *UserNonce) Response() (int, interface{}, http.Header) {
}
type Users struct {
- SessionValidator
- SessionManager
- SessionStore
+ channelling.SessionValidator
+ channelling.SessionManager
+ channelling.SessionStore
realm string
handler UsersHandler
}
-func NewUsers(sessionStore SessionStore, sessionValidator SessionValidator, sessionManager SessionManager, mode, realm string, runtime phoenix.Runtime) *Users {
+func NewUsers(sessionStore channelling.SessionStore, sessionValidator channelling.SessionValidator, sessionManager channelling.SessionManager, mode, realm string, runtime phoenix.Runtime) *Users {
var users = &Users{
sessionValidator,
@@ -463,7 +466,7 @@ func (users *Users) Post(request *http.Request) (int, interface{}, http.Header)
err error
)
if session, ok := users.GetSession(snr.Id); ok {
- nonce, err = session.Authorize(users.Realm(), &SessionToken{Id: snr.Id, Sid: snr.Sid, Userid: userid})
+ nonce, err = session.Authorize(users.Realm(), &channelling.SessionToken{Id: snr.Id, Sid: snr.Sid, Userid: userid})
} else {
err = errors.New("no such session")
}
diff --git a/src/app/spreed-webrtc-server/session.go b/go/channelling/session.go
similarity index 86%
rename from src/app/spreed-webrtc-server/session.go
rename to go/channelling/session.go
index 84043147..82c17c39 100644
--- a/src/app/spreed-webrtc-server/session.go
+++ b/go/channelling/session.go
@@ -19,14 +19,15 @@
*
*/
-package main
+package channelling
import (
"fmt"
- "github.com/gorilla/securecookie"
"strings"
"sync"
"time"
+
+ "github.com/gorilla/securecookie"
)
var sessionNonces *securecookie.SecureCookie
@@ -58,8 +59,14 @@ type Session struct {
replaced bool
}
-func NewSession(manager SessionManager, unicaster Unicaster, broadcaster Broadcaster, rooms RoomStatusManager, buddyImages ImageCache, attestations *securecookie.SecureCookie, id, sid string) *Session {
-
+func NewSession(manager SessionManager,
+ unicaster Unicaster,
+ broadcaster Broadcaster,
+ rooms RoomStatusManager,
+ buddyImages ImageCache,
+ attestations *securecookie.SecureCookie,
+ id,
+ sid string) *Session {
session := &Session{
SessionManager: manager,
Unicaster: unicaster,
@@ -75,8 +82,8 @@ func NewSession(manager SessionManager, unicaster Unicaster, broadcaster Broadca
subscribers: make(map[string]*Session),
}
session.NewAttestation()
- return session
+ return session
}
func (s *Session) authenticated() (authenticated bool) {
@@ -152,6 +159,7 @@ func (s *Session) JoinRoom(roomName, roomType string, credentials *DataRoomCrede
} else {
s.Hello = false
}
+
return room, err
}
@@ -248,7 +256,6 @@ func (s *Session) Close() {
}
func (s *Session) Replace(oldSession *Session) {
-
oldSession.mutex.Lock()
if oldSession.disconnected {
oldSession.mutex.Unlock()
@@ -265,7 +272,6 @@ func (s *Session) Replace(oldSession *Session) {
// Mark old session as replaced.
oldSession.replaced = true
oldSession.mutex.Unlock()
-
}
func (s *Session) Update(update *SessionUpdate) uint64 {
@@ -301,11 +307,9 @@ func (s *Session) Update(update *SessionUpdate) uint64 {
s.UpdateRev++
return s.UpdateRev
-
}
func (s *Session) Authorize(realm string, st *SessionToken) (string, error) {
-
s.mutex.Lock()
defer s.mutex.Unlock()
@@ -324,11 +328,9 @@ func (s *Session) Authorize(realm string, st *SessionToken) (string, error) {
}
return s.Nonce, err
-
}
func (s *Session) Authenticate(realm string, st *SessionToken, userid string) error {
-
s.mutex.Lock()
defer s.mutex.Unlock()
@@ -352,12 +354,11 @@ func (s *Session) Authenticate(realm string, st *SessionToken, userid string) er
s.userid = userid
s.stamp = time.Now().Unix()
s.UpdateRev++
- return nil
+ return nil
}
func (s *Session) Token() *SessionToken {
-
s.mutex.RLock()
defer s.mutex.RUnlock()
@@ -365,7 +366,6 @@ func (s *Session) Token() *SessionToken {
}
func (s *Session) Data() *DataSession {
-
s.mutex.RLock()
defer s.mutex.RUnlock()
@@ -378,25 +378,21 @@ func (s *Session) Data() *DataSession {
Prio: s.Prio,
stamp: s.stamp,
}
-
}
func (s *Session) Userid() (userid string) {
-
s.mutex.RLock()
userid = s.userid
s.mutex.RUnlock()
- return
+ return
}
func (s *Session) SetUseridFake(userid string) {
-
s.mutex.Lock()
s.userid = userid
s.fake = true
s.mutex.Unlock()
-
}
func (s *Session) NewAttestation() {
@@ -406,58 +402,14 @@ func (s *Session) NewAttestation() {
s.attestation.Update()
}
-func (s *Session) UpdateAttestation() {
+func (s *Session) UpdateAttestation() (string, error) {
s.mutex.Lock()
- s.attestation.Update()
- s.mutex.Unlock()
-}
-
-type SessionUpdate struct {
- Types []string
- Ua string
- Prio int
- Status interface{}
-}
-
-type SessionToken struct {
- Id string // Public session id.
- Sid string // Secret session id.
- Userid string // Public user id.
- Nonce string `json:"Nonce,omitempty"` // User autentication nonce.
-}
-
-type SessionAttestation struct {
- refresh int64
- token string
- s *Session
-}
-
-func (sa *SessionAttestation) Update() (string, error) {
- token, err := sa.Encode()
- if err == nil {
- sa.token = token
- sa.refresh = time.Now().Unix() + 180 // expires after 3 minutes
- }
- return token, err
-}
-
-func (sa *SessionAttestation) Token() (token string) {
- if sa.refresh < time.Now().Unix() {
- token, _ = sa.Update()
- } else {
- token = sa.token
- }
- return
-}
-
-func (sa *SessionAttestation) Encode() (string, error) {
- return sa.s.attestations.Encode("attestation", sa.s.Id)
+ defer s.mutex.Unlock()
+ return s.attestation.Update()
}
-func (sa *SessionAttestation) Decode(token string) (string, error) {
- var id string
- err := sa.s.attestations.Decode("attestation", token, &id)
- return id, err
+func (s *Session) DecodeAttestation(token string) (string, error) {
+ return s.attestation.Decode(token)
}
func init() {
diff --git a/src/app/spreed-webrtc-server/session_manager.go b/go/channelling/session_manager.go
similarity index 99%
rename from src/app/spreed-webrtc-server/session_manager.go
rename to go/channelling/session_manager.go
index 3ba91525..7decaa9c 100644
--- a/src/app/spreed-webrtc-server/session_manager.go
+++ b/go/channelling/session_manager.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"crypto/sha256"
@@ -89,6 +89,7 @@ func (sessionManager *sessionManager) UserInfo(details bool) (userCount int, use
users[userid] = user.Data()
}
}
+
return
}
@@ -149,6 +150,7 @@ func (sessionManager *sessionManager) Authenticate(session *Session, st *Session
}
sessionManager.Unlock()
user.AddSession(session)
+
return nil
}
@@ -177,5 +179,6 @@ func (sessionManager *sessionManager) GetUserSessions(session *Session, userid s
// Add sessions for foreign user.
users = user.SubscribeSessions(session)
}
+
return
}
diff --git a/go/channelling/sessionattestation.go b/go/channelling/sessionattestation.go
new file mode 100644
index 00000000..a180451c
--- /dev/null
+++ b/go/channelling/sessionattestation.go
@@ -0,0 +1,60 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+import (
+ "time"
+)
+
+type SessionAttestation struct {
+ refresh int64
+ token string
+ s *Session
+}
+
+func (sa *SessionAttestation) Update() (string, error) {
+ token, err := sa.Encode()
+ if err == nil {
+ sa.token = token
+ sa.refresh = time.Now().Unix() + 180 // expires after 3 minutes
+ }
+ return token, err
+}
+
+func (sa *SessionAttestation) Token() (token string) {
+ if sa.refresh < time.Now().Unix() {
+ token, _ = sa.Update()
+ } else {
+ token = sa.token
+ }
+ return
+}
+
+func (sa *SessionAttestation) Encode() (string, error) {
+ return sa.s.attestations.Encode("attestation", sa.s.Id)
+}
+
+func (sa *SessionAttestation) Decode(token string) (string, error) {
+ var id string
+ err := sa.s.attestations.Decode("attestation", token, &id)
+ return id, err
+}
diff --git a/go/channelling/sessionstore.go b/go/channelling/sessionstore.go
new file mode 100644
index 00000000..8b11a05b
--- /dev/null
+++ b/go/channelling/sessionstore.go
@@ -0,0 +1,26 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type SessionStore interface {
+ GetSession(id string) (session *Session, ok bool)
+}
diff --git a/go/channelling/sessiontoken.go b/go/channelling/sessiontoken.go
new file mode 100644
index 00000000..189375f5
--- /dev/null
+++ b/go/channelling/sessiontoken.go
@@ -0,0 +1,29 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type SessionToken struct {
+ Id string // Public session id.
+ Sid string // Secret session id.
+ Userid string // Public user id.
+ Nonce string `json:"Nonce,omitempty"` // User autentication nonce.
+}
diff --git a/go/channelling/sessionupdate.go b/go/channelling/sessionupdate.go
new file mode 100644
index 00000000..8b4ac0ae
--- /dev/null
+++ b/go/channelling/sessionupdate.go
@@ -0,0 +1,29 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type SessionUpdate struct {
+ Types []string
+ Ua string
+ Prio int
+ Status interface{}
+}
diff --git a/src/app/spreed-webrtc-server/stats_manager.go b/go/channelling/stats_manager.go
similarity index 99%
rename from src/app/spreed-webrtc-server/stats_manager.go
rename to go/channelling/stats_manager.go
index d2507db0..3c73dd06 100644
--- a/src/app/spreed-webrtc-server/stats_manager.go
+++ b/go/channelling/stats_manager.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"sync/atomic"
diff --git a/src/app/spreed-webrtc-server/tickets.go b/go/channelling/tickets.go
similarity index 94%
rename from src/app/spreed-webrtc-server/tickets.go
rename to go/channelling/tickets.go
index f75cc1d4..90145e1e 100644
--- a/src/app/spreed-webrtc-server/tickets.go
+++ b/go/channelling/tickets.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"crypto/aes"
@@ -29,6 +29,8 @@ import (
"fmt"
"log"
+ "github.com/strukturag/spreed-webrtc/go/randomstring"
+
"github.com/gorilla/securecookie"
)
@@ -86,7 +88,7 @@ func (tickets *tickets) DecodeSessionToken(token string) (st *SessionToken) {
}
if st == nil || err != nil {
- sid := NewRandomString(32)
+ sid := randomstring.NewRandomString(32)
id, _ := tickets.Encode("id", sid)
st = &SessionToken{Id: id, Sid: sid}
log.Println("Created new session id", id)
@@ -96,7 +98,7 @@ func (tickets *tickets) DecodeSessionToken(token string) (st *SessionToken) {
func (tickets *tickets) FakeSessionToken(userid string) *SessionToken {
st := &SessionToken{}
- st.Sid = fmt.Sprintf("fake-%s", NewRandomString(27))
+ st.Sid = fmt.Sprintf("fake-%s", randomstring.NewRandomString(27))
st.Id, _ = tickets.Encode("id", st.Sid)
st.Userid = userid
log.Println("Created new fake session id", st.Id)
diff --git a/src/app/spreed-webrtc-server/tokenprovider.go b/go/channelling/tokenprovider.go
similarity index 98%
rename from src/app/spreed-webrtc-server/tokenprovider.go
rename to go/channelling/tokenprovider.go
index f93fb853..a17fb826 100644
--- a/src/app/spreed-webrtc-server/tokenprovider.go
+++ b/go/channelling/tokenprovider.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"encoding/csv"
@@ -47,11 +47,11 @@ func (tf *TokenFile) ReloadIfModified() error {
tf.Info = info
tf.Reload()
}
+
return nil
}
func reloadRokens(tf *TokenFile) {
-
r, err := os.Open(tf.Path)
if err != nil {
panic(err)
@@ -71,11 +71,9 @@ func reloadRokens(tf *TokenFile) {
for _, record := range records {
tf.Tokens[strings.ToLower(record[0])] = true
}
-
}
func TokenFileProvider(filename string) TokenProvider {
-
tf := &TokenFile{Path: filename}
tf.Reload = func() { reloadRokens(tf) }
return func(token string) string {
@@ -86,5 +84,4 @@ func TokenFileProvider(filename string) TokenProvider {
}
return token
}
-
}
diff --git a/go/channelling/turndata.go b/go/channelling/turndata.go
new file mode 100644
index 00000000..71002494
--- /dev/null
+++ b/go/channelling/turndata.go
@@ -0,0 +1,26 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type TurnDataCreator interface {
+ CreateTurnData(*Session) *DataTurn
+}
diff --git a/go/channelling/unicaster.go b/go/channelling/unicaster.go
new file mode 100644
index 00000000..7f69474b
--- /dev/null
+++ b/go/channelling/unicaster.go
@@ -0,0 +1,29 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package channelling
+
+type Unicaster interface {
+ SessionStore
+ OnConnect(*Client, *Session)
+ OnDisconnect(*Client, *Session)
+ Unicast(to string, outgoing *DataOutgoing)
+}
diff --git a/src/app/spreed-webrtc-server/user.go b/go/channelling/user.go
similarity index 99%
rename from src/app/spreed-webrtc-server/user.go
rename to go/channelling/user.go
index c6e2b279..56aaddea 100644
--- a/src/app/spreed-webrtc-server/user.go
+++ b/go/channelling/user.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package channelling
import (
"log"
@@ -34,13 +34,12 @@ type User struct {
}
func NewUser(id string) *User {
-
user := &User{
Id: id,
sessionTable: make(map[string]*Session),
}
- return user
+ return user
}
// AddSession adds a session to the session table and returns true if
@@ -54,6 +53,7 @@ func (u *User) AddSession(s *Session) bool {
first = true
}
u.mutex.Unlock()
+
return first
}
@@ -68,12 +68,14 @@ func (u *User) RemoveSession(sessionID string) bool {
last = true
}
u.mutex.Unlock()
+
return last
}
func (u *User) Data() *DataUser {
u.mutex.RLock()
defer u.mutex.RUnlock()
+
return &DataUser{
Id: u.Id,
Sessions: len(u.sessionTable),
@@ -81,7 +83,6 @@ func (u *User) Data() *DataUser {
}
func (u *User) SubscribeSessions(from *Session) []*DataSession {
-
sessions := make([]*DataSession, 0, len(u.sessionTable))
u.mutex.RLock()
defer u.mutex.RUnlock()
@@ -91,8 +92,8 @@ func (u *User) SubscribeSessions(from *Session) []*DataSession {
sessions = append(sessions, session.Data())
}
sort.Sort(ByPrioAndStamp(sessions))
- return sessions
+ return sessions
}
type ByPrioAndStamp []*DataSession
@@ -112,5 +113,6 @@ func (a ByPrioAndStamp) Less(i, j int) bool {
if a[i].Prio == a[j].Prio {
return a[i].stamp < a[j].stamp
}
+
return false
}
diff --git a/src/app/spreed-webrtc-server/random.go b/go/randomstring/randomstring.go
similarity index 98%
rename from src/app/spreed-webrtc-server/random.go
rename to go/randomstring/randomstring.go
index 23e827a8..8f2ae2e9 100644
--- a/src/app/spreed-webrtc-server/random.go
+++ b/go/randomstring/randomstring.go
@@ -19,7 +19,7 @@
*
*/
-package main
+package randomstring
import (
"crypto/rand"
diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go
deleted file mode 100644
index 5a3c1c22..00000000
--- a/src/app/spreed-webrtc-server/channelling_api.go
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Spreed WebRTC.
- * Copyright (C) 2013-2015 struktur AG
- *
- * This file is part of Spreed WebRTC.
- *
- * 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 .
- *
- */
-
-package main
-
-import (
- "log"
- "time"
-)
-
-const (
- maxConferenceSize = 100
- apiVersion = 1.4 // Keep this in sync with CHANNELING-API docs.Hand
-)
-
-type ChannellingAPI interface {
- OnConnect(Client, *Session) (interface{}, error)
- OnDisconnect(Client, *Session)
- OnIncoming(Sender, *Session, *DataIncoming) (interface{}, error)
-}
-
-type channellingAPI struct {
- *Config
- RoomStatusManager
- SessionEncoder
- SessionManager
- StatsCounter
- ContactManager
- TurnDataCreator
- Unicaster
- BusManager
-}
-
-// NewChannellingAPI creates and initializes a new ChannellingAPI using
-// various other services for initialization. It is intended to handle
-// incoming and outgoing channeling API events from clients.
-func NewChannellingAPI(config *Config, roomStatus RoomStatusManager, sessionEncoder SessionEncoder, sessionManager SessionManager, statsCounter StatsCounter, contactManager ContactManager, turnDataCreator TurnDataCreator, unicaster Unicaster, busManager BusManager) ChannellingAPI {
- return &channellingAPI{
- config,
- roomStatus,
- sessionEncoder,
- sessionManager,
- statsCounter,
- contactManager,
- turnDataCreator,
- unicaster,
- busManager,
- }
-}
-
-func (api *channellingAPI) OnConnect(client Client, session *Session) (interface{}, error) {
- api.Unicaster.OnConnect(client, session)
- self, err := api.HandleSelf(session)
- if err == nil {
- api.Trigger(BusManagerConnect, session.Id, "", nil)
- }
- return self, err
-}
-
-func (api *channellingAPI) OnDisconnect(client Client, session *Session) {
- api.Unicaster.OnDisconnect(client, session)
- api.Trigger(BusManagerDisconnect, session.Id, "", nil)
-}
-
-func (api *channellingAPI) OnIncoming(sender Sender, session *Session, msg *DataIncoming) (interface{}, error) {
- switch msg.Type {
- case "Self":
- return api.HandleSelf(session)
- case "Hello":
- if msg.Hello == nil {
- return nil, NewDataError("bad_request", "message did not contain Hello")
- }
-
- return api.HandleHello(session, msg.Hello, sender)
- case "Offer":
- if msg.Offer == nil || msg.Offer.Offer == nil {
- log.Println("Received invalid offer message.", msg)
- break
- }
- if _, ok := msg.Offer.Offer["_token"]; !ok {
- // Trigger offer event when offer has no token, so this is
- // not triggered for peerxfer and peerscreenshare offers.
- api.Trigger(BusManagerOffer, session.Id, msg.Offer.To, nil)
- }
-
- session.Unicast(msg.Offer.To, msg.Offer)
- case "Candidate":
- if msg.Candidate == nil || msg.Candidate.Candidate == nil {
- log.Println("Received invalid candidate message.", msg)
- break
- }
-
- session.Unicast(msg.Candidate.To, msg.Candidate)
- case "Answer":
- if msg.Answer == nil || msg.Answer.Answer == nil {
- log.Println("Received invalid answer message.", msg)
- break
- }
- if _, ok := msg.Answer.Answer["_token"]; !ok {
- // Trigger answer event when answer has no token. so this is
- // not triggered for peerxfer and peerscreenshare answers.
- api.Trigger(BusManagerAnswer, session.Id, msg.Answer.To, nil)
- }
-
- session.Unicast(msg.Answer.To, msg.Answer)
- case "Users":
- return api.HandleUsers(session)
- case "Authentication":
- if msg.Authentication == nil || msg.Authentication.Authentication == nil {
- return nil, NewDataError("bad_request", "message did not contain Authentication")
- }
-
- return api.HandleAuthentication(session, msg.Authentication.Authentication)
- case "Bye":
- if msg.Bye == nil {
- log.Println("Received invalid bye message.", msg)
- break
- }
- api.Trigger(BusManagerBye, session.Id, msg.Bye.To, nil)
-
- session.Unicast(msg.Bye.To, msg.Bye)
- case "Status":
- if msg.Status == nil {
- log.Println("Received invalid status message.", msg)
- break
- }
-
- //log.Println("Status", msg.Status)
- session.Update(&SessionUpdate{Types: []string{"Status"}, Status: msg.Status.Status})
- session.BroadcastStatus()
- case "Chat":
- if msg.Chat == nil || msg.Chat.Chat == nil {
- log.Println("Received invalid chat message.", msg)
- break
- }
-
- api.HandleChat(session, msg.Chat)
- case "Conference":
- if msg.Conference == nil {
- log.Println("Received invalid conference message.", msg)
- break
- }
-
- api.HandleConference(session, msg.Conference)
- case "Alive":
- return msg.Alive, nil
- case "Sessions":
- if msg.Sessions == nil || msg.Sessions.Sessions == nil {
- return nil, NewDataError("bad_request", "message did not contain Sessions")
- }
-
- return api.HandleSessions(session, msg.Sessions.Sessions)
- case "Room":
- if msg.Room == nil {
- return nil, NewDataError("bad_request", "message did not contain Room")
- }
-
- return api.HandleRoom(session, msg.Room)
- default:
- log.Println("OnText unhandled message type", msg.Type)
- }
-
- return nil, nil
-}
-
-func (api *channellingAPI) HandleSelf(session *Session) (*DataSelf, error) {
- token, err := api.EncodeSessionToken(session)
- if err != nil {
- log.Println("Error in OnRegister", err)
- return nil, err
- }
-
- log.Println("Created new session token", len(token), token)
- self := &DataSelf{
- Type: "Self",
- Id: session.Id,
- Sid: session.Sid,
- Userid: session.Userid(),
- Suserid: api.EncodeSessionUserID(session),
- Token: token,
- Version: api.Version,
- ApiVersion: apiVersion,
- Turn: api.CreateTurnData(session),
- Stun: api.StunURIs,
- }
- api.Trigger(BusManagerSession, session.Id, session.Userid(), nil)
-
- return self, nil
-}
-
-func (api *channellingAPI) HandleHello(session *Session, hello *DataHello, sender Sender) (*DataWelcome, error) {
- // TODO(longsleep): Filter room id and user agent.
- session.Update(&SessionUpdate{Types: []string{"Ua"}, Ua: hello.Ua})
-
- // Compatibily for old clients.
- roomName := hello.Name
- if roomName == "" {
- roomName = hello.Id
- }
-
- room, err := session.JoinRoom(roomName, hello.Type, hello.Credentials, sender)
- if err != nil {
- return nil, err
- }
- return &DataWelcome{
- Type: "Welcome",
- Room: room,
- Users: api.RoomUsers(session),
- }, nil
-}
-
-func (api *channellingAPI) HandleUsers(session *Session) (sessions *DataSessions, err error) {
- if session.Hello {
- sessions = &DataSessions{Type: "Users", Users: api.RoomUsers(session)}
- } else {
- err = NewDataError("not_in_room", "Cannot list users without a current room")
- }
- return
-}
-
-func (api *channellingAPI) HandleAuthentication(session *Session, st *SessionToken) (*DataSelf, error) {
- if err := api.Authenticate(session, st, ""); err != nil {
- log.Println("Authentication failed", err, st.Userid, st.Nonce)
- return nil, err
- }
-
- log.Println("Authentication success", session.Userid())
- self, err := api.HandleSelf(session)
- if err == nil {
- session.BroadcastStatus()
- }
-
- return self, err
-}
-
-func (api *channellingAPI) HandleChat(session *Session, chat *DataChat) {
- // TODO(longsleep): Limit sent chat messages per incoming connection.
- msg := chat.Chat
- to := chat.To
-
- if !msg.NoEcho {
- session.Unicast(session.Id, chat)
- }
- msg.Time = time.Now().Format(time.RFC3339)
- if to == "" {
- // TODO(longsleep): Check if chat broadcast is allowed.
- if session.Hello {
- api.CountBroadcastChat()
- session.Broadcast(chat)
- }
- } else {
- if msg.Status != nil {
- if msg.Status.ContactRequest != nil {
- if !api.Config.WithModule("contacts") {
- return
- }
- if err := api.contactrequestHandler(session, to, msg.Status.ContactRequest); err != nil {
- log.Println("Ignoring invalid contact request.", err)
- return
- }
- msg.Status.ContactRequest.Userid = session.Userid()
- }
- } else {
- api.CountUnicastChat()
- }
-
- session.Unicast(to, chat)
- if msg.Mid != "" {
- // Send out delivery confirmation status chat message.
- session.Unicast(session.Id, &DataChat{To: to, Type: "Chat", Chat: &DataChatMessage{Mid: msg.Mid, Status: &DataChatStatus{State: "sent"}}})
- }
- }
-}
-
-func (api *channellingAPI) HandleConference(session *Session, conference *DataConference) {
- // Check conference maximum size.
- if len(conference.Conference) > maxConferenceSize {
- log.Println("Refusing to create conference above limit.", len(conference.Conference))
- return
- }
-
- // Send conference update to anyone.
- for _, id := range conference.Conference {
- if id != session.Id {
- session.Unicast(id, conference)
- }
- }
-}
-
-func (api *channellingAPI) HandleSessions(session *Session, sessions *DataSessionsRequest) (*DataSessions, error) {
- switch sessions.Type {
- case "contact":
- if !api.Config.WithModule("contacts") {
- return nil, NewDataError("contacts_not_enabled", "incoming contacts session request with contacts disabled")
- }
- userID, err := api.getContactID(session, sessions.Token)
- if err != nil {
- return nil, err
- }
- return &DataSessions{
- Type: "Sessions",
- Users: api.GetUserSessions(session, userID),
- Sessions: sessions,
- }, nil
- case "session":
- id, err := session.attestation.Decode(sessions.Token)
- if err != nil {
- return nil, NewDataError("bad_attestation", err.Error())
- }
- session, ok := api.GetSession(id)
- if !ok {
- return nil, NewDataError("no_such_session", "cannot retrieve session")
- }
- return &DataSessions{
- Type: "Sessions",
- Users: []*DataSession{session.Data()},
- Sessions: sessions,
- }, nil
- default:
- return nil, NewDataError("bad_request", "unknown sessions request type")
- }
-}
-
-func (api *channellingAPI) HandleRoom(session *Session, room *DataRoom) (*DataRoom, error) {
- room, err := api.UpdateRoom(session, room)
- if err == nil {
- session.Broadcast(room)
- }
- return room, err
-}
diff --git a/src/app/spreed-webrtc-server/handler_image.go b/src/app/spreed-webrtc-server/handler_image.go
new file mode 100644
index 00000000..f5d5f779
--- /dev/null
+++ b/src/app/spreed-webrtc-server/handler_image.go
@@ -0,0 +1,56 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package main
+
+import (
+ "net/http"
+ "strconv"
+ "time"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+
+ "github.com/gorilla/mux"
+)
+
+func makeImageHandler(buddyImages channelling.ImageCache, expires time.Duration) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ image := buddyImages.Get(vars["imageid"])
+ if image == nil {
+ http.Error(w, "Unknown image", http.StatusNotFound)
+ return
+ }
+
+ w.Header().Set("Content-Type", image.MimeType())
+ w.Header().Set("ETag", image.LastChangeID())
+ age := time.Now().Sub(image.LastChange())
+ if age >= time.Second {
+ w.Header().Set("Age", strconv.Itoa(int(age.Seconds())))
+ }
+ if expires >= time.Second {
+ w.Header().Set("Expires", time.Now().Add(expires).Format(time.RFC1123))
+ w.Header().Set("Cache-Control", "public, no-transform, max-age="+strconv.Itoa(int(expires.Seconds())))
+ }
+
+ http.ServeContent(w, r, "", image.LastChange(), image.Reader())
+ }
+}
diff --git a/src/app/spreed-webrtc-server/handler_main.go b/src/app/spreed-webrtc-server/handler_main.go
new file mode 100644
index 00000000..139d1049
--- /dev/null
+++ b/src/app/spreed-webrtc-server/handler_main.go
@@ -0,0 +1,30 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package main
+
+import (
+ "net/http"
+)
+
+func mainHandler(w http.ResponseWriter, r *http.Request) {
+ handleRoomView("", w, r)
+}
diff --git a/src/app/spreed-webrtc-server/handler_room.go b/src/app/spreed-webrtc-server/handler_room.go
new file mode 100644
index 00000000..df968384
--- /dev/null
+++ b/src/app/spreed-webrtc-server/handler_room.go
@@ -0,0 +1,91 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package main
+
+import (
+ "net/http"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+
+ "github.com/gorilla/mux"
+)
+
+func roomHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+
+ handleRoomView(vars["room"], w, r)
+}
+
+func handleRoomView(room string, w http.ResponseWriter, r *http.Request) {
+ var err error
+
+ w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+ w.Header().Set("Expires", "-1")
+ w.Header().Set("Cache-Control", "private, max-age=0")
+
+ csp := false
+
+ if config.ContentSecurityPolicy != "" {
+ w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy)
+ csp = true
+ }
+ if config.ContentSecurityPolicyReportOnly != "" {
+ w.Header().Set("Content-Security-Policy-Report-Only", config.ContentSecurityPolicyReportOnly)
+ csp = true
+ }
+
+ scheme := "http"
+
+ // Detect if the request was made with SSL.
+ ssl := r.TLS != nil
+ proto, ok := r.Header["X-Forwarded-Proto"]
+ if ok {
+ ssl = proto[0] == "https"
+ scheme = "https"
+ }
+
+ // Get languages from request.
+ langs := getRequestLanguages(r, []string{})
+ if len(langs) == 0 {
+ langs = append(langs, "en")
+ }
+
+ // Prepare context to deliver to HTML..
+ context := &channelling.Context{Cfg: config, App: "main", Host: r.Host, Scheme: scheme, Ssl: ssl, Csp: csp, Languages: langs, Room: room}
+
+ // Get URL parameters.
+ r.ParseForm()
+
+ // Check if incoming request is a crawler which supports AJAX crawling.
+ // See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details.
+ if _, ok := r.Form["_escaped_fragment_"]; ok {
+ // Render crawlerPage template..
+ err = templates.ExecuteTemplate(w, "crawlerPage", &context)
+ } else {
+ // Render mainPage template.
+ err = templates.ExecuteTemplate(w, "mainPage", &context)
+ }
+
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+}
diff --git a/src/app/spreed-webrtc-server/handler_sandbox.go b/src/app/spreed-webrtc-server/handler_sandbox.go
new file mode 100644
index 00000000..e41c4de2
--- /dev/null
+++ b/src/app/spreed-webrtc-server/handler_sandbox.go
@@ -0,0 +1,79 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+
+ "github.com/gorilla/mux"
+)
+
+func sandboxHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ // NOTE(longsleep): origin_scheme is window.location.protocol (eg. https:, http:).
+ originURL, err := url.Parse(fmt.Sprintf("%s//%s", vars["origin_scheme"], vars["origin_host"]))
+ if err != nil || originURL.Scheme == "" || originURL.Host == "" {
+ http.Error(w, "Invalid origin path", http.StatusBadRequest)
+ return
+ }
+ origin := fmt.Sprintf("%s://%s", originURL.Scheme, originURL.Host)
+
+ handleSandboxView(vars["sandbox"], origin, w, r)
+}
+
+func handleSandboxView(sandbox string, origin string, w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+ w.Header().Set("Expires", "-1")
+ w.Header().Set("Cache-Control", "private, max-age=0")
+
+ sandboxTemplateName := fmt.Sprintf("%s_sandbox.html", sandbox)
+
+ // Prepare context to deliver to HTML..
+ if t := templates.Lookup(sandboxTemplateName); t != nil {
+
+ // CSP support for sandboxes.
+ var csp string
+ switch sandbox {
+ case "odfcanvas":
+ csp = fmt.Sprintf("default-src 'none'; script-src %s; img-src data: blob:; style-src 'unsafe-inline'", origin)
+ case "pdfcanvas":
+ csp = fmt.Sprintf("default-src 'none'; script-src %s 'unsafe-eval'; img-src 'self' data: blob:; style-src 'unsafe-inline'", origin)
+ default:
+ csp = "default-src 'none'"
+ }
+ w.Header().Set("Content-Security-Policy", csp)
+
+ // Prepare context to deliver to HTML..
+ context := &channelling.Context{Cfg: config, Origin: origin, Csp: true}
+ err := t.Execute(w, &context)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+
+ } else {
+ http.Error(w, "404 Unknown Sandbox", http.StatusNotFound)
+ }
+}
diff --git a/src/app/spreed-webrtc-server/handler_wellknown.go b/src/app/spreed-webrtc-server/handler_wellknown.go
new file mode 100644
index 00000000..3cb8e4c9
--- /dev/null
+++ b/src/app/spreed-webrtc-server/handler_wellknown.go
@@ -0,0 +1,59 @@
+/*
+ * Spreed WebRTC.
+ * Copyright (C) 2013-2015 struktur AG
+ *
+ * This file is part of Spreed WebRTC.
+ *
+ * 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 .
+ *
+ */
+
+package main
+
+import (
+ "encoding/json"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+func wellKnownHandler(w http.ResponseWriter, r *http.Request) {
+ // Detect if the request was made with SSL.
+ ssl := r.TLS != nil
+ scheme := "http"
+ proto, ok := r.Header["X-Forwarded-Proto"]
+ if ok {
+ ssl = proto[0] == "https"
+ }
+ if ssl {
+ scheme = "https"
+ }
+
+ // Construct our URL.
+ url := url.URL{
+ Scheme: scheme,
+ Host: r.Host,
+ Path: strings.TrimSuffix(config.B, "/"),
+ }
+ doc := &map[string]string{
+ "spreed-webrtc_endpoint": url.String(),
+ }
+ data, err := json.MarshalIndent(doc, "", " ")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.Write(data)
+}
diff --git a/src/app/spreed-webrtc-server/ws.go b/src/app/spreed-webrtc-server/handler_ws.go
similarity index 81%
rename from src/app/spreed-webrtc-server/ws.go
rename to src/app/spreed-webrtc-server/handler_ws.go
index f43f01d1..cde32fac 100644
--- a/src/app/spreed-webrtc-server/ws.go
+++ b/src/app/spreed-webrtc-server/handler_ws.go
@@ -25,6 +25,8 @@ import (
"log"
"net/http"
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+
"github.com/gorilla/websocket"
)
@@ -50,7 +52,7 @@ var (
}
)
-func makeWSHandler(connectionCounter ConnectionCounter, sessionManager SessionManager, codec Codec, channellingAPI ChannellingAPI) http.HandlerFunc {
+func makeWSHandler(connectionCounter channelling.ConnectionCounter, sessionManager channelling.SessionManager, codec channelling.Codec, channellingAPI channelling.ChannellingAPI) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Validate incoming request.
if r.Method != "GET" {
@@ -69,11 +71,11 @@ func makeWSHandler(connectionCounter ConnectionCounter, sessionManager SessionMa
// Create a new connection instance.
session := sessionManager.CreateSession(r)
- client := NewClient(codec, channellingAPI, session)
- conn := NewConnection(connectionCounter.CountConnection(), ws, client)
+ client := channelling.NewClient(codec, channellingAPI, session)
+ conn := channelling.NewConnection(connectionCounter.CountConnection(), ws, client)
// Start pumps (readPump blocks).
- go conn.writePump()
- conn.readPump()
+ go conn.WritePump()
+ conn.ReadPump()
}
}
diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go
index f32b99ea..e8f31e23 100644
--- a/src/app/spreed-webrtc-server/main.go
+++ b/src/app/spreed-webrtc-server/main.go
@@ -22,230 +22,39 @@
package main
import (
- "bytes"
"crypto/rand"
"encoding/hex"
- "encoding/json"
"flag"
"fmt"
- "github.com/gorilla/mux"
- "github.com/strukturag/goacceptlanguageparser"
- "github.com/strukturag/httputils"
- "github.com/strukturag/phoenix"
- "github.com/strukturag/sloth"
"html/template"
"log"
"net/http"
_ "net/http/pprof"
- "net/url"
"os"
"path"
"path/filepath"
goruntime "runtime"
- "strconv"
"strings"
"syscall"
"time"
+
+ "github.com/strukturag/spreed-webrtc/go/channelling"
+ "github.com/strukturag/spreed-webrtc/go/channelling/api"
+ "github.com/strukturag/spreed-webrtc/go/channelling/server"
+
+ "github.com/gorilla/mux"
+ "github.com/strukturag/httputils"
+ "github.com/strukturag/phoenix"
+ "github.com/strukturag/sloth"
)
var version = "unreleased"
var defaultConfig = "./server.conf"
var templates *template.Template
-var config *Config
-
-// Helper to retrieve languages from request.
-func getRequestLanguages(r *http.Request, supportedLanguages []string) []string {
-
- acceptLanguageHeader, ok := r.Header["Accept-Language"]
- var langs []string
- if ok {
- langs = goacceptlanguageparser.ParseAcceptLanguage(acceptLanguageHeader[0], supportedLanguages)
- }
- return langs
-
-}
-
-func mainHandler(w http.ResponseWriter, r *http.Request) {
-
- handleRoomView("", w, r)
-
-}
-
-func roomHandler(w http.ResponseWriter, r *http.Request) {
-
- vars := mux.Vars(r)
- handleRoomView(vars["room"], w, r)
-
-}
-
-func sandboxHandler(w http.ResponseWriter, r *http.Request) {
-
- vars := mux.Vars(r)
- // NOTE(longsleep): origin_scheme is window.location.protocol (eg. https:, http:).
- originURL, err := url.Parse(fmt.Sprintf("%s//%s", vars["origin_scheme"], vars["origin_host"]))
- if err != nil || originURL.Scheme == "" || originURL.Host == "" {
- http.Error(w, "Invalid origin path", http.StatusBadRequest)
- return
- }
- origin := fmt.Sprintf("%s://%s", originURL.Scheme, originURL.Host)
- handleSandboxView(vars["sandbox"], origin, w, r)
-
-}
-
-func wellKnownHandler(w http.ResponseWriter, r *http.Request) {
-
- // Detect if the request was made with SSL.
- ssl := r.TLS != nil
- scheme := "http"
- proto, ok := r.Header["X-Forwarded-Proto"]
- if ok {
- ssl = proto[0] == "https"
- }
- if ssl {
- scheme = "https"
- }
-
- // Construct our URL.
- url := url.URL{
- Scheme: scheme,
- Host: r.Host,
- Path: strings.TrimSuffix(config.B, "/"),
- }
- doc := &map[string]string{
- "spreed-webrtc_endpoint": url.String(),
- }
- data, err := json.MarshalIndent(doc, "", " ")
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.Write(data)
-
-}
-
-func makeImageHandler(buddyImages ImageCache, expires time.Duration) http.HandlerFunc {
-
- return func(w http.ResponseWriter, r *http.Request) {
-
- vars := mux.Vars(r)
- image := buddyImages.Get(vars["imageid"])
- if image == nil {
- http.Error(w, "Unknown image", http.StatusNotFound)
- return
- }
-
- w.Header().Set("Content-Type", image.mimetype)
- w.Header().Set("ETag", image.lastChangeId)
- age := time.Now().Sub(image.lastChange)
- if age >= time.Second {
- w.Header().Set("Age", strconv.Itoa(int(age.Seconds())))
- }
- if expires >= time.Second {
- w.Header().Set("Expires", time.Now().Add(expires).Format(time.RFC1123))
- w.Header().Set("Cache-Control", "public, no-transform, max-age="+strconv.Itoa(int(expires.Seconds())))
- }
- http.ServeContent(w, r, "", image.lastChange, bytes.NewReader(image.data))
- }
-
-}
-
-func handleRoomView(room string, w http.ResponseWriter, r *http.Request) {
-
- var err error
-
- w.Header().Set("Content-Type", "text/html; charset=UTF-8")
- w.Header().Set("Expires", "-1")
- w.Header().Set("Cache-Control", "private, max-age=0")
-
- csp := false
-
- if config.contentSecurityPolicy != "" {
- w.Header().Set("Content-Security-Policy", config.contentSecurityPolicy)
- csp = true
- }
- if config.contentSecurityPolicyReportOnly != "" {
- w.Header().Set("Content-Security-Policy-Report-Only", config.contentSecurityPolicyReportOnly)
- csp = true
- }
-
- scheme := "http"
-
- // Detect if the request was made with SSL.
- ssl := r.TLS != nil
- proto, ok := r.Header["X-Forwarded-Proto"]
- if ok {
- ssl = proto[0] == "https"
- scheme = "https"
- }
-
- // Get languages from request.
- langs := getRequestLanguages(r, []string{})
- if len(langs) == 0 {
- langs = append(langs, "en")
- }
-
- // Prepare context to deliver to HTML..
- context := &Context{Cfg: config, App: "main", Host: r.Host, Scheme: scheme, Ssl: ssl, Csp: csp, Languages: langs, Room: room}
-
- // Get URL parameters.
- r.ParseForm()
-
- // Check if incoming request is a crawler which supports AJAX crawling.
- // See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details.
- if _, ok := r.Form["_escaped_fragment_"]; ok {
- // Render crawlerPage template..
- err = templates.ExecuteTemplate(w, "crawlerPage", &context)
- } else {
- // Render mainPage template.
- err = templates.ExecuteTemplate(w, "mainPage", &context)
- }
-
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-
-}
-
-func handleSandboxView(sandbox string, origin string, w http.ResponseWriter, r *http.Request) {
-
- w.Header().Set("Content-Type", "text/html; charset=UTF-8")
- w.Header().Set("Expires", "-1")
- w.Header().Set("Cache-Control", "private, max-age=0")
-
- sandboxTemplateName := fmt.Sprintf("%s_sandbox.html", sandbox)
-
- // Prepare context to deliver to HTML..
- if t := templates.Lookup(sandboxTemplateName); t != nil {
-
- // CSP support for sandboxes.
- var csp string
- switch sandbox {
- case "odfcanvas":
- csp = fmt.Sprintf("default-src 'none'; script-src %s; img-src data: blob:; style-src 'unsafe-inline'", origin)
- case "pdfcanvas":
- csp = fmt.Sprintf("default-src 'none'; script-src %s 'unsafe-eval'; img-src 'self' data: blob:; style-src 'unsafe-inline'", origin)
- default:
- csp = "default-src 'none'"
- }
- w.Header().Set("Content-Security-Policy", csp)
-
- // Prepare context to deliver to HTML..
- context := &Context{Cfg: config, Origin: origin, Csp: true}
- err := t.Execute(w, &context)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-
- } else {
- http.Error(w, "404 Unknown Sandbox", http.StatusNotFound)
- }
-
-}
+var config *channelling.Config
func runner(runtime phoenix.Runtime) error {
-
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
rootFolder, err := runtime.GetString("http", "root")
@@ -333,10 +142,10 @@ func runner(runtime phoenix.Runtime) error {
}
}
- var tokenProvider TokenProvider
+ var tokenProvider channelling.TokenProvider
if tokenFile != "" {
log.Printf("Using token authorization from %s\n", tokenFile)
- tokenProvider = TokenFileProvider(tokenFile)
+ tokenProvider = channelling.TokenFileProvider(tokenFile)
}
// Nats pub/sub supports.
@@ -344,18 +153,18 @@ func runner(runtime phoenix.Runtime) error {
natsChannellingTriggerSubject, _ := runtime.GetString("nats", "channelling_trigger_subject")
if natsURL, err := runtime.GetString("nats", "url"); err == nil {
if natsURL != "" {
- DefaultNatsURL = natsURL
+ channelling.DefaultNatsURL = natsURL
}
}
if natsEstablishTimeout, err := runtime.GetInt("nats", "establishTimeout"); err == nil {
if natsEstablishTimeout != 0 {
- DefaultNatsEstablishTimeout = time.Duration(natsEstablishTimeout) * time.Second
+ channelling.DefaultNatsEstablishTimeout = time.Duration(natsEstablishTimeout) * time.Second
}
}
natsClientId, _ := runtime.GetString("nats", "client_id")
// Load remaining configuration items.
- config = NewConfig(runtime, tokenProvider != nil)
+ config = server.NewConfig(runtime, tokenProvider != nil)
// Load templates.
templates = template.New("")
@@ -448,15 +257,15 @@ func runner(runtime phoenix.Runtime) error {
}
// Prepare services.
- buddyImages := NewImageCache()
- codec := NewCodec(incomingCodecLimit)
- roomManager := NewRoomManager(config, codec)
- hub := NewHub(config, sessionSecret, encryptionSecret, turnSecret, codec)
- tickets := NewTickets(sessionSecret, encryptionSecret, computedRealm)
- sessionManager := NewSessionManager(config, tickets, hub, roomManager, roomManager, buddyImages, sessionSecret)
- statsManager := NewStatsManager(hub, roomManager, sessionManager)
- busManager := NewBusManager(natsClientId, natsChannellingTrigger, natsChannellingTriggerSubject)
- channellingAPI := NewChannellingAPI(config, roomManager, tickets, sessionManager, statsManager, hub, hub, hub, busManager)
+ buddyImages := channelling.NewImageCache()
+ codec := channelling.NewCodec(incomingCodecLimit)
+ roomManager := channelling.NewRoomManager(config, codec)
+ hub := channelling.NewHub(config, sessionSecret, encryptionSecret, turnSecret, codec)
+ tickets := channelling.NewTickets(sessionSecret, encryptionSecret, computedRealm)
+ sessionManager := channelling.NewSessionManager(config, tickets, hub, roomManager, roomManager, buddyImages, sessionSecret)
+ statsManager := channelling.NewStatsManager(hub, roomManager, sessionManager)
+ busManager := channelling.NewBusManager(natsClientId, natsChannellingTrigger, natsChannellingTriggerSubject)
+ channellingAPI := api.New(config, roomManager, tickets, sessionManager, statsManager, hub, hub, hub, busManager)
// Add handlers.
r.HandleFunc("/", httputils.MakeGzipHandler(mainHandler))
@@ -473,22 +282,22 @@ func runner(runtime phoenix.Runtime) error {
// Sandbox handler.
r.HandleFunc("/sandbox/{origin_scheme}/{origin_host}/{sandbox}.html", httputils.MakeGzipHandler(sandboxHandler))
- // Add API end points.
- api := sloth.NewAPI()
- api.SetMux(r.PathPrefix("/api/v1/").Subrouter())
- api.AddResource(&Rooms{}, "/rooms")
- api.AddResource(config, "/config")
- api.AddResourceWithWrapper(&Tokens{tokenProvider}, httputils.MakeGzipHandler, "/tokens")
+ // Add RESTful API end points.
+ rest := sloth.NewAPI()
+ rest.SetMux(r.PathPrefix("/api/v1/").Subrouter())
+ rest.AddResource(&server.Rooms{}, "/rooms")
+ rest.AddResource(config, "/config")
+ rest.AddResourceWithWrapper(&server.Tokens{tokenProvider}, httputils.MakeGzipHandler, "/tokens")
if config.UsersEnabled {
// Create Users handler.
- users := NewUsers(hub, tickets, sessionManager, config.UsersMode, serverRealm, runtime)
- api.AddResource(&Sessions{tickets, hub, users}, "/sessions/{id}/")
+ users := server.NewUsers(hub, tickets, sessionManager, config.UsersMode, serverRealm, runtime)
+ rest.AddResource(&server.Sessions{tickets, hub, users}, "/sessions/{id}/")
if config.UsersAllowRegistration {
- api.AddResource(users, "/users")
+ rest.AddResource(users, "/users")
}
}
if statsEnabled {
- api.AddResourceWithWrapper(&Stats{statsManager}, httputils.MakeGzipHandler, "/stats")
+ rest.AddResourceWithWrapper(&server.Stats{statsManager}, httputils.MakeGzipHandler, "/stats")
log.Println("Stats are enabled!")
}
diff --git a/src/app/spreed-webrtc-server/utils.go b/src/app/spreed-webrtc-server/utils.go
new file mode 100644
index 00000000..b0c6f55b
--- /dev/null
+++ b/src/app/spreed-webrtc-server/utils.go
@@ -0,0 +1,17 @@
+package main
+
+import (
+ "net/http"
+
+ "github.com/strukturag/goacceptlanguageparser"
+)
+
+// Helper to retrieve languages from request.
+func getRequestLanguages(r *http.Request, supportedLanguages []string) []string {
+ acceptLanguageHeader, ok := r.Header["Accept-Language"]
+ var langs []string
+ if ok {
+ langs = goacceptlanguageparser.ParseAcceptLanguage(acceptLanguageHeader[0], supportedLanguages)
+ }
+ return langs
+}