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.
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"