Commit c6087233 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Move group and client to their own package.

parent d9cf32ed
......@@ -16,10 +16,11 @@ import (
"github.com/pion/webrtc/v3/pkg/media/samplebuilder"
"sfu/conn"
"sfu/group"
)
type diskClient struct {
group *group
group *group.Group
id string
mu sync.Mutex
......@@ -41,11 +42,11 @@ func newId() string {
return s
}
func NewDiskClient(g *group) *diskClient {
func NewDiskClient(g *group.Group) *diskClient {
return &diskClient{group: g, id: newId()}
}
func (client *diskClient) Group() *group {
func (client *diskClient) Group() *group.Group {
return client.group
}
......@@ -53,15 +54,15 @@ func (client *diskClient) Id() string {
return client.id
}
func (client *diskClient) Credentials() clientCredentials {
return clientCredentials{"RECORDING", ""}
func (client *diskClient) Credentials() group.ClientCredentials {
return group.ClientCredentials{"RECORDING", ""}
}
func (client *diskClient) SetPermissions(perms clientPermissions) {
func (client *diskClient) SetPermissions(perms group.ClientPermissions) {
return
}
func (client *diskClient) pushClient(id, username string, add bool) error {
func (client *diskClient) PushClient(id, username string, add bool) error {
return nil
}
......@@ -79,11 +80,11 @@ func (client *diskClient) Close() error {
func (client *diskClient) kick(message string) error {
err := client.Close()
delClient(client)
group.DelClient(client)
return err
}
func (client *diskClient) pushConn(id string, up conn.Up, tracks []conn.UpTrack, label string) error {
func (client *diskClient) PushConn(id string, up conn.Up, tracks []conn.UpTrack, label string) error {
client.mu.Lock()
defer client.mu.Unlock()
......@@ -101,7 +102,7 @@ func (client *diskClient) pushConn(id string, up conn.Up, tracks []conn.UpTrack,
return nil
}
directory := filepath.Join(recordingsDir, client.group.name)
directory := filepath.Join(recordingsDir, client.group.Name())
err := os.MkdirAll(directory, 0700)
if err != nil {
return err
......
package main
package group
import (
"sfu/conn"
)
type clientCredentials struct {
type ClientCredentials struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
type clientPermissions struct {
type ClientPermissions struct {
Op bool `json:"op,omitempty"`
Present bool `json:"present,omitempty"`
Record bool `json:"record,omitempty"`
}
type client interface {
Group() *group
type Client interface {
Group() *Group
Id() string
Credentials() clientCredentials
SetPermissions(clientPermissions)
pushConn(id string, conn conn.Up, tracks []conn.UpTrack, label string) error
pushClient(id, username string, add bool) error
Credentials() ClientCredentials
SetPermissions(ClientPermissions)
PushConn(id string, conn conn.Up, tracks []conn.UpTrack, label string) error
PushClient(id, username string, add bool) error
}
type kickable interface {
kick(message string) error
type Kickable interface {
Kick(message string) error
}
......@@ -3,7 +3,7 @@
// This is not open source software. Copy it, and I'll break into your
// house and tell your three year-old that Santa doesn't exist.
package main
package group
import (
"encoding/json"
......@@ -18,18 +18,60 @@ import (
"github.com/pion/webrtc/v3"
)
type chatHistoryEntry struct {
id string
user string
kind string
value string
var Directory string
type UserError string
func (err UserError) Error() string {
return string(err)
}
type ProtocolError string
func (err ProtocolError) Error() string {
return string(err)
}
var IceFilename string
var iceConf webrtc.Configuration
var iceOnce sync.Once
func IceConfiguration() webrtc.Configuration {
iceOnce.Do(func() {
var iceServers []webrtc.ICEServer
file, err := os.Open(IceFilename)
if err != nil {
log.Printf("Open %v: %v", IceFilename, err)
return
}
defer file.Close()
d := json.NewDecoder(file)
err = d.Decode(&iceServers)
if err != nil {
log.Printf("Get ICE configuration: %v", err)
return
}
iceConf = webrtc.Configuration{
ICEServers: iceServers,
}
})
return iceConf
}
type ChatHistoryEntry struct {
Id string
User string
Kind string
Value string
}
const (
minBitrate = 200000
MinBitrate = 200000
)
type group struct {
type Group struct {
name string
mu sync.Mutex
......@@ -37,64 +79,60 @@ type group struct {
// indicates that the group no longer exists, but it still has clients
dead bool
locked bool
clients map[string]client
history []chatHistoryEntry
clients map[string]Client
history []ChatHistoryEntry
}
func (g *group) Locked() bool {
func (g *Group) Name() string {
return g.name
}
func (g *Group) Locked() bool {
g.mu.Lock()
defer g.mu.Unlock()
return g.locked
}
func (g *group) SetLocked(locked bool) {
func (g *Group) SetLocked(locked bool) {
g.mu.Lock()
defer g.mu.Unlock()
g.locked = locked
}
func (g *group) Public() bool {
func (g *Group) Public() bool {
g.mu.Lock()
defer g.mu.Unlock()
return g.description.Public
}
func (g *group) Redirect() string {
func (g *Group) Redirect() string {
g.mu.Lock()
defer g.mu.Unlock()
return g.description.Redirect
}
func (g *group) AllowRecording() bool {
func (g *Group) AllowRecording() bool {
g.mu.Lock()
defer g.mu.Unlock()
return g.description.AllowRecording
}
func (g *group) Redirect() string {
return g.description.Redirect
}
func (g *group) AllowRecording() bool {
return g.description.AllowRecording
}
var groups struct {
mu sync.Mutex
groups map[string]*group
groups map[string]*Group
api *webrtc.API
}
func (g *group) API() *webrtc.API {
func (g *Group) API() *webrtc.API {
return groups.api
}
func addGroup(name string, desc *groupDescription) (*group, error) {
func Add(name string, desc *groupDescription) (*Group, error) {
groups.mu.Lock()
defer groups.mu.Unlock()
if groups.groups == nil {
groups.groups = make(map[string]*group)
groups.groups = make(map[string]*Group)
s := webrtc.SettingEngine{}
m := webrtc.MediaEngine{}
m.RegisterCodec(webrtc.NewRTPVP8CodecExt(
......@@ -121,15 +159,15 @@ func addGroup(name string, desc *groupDescription) (*group, error) {
g := groups.groups[name]
if g == nil {
if desc == nil {
desc, err = getDescription(name)
desc, err = GetDescription(name)
if err != nil {
return nil, err
}
}
g = &group{
g = &Group{
name: name,
description: desc,
clients: make(map[string]client),
clients: make(map[string]Client),
}
groups.groups[name] = g
return g, nil
......@@ -155,7 +193,7 @@ func addGroup(name string, desc *groupDescription) (*group, error) {
return nil, err
}
if changed {
desc, err := getDescription(name)
desc, err := GetDescription(name)
if err != nil {
if !os.IsNotExist(err) {
log.Printf("Reading group %v: %v",
......@@ -175,7 +213,7 @@ func addGroup(name string, desc *groupDescription) (*group, error) {
return g, nil
}
func rangeGroups(f func(g *group) bool) {
func Range(f func(g *Group) bool) {
groups.mu.Lock()
defer groups.mu.Unlock()
......@@ -187,17 +225,17 @@ func rangeGroups(f func(g *group) bool) {
}
}
func getGroupNames() []string {
func GetNames() []string {
names := make([]string, 0)
rangeGroups(func(g *group) bool {
Range(func(g *Group) bool {
names = append(names, g.name)
return true
})
return names
}
func getGroup(name string) *group {
func Get(name string) *Group {
groups.mu.Lock()
defer groups.mu.Unlock()
......@@ -218,8 +256,8 @@ func delGroupUnlocked(name string) bool {
return true
}
func addClient(name string, c client) (*group, error) {
g, err := addGroup(name, nil)
func AddClient(name string, c Client) (*Group, error) {
g, err := Add(name, nil)
if err != nil {
return nil, err
}
......@@ -227,7 +265,7 @@ func addClient(name string, c client) (*group, error) {
g.mu.Lock()
defer g.mu.Unlock()
perms, err := getPermission(g.description, c.Credentials())
perms, err := g.description.GetPermission(c.Credentials())
if err != nil {
return nil, err
}
......@@ -235,37 +273,34 @@ func addClient(name string, c client) (*group, error) {
c.SetPermissions(perms)
if !perms.Op && g.locked {
return nil, userError("group is locked")
return nil, UserError("group is locked")
}
if !perms.Op && g.description.MaxClients > 0 {
if len(g.clients) >= g.description.MaxClients {
return nil, userError("too many users")
return nil, UserError("too many users")
}
}
if g.clients[c.Id()] != nil {
return nil, protocolError("duplicate client id")
return nil, ProtocolError("duplicate client id")
}
g.clients[c.Id()] = c
go func(clients []client) {
go func(clients []Client) {
u := c.Credentials().Username
c.pushClient(c.Id(), u, true)
c.PushClient(c.Id(), u, true)
for _, cc := range clients {
uu := cc.Credentials().Username
err := c.pushClient(cc.Id(), uu, true)
if err == ErrClientDead {
return
}
cc.pushClient(c.Id(), u, true)
c.PushClient(cc.Id(), uu, true)
cc.PushClient(c.Id(), u, true)
}
}(g.getClientsUnlocked(c))
return g, nil
}
func delClient(c client) {
func DelClient(c Client) {
g := c.Group()
if g == nil {
return
......@@ -279,21 +314,21 @@ func delClient(c client) {
}
delete(g.clients, c.Id())
go func(clients []client) {
go func(clients []Client) {
for _, cc := range clients {
cc.pushClient(c.Id(), c.Credentials().Username, false)
cc.PushClient(c.Id(), c.Credentials().Username, false)
}
}(g.getClientsUnlocked(nil))
}
func (g *group) getClients(except client) []client {
func (g *Group) GetClients(except Client) []Client {
g.mu.Lock()
defer g.mu.Unlock()
return g.getClientsUnlocked(except)
}
func (g *group) getClientsUnlocked(except client) []client {
clients := make([]client, 0, len(g.clients))
func (g *Group) getClientsUnlocked(except Client) []Client {
clients := make([]Client, 0, len(g.clients))
for _, c := range g.clients {
if c != except {
clients = append(clients, c)
......@@ -302,13 +337,13 @@ func (g *group) getClientsUnlocked(except client) []client {
return clients
}
func (g *group) getClient(id string) client {
func (g *Group) GetClient(id string) Client {
g.mu.Lock()
defer g.mu.Unlock()
return g.getClientUnlocked(id)
}
func (g *group) getClientUnlocked(id string) client {
func (g *Group) getClientUnlocked(id string) Client {
for idd, c := range g.clients {
if idd == id {
return c
......@@ -317,7 +352,7 @@ func (g *group) getClientUnlocked(id string) client {
return nil
}
func (g *group) Range(f func(c client) bool) {
func (g *Group) Range(f func(c Client) bool) {
g.mu.Lock()
defer g.mu.Unlock()
for _, c := range g.clients {
......@@ -328,11 +363,11 @@ func (g *group) Range(f func(c client) bool) {
}
}
func (g *group) shutdown(message string) {
g.Range(func(c client) bool {
cc, ok := c.(kickable)
func (g *Group) Shutdown(message string) {
g.Range(func(c Client) bool {
cc, ok := c.(Kickable)
if ok {
cc.kick(message)
cc.Kick(message)
}
return true
})
......@@ -340,13 +375,13 @@ func (g *group) shutdown(message string) {
const maxChatHistory = 20
func (g *group) clearChatHistory() {
func (g *Group) ClearChatHistory() {
g.mu.Lock()
defer g.mu.Unlock()
g.history = nil
}
func (g *group) addToChatHistory(id, user, kind, value string) {
func (g *Group) AddToChatHistory(id, user, kind, value string) {
g.mu.Lock()
defer g.mu.Unlock()
......@@ -355,20 +390,20 @@ func (g *group) addToChatHistory(id, user, kind, value string) {
g.history = g.history[:len(g.history)-1]
}
g.history = append(g.history,
chatHistoryEntry{id: id, user: user, kind: kind, value: value},
ChatHistoryEntry{Id: id, User: user, Kind: kind, Value: value},
)
}
func (g *group) getChatHistory() []chatHistoryEntry {
func (g *Group) GetChatHistory() []ChatHistoryEntry {
g.mu.Lock()
defer g.mu.Unlock()
h := make([]chatHistoryEntry, len(g.history))
h := make([]ChatHistoryEntry, len(g.history))
copy(h, g.history)
return h
}
func matchUser(user clientCredentials, users []clientCredentials) (bool, bool) {
func matchUser(user ClientCredentials, users []ClientCredentials) (bool, bool) {
for _, u := range users {
if u.Username == "" {
if u.Password == "" || u.Password == user.Password {
......@@ -391,13 +426,13 @@ type groupDescription struct {
MaxClients int `json:"max-clients,omitempty"`
AllowAnonymous bool `json:"allow-anonymous,omitempty"`
AllowRecording bool `json:"allow-recording,omitempty"`
Op []clientCredentials `json:"op,omitempty"`
Presenter []clientCredentials `json:"presenter,omitempty"`
Other []clientCredentials `json:"other,omitempty"`
Op []ClientCredentials `json:"op,omitempty"`
Presenter []ClientCredentials `json:"presenter,omitempty"`
Other []ClientCredentials `json:"other,omitempty"`
}
func descriptionChanged(name string, old *groupDescription) (bool, error) {
fi, err := os.Stat(filepath.Join(groupsDir, name+".json"))
fi, err := os.Stat(filepath.Join(Directory, name+".json"))
if err != nil {
return false, err
}
......@@ -407,8 +442,8 @@ func descriptionChanged(name string, old *groupDescription) (bool, error) {
return false, err
}
func getDescription(name string) (*groupDescription, error) {
r, err := os.Open(filepath.Join(groupsDir, name+".json"))
func GetDescription(name string) (*groupDescription, error) {
r, err := os.Open(filepath.Join(Directory, name+".json"))
if err != nil {
return nil, err
}
......@@ -432,10 +467,10 @@ func getDescription(name string) (*groupDescription, error) {
return &desc, nil
}
func getPermission(desc *groupDescription, creds clientCredentials) (clientPermissions, error) {
var p clientPermissions
func (desc *groupDescription) GetPermission (creds ClientCredentials) (ClientPermissions, error) {
var p ClientPermissions
if !desc.AllowAnonymous && creds.Username == "" {
return p, userError("anonymous users not allowed in this group, please choose a username")
return p, UserError("anonymous users not allowed in this group, please choose a username")
}
if found, good := matchUser(creds, desc.Op); found {
if good {
......@@ -446,34 +481,34 @@ func getPermission(desc *groupDescription, creds clientCredentials) (clientPermi
}
return p, nil
}
return p, userError("not authorised")
return p, UserError("not authorised")
}
if found, good := matchUser(creds, desc.Presenter); found {
if good {
p.Present = true
return p, nil
}
return p, userError("not authorised")
return p, UserError("not authorised")
}
if found, good := matchUser(creds, desc.Other); found {
if good {
return p, nil
}
return p, userError("not authorised")
return p, UserError("not authorised")
}
return p, userError("not authorised")
return p, UserError("not authorised")
}
type publicGroup struct {
type Public struct {
Name string `json:"name"`
ClientCount int `json:"clientCount"`
}
func getPublicGroups() []publicGroup {
gs := make([]publicGroup, 0)
rangeGroups(func(g *group) bool {
func GetPublic() []Public {
gs := make([]Public, 0)
Range(func(g *Group) bool {
if g.Public() {
gs = append(gs, publicGroup{
gs = append(gs, Public{
Name: g.name,
ClientCount: len(g.clients),
})
......@@ -486,8 +521,8 @@ func getPublicGroups() []publicGroup {
return gs
}
func readPublicGroups() {
dir, err := os.Open(groupsDir)
func ReadPublicGroups() {
dir, err := os.Open(Directory)
if err != nil {
return
}
......@@ -504,7 +539,7 @@ func readPublicGroups() {
continue
}
name := fi.Name()[:len(fi.Name())-5]
desc, err := getDescription(name)
desc, err := GetDescription(name)
if err != nil {
if !os.IsNotExist(err) {
log.Printf("Reading group %v: %v", name, err)
......@@ -512,7 +547,7 @@ func readPublicGroups() {
continue
}
if desc.Public {
addGroup(name, desc)
Add(name, desc)
}
}
}
......@@ -20,6 +20,7 @@ import (
"sfu/conn"
"sfu/estimator"
"sfu/group"
"sfu/jitter"
"sfu/packetcache"
"sfu/rtptime"
......@@ -110,8 +111,8 @@ type rtpDownConnection struct {
iceCandidates []*webrtc.ICECandidateInit
}
func newDownConn(c client, id string, remote conn.Up) (*rtpDownConnection, error) {
pc, err := c.Group().API().NewPeerConnection(iceConfiguration())
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
pc, err := c.Group().API().NewPeerConnection(group.IceConfiguration())
if err != nil {
return nil, err
}
......@@ -371,8 +372,8 @@ func (up *rtpUpConnection) complete() bool {
return true
}
func newUpConn(c client, id string) (*rtpUpConnection, error) {
pc, err := c.Group().API().NewPeerConnection(iceConfiguration())
func newUpConn(c group.Client, id string) (*rtpUpConnection, error) {
pc, err := c.Group().API().NewPeerConnection(group.IceConfiguration())
if err != nil {
return nil, err
}
......@@ -448,9 +449,9 @@ func newUpConn(c client, id string) (*rtpUpConnection, error) {
up.mu.Unlock()
if complete {
clients := c.Group().getClients(c)
clients := c.Group().GetClients(c)
for _, cc := range clients {
cc.pushConn(up.id, up, tracks, up.label)
cc.PushConn(up.id, up, tracks, up.label)
}
go rtcpUpSender(up)
}
......@@ -750,8 +751,8 @@ func sendUpRTCP(conn *rtpUpConnection) error {
rate = r
}
}
if rate < minBitrate {
rate = minBitrate
if rate < group.MinBitrate {
rate = group.MinBitrate
}
var ssrcs []uint32
......
......@@ -14,14 +14,14 @@ import (
"runtime"
"runtime/pprof"
"syscall"
"sfu/group"
)
var httpAddr string
var staticRoot string
var dataDir string
var groupsDir string
var recordingsDir string
var iceFilename string
func main() {
var cpuprofile, memprofile, mutexprofile string
......@@ -31,7 +31,7 @@ func main() {
"web server root `directory`")
flag.StringVar(&dataDir, "data", "./data/",
"data `directory`")
flag.StringVar(&groupsDir, "groups", "./groups/",
flag.StringVar(&group.Directory, "groups", "./groups/",
"group description `directory`")
flag.StringVar(&recordingsDir, "recordings", "./recordings/",
"recordings `directory`")
......@@ -81,9 +81,9 @@ func main() {
}()
}
iceFilename = filepath.Join(dataDir, "ice-servers.json")
group.IceFilename = filepath.Join(dataDir, "ice-servers.json")
go readPublicGroups()
go group.ReadPublicGroups()
webserver()
terminate := make(chan os.Signal, 1)
......
......@@ -5,6 +5,7 @@ import (
"sync/atomic"
"time"
"sfu/group"
"sfu/rtptime"
)
......@@ -33,15 +34,15 @@ type trackStats struct {
}
func getGroupStats() []groupStats {
names := getGroupNames()
names := group.GetNames()
gs := make([]groupStats, 0, len(names))
for _, name := range names {
g := getGroup(name)
g := group.Get(name)
if g == nil {
continue
}
clients := g.getClients(nil)
clients := g.GetClients(nil)
stats := groupStats{
name: name,
clients: make([]clientStats, 0, len(clients)),
......
......@@ -19,56 +19,19 @@ import (
"sfu/conn"
"sfu/estimator"
"sfu/group"
)
var iceConf webrtc.Configuration
var iceOnce sync.Once
func iceConfiguration() webrtc.Configuration {
iceOnce.Do(func() {
var iceServers []webrtc.ICEServer
file, err := os.Open(iceFilename)
if err != nil {
log.Printf("Open %v: %v", iceFilename, err)
return
}
defer file.Close()
d := json.NewDecoder(file)
err = d.Decode(&iceServers)
if err != nil {
log.Printf("Get ICE configuration: %v", err)
return
}
iceConf = webrtc.Configuration{
ICEServers: iceServers,
}
})
return iceConf
}
type protocolError string
func (err protocolError) Error() string {
return string(err)
}
type userError string
func (err userError) Error() string {
return string(err)
}
func errorToWSCloseMessage(err error) (string, []byte) {
var code int
var text string
switch e := err.(type) {
case *websocket.CloseError:
code = websocket.CloseNormalClosure
case protocolError:
case group.ProtocolError:
code = websocket.CloseProtocolError
text = string(e)
case userError:
case group.UserError:
code = websocket.CloseNormalClosure
text = string(e)
default:
......@@ -84,10 +47,10 @@ func isWSNormalError(err error) bool {
}
type webClient struct {
group *group
group *group.Group
id string
credentials clientCredentials
permissions clientPermissions
credentials group.ClientCredentials
permissions group.ClientPermissions
requested map[string]uint32
done chan struct{}
writeCh chan interface{}
......@@ -99,7 +62,7 @@ type webClient struct {
up map[string]*rtpUpConnection
}
func (c *webClient) Group() *group {
func (c *webClient) Group() *group.Group {
return c.group
}
......@@ -107,15 +70,15 @@ func (c *webClient) Id() string {
return c.id
}
func (c *webClient) Credentials() clientCredentials {
func (c *webClient) Credentials() group.ClientCredentials {
return c.credentials
}
func (c *webClient) SetPermissions(perms clientPermissions) {
func (c *webClient) SetPermissions(perms group.ClientPermissions) {
c.permissions = perms
}
func (c *webClient) pushClient(id, username string, add bool) error {
func (c *webClient) PushClient(id, username string, add bool) error {
kind := "add"
if !add {
kind = "delete"
......@@ -181,7 +144,7 @@ type clientMessage struct {
Id string `json:"id,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Permissions clientPermissions `json:"permissions,omitempty"`
Permissions group.ClientPermissions `json:"permissions,omitempty"`
Group string `json:"group,omitempty"`
Value string `json:"value,omitempty"`
Offer *webrtc.SessionDescription `json:"offer,omitempty"`
......@@ -265,11 +228,11 @@ func delUpConn(c *webClient, id string) bool {
delete(c.up, id)
c.mu.Unlock()
go func(clients []client) {
go func(clients []group.Client) {
for _, c := range clients {
c.pushConn(conn.id, nil, nil, "")
c.PushConn(conn.id, nil, nil, "")
}
}(c.Group().getClients(c))
}(c.Group().GetClients(c))
conn.pc.Close()
return true
......@@ -512,7 +475,7 @@ func gotOffer(c *webClient, id string, offer webrtc.SessionDescription, renegoti
func gotAnswer(c *webClient, id string, answer webrtc.SessionDescription) error {
down := getDownConn(c, id)
if down == nil {
return protocolError("unknown id in answer")
return group.ProtocolError("unknown id in answer")
}
err := down.pc.SetRemoteDescription(answer)
if err != nil {
......@@ -555,8 +518,8 @@ func (c *webClient) setRequested(requested map[string]uint32) error {
return nil
}
func pushConns(c client) {
clients := c.Group().getClients(c)
func pushConns(c group.Client) {
clients := c.Group().GetClients(c)
for _, cc := range clients {
ccc, ok := cc.(*webClient)
if ok {
......@@ -602,7 +565,7 @@ func addDownConnTracks(c *webClient, remote conn.Up, tracks []conn.UpTrack) (*rt
return down, nil
}
func (c *webClient) pushConn(id string, up conn.Up, tracks []conn.UpTrack, label string) error {
func (c *webClient) PushConn(id string, up conn.Up, tracks []conn.UpTrack, label string) error {
err := c.action(pushConnAction{id, up, tracks})
if err != nil {
return err
......@@ -666,7 +629,7 @@ func startClient(conn *websocket.Conn) (err error) {
c := &webClient{
id: m.Id,
credentials: clientCredentials{
credentials: group.ClientCredentials{
m.Username,
m.Password,
},
......@@ -703,24 +666,24 @@ func startClient(conn *websocket.Conn) (err error) {
}
if m.Type != "join" {
return protocolError("you must join a group first")
return group.ProtocolError("you must join a group first")
}
g, err := addClient(m.Group, c)
g, err := group.AddClient(m.Group, c)
if err != nil {
if os.IsNotExist(err) {
err = userError("group does not exist")
err = group.UserError("group does not exist")
}
return
}
if redirect := g.Redirect(); redirect != "" {
// We normally redirect at the HTTP level, but the group
// description could have been edited in the meantime.
err = userError("group is now at " + redirect)
err = group.UserError("group is now at " + redirect)
return
}
c.group = g
defer delClient(c)
defer group.DelClient(c)
return clientLoop(c, conn)
}
......@@ -737,7 +700,7 @@ type addLabelAction struct {
}
type pushConnsAction struct {
c client
c group.Client
}
type connectionFailedAction struct {
......@@ -768,14 +731,14 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
Permissions: c.permissions,
})
h := c.group.getChatHistory()
h := c.group.GetChatHistory()
for _, m := range h {
err := c.write(clientMessage{
Type: "chat",
Id: m.id,
Username: m.user,
Value: m.value,
Kind: m.kind,
Id: m.Id,
Username: m.User,
Value: m.Value,
Kind: m.Kind,
})
if err != nil {
return err
......@@ -853,7 +816,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
for i, t := range tracks {
ts[i] = t
}
go a.c.pushConn(u.id, u, ts, u.label)
go a.c.PushConn(u.id, u, ts, u.label)
}
case connectionFailedAction:
if down := getDownConn(c, a.id); down != nil {
......@@ -867,7 +830,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
for i, t := range down.tracks {
tracks[i] = t.remote
}
go c.pushConn(
go c.PushConn(
down.remote.Id(), down.remote,
tracks, down.remote.Label(),
)
......@@ -899,7 +862,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
}
}
case kickAction:
return userError(a.message)
return group.UserError(a.message)
default:
log.Printf("unexpected action %T", a)
return errors.New("unexpected action")
......@@ -931,7 +894,7 @@ func failConnection(c *webClient, id string, message string) error {
}
}
if message != "" {
err := c.error(userError(message))
err := c.error(group.UserError(message))
if err != nil {
return err
}
......@@ -939,15 +902,15 @@ func failConnection(c *webClient, id string, message string) error {
return nil
}
func setPermissions(g *group, id string, perm string) error {
client := g.getClient(id)
func setPermissions(g *group.Group, id string, perm string) error {
client := g.GetClient(id)
if client == nil {
return userError("no such user")
return group.UserError("no such user")
}
c, ok := client.(*webClient)
if !ok {
return userError("this is not a real user")
return group.UserError("this is not a real user")
}
switch perm {
......@@ -964,7 +927,7 @@ func setPermissions(g *group, id string, perm string) error {
case "unpresent":
c.permissions.Present = false
default:
return userError("unknown permission")
return group.UserError("unknown permission")
}
return c.action(permissionsChangedAction{})
}
......@@ -973,18 +936,18 @@ func (c *webClient) kick(message string) error {
return c.action(kickAction{message})
}
func kickClient(g *group, id string, message string) error {
client := g.getClient(id)
func kickClient(g *group.Group, id string, message string) error {
client := g.GetClient(id)
if client == nil {
return userError("no such user")
return group.UserError("no such user")
}
c, ok := client.(kickable)
c, ok := client.(group.Kickable)
if !ok {
return userError("this client is not kickable")
return group.UserError("this client is not kickable")
}
return c.kick(message)
return c.Kick(message)
}
func handleClientMessage(c *webClient, m clientMessage) error {
......@@ -1000,10 +963,10 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Type: "abort",
Id: m.Id,
})
return c.error(userError("not authorised"))
return c.error(group.UserError("not authorised"))
}
if m.Offer == nil {
return protocolError("null offer")
return group.ProtocolError("null offer")
}
err := gotOffer(
c, m.Id, *m.Offer, m.Kind == "renegotiate", m.Labels,
......@@ -1014,7 +977,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
case "answer":
if m.Answer == nil {
return protocolError("null answer")
return group.ProtocolError("null answer")
}
err := gotAnswer(c, m.Id, *m.Answer)
if err != nil {
......@@ -1037,15 +1000,15 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
case "ice":
if m.Candidate == nil {
return protocolError("null candidate")
return group.ProtocolError("null candidate")
}
err := gotICE(c, m.Candidate, m.Id)
if err != nil {
log.Printf("ICE: %v", err)
}
case "chat":
c.group.addToChatHistory(m.Id, m.Username, m.Kind, m.Value)
clients := c.group.getClients(nil)
c.group.AddToChatHistory(m.Id, m.Username, m.Kind, m.Value)
clients := c.group.GetClients(nil)
for _, cc := range clients {
cc, ok := cc.(*webClient)
if ok {
......@@ -1055,9 +1018,9 @@ func handleClientMessage(c *webClient, m clientMessage) error {
case "groupaction":
switch m.Kind {
case "clearchat":
c.group.clearChatHistory()
c.group.ClearChatHistory()
m := clientMessage{Type: "clearchat"}
clients := c.group.getClients(nil)
clients := c.group.GetClients(nil)
for _, cc := range clients {
cc, ok := cc.(*webClient)
if ok {
......@@ -1066,21 +1029,21 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
case "lock", "unlock":
if !c.permissions.Op {
return c.error(userError("not authorised"))
return c.error(group.UserError("not authorised"))
}
c.group.SetLocked(m.Kind == "lock")
case "record":
if !c.permissions.Record {
return c.error(userError("not authorised"))
return c.error(group.UserError("not authorised"))
}
for _, cc := range c.group.getClients(c) {
for _, cc := range c.group.GetClients(c) {
_, ok := cc.(*diskClient)
if ok {
return c.error(userError("already recording"))
return c.error(group.UserError("already recording"))
}
}
disk := NewDiskClient(c.group)
_, err := addClient(c.group.name, disk)
_, err := group.AddClient(c.group.Name(), disk)
if err != nil {
disk.Close()
return c.error(err)
......@@ -1088,23 +1051,23 @@ func handleClientMessage(c *webClient, m clientMessage) error {
go pushConns(disk)
case "unrecord":
if !c.permissions.Record {
return c.error(userError("not authorised"))
return c.error(group.UserError("not authorised"))
}
for _, cc := range c.group.getClients(c) {
for _, cc := range c.group.GetClients(c) {
disk, ok := cc.(*diskClient)
if ok {
disk.Close()
delClient(disk)
group.DelClient(disk)
}
}
default:
return protocolError("unknown group action")
return group.ProtocolError("unknown group action")
}
case "useraction":
switch m.Kind {
case "op", "unop", "present", "unpresent":
if !c.permissions.Op {
return c.error(userError("not authorised"))
return c.error(group.UserError("not authorised"))
}
err := setPermissions(c.group, m.Id, m.Kind)
if err != nil {
......@@ -1112,7 +1075,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
case "kick":
if !c.permissions.Op {
return c.error(userError("not authorised"))
return c.error(group.UserError("not authorised"))
}
message := m.Value
if message == "" {
......@@ -1123,7 +1086,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
return c.error(err)
}
default:
return protocolError("unknown user action")
return group.ProtocolError("unknown user action")
}
case "pong":
// nothing
......@@ -1133,7 +1096,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
})
default:
log.Printf("unexpected message: %v", m.Type)
return protocolError("unexpected message")
return group.ProtocolError("unexpected message")
}
return nil
}
......@@ -1227,7 +1190,7 @@ func (c *webClient) close(data []byte) error {
func (c *webClient) error(err error) error {
switch e := err.(type) {
case userError:
case group.UserError:
return c.write(clientMessage{
Type: "usermessage",
Kind: "error",
......
......@@ -18,6 +18,8 @@ import (
"time"
"github.com/gorilla/websocket"
"sfu/group"
)
var server *http.Server
......@@ -47,8 +49,8 @@ func webserver() {
IdleTimeout: 120 * time.Second,
}
server.RegisterOnShutdown(func() {
rangeGroups(func (g *group) bool {
go g.shutdown("server is shutting down")
group.Range(func (g *group.Group) bool {
go g.Shutdown("server is shutting down")
return true
})
})
......@@ -139,7 +141,7 @@ func groupHandler(w http.ResponseWriter, r *http.Request) {
return
}
g, err := addGroup(name, nil)
g, err := group.Add(name, nil)
if err != nil {
if os.IsNotExist(err) {
notFound(w)
......@@ -168,7 +170,7 @@ func publicHandler(w http.ResponseWriter, r *http.Request) {
return
}
g := getPublicGroups()
g := group.GetPublic()
e := json.NewEncoder(w)
e.Encode(g)
return
......@@ -409,8 +411,8 @@ func handleGroupAction(w http.ResponseWriter, r *http.Request, group string) {
}
}
func checkGroupPermissions(w http.ResponseWriter, r *http.Request, group string) bool {
desc, err := getDescription(group)
func checkGroupPermissions(w http.ResponseWriter, r *http.Request, groupname string) bool {
desc, err := group.GetDescription(groupname)
if err != nil {
return false
}
......@@ -420,7 +422,7 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, group string)
return false
}
p, err := getPermission(desc, clientCredentials{user, pass})
p, err := desc.GetPermission(group.ClientCredentials{user, pass})
if err != nil || !p.Record {
return false
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment