I'm developing chat rooms based on Twitter hashtag with Server sent events, with the package https://github.com/antage/eventsource
I have a problem concerning the disconnection of the client. I run a goroutine to send messages to the client, but when the client disconnects, the goroutine still runs.
I don't know how to detect on the server side that the client is disconnected.
func (sh StreamHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
es := eventsource.New(
&eventsource.Settings{
Timeout: 2 * time.Second,
CloseOnTimeout: true,
IdleTimeout: 2 * time.Second,
Gzip: true,
},
func(req *http.Request) [][]byte {
return [][]byte{
[]byte("X-Accel-Buffering: no"),
[]byte("Access-Control-Allow-Origin: *"),
}
},
)
es.ServeHTTP(resp, req)
go func() {
var id int
for {
id++
time.Sleep(1 * time.Second)
es.SendEventMessage("blabla", "message", strconv.Itoa(id))
}
}()
}
You could check ConsumersCount()
:
go func() {
var id int
for es.ConsumersCount() > 0 {
id++
es.SendEventMessage("blabla", "message", strconv.Itoa(id))
time.Sleep(1 * time.Second)
}
fmt.Println("closed")
}()
Kinda hacky, but it seems to work.
You may be better off using a different package or rolling your own so you could have better control over the lifetime of your goroutines. You can detect a closed connection on .Write
(which this package isn't exposing).
If you want here's an example chat server in TCP: chat-server. And a video tutorial to go with it: tutorial.
The same basic pattern should work for SSE.
You can use CloseNotifier which lets you know if the underlying http connection has closed. Like:
notify := w.(http.CloseNotifier).CloseNotify()
go func() {
<-notify
// connection close, do cleanup, etc.
}()
HTH
As of December 2018, apparently CloseNotifier is deprecated. The recommended solution is to use the Request
Context. The following worked for me:
done := make(chan bool)
go func() {
<-req.Context().Done()
done <- true
}()
<-done