aws-eventstream 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/aws-eventstream.rb +8 -0
- data/lib/aws-eventstream/bytes_buffer.rb +66 -0
- data/lib/aws-eventstream/decoder.rb +247 -0
- data/lib/aws-eventstream/encoder.rb +136 -0
- data/lib/aws-eventstream/errors.rb +35 -0
- data/lib/aws-eventstream/header_value.rb +46 -0
- data/lib/aws-eventstream/message.rb +20 -0
- data/lib/aws-eventstream/types.rb +40 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0bd89e470bb670750b5db3fa159c05c47f6ae848
|
4
|
+
data.tar.gz: 0e6a31068166775645f803c36f2aa27c7b7341ce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 475cdba6288c5ba3224a65d18f9b3d16feba99d2b9868043af4c01194adeeb55f686200cac511e3067465ffe8b7cfa93dbe306751f31f6ce93966d5b052f4b6c
|
7
|
+
data.tar.gz: b96b77164bc0e6e1f9095de872400f9a589f912d450f6cdb0c40c3b769888f38f90be9b572b09f2715f1358ba43b71d06842d95c628108e57bdd1c5201aba3be
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require_relative 'aws-eventstream/decoder'
|
2
|
+
require_relative 'aws-eventstream/encoder'
|
3
|
+
|
4
|
+
require_relative 'aws-eventstream/bytes_buffer'
|
5
|
+
require_relative 'aws-eventstream/message'
|
6
|
+
require_relative 'aws-eventstream/header_value'
|
7
|
+
require_relative 'aws-eventstream/types'
|
8
|
+
require_relative 'aws-eventstream/errors'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Aws
|
2
|
+
module EventStream
|
3
|
+
|
4
|
+
# @api private
|
5
|
+
class BytesBuffer
|
6
|
+
|
7
|
+
# This Util class is for Decoder/Encoder usage only
|
8
|
+
# Not for public common bytes buffer usage
|
9
|
+
def initialize(data)
|
10
|
+
@data = data
|
11
|
+
@pos = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def read(len = nil, offset = 0)
|
15
|
+
return '' if len == 0 || bytesize == 0
|
16
|
+
unless eof?
|
17
|
+
start_byte = @pos + offset
|
18
|
+
end_byte = len ?
|
19
|
+
start_byte + len - 1 :
|
20
|
+
bytesize - 1
|
21
|
+
|
22
|
+
error = Errors::ReadBytesExceedLengthError.new(end_byte, bytesize)
|
23
|
+
raise error if end_byte >= bytesize
|
24
|
+
|
25
|
+
@pos = end_byte + 1
|
26
|
+
@data[start_byte..end_byte]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def readbyte
|
31
|
+
unless eof?
|
32
|
+
@pos += 1
|
33
|
+
@data[@pos - 1]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def write(bytes)
|
38
|
+
@data <<= bytes
|
39
|
+
bytes.bytesize
|
40
|
+
end
|
41
|
+
alias_method :<<, :write
|
42
|
+
|
43
|
+
def rewind
|
44
|
+
@pos = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def eof?
|
48
|
+
@pos == bytesize
|
49
|
+
end
|
50
|
+
|
51
|
+
def bytesize
|
52
|
+
@data.bytesize
|
53
|
+
end
|
54
|
+
|
55
|
+
def tell
|
56
|
+
@pos
|
57
|
+
end
|
58
|
+
|
59
|
+
def clear!
|
60
|
+
@data = ''
|
61
|
+
@pos = 0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'zlib'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module EventStream
|
7
|
+
|
8
|
+
# This class provides method for decoding binary inputs into
|
9
|
+
# single or multiple messages (Aws::EventStream::Message).
|
10
|
+
#
|
11
|
+
# * {#decode} - decodes messages from an IO like object responds
|
12
|
+
# to #read that containing binary data, returning decoded
|
13
|
+
# Aws::EventStream::Message along the way or wrapped in an enumerator
|
14
|
+
#
|
15
|
+
# ## Examples
|
16
|
+
#
|
17
|
+
# decoder = Aws::EventStream::Decoder.new
|
18
|
+
#
|
19
|
+
# # decoding from IO
|
20
|
+
# decoder.decode(io) do |message|
|
21
|
+
# message.headers
|
22
|
+
# # => { ... }
|
23
|
+
# message.payload
|
24
|
+
# # => StringIO / Tempfile
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # alternatively
|
28
|
+
# message_pool = decoder.decode(io)
|
29
|
+
# message_pool.next
|
30
|
+
# # => Aws::EventStream::Message
|
31
|
+
#
|
32
|
+
# * {#decode_chunk} - decodes a single message from a chunk of data,
|
33
|
+
# returning message object followed by boolean(indicating eof status
|
34
|
+
# of data) in an array object
|
35
|
+
#
|
36
|
+
# ## Examples
|
37
|
+
#
|
38
|
+
# # chunk containing exactly one message data
|
39
|
+
# message, chunk_eof = decoder.decode_chunk(chunk_str)
|
40
|
+
# message
|
41
|
+
# # => Aws::EventStream::Message
|
42
|
+
# chunk_eof
|
43
|
+
# # => true
|
44
|
+
#
|
45
|
+
# # chunk containing a partial message
|
46
|
+
# message, chunk_eof = decoder.decode_chunk(chunk_str)
|
47
|
+
# message
|
48
|
+
# # => nil
|
49
|
+
# chunk_eof
|
50
|
+
# # => true
|
51
|
+
# # chunk data is saved at decoder's message_buffer
|
52
|
+
#
|
53
|
+
# # chunk containing more that one data message
|
54
|
+
# message, chunk_eof = decoder.decode_chunk(chunk_str)
|
55
|
+
# message
|
56
|
+
# # => Aws::EventStream::Message
|
57
|
+
# chunk_eof
|
58
|
+
# # => false
|
59
|
+
# # extra chunk data is saved at message_buffer of the decoder
|
60
|
+
#
|
61
|
+
class Decoder
|
62
|
+
|
63
|
+
include Enumerable
|
64
|
+
|
65
|
+
ONE_MEGABYTE = 1024 * 1024
|
66
|
+
|
67
|
+
# bytes of prelude part, including 4 bytes of
|
68
|
+
# total message length, headers length and crc checksum of prelude
|
69
|
+
PRELUDE_LENGTH = 12
|
70
|
+
|
71
|
+
# bytes of total overhead in a message, including prelude
|
72
|
+
# and 4 bytes total message crc checksum
|
73
|
+
OVERHEAD_LENGTH = 16
|
74
|
+
|
75
|
+
# @options options [Boolean] format (true) When `false`
|
76
|
+
# disable user-friendly formatting for message header values
|
77
|
+
# including timestamp and uuid etc.
|
78
|
+
#
|
79
|
+
def initialize(options = {})
|
80
|
+
@format = options.fetch(:format, true)
|
81
|
+
@message_buffer = BytesBuffer.new('')
|
82
|
+
end
|
83
|
+
|
84
|
+
# @returns [BytesBuffer]
|
85
|
+
attr_reader :message_buffer
|
86
|
+
|
87
|
+
# Decodes messages from a binary stream
|
88
|
+
#
|
89
|
+
# @param [IO#read] io An IO-like object
|
90
|
+
# that responds to `#read`
|
91
|
+
#
|
92
|
+
# @yieldparam [Message] message
|
93
|
+
# @return [Enumerable<Message>, nil] Returns a new Enumerable
|
94
|
+
# containing decoded messages if no block is given
|
95
|
+
def decode(io, &block)
|
96
|
+
io = BytesBuffer.new(io.read)
|
97
|
+
return decode_io(io) unless block_given?
|
98
|
+
until io.eof?
|
99
|
+
# fetch message only
|
100
|
+
yield(decode_message(io).first)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Decodes a single message from a chunk of string
|
105
|
+
#
|
106
|
+
# @param [String] chunk A chunk of string to be decoded,
|
107
|
+
# chunk can contain partial event message to multiple event messages
|
108
|
+
# When not provided, decode data from #message_buffer
|
109
|
+
#
|
110
|
+
# @return [Array<Message|nil, Boolean>] Returns single decoded message
|
111
|
+
# and boolean pair, the boolean flag indicates whether this chunk
|
112
|
+
# has been fully consumed, unused data is tracked at #message_buffer
|
113
|
+
def decode_chunk(chunk = nil)
|
114
|
+
@message_buffer.write(chunk) if chunk
|
115
|
+
@message_buffer.rewind
|
116
|
+
decode_message(@message_buffer)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def decode_io(io)
|
122
|
+
::Enumerator.new {|e| e << decode_message(io) unless io.eof? }
|
123
|
+
end
|
124
|
+
|
125
|
+
def decode_message(io)
|
126
|
+
# decode prelude
|
127
|
+
total_len, headers_len, prelude_buffer = prelude(io)
|
128
|
+
|
129
|
+
# incomplete message received, leave it in the buffer
|
130
|
+
return [nil, true] if io.bytesize < total_len
|
131
|
+
|
132
|
+
# decode headers and payload
|
133
|
+
headers, payload = context(io, total_len, headers_len, prelude_buffer)
|
134
|
+
|
135
|
+
# track extra message data in the buffer if exists
|
136
|
+
# for #decode_chunk, io is @message_buffer
|
137
|
+
if eof = io.eof?
|
138
|
+
@message_buffer.clear!
|
139
|
+
else
|
140
|
+
@message_buffer = BytesBuffer.new(@message_buffer.read)
|
141
|
+
end
|
142
|
+
|
143
|
+
[Message.new(headers: headers, payload: payload), eof]
|
144
|
+
end
|
145
|
+
|
146
|
+
def prelude(io)
|
147
|
+
# buffer prelude into bytes buffer
|
148
|
+
# prelude contains length of message and headers,
|
149
|
+
# followed with CRC checksum of itself
|
150
|
+
buffer = BytesBuffer.new(io.read(PRELUDE_LENGTH))
|
151
|
+
|
152
|
+
# prelude checksum takes last 4 bytes
|
153
|
+
checksum = Zlib.crc32(buffer.read(PRELUDE_LENGTH - 4))
|
154
|
+
unless checksum == unpack_uint32(buffer)
|
155
|
+
raise Errors::PreludeChecksumError
|
156
|
+
end
|
157
|
+
|
158
|
+
buffer.rewind
|
159
|
+
total_len, headers_len, _ = buffer.read.unpack("N*")
|
160
|
+
[total_len, headers_len, buffer]
|
161
|
+
end
|
162
|
+
|
163
|
+
def context(io, total_len, headers_len, prelude_buffer)
|
164
|
+
# buffer rest of the message except prelude length
|
165
|
+
# including context and total message checksum
|
166
|
+
buffer = BytesBuffer.new(io.read(total_len - PRELUDE_LENGTH))
|
167
|
+
context_len = total_len - OVERHEAD_LENGTH
|
168
|
+
|
169
|
+
prelude_buffer.rewind
|
170
|
+
checksum = Zlib.crc32(prelude_buffer.read << buffer.read(context_len))
|
171
|
+
unless checksum == unpack_uint32(buffer)
|
172
|
+
raise Errors::MessageChecksumError
|
173
|
+
end
|
174
|
+
|
175
|
+
buffer.rewind
|
176
|
+
[
|
177
|
+
extract_headers(BytesBuffer.new(buffer.read(headers_len))),
|
178
|
+
extract_payload(BytesBuffer.new(buffer.read(context_len - headers_len)))
|
179
|
+
]
|
180
|
+
end
|
181
|
+
|
182
|
+
def extract_headers(buffer)
|
183
|
+
headers = {}
|
184
|
+
until buffer.eof?
|
185
|
+
# header key
|
186
|
+
key_len = unpack_uint8(buffer)
|
187
|
+
key = buffer.read(key_len)
|
188
|
+
|
189
|
+
# header value
|
190
|
+
value_type = Types.types[unpack_uint8(buffer)]
|
191
|
+
unpack_pattern, value_len, _ = Types.pattern[value_type]
|
192
|
+
if !!unpack_pattern == unpack_pattern
|
193
|
+
# boolean types won't have value specified
|
194
|
+
value = unpack_pattern
|
195
|
+
else
|
196
|
+
value_len = unpack_uint16(buffer) unless value_len
|
197
|
+
value = unpack_pattern ?
|
198
|
+
buffer.read(value_len).unpack(unpack_pattern)[0] :
|
199
|
+
buffer.read(value_len)
|
200
|
+
end
|
201
|
+
|
202
|
+
headers[key] = HeaderValue.new(
|
203
|
+
format: @format,
|
204
|
+
value: value,
|
205
|
+
type: value_type
|
206
|
+
)
|
207
|
+
end
|
208
|
+
headers
|
209
|
+
end
|
210
|
+
|
211
|
+
def extract_payload(buffer)
|
212
|
+
buffer.bytesize <= ONE_MEGABYTE ?
|
213
|
+
payload_stringio(buffer) :
|
214
|
+
payload_tempfile(buffer)
|
215
|
+
end
|
216
|
+
|
217
|
+
def payload_stringio(buffer)
|
218
|
+
StringIO.new(buffer.read)
|
219
|
+
end
|
220
|
+
|
221
|
+
def payload_tempfile(buffer)
|
222
|
+
payload = Tempfile.new
|
223
|
+
payload.binmode
|
224
|
+
until buffer.eof?
|
225
|
+
payload.write(buffer.read(ONE_MEGABYTE))
|
226
|
+
end
|
227
|
+
payload.rewind
|
228
|
+
payload
|
229
|
+
end
|
230
|
+
|
231
|
+
# overhead decode helpers
|
232
|
+
|
233
|
+
def unpack_uint32(buffer)
|
234
|
+
buffer.read(4).unpack("N")[0]
|
235
|
+
end
|
236
|
+
|
237
|
+
def unpack_uint16(buffer)
|
238
|
+
buffer.read(2).unpack("S>")[0]
|
239
|
+
end
|
240
|
+
|
241
|
+
def unpack_uint8(buffer)
|
242
|
+
buffer.readbyte.unpack("C")[0]
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module EventStream
|
5
|
+
|
6
|
+
# This class provides #encode method for encoding
|
7
|
+
# Aws::EventStream::Message into binary.
|
8
|
+
#
|
9
|
+
# * {#encode} - encode Aws::EventStream::Message into binary
|
10
|
+
# when output IO-like object is provided, binary string
|
11
|
+
# would be written to IO. If not, the encoded binary string
|
12
|
+
# would be returned directly
|
13
|
+
#
|
14
|
+
# ## Examples
|
15
|
+
#
|
16
|
+
# message = Aws::EventStream::Message.new(
|
17
|
+
# headers: {
|
18
|
+
# "foo" => Aws::EventStream::HeaderValue.new(
|
19
|
+
# value: "bar", type: "string"
|
20
|
+
# )
|
21
|
+
# },
|
22
|
+
# payload: "payload"
|
23
|
+
# )
|
24
|
+
# encoder = Aws::EventsStream::Encoder.new
|
25
|
+
# file = Tempfile.new
|
26
|
+
#
|
27
|
+
# # encode into IO ouput
|
28
|
+
# encoder.encode(message, file)
|
29
|
+
#
|
30
|
+
# # get encoded binary string
|
31
|
+
# encoded_message = encoder.encode(message)
|
32
|
+
#
|
33
|
+
# file.read == encoded_message
|
34
|
+
# # => true
|
35
|
+
#
|
36
|
+
class Encoder
|
37
|
+
|
38
|
+
# bytes of total overhead in a message, including prelude
|
39
|
+
# and 4 bytes total message crc checksum
|
40
|
+
OVERHEAD_LENGTH = 16
|
41
|
+
|
42
|
+
# Encodes Aws::EventStream::Message to output IO when
|
43
|
+
# provided, else return the encoded binary string
|
44
|
+
#
|
45
|
+
# @param [Aws::EventStream::Message] message
|
46
|
+
#
|
47
|
+
# @param [IO#write, nil] io An IO-like object that
|
48
|
+
# responds to `#write`, encoded message will be
|
49
|
+
# written to this IO when provided
|
50
|
+
#
|
51
|
+
# @return [nil, String] when output IO is provided,
|
52
|
+
# encoded message will be written to that IO, nil
|
53
|
+
# will be returned. Else, encoded binary string is
|
54
|
+
# returned.
|
55
|
+
def encode(message, io = nil)
|
56
|
+
encoded = encode_message(message).read
|
57
|
+
if io
|
58
|
+
io.write(encoded)
|
59
|
+
io.close
|
60
|
+
else
|
61
|
+
encoded
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def encode_message(message)
|
68
|
+
# create context buffer with encode headers
|
69
|
+
ctx_buffer = encode_headers(message)
|
70
|
+
headers_len = ctx_buffer.bytesize
|
71
|
+
# encode payload
|
72
|
+
ctx_buffer << message.payload.read
|
73
|
+
total_len = ctx_buffer.bytesize + OVERHEAD_LENGTH
|
74
|
+
|
75
|
+
# create message buffer with prelude section
|
76
|
+
buffer = prelude(total_len, headers_len)
|
77
|
+
|
78
|
+
# append message context (headers, payload)
|
79
|
+
buffer << ctx_buffer.read
|
80
|
+
# append message checksum
|
81
|
+
buffer << pack_uint32(Zlib.crc32(buffer.read))
|
82
|
+
|
83
|
+
# write buffered message to io
|
84
|
+
buffer.rewind
|
85
|
+
buffer
|
86
|
+
end
|
87
|
+
|
88
|
+
def encode_headers(msg)
|
89
|
+
buffer = BytesBuffer.new('')
|
90
|
+
msg.headers.each do |k, v|
|
91
|
+
# header key
|
92
|
+
buffer << pack_uint8(k.bytesize)
|
93
|
+
buffer << k
|
94
|
+
|
95
|
+
# header value
|
96
|
+
pattern, val_len, idx = Types.pattern[v.type]
|
97
|
+
buffer << pack_uint8(idx)
|
98
|
+
# boolean types doesn't need to specify value
|
99
|
+
next if !!pattern == pattern
|
100
|
+
buffer << pack_uint16(v.value.bytesize) unless val_len
|
101
|
+
pattern ? buffer << [v.value].pack(pattern) :
|
102
|
+
buffer << v.value
|
103
|
+
end
|
104
|
+
buffer
|
105
|
+
end
|
106
|
+
|
107
|
+
def prelude(total_len, headers_len)
|
108
|
+
BytesBuffer.new(pack_uint32([
|
109
|
+
total_len,
|
110
|
+
headers_len,
|
111
|
+
Zlib.crc32(pack_uint32([total_len, headers_len]))
|
112
|
+
]))
|
113
|
+
end
|
114
|
+
|
115
|
+
# overhead encode helpers
|
116
|
+
|
117
|
+
def pack_uint8(val)
|
118
|
+
[val].pack("C")
|
119
|
+
end
|
120
|
+
|
121
|
+
def pack_uint16(val)
|
122
|
+
[val].pack("S>")
|
123
|
+
end
|
124
|
+
|
125
|
+
def pack_uint32(val)
|
126
|
+
if val.respond_to?(:each)
|
127
|
+
val.pack("N*")
|
128
|
+
else
|
129
|
+
[val].pack("N")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Aws
|
2
|
+
module EventStream
|
3
|
+
module Errors
|
4
|
+
|
5
|
+
# Raised when reading bytes exceed buffer total bytes
|
6
|
+
class ReadBytesExceedLengthError < RuntimeError
|
7
|
+
def initialize(target_byte, total_len)
|
8
|
+
msg = "Attempting reading bytes to offset #{target_byte} exceeds"\
|
9
|
+
" buffer length of #{total_len}"
|
10
|
+
super(msg)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Raise when insufficient bytes of a message is received
|
15
|
+
class IncompleteMessageError < RuntimeError
|
16
|
+
def initialize(*args)
|
17
|
+
super("Not enough bytes for event message")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class PreludeChecksumError < RuntimeError
|
22
|
+
def initialize(*args)
|
23
|
+
super("Prelude checksum mismatch")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class MessageChecksumError < RuntimeError
|
28
|
+
def initialize(*args)
|
29
|
+
super("Message checksum mismatch")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Aws
|
2
|
+
module EventStream
|
3
|
+
|
4
|
+
class HeaderValue
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@type = options.fetch(:type)
|
8
|
+
@value = options[:format] ?
|
9
|
+
format_value(options.fetch(:value)) :
|
10
|
+
options.fetch(:value)
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :value
|
14
|
+
|
15
|
+
# @return [String] type of the header value
|
16
|
+
# complete type list see Aws::EventStream::Types
|
17
|
+
attr_reader :type
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def format_value(value)
|
22
|
+
case @type
|
23
|
+
when "timestamp" then format_timestamp(value)
|
24
|
+
when "uuid" then format_uuid(value)
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def format_uuid(value)
|
31
|
+
bytes = value.bytes
|
32
|
+
# For user-friendly uuid representation,
|
33
|
+
# format binary bytes into uuid string format
|
34
|
+
uuid_pattern = [ [ 3, 2, 1, 0 ], [ 5, 4 ], [ 7, 6 ], [ 8, 9 ], 10..15 ]
|
35
|
+
uuid_pattern.map {|p| p.map {|n| "%02x" % bytes.to_a[n] }.join }.join("-")
|
36
|
+
end
|
37
|
+
|
38
|
+
def format_timestamp(value)
|
39
|
+
# millis_since_epoch to sec_since_epoch
|
40
|
+
Time.at(value / 1000.0)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Aws
|
2
|
+
module EventStream
|
3
|
+
class Message
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@headers = options[:headers] || {}
|
7
|
+
@payload = options[:payload] || StringIO.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [Hash] headers of a message
|
11
|
+
attr_reader :headers
|
12
|
+
|
13
|
+
# @return [IO] payload of a message, size not exceed 16MB.
|
14
|
+
# StringIO is returned for <= 1MB payload
|
15
|
+
# Tempfile is returned for > 1MB payload
|
16
|
+
attr_reader :payload
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Aws
|
2
|
+
module EventStream
|
3
|
+
|
4
|
+
# Message Header Value Types
|
5
|
+
module Types
|
6
|
+
|
7
|
+
def self.types
|
8
|
+
[
|
9
|
+
"bool_true",
|
10
|
+
"bool_false",
|
11
|
+
"byte",
|
12
|
+
"short",
|
13
|
+
"integer",
|
14
|
+
"long",
|
15
|
+
"bytes",
|
16
|
+
"string",
|
17
|
+
"timestamp",
|
18
|
+
"uuid"
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
# pack/unpack pattern, byte size, type idx
|
23
|
+
def self.pattern
|
24
|
+
{
|
25
|
+
"bool_true" => [true, 0, 0],
|
26
|
+
"bool_false" => [false, 0, 1],
|
27
|
+
"byte" => ["c", 1, 2],
|
28
|
+
"short" => ["s>", 2, 3],
|
29
|
+
"integer" => ["l>", 4, 4],
|
30
|
+
"long" => ["q>", 8, 5],
|
31
|
+
"bytes" => [nil, nil, 6],
|
32
|
+
"string" => [nil, nil, 7],
|
33
|
+
"timestamp" => ["q>", 8, 8],
|
34
|
+
"uuid" => [nil, 16, 9]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aws-eventstream
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Amazon Web Services
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Amazon Web Services event stream library. Decodes and encodes binary
|
14
|
+
stream under `vnd.amazon.event-stream` content-type
|
15
|
+
email:
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/aws-eventstream.rb
|
21
|
+
- lib/aws-eventstream/bytes_buffer.rb
|
22
|
+
- lib/aws-eventstream/decoder.rb
|
23
|
+
- lib/aws-eventstream/encoder.rb
|
24
|
+
- lib/aws-eventstream/errors.rb
|
25
|
+
- lib/aws-eventstream/header_value.rb
|
26
|
+
- lib/aws-eventstream/message.rb
|
27
|
+
- lib/aws-eventstream/types.rb
|
28
|
+
homepage: http://github.com/aws/aws-sdk-ruby
|
29
|
+
licenses:
|
30
|
+
- Apache-2.0
|
31
|
+
metadata:
|
32
|
+
source_code_uri: https://github.com/aws/aws-sdk-ruby/tree/master/gems/aws-eventstream
|
33
|
+
changelog_uri: https://github.com/aws/aws-sdk-ruby/tree/master/gems/aws-eventstream/CHANGELOG.md
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.5.2.3
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: AWS Event Stream Library
|
54
|
+
test_files: []
|