github.com/anycable/anycable-go@v1.5.1/sse/encoder.go (about) 1 package sse 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 8 "github.com/anycable/anycable-go/common" 9 "github.com/anycable/anycable-go/encoders" 10 "github.com/anycable/anycable-go/utils" 11 "github.com/anycable/anycable-go/ws" 12 ) 13 14 const sseEncoderID = "sse" 15 16 // Tell the client to reconnect in a year in case we don't really want it to re-connect 17 const retryNoReconnect = int64(31536000000) 18 19 const lastIdDelimeter = "/" 20 21 // Encoder is responsible for converting messages to SSE format (event:, data:, etc.) 22 // NOTE: It's only used to encode messages from server to client. 23 type Encoder struct { 24 // Whether to send only the "message" field of the payload as data or the whole payload 25 UnwrapData bool 26 } 27 28 func (Encoder) ID() string { 29 return sseEncoderID 30 } 31 32 func (e *Encoder) Encode(msg encoders.EncodedMessage) (*ws.SentFrame, error) { 33 msgType := msg.GetType() 34 35 b, err := json.Marshal(&msg) 36 if err != nil { 37 panic("Failed to build JSON 😲") 38 } 39 40 var payload string 41 42 reply, isReply := msg.(*common.Reply) 43 44 if isReply && reply.Type == "" && e.UnwrapData { 45 var data string 46 47 if replyStr, ok := reply.Message.(string); ok { 48 data = replyStr 49 } else { 50 data = string(utils.ToJSON(reply.Message)) 51 } 52 payload = "data: " + data 53 } else { 54 payload = "data: " + string(b) 55 } 56 57 if msgType != "" { 58 payload = "event: " + msgType + "\n" + payload 59 } 60 61 if reply, ok := msg.(*common.Reply); ok { 62 if reply.Offset > 0 && reply.Epoch != "" && reply.StreamID != "" { 63 payload += "\nid: " + fmt.Sprintf("%d%s%s%s%s", reply.Offset, lastIdDelimeter, reply.Epoch, lastIdDelimeter, reply.StreamID) 64 } 65 } 66 67 if msgType == "disconnect" { 68 dmsg, ok := msg.(*common.DisconnectMessage) 69 if ok && !dmsg.Reconnect { 70 payload += "\nretry: " + fmt.Sprintf("%d", retryNoReconnect) 71 } 72 } 73 74 return &ws.SentFrame{FrameType: ws.TextFrame, Payload: []byte(payload)}, nil 75 } 76 77 func (e Encoder) EncodeTransmission(raw string) (*ws.SentFrame, error) { 78 msg := common.Reply{} 79 80 if err := json.Unmarshal([]byte(raw), &msg); err != nil { 81 return nil, err 82 } 83 84 return e.Encode(&msg) 85 } 86 87 func (Encoder) Decode(raw []byte) (*common.Message, error) { 88 return nil, errors.New("unsupported") 89 }