@@ -19,7 +19,7 @@ connections and disconnectinos.
19
19
A quick example of a simple sever that broadcasts a "tick" event every second
20
20
21
21
func main() {
22
- stream := & eventsource.Stream{}
22
+ stream := eventsource.NewStream()
23
23
go func(s *eventsource.Stream) {
24
24
for {
25
25
time.Sleep(time.Second)
@@ -33,7 +33,6 @@ A quick example of a simple sever that broadcasts a "tick" event every second
33
33
package eventsource
34
34
35
35
import (
36
- "container/list"
37
36
"net/http"
38
37
"sync"
39
38
)
@@ -43,52 +42,49 @@ import (
43
42
// A stream also implements an http.Handler to easily register incoming
44
43
// http requests as new clients.
45
44
type Stream struct {
46
- clients list. List
45
+ clients map [ * Client ] topicList
47
46
listLock sync.RWMutex
48
47
shutdownWait sync.WaitGroup
49
48
clientConnectHook func (* http.Request , * Client )
50
49
}
51
50
52
- type registeredClient struct {
53
- c * Client
54
- topics map [string ]bool
51
+ type topicList map [string ]bool
52
+
53
+ // NewStream creates a new stream object
54
+ func NewStream () * Stream {
55
+ return & Stream {
56
+ clients : make (map [* Client ]topicList ),
57
+ }
55
58
}
56
59
57
60
// Register adds a client to the stream to receive all broadcast
58
61
// messages. Has no effect if the client is already registered.
59
62
func (s * Stream ) Register (c * Client ) {
60
63
61
64
// see if the client has been registered
62
- if cli := s .getClient ( c ); cli != nil {
65
+ if _ , found := s .clients [ c ]; found {
63
66
return
64
67
}
65
68
66
69
// append new client
67
- s .addClient ( c )
70
+ s .clients [ c ] = make ( topicList )
68
71
}
69
72
70
73
// Remove will remove a client from this stream, but not shut the client down.
71
74
func (s * Stream ) Remove (c * Client ) {
72
75
s .listLock .Lock ()
73
76
defer s .listLock .Unlock ()
74
77
75
- for element := s .clients .Front (); element != nil ; element = element .Next () {
76
- if regCli := element .Value .(* registeredClient ); regCli .c == c {
77
- // client found
78
- s .clients .Remove (element )
79
- return
80
- }
81
- }
78
+ delete (s .clients , c )
82
79
}
83
80
84
81
// Broadcast sends the event to all clients registered on this stream.
85
82
func (s * Stream ) Broadcast (e * Event ) {
86
83
s .listLock .RLock ()
87
84
defer s .listLock .RUnlock ()
88
85
89
- for element := s .clients .Front (); element != nil ; element = element .Next () {
90
- cli := element .Value .(* registeredClient )
91
- cli .c .Send (e )
86
+ for cli := range s .clients {
87
+ cli .Send (e )
92
88
}
93
89
}
94
90
@@ -97,35 +93,35 @@ func (s *Stream) Broadcast(e *Event) {
97
93
// client.
98
94
func (s * Stream ) Subscribe (topic string , c * Client ) {
99
95
// see if the client is registered
100
- cli := s .getClient ( c )
96
+ topics , found := s .clients [ c ]
101
97
102
98
// register if not
103
- if cli == nil {
104
- cli = s .addClient (c )
99
+ if ! found {
100
+ topics = make (topicList )
101
+ s .clients [c ] = topics
105
102
}
106
103
107
- cli . topics [topic ] = true
104
+ topics [topic ] = true
108
105
}
109
106
110
107
// Unsubscribe removes clients from the topic, but not from broadcasts.
111
108
func (s * Stream ) Unsubscribe (topic string , c * Client ) {
112
109
113
- cli := s .getClient ( c )
114
- if cli == nil {
110
+ topics , found := s .clients [ c ]
111
+ if ! found {
115
112
return
116
113
}
117
- cli . topics [topic ] = false
114
+ topics [topic ] = false
118
115
}
119
116
120
117
// Publish sends the event to clients that have subscribed to the given topic.
121
118
func (s * Stream ) Publish (topic string , e * Event ) {
122
119
s .listLock .RLock ()
123
120
defer s .listLock .RUnlock ()
124
121
125
- for element := s .clients .Front (); element != nil ; element = element .Next () {
126
- cli := element .Value .(* registeredClient )
127
- if cli .topics [topic ] {
128
- cli .c .Send (e )
122
+ for cli , topics := range s .clients {
123
+ if topics [topic ] {
124
+ cli .Send (e )
129
125
}
130
126
}
131
127
}
@@ -135,12 +131,9 @@ func (s *Stream) Shutdown() {
135
131
s .listLock .Lock ()
136
132
defer s .listLock .Unlock ()
137
133
138
- for element := s .clients .Front (); element != nil ; {
139
- cli := element .Value .(* registeredClient )
140
- cli .c .Shutdown ()
141
- next := element .Next ()
142
- s .clients .Remove (element )
143
- element = next
134
+ for client := range s .clients {
135
+ client .Shutdown ()
136
+ delete (s .clients , client )
144
137
}
145
138
}
146
139
@@ -223,32 +216,3 @@ func (s *Stream) ClientConnectHook(fn func(*http.Request, *Client)) {
223
216
func checkRequest (r * http.Request ) bool {
224
217
return r .Header .Get ("Accept" ) == "text/event-stream"
225
218
}
226
-
227
- func (s * Stream ) getClient (c * Client ) * registeredClient {
228
- s .listLock .RLock ()
229
- defer s .listLock .RUnlock ()
230
-
231
- for element := s .clients .Front (); element != nil ; element = element .Next () {
232
- if regCli := element .Value .(* registeredClient ); regCli .c == c {
233
- // client found
234
- return regCli
235
- }
236
- }
237
-
238
- // not found
239
- return nil
240
- }
241
-
242
- func (s * Stream ) addClient (c * Client ) * registeredClient {
243
-
244
- cli := & registeredClient {
245
- c : c ,
246
- topics : make (map [string ]bool ),
247
- }
248
-
249
- s .listLock .Lock ()
250
- s .clients .PushBack (cli )
251
- s .listLock .Unlock ()
252
-
253
- return cli
254
- }
0 commit comments