mirror of
https://github.com/jech/galene.git
synced 2024-12-22 23:35:46 +01:00
Move group and client to their own package.
This commit is contained in:
parent
d9cf32eda7
commit
c608723394
9 changed files with 258 additions and 255 deletions
29
client.go
29
client.go
|
@ -1,29 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"sfu/conn"
|
||||
)
|
||||
|
||||
type clientCredentials struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type clientPermissions struct {
|
||||
Op bool `json:"op,omitempty"`
|
||||
Present bool `json:"present,omitempty"`
|
||||
Record bool `json:"record,omitempty"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type kickable interface {
|
||||
kick(message string) error
|
||||
}
|
21
disk.go
21
disk.go
|
@ -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
|
||||
|
|
29
group/client.go
Normal file
29
group/client.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package group
|
||||
|
||||
import (
|
||||
"sfu/conn"
|
||||
)
|
||||
|
||||
type ClientCredentials struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type ClientPermissions struct {
|
||||
Op bool `json:"op,omitempty"`
|
||||
Present bool `json:"present,omitempty"`
|
||||
Record bool `json:"record,omitempty"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
17
rtpconn.go
17
rtpconn.go
|
@ -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
|
||||
|
|
10
sfu.go
10
sfu.go
|
@ -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)
|
||||
|
|
7
stats.go
7
stats.go
|
@ -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)),
|
||||
|
|
171
webclient.go
171
webclient.go
|
@ -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",
|
||||
|
|
16
webserver.go
16
webserver.go
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue