...

Source file src/github.com/gin-contrib/sse/sse-encoder.go

Documentation: github.com/gin-contrib/sse

     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  }
   111  

View as plain text