Opt: clients reg lock

pull/39/head
zijiren233 2 years ago
parent 8147854f35
commit ada805367f

@ -14,9 +14,14 @@ import (
"github.com/zijiren233/gencontainer/rwmap" "github.com/zijiren233/gencontainer/rwmap"
) )
type clients struct {
lock sync.RWMutex
m map[*Client]struct{}
}
type Hub struct { type Hub struct {
id string id string
clients rwmap.RWMap[string, *rwmap.RWMap[*Client, struct{}]] clients rwmap.RWMap[string, *clients]
broadcast chan *broadcastMessage broadcast chan *broadcastMessage
exit chan struct{} exit chan struct{}
closed uint32 closed uint32
@ -66,8 +71,11 @@ func (h *Hub) serve() error {
select { select {
case message := <-h.broadcast: case message := <-h.broadcast:
h.devMessage(message.data) h.devMessage(message.data)
h.clients.Range(func(id string, cli *rwmap.RWMap[*Client, struct{}]) bool { h.clients.Range(func(id string, clients *clients) bool {
cli.Range(func(c *Client, value struct{}) bool { clients.lock.RLock()
defer clients.lock.RUnlock()
for c := range clients.m {
if utils.In(message.ignoreId, c.u.ID) { if utils.In(message.ignoreId, c.u.ID) {
return true return true
} }
@ -75,11 +83,9 @@ func (h *Hub) serve() error {
return true return true
} }
if err := c.Send(message.data); err != nil { if err := c.Send(message.data); err != nil {
log.Debugf("hub: %s, write to client err: %s\nmessage: %+v", h.id, err, message)
c.Close() c.Close()
} }
return true }
})
return true return true
}) })
@ -122,7 +128,7 @@ func (h *Hub) ping() {
func (h *Hub) devMessage(msg Message) { func (h *Hub) devMessage(msg Message) {
switch msg.MessageType() { switch msg.MessageType() {
case websocket.TextMessage: case websocket.BinaryMessage:
log.Debugf("hub: %s, broadcast:\nmessage: %+v", h.id, msg.String()) log.Debugf("hub: %s, broadcast:\nmessage: %+v", h.id, msg.String())
} }
} }
@ -140,13 +146,12 @@ func (h *Hub) Close() error {
return ErrAlreadyClosed return ErrAlreadyClosed
} }
close(h.exit) close(h.exit)
h.clients.Range(func(id string, client *rwmap.RWMap[*Client, struct{}]) bool { h.clients.Range(func(id string, clients *clients) bool {
h.clients.Delete(id) h.clients.Delete(id)
client.Range(func(key *Client, value struct{}) bool { for c := range clients.m {
client.Delete(key) delete(clients.m, c)
key.Close() c.Close()
return true }
})
return true return true
}) })
h.wg.Wait() h.wg.Wait()
@ -181,11 +186,15 @@ func (h *Hub) RegClient(cli *Client) error {
if err != nil { if err != nil {
return err return err
} }
c, _ := h.clients.LoadOrStore(cli.u.ID, &rwmap.RWMap[*Client, struct{}]{}) c, _ := h.clients.LoadOrStore(cli.u.ID, &clients{})
_, loaded := c.LoadOrStore(cli, struct{}{}) c.lock.Lock()
if loaded { defer c.lock.Unlock()
return errors.New("client already exist") if c.m == nil {
c.m = make(map[*Client]struct{})
} else if _, ok := c.m[cli]; ok {
return errors.New("client already exists")
} }
c.m[cli] = struct{}{}
return nil return nil
} }
@ -200,18 +209,14 @@ func (h *Hub) UnRegClient(cli *Client) error {
if !loaded { if !loaded {
return errors.New("client not found") return errors.New("client not found")
} }
_, loaded2 := c.LoadAndDelete(cli) c.lock.Lock()
if !loaded2 { defer c.lock.Unlock()
if _, ok := c.m[cli]; !ok {
return errors.New("client not found") return errors.New("client not found")
} }
if c.Len() == 0 { delete(c.m, cli)
if h.clients.CompareAndDelete(cli.u.ID, c) { if len(c.m) == 0 {
c.Range(func(key *Client, value struct{}) bool { h.clients.CompareAndDelete(cli.u.ID, c)
c.Delete(key)
h.RegClient(key)
return true
})
}
} }
return nil return nil
} }
@ -228,17 +233,12 @@ func (h *Hub) SendToUser(userID string, data Message) (err error) {
if !ok { if !ok {
return nil return nil
} }
cli.Range(func(key *Client, value struct{}) bool { cli.lock.RLock()
if err = key.Send(data); err != nil { defer cli.lock.RUnlock()
cli.CompareAndDelete(key, value) for c := range cli.m {
log.Debugf("hub: %s, write to client err: %s\nmessage: %+v", h.id, err, data) if err = c.Send(data); err != nil {
key.Close() c.Close()
}
} }
return true
})
return return
} }
func (h *Hub) LoadClient(userID string) (*rwmap.RWMap[*Client, struct{}], bool) {
return h.clients.Load(userID)
}

@ -9,7 +9,6 @@ import (
"github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/db"
"github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/utils" "github.com/synctv-org/synctv/utils"
"github.com/zijiren233/gencontainer/rwmap"
rtmps "github.com/zijiren233/livelib/server" rtmps "github.com/zijiren233/livelib/server"
"github.com/zijiren233/stream" "github.com/zijiren233/stream"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@ -44,13 +43,6 @@ func (r *Room) Broadcast(data Message, conf ...BroadcastConf) error {
return r.hub.Broadcast(data, conf...) return r.hub.Broadcast(data, conf...)
} }
func (r *Room) LoadClient(userID string) (*rwmap.RWMap[*Client, struct{}], bool) {
if r.hub == nil {
return nil, false
}
return r.hub.LoadClient(userID)
}
func (r *Room) SendToUser(user *User, data Message) error { func (r *Room) SendToUser(user *User, data Message) error {
if r.hub == nil { if r.hub == nil {
return nil return nil

Loading…
Cancel
Save