arf 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/LICENSE.txt +21 -0
- data/Rakefile +12 -0
- data/lib/arf/configuration.rb +67 -0
- data/lib/arf/context.rb +170 -0
- data/lib/arf/errors.rb +10 -0
- data/lib/arf/io/buffer.rb +25 -0
- data/lib/arf/io/compression.rb +44 -0
- data/lib/arf/io/limit_reader.rb +30 -0
- data/lib/arf/observer.rb +29 -0
- data/lib/arf/proto/array.rb +31 -0
- data/lib/arf/proto/boolean.rb +15 -0
- data/lib/arf/proto/bytes.rb +35 -0
- data/lib/arf/proto/decoder.rb +31 -0
- data/lib/arf/proto/encoder.rb +71 -0
- data/lib/arf/proto/float.rb +48 -0
- data/lib/arf/proto/map.rb +49 -0
- data/lib/arf/proto/registry.rb +27 -0
- data/lib/arf/proto/scalar.rb +55 -0
- data/lib/arf/proto/string.rb +36 -0
- data/lib/arf/proto/struct.rb +84 -0
- data/lib/arf/proto/types.rb +67 -0
- data/lib/arf/proto/union.rb +25 -0
- data/lib/arf/proto.rb +17 -0
- data/lib/arf/reactor.rb +270 -0
- data/lib/arf/rpc/base_message.rb +119 -0
- data/lib/arf/rpc/client_base.rb +110 -0
- data/lib/arf/rpc/end_stream.rb +9 -0
- data/lib/arf/rpc/enum.rb +51 -0
- data/lib/arf/rpc/message_kind.rb +27 -0
- data/lib/arf/rpc/metadata.rb +120 -0
- data/lib/arf/rpc/method_meta.rb +42 -0
- data/lib/arf/rpc/request.rb +39 -0
- data/lib/arf/rpc/responder.rb +186 -0
- data/lib/arf/rpc/response.rb +46 -0
- data/lib/arf/rpc/service_base.rb +137 -0
- data/lib/arf/rpc/start_stream.rb +9 -0
- data/lib/arf/rpc/stream_error.rb +23 -0
- data/lib/arf/rpc/stream_item.rb +16 -0
- data/lib/arf/rpc/stream_metadata.rb +16 -0
- data/lib/arf/rpc/struct.rb +255 -0
- data/lib/arf/rpc.rb +19 -0
- data/lib/arf/server.rb +123 -0
- data/lib/arf/status.rb +75 -0
- data/lib/arf/types/array_type.rb +24 -0
- data/lib/arf/types/base_type.rb +14 -0
- data/lib/arf/types/coercion.rb +36 -0
- data/lib/arf/types/in_out_stream.rb +28 -0
- data/lib/arf/types/input_stream.rb +8 -0
- data/lib/arf/types/map_type.rb +32 -0
- data/lib/arf/types/mixin.rb +29 -0
- data/lib/arf/types/output_stream.rb +8 -0
- data/lib/arf/types/streamer.rb +21 -0
- data/lib/arf/types.rb +69 -0
- data/lib/arf/version.rb +5 -0
- data/lib/arf/wire/base_connection.rb +177 -0
- data/lib/arf/wire/client.rb +101 -0
- data/lib/arf/wire/encoding.rb +49 -0
- data/lib/arf/wire/error_code.rb +35 -0
- data/lib/arf/wire/errors.rb +88 -0
- data/lib/arf/wire/frame.rb +111 -0
- data/lib/arf/wire/frame_kind.rb +23 -0
- data/lib/arf/wire/frame_reader.rb +104 -0
- data/lib/arf/wire/frames/base_frame.rb +108 -0
- data/lib/arf/wire/frames/configuration_frame.rb +33 -0
- data/lib/arf/wire/frames/data_frame.rb +21 -0
- data/lib/arf/wire/frames/go_away_frame.rb +29 -0
- data/lib/arf/wire/frames/make_stream_frame.rb +15 -0
- data/lib/arf/wire/frames/ping_frame.rb +18 -0
- data/lib/arf/wire/frames/reset_stream_frame.rb +19 -0
- data/lib/arf/wire/frames.rb +9 -0
- data/lib/arf/wire/server/peer.rb +85 -0
- data/lib/arf/wire/server.rb +63 -0
- data/lib/arf/wire/stream/state.rb +69 -0
- data/lib/arf/wire/stream.rb +128 -0
- data/lib/arf/wire/wait_signal.rb +24 -0
- data/lib/arf/wire.rb +14 -0
- data/lib/arf.rb +46 -0
- metadata +195 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
ERROR_CODE_NO_ERROR = 0x00
|
6
|
+
ERROR_CODE_PROTOCOL_ERROR = 0x01
|
7
|
+
ERROR_CODE_INTERNAL_ERROR = 0x02
|
8
|
+
ERROR_CODE_STREAM_CLOSED = 0x03
|
9
|
+
ERROR_CODE_FRAME_SIZE_ERROR = 0x04
|
10
|
+
ERROR_CODE_REFUSED_STREAM = 0x05
|
11
|
+
ERROR_CODE_CANCEL = 0x06
|
12
|
+
ERROR_CODE_COMPRESSION_ERROR = 0x07
|
13
|
+
ERROR_CODE_ENHANCE_YOUR_CALM = 0x08
|
14
|
+
ERROR_CODE_INADEQUATE_SECURITY = 0x09
|
15
|
+
|
16
|
+
ERROR_TO_STRING = {
|
17
|
+
ERROR_CODE_NO_ERROR => "No error",
|
18
|
+
ERROR_CODE_PROTOCOL_ERROR => "Protocol Error",
|
19
|
+
ERROR_CODE_INTERNAL_ERROR => "Internal Error",
|
20
|
+
ERROR_CODE_STREAM_CLOSED => "Stream Closed",
|
21
|
+
ERROR_CODE_FRAME_SIZE_ERROR => "Frame Size Error",
|
22
|
+
ERROR_CODE_REFUSED_STREAM => "Refused Stream",
|
23
|
+
ERROR_CODE_CANCEL => "Cancel",
|
24
|
+
ERROR_CODE_COMPRESSION_ERROR => "Compression Error",
|
25
|
+
ERROR_CODE_ENHANCE_YOUR_CALM => "Enhance Your Calm",
|
26
|
+
ERROR_CODE_INADEQUATE_SECURITY => "Inadequate Security"
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
def self.error_code_to_string(code)
|
30
|
+
return ERROR_TO_STRING[code] if ERROR_TO_STRING.key? code
|
31
|
+
|
32
|
+
"Unknown error 0x#{code.to_s(16)}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class WireError < Arf::Error; end
|
6
|
+
|
7
|
+
class FrameMismatchError < WireError
|
8
|
+
attr_reader :expected, :received
|
9
|
+
|
10
|
+
def initialize(expected, received)
|
11
|
+
@expected = expected
|
12
|
+
@received = received
|
13
|
+
super("Frame type mismatch: Expected #{expected}, got #{received}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class UnexpectedUnassociatedFrameError < WireError
|
18
|
+
attr_reader :kind
|
19
|
+
|
20
|
+
def initialize(kind)
|
21
|
+
@kind = kind
|
22
|
+
super("Frame #{kind} must be associated to a stream")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class UnexpectedAssociatedFrameError < WireError
|
27
|
+
attr_reader :kind
|
28
|
+
|
29
|
+
def initialize(kind)
|
30
|
+
@kind = kind
|
31
|
+
super("Frame #{kind} must not be associated to a stream")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class InvalidFrameLengthError < WireError; end
|
36
|
+
|
37
|
+
class InvalidFrameError < WireError; end
|
38
|
+
|
39
|
+
class StreamResetError < WireError
|
40
|
+
attr_reader :reason
|
41
|
+
|
42
|
+
def initialize(reason)
|
43
|
+
@reason = reason
|
44
|
+
super("Stream reset: #{Wire.error_code_to_string(reason)}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class StreamCanceledError < WireError
|
49
|
+
attr_reader :reason
|
50
|
+
|
51
|
+
def initialize(reason)
|
52
|
+
@reason = reason
|
53
|
+
super("Stream canceled: #{Wire.error_code_to_string(reason)}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ConnectionResetError < WireError
|
58
|
+
attr_reader :reason, :details
|
59
|
+
|
60
|
+
def initialize(reason, details = nil)
|
61
|
+
@reason = reason
|
62
|
+
@details = details
|
63
|
+
super(if details
|
64
|
+
"Connection reset: #{Wire.error_code_to_string(reason)} #{details}"
|
65
|
+
else
|
66
|
+
"Connection reset: #{Wire.error_code_to_string(reason)}"
|
67
|
+
end)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class UnknownFrameKindError < WireError
|
72
|
+
attr_reader :received_kind
|
73
|
+
|
74
|
+
def initialize(kind)
|
75
|
+
@received_kind = kind
|
76
|
+
if kind.is_a? Symbol
|
77
|
+
super("Unknown frame kind 0x#{received_kind}")
|
78
|
+
else
|
79
|
+
super("Unknown frame kind 0x#{received_kind.to_s(16)}")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class MagicNumberMismatchError < WireError; end
|
85
|
+
|
86
|
+
class ClosedStreamError < WireError; end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class Frame
|
6
|
+
MAGIC = "arf"
|
7
|
+
MAGIC_SIZE = 3
|
8
|
+
STREAM_ID_SIZE = 4
|
9
|
+
FRAME_KIND_SIZE = 1
|
10
|
+
FLAGS_SIZE = 1
|
11
|
+
LENGTH_SIZE = 2
|
12
|
+
FRAME_SIZE = MAGIC_SIZE + STREAM_ID_SIZE + FRAME_KIND_SIZE + FLAGS_SIZE + LENGTH_SIZE
|
13
|
+
|
14
|
+
attr_accessor :stream_id, :frame_kind, :flags, :length
|
15
|
+
attr_reader :payload
|
16
|
+
|
17
|
+
def empty? = length ? length.zero? : true
|
18
|
+
|
19
|
+
def self.read_exactly(io, into, n)
|
20
|
+
into.truncate(0)
|
21
|
+
into.write(io.read(n - into.length)) until into.length == n
|
22
|
+
into.rewind
|
23
|
+
into
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_io(io)
|
27
|
+
buf = StringIO.new
|
28
|
+
read_exactly(io, buf, FRAME_SIZE)
|
29
|
+
raise MagicNumberMismatchError if buf.read(3) != Frame::MAGIC
|
30
|
+
|
31
|
+
stream_id = Wire.decode_uint32(buf)
|
32
|
+
raw_kind = buf.readbyte
|
33
|
+
frame_kind = Wire::FRAME_TO_SYMBOL[raw_kind]
|
34
|
+
raise UnknownFrameKindError, raw_kind unless frame_kind
|
35
|
+
|
36
|
+
flags = buf.readbyte
|
37
|
+
length = Wire.decode_uint16(buf)
|
38
|
+
payload = nil
|
39
|
+
if length.positive?
|
40
|
+
payload = StringIO.new
|
41
|
+
read_exactly(io, payload, length)
|
42
|
+
end
|
43
|
+
|
44
|
+
new.tap do |f|
|
45
|
+
f.stream_id = stream_id
|
46
|
+
f.frame_kind = frame_kind
|
47
|
+
f.flags = flags
|
48
|
+
f.payload = payload
|
49
|
+
f.length = length
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def bytes(compressor)
|
54
|
+
@payload = IO::COMPRESSOR[compressor].compress(@payload)
|
55
|
+
@length = @payload&.length || 0
|
56
|
+
|
57
|
+
IO::Buffer.new
|
58
|
+
.write_raw(MAGIC)
|
59
|
+
.write_raw(Wire.encode_uint32(@stream_id || 0))
|
60
|
+
.write_raw([SYMBOL_TO_FRAME[@frame_kind]].pack("C*"))
|
61
|
+
.write_raw(@flags || 0)
|
62
|
+
.write_raw(Wire.encode_uint16(@length))
|
63
|
+
.write_raw(@payload&.string || "")
|
64
|
+
.string
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_kind(expected, associated)
|
68
|
+
raise FrameMismatchError.new(expected, @frame_kind) if @frame_kind != expected
|
69
|
+
|
70
|
+
if associated && (@stream_id.nil? || @stream_id.zero?)
|
71
|
+
raise UnexpectedUnassociatedFrameError, @frame_kind
|
72
|
+
elsif !associated && (!@stream_id.nil? && @stream_id != 0)
|
73
|
+
raise UnexpectedAssociatedFrameError, @frame_kind
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_size(size)
|
78
|
+
return unless @length != size
|
79
|
+
|
80
|
+
raise InvalidFrameLengthError, "invalid length for frame #{@frame_kind} " \
|
81
|
+
"#{size} bytes are required, received #{@length}"
|
82
|
+
end
|
83
|
+
|
84
|
+
def decompress(compressor)
|
85
|
+
@payload = IO::COMPRESSOR[compressor].decompress(@payload)
|
86
|
+
@length = @payload&.length || 0
|
87
|
+
end
|
88
|
+
|
89
|
+
def payload=(value)
|
90
|
+
if value.nil?
|
91
|
+
@payload = nil
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
95
|
+
@payload = if value.is_a? StringIO
|
96
|
+
value
|
97
|
+
else
|
98
|
+
StringIO.new(value)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def specialize(compressor)
|
103
|
+
cls = BaseFrame.frame_by_kind(@frame_kind)
|
104
|
+
raise UnknownFrameKindError, @frame_kind if cls.nil?
|
105
|
+
|
106
|
+
decompress(compressor)
|
107
|
+
cls.new(self)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
FRAME_KIND_CONFIGURATION = 0x0
|
6
|
+
FRAME_KIND_PING = 0x1
|
7
|
+
FRAME_KIND_GO_AWAY = 0x2
|
8
|
+
FRAME_KIND_MAKE_STREAM = 0x3
|
9
|
+
FRAME_KIND_RESET_STREAM = 0x4
|
10
|
+
FRAME_KIND_DATA = 0x5
|
11
|
+
|
12
|
+
FRAME_TO_SYMBOL = {
|
13
|
+
FRAME_KIND_CONFIGURATION => :configuration,
|
14
|
+
FRAME_KIND_PING => :ping,
|
15
|
+
FRAME_KIND_GO_AWAY => :go_away,
|
16
|
+
FRAME_KIND_MAKE_STREAM => :make_stream,
|
17
|
+
FRAME_KIND_RESET_STREAM => :reset_stream,
|
18
|
+
FRAME_KIND_DATA => :data
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
SYMBOL_TO_FRAME = FRAME_TO_SYMBOL.to_a.to_h(&:reverse)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class FrameReader
|
6
|
+
STATES = %i[
|
7
|
+
magic
|
8
|
+
stream_id
|
9
|
+
kind
|
10
|
+
flags
|
11
|
+
length
|
12
|
+
payload
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@data = IO::Buffer.new
|
17
|
+
@fr = Frame.new
|
18
|
+
@state = :magic
|
19
|
+
@c = 0
|
20
|
+
@data.reset
|
21
|
+
end
|
22
|
+
|
23
|
+
def feed_all(data)
|
24
|
+
c = 0
|
25
|
+
data.each_byte do |b|
|
26
|
+
v = feed b
|
27
|
+
c += 1
|
28
|
+
if v && c < data.length
|
29
|
+
raise "Short read: Read #{c} bytes of #{data.length}"
|
30
|
+
elsif v
|
31
|
+
return v
|
32
|
+
end
|
33
|
+
end
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def feed(b)
|
38
|
+
case @state
|
39
|
+
when :magic
|
40
|
+
@data.write(b)
|
41
|
+
return nil if @data.length < 3
|
42
|
+
|
43
|
+
if @data.string != Frame::MAGIC
|
44
|
+
@data.reset
|
45
|
+
raise MagicNumberMismatchError
|
46
|
+
end
|
47
|
+
@data.reset
|
48
|
+
@state = :stream_id
|
49
|
+
|
50
|
+
when :stream_id
|
51
|
+
@data.write(b)
|
52
|
+
return nil if @data.length < 4
|
53
|
+
|
54
|
+
@data.rewind
|
55
|
+
@fr.stream_id = Wire.decode_uint32(@data)
|
56
|
+
@data.reset
|
57
|
+
@state = :kind
|
58
|
+
|
59
|
+
when :kind
|
60
|
+
raw_frame_kind = b
|
61
|
+
frame_kind = Wire::FRAME_TO_SYMBOL[raw_frame_kind]
|
62
|
+
raise UnknownFrameKindError, raw_frame_kind unless frame_kind
|
63
|
+
|
64
|
+
@fr.frame_kind = frame_kind
|
65
|
+
@state = :flags
|
66
|
+
|
67
|
+
when :flags
|
68
|
+
@fr.flags = b
|
69
|
+
@state = :length
|
70
|
+
|
71
|
+
when :length
|
72
|
+
@data.write(b)
|
73
|
+
return nil if @data.length < 2
|
74
|
+
|
75
|
+
@data.rewind
|
76
|
+
@fr.length = Wire.decode_uint16(@data)
|
77
|
+
@data.reset
|
78
|
+
@state = :payload
|
79
|
+
if @fr.empty?
|
80
|
+
@state = :magic
|
81
|
+
frame = @fr
|
82
|
+
@fr = Frame.new
|
83
|
+
return frame
|
84
|
+
end
|
85
|
+
|
86
|
+
when :payload
|
87
|
+
@data.write(b)
|
88
|
+
return nil if @data.length < @fr.length
|
89
|
+
|
90
|
+
@fr.payload = @data.extract
|
91
|
+
@fr.payload.rewind
|
92
|
+
@data = IO::Buffer.new
|
93
|
+
@state = :magic
|
94
|
+
@data.reset
|
95
|
+
frame = @fr
|
96
|
+
@fr = Frame.new
|
97
|
+
return frame
|
98
|
+
end
|
99
|
+
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class BaseFrame
|
6
|
+
def self.register_frame(kind, cls)
|
7
|
+
@frames ||= {}
|
8
|
+
@frames[kind] = cls
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.frame_by_kind(kind) = @frames[kind]
|
12
|
+
|
13
|
+
def self.frame_kind(name = nil)
|
14
|
+
BaseFrame.register_frame(name, self) if name
|
15
|
+
@frame_kind ||= name
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.value_size(size = nil)
|
19
|
+
@value_size ||= size
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.wants_stream_id!
|
23
|
+
attr_accessor :stream_id
|
24
|
+
|
25
|
+
@wants_stream_id = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.wants_stream_id?
|
29
|
+
@wants_stream_id || false
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.define_flag(name, offset)
|
33
|
+
@flags ||= {}
|
34
|
+
@flags[name] = offset
|
35
|
+
define_method("#{name}!") do
|
36
|
+
instance_variable_set("@#{name}", true)
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method("#{name}?") do
|
40
|
+
instance_variable_get("@#{name}") || false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.flags
|
45
|
+
@flags || {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(frame = nil)
|
49
|
+
if frame
|
50
|
+
frame.validate_kind(frame_kind, wants_stream_id?)
|
51
|
+
frame.validate_size(value_size) unless value_size.nil?
|
52
|
+
@stream_id = frame.stream_id if wants_stream_id?
|
53
|
+
decode_flags(frame)
|
54
|
+
from_frame(frame)
|
55
|
+
end
|
56
|
+
yield self if block_given?
|
57
|
+
end
|
58
|
+
|
59
|
+
def frame_kind = self.class.frame_kind
|
60
|
+
def wants_stream_id? = self.class.wants_stream_id?
|
61
|
+
def value_size = self.class.value_size
|
62
|
+
def from_frame(_frame) = nil
|
63
|
+
def encode_payload = nil
|
64
|
+
def flags = self.class.flags
|
65
|
+
|
66
|
+
# :nocov:
|
67
|
+
|
68
|
+
def inspect_flags
|
69
|
+
flags.keys.to_h do |k|
|
70
|
+
[k, instance_variable_get("@#{k}")]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# :nocov:
|
75
|
+
|
76
|
+
def encode_uint16(*) = Wire.encode_uint16(*)
|
77
|
+
def encode_uint32(*) = Wire.encode_uint32(*)
|
78
|
+
def decode_uint16(*) = Wire.decode_uint16(*)
|
79
|
+
def decode_uint32(*) = Wire.decode_uint32(*)
|
80
|
+
|
81
|
+
def encode_flags
|
82
|
+
value = 0x00
|
83
|
+
flags.each_pair do |name, offset|
|
84
|
+
value |= (0x01 << offset) if send("#{name}?")
|
85
|
+
end
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
def decode_flags(frame)
|
90
|
+
flags.each_pair do |name, offset|
|
91
|
+
send("#{name}!") if frame.flags.anybits?((0x01 << offset))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_frame
|
96
|
+
Frame.new.tap do |f|
|
97
|
+
f.stream_id = stream_id if wants_stream_id?
|
98
|
+
f.frame_kind = frame_kind
|
99
|
+
f.flags = encode_flags
|
100
|
+
payload = encode_payload
|
101
|
+
payload = StringIO.new(payload) if payload && !payload.is_a?(StringIO)
|
102
|
+
f.length = (payload || "").length
|
103
|
+
f.payload = payload
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class ConfigurationFrame < BaseFrame
|
6
|
+
frame_kind :configuration
|
7
|
+
define_flag :compression_gzip, 0
|
8
|
+
define_flag :compression_brotli, 1
|
9
|
+
define_flag :ack, 2
|
10
|
+
attr_accessor :max_concurrent_streams
|
11
|
+
|
12
|
+
def from_frame(frame)
|
13
|
+
if !frame.empty? && frame.length != 4
|
14
|
+
raise InvalidFrameLengthError, "invalid length for frame CONFIGURATION " \
|
15
|
+
"expected 0 or 4 bytes, got #{frame.length}"
|
16
|
+
end
|
17
|
+
|
18
|
+
@max_concurrent_streams = decode_uint32(frame.payload) unless frame.empty?
|
19
|
+
|
20
|
+
return unless @max_concurrent_streams && @max_concurrent_streams != 0 && !ack?
|
21
|
+
|
22
|
+
raise InvalidFrameError, "received non-ack CONFIGURATION with " \
|
23
|
+
"non-zero max_concurrent_streams"
|
24
|
+
end
|
25
|
+
|
26
|
+
def encode_payload
|
27
|
+
return unless @max_concurrent_streams
|
28
|
+
|
29
|
+
encode_uint32(@max_concurrent_streams)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class DataFrame < BaseFrame
|
6
|
+
frame_kind :data
|
7
|
+
wants_stream_id!
|
8
|
+
|
9
|
+
define_flag :end_stream, 0
|
10
|
+
define_flag :end_data, 1
|
11
|
+
|
12
|
+
attr_accessor :payload
|
13
|
+
|
14
|
+
def from_frame(fr)
|
15
|
+
@payload = fr.payload
|
16
|
+
end
|
17
|
+
|
18
|
+
def encode_payload = @payload
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class GoAwayFrame < BaseFrame
|
6
|
+
frame_kind :go_away
|
7
|
+
|
8
|
+
attr_accessor :last_stream_id, :error_code, :additional_data
|
9
|
+
|
10
|
+
def from_frame(fr)
|
11
|
+
if fr.length < 8
|
12
|
+
raise InvalidFrameLengthError, "Invalid length for frame GOAWAY: at" \
|
13
|
+
"least 8 bytes are required"
|
14
|
+
end
|
15
|
+
@last_stream_id = decode_uint32(fr.payload)
|
16
|
+
@error_code = decode_uint32(fr.payload)
|
17
|
+
@additional_data = fr.payload.read
|
18
|
+
end
|
19
|
+
|
20
|
+
def encode_payload
|
21
|
+
buf = IO::Buffer.new
|
22
|
+
.write_raw(encode_uint32(last_stream_id))
|
23
|
+
.write_raw(encode_uint32(error_code))
|
24
|
+
buf.write_raw(additional_data) if additional_data
|
25
|
+
buf.string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class PingFrame < BaseFrame
|
6
|
+
frame_kind :ping
|
7
|
+
value_size 8
|
8
|
+
define_flag :ack, 2
|
9
|
+
attr_accessor :payload
|
10
|
+
|
11
|
+
def from_frame(fr)
|
12
|
+
@payload = fr.payload
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode_payload = @payload
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module Wire
|
5
|
+
class ResetStreamFrame < BaseFrame
|
6
|
+
frame_kind :reset_stream
|
7
|
+
value_size 4
|
8
|
+
wants_stream_id!
|
9
|
+
attr_accessor :error_code
|
10
|
+
|
11
|
+
def from_frame(fr)
|
12
|
+
@stream_id = fr.stream_id
|
13
|
+
@error_code = decode_uint32(fr.payload)
|
14
|
+
end
|
15
|
+
|
16
|
+
def encode_payload = encode_uint32(error_code)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "frames/base_frame"
|
4
|
+
require_relative "frames/configuration_frame"
|
5
|
+
require_relative "frames/ping_frame"
|
6
|
+
require_relative "frames/go_away_frame"
|
7
|
+
require_relative "frames/make_stream_frame"
|
8
|
+
require_relative "frames/reset_stream_frame"
|
9
|
+
require_relative "frames/data_frame"
|