@@ -45,7 +45,24 @@ func Bind(obj interface{}, opts ...Options) flamego.Handler {
4545 }
4646 c .Set (reflect .ChanOf (reflect .SendDir , sse .sender .Type ().Elem ()), sse .sender )
4747
48- go sse .handle (log , c .ResponseWriter ())
48+ // stopCh is closed when the next handler returns, signaling handle()
49+ // to stop writing to the ResponseWriter.
50+ stopCh := make (chan struct {})
51+ // doneCh is closed when handle() exits, allowing the handler to wait
52+ // for the goroutine to fully stop before returning.
53+ doneCh := make (chan struct {})
54+
55+ go func () {
56+ defer close (doneCh )
57+ sse .handle (log , c , stopCh )
58+ }()
59+
60+ // Call the next handler(s) in the chain. When they return, signal
61+ // the handle goroutine to stop, then wait for it to finish before
62+ // returning control to the HTTP server.
63+ c .Next ()
64+ close (stopCh )
65+ <- doneCh
4966 }
5067}
5168
@@ -59,7 +76,8 @@ func newOptions(opts []Options) Options {
5976 return opts [0 ]
6077}
6178
62- func (c * connection ) handle (log * log.Logger , w flamego.ResponseWriter ) {
79+ func (c * connection ) handle (log * log.Logger , ctx flamego.Context , stopCh <- chan struct {}) {
80+ w := ctx .ResponseWriter ()
6381 ticker := time .NewTicker (c .PingInterval )
6482 defer func () { ticker .Stop () }()
6583
@@ -78,11 +96,15 @@ func (c *connection) handle(log *log.Logger, w flamego.ResponseWriter) {
7896 senderSend = iota
7997 tickerTick
8098 timeout
99+ closed
100+ stopped
81101 )
82- cases := make ([]reflect.SelectCase , 3 )
102+ cases := make ([]reflect.SelectCase , 5 )
83103 cases [senderSend ] = reflect.SelectCase {Dir : reflect .SelectRecv , Chan : c .sender , Send : reflect .ValueOf (nil )}
84104 cases [tickerTick ] = reflect.SelectCase {Dir : reflect .SelectRecv , Chan : reflect .ValueOf (ticker .C ), Send : reflect .ValueOf (nil )}
85105 cases [timeout ] = reflect.SelectCase {Dir : reflect .SelectRecv , Chan : reflect .ValueOf (time .After (time .Hour )), Send : reflect .ValueOf (nil )}
106+ cases [closed ] = reflect.SelectCase {Dir : reflect .SelectRecv , Chan : reflect .ValueOf (ctx .Request ().Context ().Done ()), Send : reflect .ValueOf (nil )}
107+ cases [stopped ] = reflect.SelectCase {Dir : reflect .SelectRecv , Chan : reflect .ValueOf (stopCh ), Send : reflect .ValueOf (nil )}
86108
87109loop:
88110 for {
@@ -112,6 +134,12 @@ loop:
112134 write ("events: stream timeout\n \n " )
113135 w .Flush ()
114136 break loop
137+
138+ case closed :
139+ return
140+
141+ case stopped :
142+ return
115143 }
116144 }
117145
0 commit comments