github.com/haraldLmueller/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  }