src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

decode.go (4892B)


      1 package eventstream
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/binary"
      6 	"encoding/hex"
      7 	"encoding/json"
      8 	"fmt"
      9 	"hash"
     10 	"hash/crc32"
     11 	"io"
     12 
     13 	"github.com/aws/smithy-go/logging"
     14 )
     15 
     16 // DecoderOptions is the Decoder configuration options.
     17 type DecoderOptions struct {
     18 	Logger      logging.Logger
     19 	LogMessages bool
     20 }
     21 
     22 // Decoder provides decoding of an Event Stream messages.
     23 type Decoder struct {
     24 	options DecoderOptions
     25 }
     26 
     27 // NewDecoder initializes and returns a Decoder for decoding event
     28 // stream messages from the reader provided.
     29 func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder {
     30 	options := DecoderOptions{}
     31 
     32 	for _, fn := range optFns {
     33 		fn(&options)
     34 	}
     35 
     36 	return &Decoder{
     37 		options: options,
     38 	}
     39 }
     40 
     41 // Decode attempts to decode a single message from the event stream reader.
     42 // Will return the event stream message, or error if decodeMessage fails to read
     43 // the message from the stream.
     44 //
     45 // payloadBuf is a byte slice that will be used in the returned Message.Payload. Callers
     46 // must ensure that the Message.Payload from a previous decode has been consumed before passing in the same underlying
     47 // payloadBuf byte slice.
     48 func (d *Decoder) Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
     49 	if d.options.Logger != nil && d.options.LogMessages {
     50 		debugMsgBuf := bytes.NewBuffer(nil)
     51 		reader = io.TeeReader(reader, debugMsgBuf)
     52 		defer func() {
     53 			logMessageDecode(d.options.Logger, debugMsgBuf, m, err)
     54 		}()
     55 	}
     56 
     57 	m, err = decodeMessage(reader, payloadBuf)
     58 
     59 	return m, err
     60 }
     61 
     62 // decodeMessage attempts to decode a single message from the event stream reader.
     63 // Will return the event stream message, or error if decodeMessage fails to read
     64 // the message from the reader.
     65 func decodeMessage(reader io.Reader, payloadBuf []byte) (m Message, err error) {
     66 	crc := crc32.New(crc32IEEETable)
     67 	hashReader := io.TeeReader(reader, crc)
     68 
     69 	prelude, err := decodePrelude(hashReader, crc)
     70 	if err != nil {
     71 		return Message{}, err
     72 	}
     73 
     74 	if prelude.HeadersLen > 0 {
     75 		lr := io.LimitReader(hashReader, int64(prelude.HeadersLen))
     76 		m.Headers, err = decodeHeaders(lr)
     77 		if err != nil {
     78 			return Message{}, err
     79 		}
     80 	}
     81 
     82 	if payloadLen := prelude.PayloadLen(); payloadLen > 0 {
     83 		buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen)))
     84 		if err != nil {
     85 			return Message{}, err
     86 		}
     87 		m.Payload = buf
     88 	}
     89 
     90 	msgCRC := crc.Sum32()
     91 	if err := validateCRC(reader, msgCRC); err != nil {
     92 		return Message{}, err
     93 	}
     94 
     95 	return m, nil
     96 }
     97 
     98 func logMessageDecode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
     99 	w := bytes.NewBuffer(nil)
    100 	defer func() { logger.Logf(logging.Debug, w.String()) }()
    101 
    102 	fmt.Fprintf(w, "Raw message:\n%s\n",
    103 		hex.Dump(msgBuf.Bytes()))
    104 
    105 	if decodeErr != nil {
    106 		fmt.Fprintf(w, "decodeMessage error: %v\n", decodeErr)
    107 		return
    108 	}
    109 
    110 	rawMsg, err := msg.rawMessage()
    111 	if err != nil {
    112 		fmt.Fprintf(w, "failed to create raw message, %v\n", err)
    113 		return
    114 	}
    115 
    116 	decodedMsg := decodedMessage{
    117 		rawMessage: rawMsg,
    118 		Headers:    decodedHeaders(msg.Headers),
    119 	}
    120 
    121 	fmt.Fprintf(w, "Decoded message:\n")
    122 	encoder := json.NewEncoder(w)
    123 	if err := encoder.Encode(decodedMsg); err != nil {
    124 		fmt.Fprintf(w, "failed to generate decoded message, %v\n", err)
    125 	}
    126 }
    127 
    128 func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) {
    129 	var p messagePrelude
    130 
    131 	var err error
    132 	p.Length, err = decodeUint32(r)
    133 	if err != nil {
    134 		return messagePrelude{}, err
    135 	}
    136 
    137 	p.HeadersLen, err = decodeUint32(r)
    138 	if err != nil {
    139 		return messagePrelude{}, err
    140 	}
    141 
    142 	if err := p.ValidateLens(); err != nil {
    143 		return messagePrelude{}, err
    144 	}
    145 
    146 	preludeCRC := crc.Sum32()
    147 	if err := validateCRC(r, preludeCRC); err != nil {
    148 		return messagePrelude{}, err
    149 	}
    150 
    151 	p.PreludeCRC = preludeCRC
    152 
    153 	return p, nil
    154 }
    155 
    156 func decodePayload(buf []byte, r io.Reader) ([]byte, error) {
    157 	w := bytes.NewBuffer(buf[0:0])
    158 
    159 	_, err := io.Copy(w, r)
    160 	return w.Bytes(), err
    161 }
    162 
    163 func decodeUint8(r io.Reader) (uint8, error) {
    164 	type byteReader interface {
    165 		ReadByte() (byte, error)
    166 	}
    167 
    168 	if br, ok := r.(byteReader); ok {
    169 		v, err := br.ReadByte()
    170 		return v, err
    171 	}
    172 
    173 	var b [1]byte
    174 	_, err := io.ReadFull(r, b[:])
    175 	return b[0], err
    176 }
    177 
    178 func decodeUint16(r io.Reader) (uint16, error) {
    179 	var b [2]byte
    180 	bs := b[:]
    181 	_, err := io.ReadFull(r, bs)
    182 	if err != nil {
    183 		return 0, err
    184 	}
    185 	return binary.BigEndian.Uint16(bs), nil
    186 }
    187 
    188 func decodeUint32(r io.Reader) (uint32, error) {
    189 	var b [4]byte
    190 	bs := b[:]
    191 	_, err := io.ReadFull(r, bs)
    192 	if err != nil {
    193 		return 0, err
    194 	}
    195 	return binary.BigEndian.Uint32(bs), nil
    196 }
    197 
    198 func decodeUint64(r io.Reader) (uint64, error) {
    199 	var b [8]byte
    200 	bs := b[:]
    201 	_, err := io.ReadFull(r, bs)
    202 	if err != nil {
    203 		return 0, err
    204 	}
    205 	return binary.BigEndian.Uint64(bs), nil
    206 }
    207 
    208 func validateCRC(r io.Reader, expect uint32) error {
    209 	msgCRC, err := decodeUint32(r)
    210 	if err != nil {
    211 		return err
    212 	}
    213 
    214 	if msgCRC != expect {
    215 		return ChecksumError{}
    216 	}
    217 
    218 	return nil
    219 }