Commit 183ab4fe authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Use an unbounded buffer for client actions.

We no longer risk deadlocking when sending actions, which in turn
enables pushing connections synchronously.
parent 3b505a89
...@@ -67,6 +67,7 @@ type webClient struct { ...@@ -67,6 +67,7 @@ type webClient struct {
mu sync.Mutex mu sync.Mutex
down map[string]*rtpDownConnection down map[string]*rtpDownConnection
up map[string]*rtpUpConnection up map[string]*rtpUpConnection
actions []interface{}
} }
func (c *webClient) Group() *group.Group { func (c *webClient) Group() *group.Group {
...@@ -276,14 +277,12 @@ func delUpConn(c *webClient, id string, userId string, push bool) error { ...@@ -276,14 +277,12 @@ func delUpConn(c *webClient, id string, userId string, push bool) error {
conn.pc.Close() conn.pc.Close()
if push && g != nil { if push && g != nil {
go func(clients []group.Client) { for _, c := range g.GetClients(c) {
for _, c := range clients {
err := c.PushConn(g, id, nil, nil, replace) err := c.PushConn(g, id, nil, nil, replace)
if err != nil { if err != nil {
log.Printf("PushConn: %v", err) log.Printf("PushConn: %v", err)
} }
} }
}(g.GetClients(c))
} }
return nil return nil
...@@ -681,7 +680,7 @@ func gotICE(c *webClient, candidate *webrtc.ICECandidateInit, id string) error { ...@@ -681,7 +680,7 @@ func gotICE(c *webClient, candidate *webrtc.ICECandidateInit, id string) error {
func (c *webClient) setRequested(requested map[string]uint32) error { func (c *webClient) setRequested(requested map[string]uint32) error {
c.requested = requested c.requested = requested
go pushConns(c, c.group) pushConns(c, c.group)
return nil return nil
} }
...@@ -811,6 +810,13 @@ func clientLoop(c *webClient, ws *websocket.Conn) error { ...@@ -811,6 +810,13 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
} }
for { for {
c.mu.Lock()
actions := c.actions
c.actions = nil
c.mu.Unlock()
for _, a := range actions {
handleAction(c, a)
}
select { select {
case m, ok := <-read: case m, ok := <-read:
if !ok { if !ok {
...@@ -921,19 +927,10 @@ func handleAction(c *webClient, a interface{}) error { ...@@ -921,19 +927,10 @@ func handleAction(c *webClient, a interface{}) error {
for i, t := range tracks { for i, t := range tracks {
ts[i] = t ts[i] = t
} }
go func(u *rtpUpConnection, err := a.client.PushConn(g, u.id, u, ts, replace)
ts []conn.UpTrack,
replace string) {
err := a.client.PushConn(
g, u.id, u, ts, replace,
)
if err != nil { if err != nil {
log.Printf( log.Printf("PushConn: %v", err)
"PushConn: %v",
err,
)
} }
}(u, ts, replace)
} }
case connectionFailedAction: case connectionFailedAction:
if down := getDownConn(c, a.id); down != nil { if down := getDownConn(c, a.id); down != nil {
...@@ -947,7 +944,7 @@ func handleAction(c *webClient, a interface{}) error { ...@@ -947,7 +944,7 @@ func handleAction(c *webClient, a interface{}) error {
for i, t := range down.tracks { for i, t := range down.tracks {
tracks[i] = t.remote tracks[i] = t.remote
} }
go c.PushConn( c.PushConn(
c.group, c.group,
down.remote.Id(), down.remote, down.remote.Id(), down.remote,
tracks, "", tracks, "",
...@@ -1393,7 +1390,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1393,7 +1390,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
disk.Close() disk.Close()
return c.error(err) return c.error(err)
} }
go pushConns(disk, c.group) pushConns(disk, c.group)
case "unrecord": case "unrecord":
if !c.permissions.Record { if !c.permissions.Record {
return c.error(group.UserError("not authorised")) return c.error(group.UserError("not authorised"))
...@@ -1551,13 +1548,20 @@ func (c *webClient) Warn(oponly bool, message string) error { ...@@ -1551,13 +1548,20 @@ func (c *webClient) Warn(oponly bool, message string) error {
var ErrClientDead = errors.New("client is dead") var ErrClientDead = errors.New("client is dead")
func (c *webClient) action(m interface{}) error { func (c *webClient) action(a interface{}) error {
c.mu.Lock()
defer c.mu.Unlock()
if len(c.actions) == 0 {
select { select {
case c.actionCh <- m: case c.actionCh <- a:
return nil return nil
case <-c.done: case <-c.done:
return ErrClientDead return ErrClientDead
default:
}
} }
c.actions = append(c.actions, a)
return nil
} }
func (c *webClient) write(m clientMessage) error { func (c *webClient) write(m clientMessage) error {
......
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