Class: Aws::EventStream::Encoder

Inherits:
Object
  • Object
show all
Defined in:
lib/aws-eventstream/encoder.rb

Overview

This class provides #encode method for encoding Aws::EventStream::Message into binary.

  • #encode - encode Aws::EventStream::Message into binary when output IO-like object is provided, binary string would be written to IO. If not, the encoded binary string would be returned directly

## Examples

message = Aws::EventStream::Message.new(
  headers: {
    "foo" => Aws::EventStream::HeaderValue.new(
      value: "bar", type: "string"
     )
  },
  payload: "payload"
)
encoder = Aws::EventsStream::Encoder.new
file = Tempfile.new

# encode into IO ouput
encoder.encode(message, file)

# get encoded binary string
encoded_message = encoder.encode(message)

file.read == encoded_message
# => true

Constant Summary collapse

OVERHEAD_LENGTH =

bytes of total overhead in a message, including prelude and 4 bytes total message crc checksum

16
MAX_HEADERS_LENGTH =

Maximum header length allowed (after encode) 128kb

1024 * 128
MAX_PAYLOAD_LENGTH =

Maximum payload length allowed (after encode) 24mb

1024 * 1024 * 24

Instance Method Summary collapse

Instance Method Details

#encode(message, io = nil) ⇒ nil, String

Encodes Aws::EventStream::Message to output IO when

provided, else return the encoded binary string


63
64
65
66
67
68
69
70
71
# File 'lib/aws-eventstream/encoder.rb', line 63

def encode(message, io = nil)
  encoded = encode_message(message)
  if io
    io.write(encoded)
    io.close
  else
    encoded
  end
end

#encode_headers(message) ⇒ String

Encodes headers part of an Aws::EventStream::Message

into String


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/aws-eventstream/encoder.rb', line 110

def encode_headers(message)
  header_entries = message.headers.map do |key, value|
    encoded_key = [key.bytesize, key].pack('Ca*')

    # header value
    pattern, value_length, type_index = Types.pattern[value.type]
    encoded_value = [type_index].pack('C')
    # boolean types doesn't need to specify value
    next [encoded_key, encoded_value].pack('a*a*') if !!pattern == pattern
    encoded_value = [encoded_value, value.value.bytesize].pack('a*S>') unless value_length

    [
      encoded_key,
      encoded_value,
      pattern ? [value.value].pack(pattern) : value.value,
    ].pack('a*a*a*')
  end
  header_entries.join.tap do |encoded_header|
    break encoded_header if encoded_header.bytesize <= MAX_HEADERS_LENGTH
    raise Aws::EventStream::Errors::EventHeadersLengthExceedError.new
  end
end

#encode_message(message) ⇒ String

Encodes an Aws::EventStream::Message

into String


79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/aws-eventstream/encoder.rb', line 79

def encode_message(message)
  # create context buffer with encode headers
  encoded_header = encode_headers(message)
  header_length = encoded_header.bytesize
  # encode payload
  if message.payload.length > MAX_PAYLOAD_LENGTH
    raise Aws::EventStream::Errors::EventPayloadLengthExceedError.new
  end
  encoded_payload = message.payload.read
  total_length = header_length + encoded_payload.bytesize + OVERHEAD_LENGTH

  # create message buffer with prelude section
  encoded_prelude = encode_prelude(total_length, header_length)

  # append message context (headers, payload)
  encoded_content = [
    encoded_prelude,
    encoded_header,
    encoded_payload,
  ].pack('a*a*a*')
  # append message checksum
  message_checksum = Zlib.crc32(encoded_content)
  [encoded_content, message_checksum].pack('a*N')
end