github.com/rjeczalik/buffalo@v0.11.1/render/sse.go (about) 1 package render 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 ) 9 10 type sse struct { 11 Data interface{} `json:"data"` 12 Type string `json:"type"` 13 } 14 15 func (s *sse) String() string { 16 b, _ := json.Marshal(s) 17 return fmt.Sprintf("data: %s\n\n", string(b)) 18 } 19 20 func (s *sse) Bytes() []byte { 21 return []byte(s.String()) 22 } 23 24 // EventSource is designed to work with JavaScript EventSource objects. 25 // see https://developer.mozilla.org/en-US/docs/Web/API/EventSource for 26 // more details 27 type EventSource struct { 28 w http.ResponseWriter 29 fl http.Flusher 30 } 31 32 func (es *EventSource) Write(t string, d interface{}) error { 33 s := &sse{Type: t, Data: d} 34 _, err := es.w.Write(s.Bytes()) 35 if err != nil { 36 return err 37 } 38 es.Flush() 39 return nil 40 } 41 42 // Flush messages down the pipe. If messages aren't flushed they 43 // won't be sent. 44 func (es *EventSource) Flush() { 45 es.fl.Flush() 46 } 47 48 // CloseNotify return true across the channel when the connection 49 // in the browser has been severed. 50 func (es *EventSource) CloseNotify() <-chan bool { 51 return es.w.(http.CloseNotifier).CloseNotify() 52 } 53 54 // NewEventSource returns a new EventSource instance while ensuring 55 // that the http.ResponseWriter is able to handle EventSource messages. 56 // It also makes sure to set the proper response heads. 57 func NewEventSource(w http.ResponseWriter) (*EventSource, error) { 58 es := &EventSource{w: w} 59 var ok bool 60 es.fl, ok = w.(http.Flusher) 61 if !ok { 62 return es, errors.New("streaming is not supported") 63 } 64 65 es.w.Header().Set("Content-Type", "text/event-stream") 66 es.w.Header().Set("Cache-Control", "no-cache") 67 es.w.Header().Set("Connection", "keep-alive") 68 es.w.Header().Set("Access-Control-Allow-Origin", "*") 69 return es, nil 70 }