arf 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/LICENSE.txt +21 -0
  4. data/Rakefile +12 -0
  5. data/lib/arf/configuration.rb +67 -0
  6. data/lib/arf/context.rb +170 -0
  7. data/lib/arf/errors.rb +10 -0
  8. data/lib/arf/io/buffer.rb +25 -0
  9. data/lib/arf/io/compression.rb +44 -0
  10. data/lib/arf/io/limit_reader.rb +30 -0
  11. data/lib/arf/observer.rb +29 -0
  12. data/lib/arf/proto/array.rb +31 -0
  13. data/lib/arf/proto/boolean.rb +15 -0
  14. data/lib/arf/proto/bytes.rb +35 -0
  15. data/lib/arf/proto/decoder.rb +31 -0
  16. data/lib/arf/proto/encoder.rb +71 -0
  17. data/lib/arf/proto/float.rb +48 -0
  18. data/lib/arf/proto/map.rb +49 -0
  19. data/lib/arf/proto/registry.rb +27 -0
  20. data/lib/arf/proto/scalar.rb +55 -0
  21. data/lib/arf/proto/string.rb +36 -0
  22. data/lib/arf/proto/struct.rb +84 -0
  23. data/lib/arf/proto/types.rb +67 -0
  24. data/lib/arf/proto/union.rb +25 -0
  25. data/lib/arf/proto.rb +17 -0
  26. data/lib/arf/reactor.rb +270 -0
  27. data/lib/arf/rpc/base_message.rb +119 -0
  28. data/lib/arf/rpc/client_base.rb +110 -0
  29. data/lib/arf/rpc/end_stream.rb +9 -0
  30. data/lib/arf/rpc/enum.rb +51 -0
  31. data/lib/arf/rpc/message_kind.rb +27 -0
  32. data/lib/arf/rpc/metadata.rb +120 -0
  33. data/lib/arf/rpc/method_meta.rb +42 -0
  34. data/lib/arf/rpc/request.rb +39 -0
  35. data/lib/arf/rpc/responder.rb +186 -0
  36. data/lib/arf/rpc/response.rb +46 -0
  37. data/lib/arf/rpc/service_base.rb +137 -0
  38. data/lib/arf/rpc/start_stream.rb +9 -0
  39. data/lib/arf/rpc/stream_error.rb +23 -0
  40. data/lib/arf/rpc/stream_item.rb +16 -0
  41. data/lib/arf/rpc/stream_metadata.rb +16 -0
  42. data/lib/arf/rpc/struct.rb +255 -0
  43. data/lib/arf/rpc.rb +19 -0
  44. data/lib/arf/server.rb +123 -0
  45. data/lib/arf/status.rb +75 -0
  46. data/lib/arf/types/array_type.rb +24 -0
  47. data/lib/arf/types/base_type.rb +14 -0
  48. data/lib/arf/types/coercion.rb +36 -0
  49. data/lib/arf/types/in_out_stream.rb +28 -0
  50. data/lib/arf/types/input_stream.rb +8 -0
  51. data/lib/arf/types/map_type.rb +32 -0
  52. data/lib/arf/types/mixin.rb +29 -0
  53. data/lib/arf/types/output_stream.rb +8 -0
  54. data/lib/arf/types/streamer.rb +21 -0
  55. data/lib/arf/types.rb +69 -0
  56. data/lib/arf/version.rb +5 -0
  57. data/lib/arf/wire/base_connection.rb +177 -0
  58. data/lib/arf/wire/client.rb +101 -0
  59. data/lib/arf/wire/encoding.rb +49 -0
  60. data/lib/arf/wire/error_code.rb +35 -0
  61. data/lib/arf/wire/errors.rb +88 -0
  62. data/lib/arf/wire/frame.rb +111 -0
  63. data/lib/arf/wire/frame_kind.rb +23 -0
  64. data/lib/arf/wire/frame_reader.rb +104 -0
  65. data/lib/arf/wire/frames/base_frame.rb +108 -0
  66. data/lib/arf/wire/frames/configuration_frame.rb +33 -0
  67. data/lib/arf/wire/frames/data_frame.rb +21 -0
  68. data/lib/arf/wire/frames/go_away_frame.rb +29 -0
  69. data/lib/arf/wire/frames/make_stream_frame.rb +15 -0
  70. data/lib/arf/wire/frames/ping_frame.rb +18 -0
  71. data/lib/arf/wire/frames/reset_stream_frame.rb +19 -0
  72. data/lib/arf/wire/frames.rb +9 -0
  73. data/lib/arf/wire/server/peer.rb +85 -0
  74. data/lib/arf/wire/server.rb +63 -0
  75. data/lib/arf/wire/stream/state.rb +69 -0
  76. data/lib/arf/wire/stream.rb +128 -0
  77. data/lib/arf/wire/wait_signal.rb +24 -0
  78. data/lib/arf/wire.rb +14 -0
  79. data/lib/arf.rb +46 -0
  80. 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,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arf
4
+ module Wire
5
+ class MakeStreamFrame < BaseFrame
6
+ frame_kind :make_stream
7
+ value_size 0
8
+ wants_stream_id!
9
+
10
+ def from_frame(fr)
11
+ @stream_id = fr.stream_id
12
+ end
13
+ end
14
+ end
15
+ 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"