-
-
Notifications
You must be signed in to change notification settings - Fork 124
Expand file tree
/
Copy pathclients.go
More file actions
99 lines (81 loc) · 1.58 KB
/
Copy pathclients.go
File metadata and controls
99 lines (81 loc) · 1.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package statsviz
import (
"context"
"sync"
"github.com/gorilla/websocket"
"github.com/arl/statsviz/internal/plot"
)
type clients struct {
cfg *plot.Config
ctx context.Context
mu sync.RWMutex
m map[*websocket.Conn]chan []byte
}
func newClients(ctx context.Context, cfg *plot.Config) *clients {
return &clients{
m: make(map[*websocket.Conn]chan []byte),
cfg: cfg,
ctx: ctx,
}
}
type wsmsg struct {
Event string `json:"event"`
Data any `json:"data"`
}
func (c *clients) add(conn *websocket.Conn) {
dbglog("adding client")
// Send config first.
err := conn.WriteJSON(wsmsg{Event: "config", Data: c.cfg})
if err != nil {
dbglog("failed to send config: %v", err)
return
}
ch := make(chan []byte)
go func() {
defer func() {
c.mu.Lock()
delete(c.m, conn)
c.mu.Unlock()
dbglog("removed client")
}()
for {
select {
case <-c.ctx.Done():
return
case msg := <-ch:
if err := sendbuf(conn, msg); err != nil {
dbglog("failed to send data: %v", err)
return
}
}
}
}()
c.mu.Lock()
defer c.mu.Unlock()
c.m[conn] = ch
}
func sendbuf(conn *websocket.Conn, buf []byte) error {
w, err := conn.NextWriter(websocket.TextMessage)
if err != nil {
return err
}
_, err1 := w.Write(buf)
err2 := w.Close()
if err1 != nil {
return err1
}
return err2
}
func (c *clients) broadcast(buf []byte) {
c.mu.RLock()
defer c.mu.RUnlock()
for _, ch := range c.m {
select {
case ch <- buf:
default:
// if a client is not keeping up, we
// drop the message for that client.
dbglog("dropping message to client")
}
}
}