arf 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|