1
1
package eventsource
2
2
3
3
import (
4
+ "context"
4
5
"io"
5
6
"net/http"
6
7
"sync"
@@ -12,7 +13,7 @@ import (
12
13
type Client struct {
13
14
flush http.Flusher
14
15
write io.Writer
15
- close http. CloseNotifier
16
+ ctx context. Context
16
17
events chan * Event
17
18
closed bool
18
19
waiter sync.WaitGroup
@@ -22,8 +23,7 @@ type Client struct {
22
23
}
23
24
24
25
// NewClient creates a client wrapping a response writer.
25
- // The response writer must support http.Flusher and http.CloseNotifier
26
- // interfaces.
26
+ // The response writer must support http.Flusher interface.
27
27
// When writing, the client will automatically send some headers. Passing the
28
28
// original http.Request helps determine which headers, but the request it is
29
29
// optional.
@@ -41,12 +41,7 @@ func NewClient(w http.ResponseWriter, req *http.Request) *Client {
41
41
}
42
42
c .flush = flush
43
43
44
- // Check to ensure we support close notifications
45
- closer , ok := w .(http.CloseNotifier )
46
- if ! ok {
47
- return nil
48
- }
49
- c .close = closer
44
+ c .ctx = req .Context ()
50
45
51
46
// Send the initial headers
52
47
w .Header ().Set ("Content-Type" , "text/event-stream" )
@@ -57,14 +52,15 @@ func NewClient(w http.ResponseWriter, req *http.Request) *Client {
57
52
flush .Flush ()
58
53
59
54
// start the sending thread
60
- c .waiter .Add (1 )
55
+ c .waiter .Add (2 )
61
56
go c .run ()
62
57
go c .flusher ()
63
58
return c
64
59
}
65
60
66
61
// Send queues an event to be sent to the client.
67
- // This does not block until the event has been sent.
62
+ // This does not block until the event has been sent,
63
+ // however it could block if the event queue is full.
68
64
// Returns an error if the Client has disconnected
69
65
func (c * Client ) Send (ev * Event ) error {
70
66
if c .closed {
@@ -74,6 +70,22 @@ func (c *Client) Send(ev *Event) error {
74
70
return nil
75
71
}
76
72
73
+ // Send queues an event to be sent to the client.
74
+ // This guarantees not block until the event has been sent.
75
+ // Returns true if blocked
76
+ // Returns an error if the Client has disconnected
77
+ func (c * Client ) SendNonBlocking (ev * Event ) (bool , error ) {
78
+ if c .closed {
79
+ return false , io .ErrClosedPipe
80
+ }
81
+ select {
82
+ case c .events <- ev .Clone ():
83
+ default :
84
+ return true , nil
85
+ }
86
+ return false , nil
87
+ }
88
+
77
89
// Shutdown terminates a client connection
78
90
func (c * Client ) Shutdown () {
79
91
close (c .events )
@@ -89,6 +101,7 @@ func (c *Client) Wait() {
89
101
90
102
// Worker thread for the client responsible for writing events
91
103
func (c * Client ) run () {
104
+ done := c .ctx .Done ()
92
105
for {
93
106
select {
94
107
case ev , ok := <- c .events :
@@ -105,7 +118,7 @@ func (c *Client) run() {
105
118
c .lastWrite = time .Now ()
106
119
c .lock .Unlock ()
107
120
108
- case <- c . close . CloseNotify () :
121
+ case <- done :
109
122
c .closed = true
110
123
c .waiter .Done ()
111
124
return
@@ -132,4 +145,5 @@ func (c *Client) flusher() {
132
145
}
133
146
134
147
ticker .Stop ()
148
+ c .waiter .Done ()
135
149
}
0 commit comments