github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin-contrib/sse/sse-encoder.go (about) 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 "reflect" 12 "strconv" 13 "strings" 14 15 "github.com/hellobchain/newcryptosm/http" 16 ) 17 18 // Server-Sent Events 19 // W3C Working Draft 29 October 2009 20 // http://www.w3.org/TR/2009/WD-eventsource-20091029/ 21 22 const ContentType = "text/event-stream" 23 24 var contentType = []string{ContentType} 25 var noCache = []string{"no-cache"} 26 27 var fieldReplacer = strings.NewReplacer( 28 "\n", "\\n", 29 "\r", "\\r") 30 31 var dataReplacer = strings.NewReplacer( 32 "\n", "\ndata:", 33 "\r", "\\r") 34 35 type Event struct { 36 Event string 37 Id string 38 Retry uint 39 Data interface{} 40 } 41 42 func Encode(writer io.Writer, event Event) error { 43 w := checkWriter(writer) 44 writeId(w, event.Id) 45 writeEvent(w, event.Event) 46 writeRetry(w, event.Retry) 47 return writeData(w, event.Data) 48 } 49 50 func writeId(w stringWriter, id string) { 51 if len(id) > 0 { 52 w.WriteString("id:") 53 fieldReplacer.WriteString(w, id) 54 w.WriteString("\n") 55 } 56 } 57 58 func writeEvent(w stringWriter, event string) { 59 if len(event) > 0 { 60 w.WriteString("event:") 61 fieldReplacer.WriteString(w, event) 62 w.WriteString("\n") 63 } 64 } 65 66 func writeRetry(w stringWriter, retry uint) { 67 if retry > 0 { 68 w.WriteString("retry:") 69 w.WriteString(strconv.FormatUint(uint64(retry), 10)) 70 w.WriteString("\n") 71 } 72 } 73 74 func writeData(w stringWriter, data interface{}) error { 75 w.WriteString("data:") 76 switch kindOfData(data) { 77 case reflect.Struct, reflect.Slice, reflect.Map: 78 err := json.NewEncoder(w).Encode(data) 79 if err != nil { 80 return err 81 } 82 w.WriteString("\n") 83 default: 84 dataReplacer.WriteString(w, fmt.Sprint(data)) 85 w.WriteString("\n\n") 86 } 87 return nil 88 } 89 90 func (r Event) Render(w http.ResponseWriter) error { 91 r.WriteContentType(w) 92 return Encode(w, r) 93 } 94 95 func (r Event) WriteContentType(w http.ResponseWriter) { 96 header := w.Header() 97 header["Content-Type"] = contentType 98 99 if _, exist := header["Cache-Control"]; !exist { 100 header["Cache-Control"] = noCache 101 } 102 } 103 104 func kindOfData(data interface{}) reflect.Kind { 105 value := reflect.ValueOf(data) 106 valueType := value.Kind() 107 if valueType == reflect.Ptr { 108 valueType = value.Elem().Kind() 109 } 110 return valueType 111 }