@@ -3,7 +3,6 @@ package sse
3
3
import (
4
4
"context"
5
5
"net/http"
6
- "sync"
7
6
)
8
7
9
8
type ClientManager interface {
@@ -28,10 +27,55 @@ type Client struct {
28
27
Ctx context.Context
29
28
}
30
29
30
+ type eventType int
31
+
32
+ const (
33
+ eTypeNewClient eventType = iota
34
+ eTypeClientList
35
+ eTypeRemoveClient
36
+ eTypeActiveClientCount
37
+ eTypeClient
38
+ )
39
+
40
+ type event struct {
41
+ Type eventType
42
+ ClientID string
43
+ Client * Client
44
+ Response chan * eventResponse
45
+ }
46
+ type eventResponse struct {
47
+ Clients []* Client
48
+ RemainingClients int
49
+ Client * Client
50
+ }
31
51
type Clients struct {
32
52
clients map [string ]* Client
33
- locker sync.Mutex
34
53
MsgBuffer int
54
+ events chan <- event
55
+ }
56
+
57
+ func (cs * Clients ) listener (events <- chan event ) {
58
+ for ev := range events {
59
+ switch ev .Type {
60
+ case eTypeNewClient :
61
+ cs .clients [ev .Client .ID ] = ev .Client
62
+ case eTypeClientList :
63
+ copied := make ([]* Client , 0 , len (cs .clients ))
64
+ for clientID := range cs .clients {
65
+ copied = append (copied , cs .clients [clientID ])
66
+ }
67
+ ev .Response <- & eventResponse {
68
+ Clients : copied ,
69
+ }
70
+ case eTypeRemoveClient :
71
+ delete (cs .clients , ev .ClientID )
72
+ ev .Response <- nil
73
+ case eTypeClient :
74
+ ev .Response <- & eventResponse {
75
+ Client : cs .clients [ev .ClientID ],
76
+ }
77
+ }
78
+ }
35
79
}
36
80
37
81
func (cs * Clients ) New (ctx context.Context , w http.ResponseWriter , clientID string ) (* Client , int ) {
@@ -42,75 +86,75 @@ func (cs *Clients) New(ctx context.Context, w http.ResponseWriter, clientID stri
42
86
ResponseWriter : w ,
43
87
Ctx : ctx ,
44
88
}
45
-
46
- cs .locker .Lock ()
47
- defer cs .locker .Unlock ()
48
-
49
- cs .clients [clientID ] = cli
89
+ cs .events <- event {
90
+ Type : eTypeNewClient ,
91
+ Client : cli ,
92
+ }
50
93
51
94
return cli , len (cs .clients )
52
95
}
53
96
54
97
func (cs * Clients ) Range (f func (cli * Client )) {
55
- cs . locker . Lock ( )
56
- copied := make ([] * Client , 0 , len ( cs .clients ))
57
- for clientID := range cs . clients {
58
- copied = append ( copied , cs . clients [ clientID ])
98
+ rch := make ( chan * eventResponse )
99
+ cs .events <- event {
100
+ Type : eTypeClientList ,
101
+ Response : rch ,
59
102
}
60
- cs .locker .Unlock ()
61
103
62
- for i := range copied {
63
- f (copied [i ])
104
+ response := <- rch
105
+ for i := range response .Clients {
106
+ f (response .Clients [i ])
64
107
}
65
108
}
66
109
67
110
func (cs * Clients ) Remove (clientID string ) int {
68
- cs .locker .Lock ()
69
- defer cs .locker .Unlock ()
111
+ rch := make (chan * eventResponse )
112
+ cs .events <- event {
113
+ Type : eTypeRemoveClient ,
114
+ ClientID : clientID ,
115
+ Response : rch ,
116
+ }
70
117
71
- delete (cs .clients , clientID )
72
- count := len (cs .clients )
118
+ <- rch
73
119
74
- return count
120
+ return len ( cs . clients )
75
121
}
76
122
77
123
func (cs * Clients ) Active () int {
78
- cs .locker .Lock ()
79
- defer cs .locker .Unlock ()
80
-
81
- count := len (cs .clients )
82
- return count
124
+ return len (cs .clients )
83
125
84
126
}
85
127
86
128
// MessageChannels returns a slice of message channels of all clients
87
129
// which you can then use to send message concurrently
88
130
func (cs * Clients ) Clients () []* Client {
89
- idx := 0
90
- cs .locker .Lock ()
91
- defer cs .locker .Unlock ()
92
-
93
- list := make ([]* Client , len (cs .clients ))
94
- for clientID := range cs .clients {
95
- cli := cs .clients [clientID ]
96
- list [idx ] = cli
97
- idx ++
131
+ rch := make (chan * eventResponse )
132
+ cs .events <- event {
133
+ Type : eTypeClientList ,
134
+ Response : rch ,
98
135
}
99
136
100
- return list
137
+ response := <- rch
138
+ return response .Clients
101
139
}
102
140
103
141
func (cs * Clients ) Client (clientID string ) * Client {
104
- cs .locker .Lock ()
105
- defer cs .locker .Unlock ()
106
- cli := cs .clients [clientID ]
107
-
108
- return cli
142
+ rch := make (chan * eventResponse )
143
+ cs .events <- event {
144
+ Type : eTypeClientList ,
145
+ Response : rch ,
146
+ }
147
+ cli := <- rch
148
+ return cli .Client
109
149
}
110
150
111
151
func NewClientManager () ClientManager {
112
- return & Clients {
113
- clients : make (map [string ]* Client ),
114
- locker : sync.Mutex {},
152
+ events := make (chan event , 10 )
153
+ cli := & Clients {
154
+ clients : make (map [string ]* Client ),
155
+ events : events ,
156
+ MsgBuffer : 10 ,
115
157
}
158
+ go cli .listener (events )
159
+ return cli
116
160
}
0 commit comments