| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
- // Use of this source code is governed by a MIT style
- // license that can be found in the LICENSE file.
- package sse
- import (
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "reflect"
- "strings"
- )
- // Server-Sent Events
- // W3C Working Draft 29 October 2009
- // http://www.w3.org/TR/2009/WD-eventsource-20091029/
- const ContentType = "text/event-stream"
- type Event struct {
- Event string
- Id string
- Retry uint
- Data interface{}
- }
- func Encode(w io.Writer, event Event) error {
- writeId(w, event.Id)
- writeEvent(w, event.Event)
- writeRetry(w, event.Retry)
- return writeData(w, event.Data)
- }
- func writeId(w io.Writer, id string) {
- if len(id) > 0 {
- w.Write([]byte("id: "))
- w.Write([]byte(escape(id)))
- w.Write([]byte("\n"))
- }
- }
- func writeEvent(w io.Writer, event string) {
- if len(event) > 0 {
- w.Write([]byte("event: "))
- w.Write([]byte(escape(event)))
- w.Write([]byte("\n"))
- }
- }
- func writeRetry(w io.Writer, retry uint) {
- if retry > 0 {
- fmt.Fprintf(w, "retry: %d\n", retry)
- }
- }
- func writeData(w io.Writer, data interface{}) error {
- w.Write([]byte("data: "))
- switch typeOfData(data) {
- case reflect.Struct, reflect.Slice, reflect.Map:
- err := json.NewEncoder(w).Encode(data)
- if err != nil {
- return err
- }
- w.Write([]byte("\n"))
- default:
- text := fmt.Sprint(data)
- w.Write([]byte(escape(text)))
- w.Write([]byte("\n\n"))
- }
- return nil
- }
- func (r Event) Write(w http.ResponseWriter) error {
- header := w.Header()
- header.Set("Content-Type", ContentType)
- if _, exist := header["Cache-Control"]; !exist {
- header.Set("Cache-Control", "no-cache")
- }
- return Encode(w, r)
- }
- func typeOfData(data interface{}) reflect.Kind {
- value := reflect.ValueOf(data)
- valueType := value.Kind()
- if valueType == reflect.Ptr {
- valueType = value.Elem().Kind()
- }
- return valueType
- }
- func escape(str string) string {
- // any-char = %x0000-0009 / %x000B-000C / %x000E-10FFFF
- // ; a Unicode character other than U+000A LINE FEED (LF) or U+000D CARRIAGE RETURN (CR)
- str = strings.Replace(str, "\n", "\\n", -1)
- str = strings.Replace(str, "\r", "\\r", -1)
- return str
- }
|