diff --git a/README b/README index 9a10900..834bf04 100644 --- a/README +++ b/README @@ -242,6 +242,8 @@ the group. are automatically created when first accessed; - `autolock`: if true, the group will start locked and become locked whenever there are no clients with operator privileges; + - `autokick`: if true, all clients will be kicked out whenever there are + no clients with operator privileges. - `redirect`: if set, then attempts to join the group will be redirected to the given URL; most other fields are ignored in this case; - `codecs`: this is a list of codecs allowed in this group. The default diff --git a/group/group.go b/group/group.go index 413e2fa..cc5527a 100644 --- a/group/group.go +++ b/group/group.go @@ -293,7 +293,7 @@ func Add(name string, desc *description) (*Group, error) { timestamp: time.Now(), api: APIFromNames(desc.Codecs), } - autolock(g, g.getClientsUnlocked(nil)) + autoLockKick(g, g.getClientsUnlocked(nil)) groups.groups[name] = g return g, nil } @@ -320,7 +320,7 @@ func Add(name string, desc *description) (*Group, error) { } g.description = desc g.api = APIFromNames(desc.Codecs) - autolock(g, g.getClientsUnlocked(nil)) + autoLockKick(g, g.getClientsUnlocked(nil)) return g, nil } @@ -461,10 +461,27 @@ func AddClient(group string, c Client) (*Group, error) { } } + clients := g.getClientsUnlocked(nil) + if g.clients[c.Id()] != nil { return nil, ProtocolError("duplicate client id") } + if !c.Permissions().Op && g.description.Autokick { + ops := false + for _, c := range clients { + if c.Permissions().Op { + ops = true + break + } + } + if !ops { + return nil, UserError( + "there are no operators in this group", + ) + } + } + g.clients[c.Id()] = c g.timestamp = time.Now() @@ -476,25 +493,30 @@ func AddClient(group string, c Client) (*Group, error) { c.PushClient(cc.Id(), uu, true) cc.PushClient(c.Id(), u, true) } - }(g.getClientsUnlocked(c)) + }(clients) return g, nil } // called locked -func autolock(g *Group, clients []Client) { - if g.locked == nil && g.description.Autolock { - lock := true - for _, c := range clients { - if c.Permissions().Op { - lock = false - } - } - if lock { - m := "this group is locked" - g.locked = &m +func autoLockKick(g *Group, clients []Client) { + if !(g.description.Autolock && g.locked == nil) && + !g.description.Autokick { + return + } + for _, c := range clients { + if c.Permissions().Op { + return } } + if g.description.Autolock && g.locked == nil { + m := "this group is locked" + g.locked = &m + } + + if g.description.Autokick { + go kickall(g, "there are no operators in this group") + } } func DelClient(c Client) { @@ -520,7 +542,7 @@ func DelClient(c Client) { } }(clients) - autolock(g, clients) + autoLockKick(g, clients) } func (g *Group) GetClients(except Client) []Client { @@ -565,7 +587,7 @@ func (g *Group) Range(f func(c Client) bool) { } } -func (g *Group) Shutdown(message string) { +func kickall(g *Group, message string) { g.Range(func(c Client) bool { cc, ok := c.(Kickable) if ok { @@ -575,6 +597,10 @@ func (g *Group) Shutdown(message string) { }) } +func (g *Group) Shutdown(message string) { + kickall(g, message) +} + type warner interface { Warn(oponly bool, message string) error } @@ -687,6 +713,7 @@ type description struct { AllowRecording bool `json:"allow-recording,omitempty"` AllowSubgroups bool `json:"allow-subgroups,omitempty"` Autolock bool `json:"autolock,omitempty"` + Autokick bool `json:"autokick,omitempty"` Op []ClientCredentials `json:"op,omitempty"` Presenter []ClientCredentials `json:"presenter,omitempty"` Other []ClientCredentials `json:"other,omitempty"`