package render import ( "encoding/json" "fmt" "net/http" "reflect" ) type sseRender struct{} var SSEvent Render = sseRender{} func (_ sseRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { eventName := data[0].(string) obj := data[1] return WriteSSEvent(w, eventName, obj) } func WriteSSEvent(w http.ResponseWriter, eventName string, data interface{}) error { header := w.Header() if len(header.Get("Content-Type")) == 0 { w.Header().Set("Content-Type", "text/event-stream") } var stringData string switch typeOfData(data) { case reflect.Struct, reflect.Slice: if jsonBytes, err := json.Marshal(data); err == nil { stringData = string(jsonBytes) } else { return err } case reflect.Ptr: stringData = escape(fmt.Sprintf("%v", &data)) + "\n" default: stringData = escape(fmt.Sprintf("%v", data)) + "\n" } _, err := fmt.Fprintf(w, "event: %s\ndata: %s\n", escape(eventName), stringData) return err } func typeOfData(data interface{}) reflect.Kind { value := reflect.ValueOf(data) valueType := value.Kind() if valueType == reflect.Ptr { newValue := value.Elem().Kind() if newValue == reflect.Struct || newValue == reflect.Slice { return newValue } else { return valueType } } return valueType } func escape(str string) string { return str }