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  }