OSDN Git Service

feat(warder): add warder backbone (#181)
[bytom/vapor.git] / vendor / github.com / gin-contrib / sse / sse-encoder.go
1 // Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
2 // Use of this source code is governed by a MIT style
3 // license that can be found in the LICENSE file.
4
5 package sse
6
7 import (
8         "encoding/json"
9         "fmt"
10         "io"
11         "net/http"
12         "reflect"
13         "strconv"
14         "strings"
15 )
16
17 // Server-Sent Events
18 // W3C Working Draft 29 October 2009
19 // http://www.w3.org/TR/2009/WD-eventsource-20091029/
20
21 const ContentType = "text/event-stream"
22
23 var contentType = []string{ContentType}
24 var noCache = []string{"no-cache"}
25
26 var fieldReplacer = strings.NewReplacer(
27         "\n", "\\n",
28         "\r", "\\r")
29
30 var dataReplacer = strings.NewReplacer(
31         "\n", "\ndata:",
32         "\r", "\\r")
33
34 type Event struct {
35         Event string
36         Id    string
37         Retry uint
38         Data  interface{}
39 }
40
41 func Encode(writer io.Writer, event Event) error {
42         w := checkWriter(writer)
43         writeId(w, event.Id)
44         writeEvent(w, event.Event)
45         writeRetry(w, event.Retry)
46         return writeData(w, event.Data)
47 }
48
49 func writeId(w stringWriter, id string) {
50         if len(id) > 0 {
51                 w.WriteString("id:")
52                 fieldReplacer.WriteString(w, id)
53                 w.WriteString("\n")
54         }
55 }
56
57 func writeEvent(w stringWriter, event string) {
58         if len(event) > 0 {
59                 w.WriteString("event:")
60                 fieldReplacer.WriteString(w, event)
61                 w.WriteString("\n")
62         }
63 }
64
65 func writeRetry(w stringWriter, retry uint) {
66         if retry > 0 {
67                 w.WriteString("retry:")
68                 w.WriteString(strconv.FormatUint(uint64(retry), 10))
69                 w.WriteString("\n")
70         }
71 }
72
73 func writeData(w stringWriter, data interface{}) error {
74         w.WriteString("data:")
75         switch kindOfData(data) {
76         case reflect.Struct, reflect.Slice, reflect.Map:
77                 err := json.NewEncoder(w).Encode(data)
78                 if err != nil {
79                         return err
80                 }
81                 w.WriteString("\n")
82         default:
83                 dataReplacer.WriteString(w, fmt.Sprint(data))
84                 w.WriteString("\n\n")
85         }
86         return nil
87 }
88
89 func (r Event) Render(w http.ResponseWriter) error {
90         r.WriteContentType(w)
91         return Encode(w, r)
92 }
93
94 func (r Event) WriteContentType(w http.ResponseWriter) {
95         header := w.Header()
96         header["Content-Type"] = contentType
97
98         if _, exist := header["Cache-Control"]; !exist {
99                 header["Cache-Control"] = noCache
100         }
101 }
102
103 func kindOfData(data interface{}) reflect.Kind {
104         value := reflect.ValueOf(data)
105         valueType := value.Kind()
106         if valueType == reflect.Ptr {
107                 valueType = value.Elem().Kind()
108         }
109         return valueType
110 }