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,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class BaseMessage
|
6
|
+
def self.register(kind, cls)
|
7
|
+
@messages ||= {}
|
8
|
+
@messages[kind] = cls
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.message_by_kind(kind)
|
12
|
+
@messages ||= {}
|
13
|
+
@messages[kind]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.initialize_from(data)
|
17
|
+
type = MESSAGE_KIND_FROM_BYTE[data.readbyte] || :invalid
|
18
|
+
raise "Cannot decode invalid message" if type == :invalid
|
19
|
+
|
20
|
+
instance = message_by_kind(type).new
|
21
|
+
instance.decode(data)
|
22
|
+
instance
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.encode(message)
|
26
|
+
IO::Buffer.new
|
27
|
+
.write(MESSAGE_KIND_FROM_SYMBOL[message.kind])
|
28
|
+
.write_raw(message.encode)
|
29
|
+
.string
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.has_status
|
33
|
+
define_method(:status=) do |val|
|
34
|
+
case val
|
35
|
+
when Symbol
|
36
|
+
@status = Status::FROM_SYMBOL[val]
|
37
|
+
raise ArgumentError, "Invalid value #{val.inspect} for status: Unknown status" unless @status
|
38
|
+
when Integer
|
39
|
+
if Status::TO_SYMBOL[val].nil?
|
40
|
+
raise ArgumentError, "Invalid value #{val.inspect} for status: Unknown status"
|
41
|
+
end
|
42
|
+
|
43
|
+
@status = val
|
44
|
+
else
|
45
|
+
raise ArgumentError, "Invalid value #{val.inspect} for status: Expected symbol or integer"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
define_method(:status) do
|
50
|
+
return nil if @status.nil?
|
51
|
+
|
52
|
+
Status::TO_SYMBOL[@status] || :unknown
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.has_metadata
|
57
|
+
attr_reader :metadata
|
58
|
+
|
59
|
+
define_method(:metadata=) do |val|
|
60
|
+
case val
|
61
|
+
when NilClass
|
62
|
+
@metadata = Metadata.new
|
63
|
+
when Metadata
|
64
|
+
@metadata = val
|
65
|
+
when Hash
|
66
|
+
@metadata = Metadata.new(**val)
|
67
|
+
else
|
68
|
+
raise ArgumentError, "Invalid value #{val.inspect} for metadata: Expected nil, Arf::RPC::Metadata, or Hash"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.has_streaming
|
74
|
+
attr_accessor :streaming
|
75
|
+
|
76
|
+
define_method(:streaming?) { @streaming }
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.kind(kind = nil)
|
80
|
+
return @kind if kind.nil?
|
81
|
+
|
82
|
+
@kind = kind
|
83
|
+
define_method(:kind) { self.class.kind }
|
84
|
+
BaseMessage.register(kind, self)
|
85
|
+
kind
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize(**kwargs)
|
89
|
+
kwargs.each { |k, v| send("#{k}=", v) }
|
90
|
+
@params ||= [] if respond_to? :params=
|
91
|
+
@streaming ||= false if respond_to? :streaming=
|
92
|
+
@metadata ||= Metadata.new if respond_to? :metadata=
|
93
|
+
end
|
94
|
+
|
95
|
+
def encode = ""
|
96
|
+
|
97
|
+
def decode(_data) = nil
|
98
|
+
|
99
|
+
def decode_string(data)
|
100
|
+
type, header = Proto.read_type(data)
|
101
|
+
raise "Invalid message payload" if type != Proto::TYPE_STRING
|
102
|
+
|
103
|
+
Proto.decode_string(header, data)
|
104
|
+
end
|
105
|
+
|
106
|
+
def decode_bytes(data)
|
107
|
+
type, header = Proto.read_type(data)
|
108
|
+
raise "Invalid message payload" if type != Proto::TYPE_BYTES
|
109
|
+
|
110
|
+
Proto.decode_bytes(header, data)
|
111
|
+
end
|
112
|
+
|
113
|
+
def decode_uint16(data) = Wire.decode_uint16(data)
|
114
|
+
def encode_uint16(value) = Wire.encode_uint16(value)
|
115
|
+
def encode_string(str) = Proto.encode_string(str)
|
116
|
+
def encode_bytes(data) = Proto.encode_bytes(data)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class ClientBase
|
6
|
+
include Arf::Types::Mixin
|
7
|
+
|
8
|
+
def self.arf_service_id(id)
|
9
|
+
@arf_service_id = id
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.rpc(name, inputs: nil, outputs: nil)
|
13
|
+
@rpc_metadata ||= {}
|
14
|
+
inputs ||= {}
|
15
|
+
outputs = [outputs].compact unless outputs.is_a? Array
|
16
|
+
|
17
|
+
@rpc_metadata[name] = {
|
18
|
+
name:, inputs: inputs.dup, outputs: outputs.dup
|
19
|
+
}
|
20
|
+
|
21
|
+
inputs = inputs.to_a
|
22
|
+
.map do |type|
|
23
|
+
if type.last.is_a? InputStream
|
24
|
+
outputs << type.last
|
25
|
+
next nil
|
26
|
+
end
|
27
|
+
type
|
28
|
+
end
|
29
|
+
.compact.to_h
|
30
|
+
|
31
|
+
if outputs.length > 1 && outputs[-2].is_a?(Streamer) && outputs[-1].is_a?(Streamer)
|
32
|
+
input = outputs.find { _1.is_a? InputStream }
|
33
|
+
output = outputs.find { _1.is_a? OutputStream }
|
34
|
+
|
35
|
+
outputs = outputs[...-2]
|
36
|
+
outputs << InOutStream[input.type, output.type]
|
37
|
+
end
|
38
|
+
|
39
|
+
@rpc_metadata[name][:native_inputs] = inputs
|
40
|
+
@rpc_metadata[name][:native_outputs] = outputs
|
41
|
+
|
42
|
+
internal_name = "_#{name}"
|
43
|
+
service_name = @arf_service_id
|
44
|
+
|
45
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
46
|
+
# def name(param, param, param, **metadata, &block)
|
47
|
+
# internal_name(params, param, param, **metadata, &block)
|
48
|
+
# end
|
49
|
+
def #{name}(#{inputs.keys.join(", ")}#{inputs.length.positive? ? ", " : ""}**metadata, &block)
|
50
|
+
#{internal_name}(#{inputs.keys.join(", ")}#{inputs.length.positive? ? ", " : ""}**metadata, &block)
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
|
54
|
+
define_method(internal_name) do |*args, **metadata, &block|
|
55
|
+
_invoke_method(service_name, name, inputs.values, outputs, args, metadata, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(client)
|
60
|
+
@client = client
|
61
|
+
end
|
62
|
+
|
63
|
+
def _invoke_method(service_id, method_name, inputs, outputs, args, meta)
|
64
|
+
mapped_args = args.map.with_index do |v, idx|
|
65
|
+
raw_type = case (t = inputs[idx])
|
66
|
+
when Symbol then t
|
67
|
+
when String then self.class.find_type(t)
|
68
|
+
else
|
69
|
+
raise ArgumentError, "Unknown type definition #{v.inspect}"
|
70
|
+
end
|
71
|
+
|
72
|
+
Arf::Types.coerce_value(v, raw_type)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Obtain a stream from @client
|
76
|
+
str = @client.new_stream
|
77
|
+
|
78
|
+
# Push the request
|
79
|
+
streaming = outputs.any? { _1.is_a?(InputStream) || _1.is_a?(InOutStream) }
|
80
|
+
req = Request.new(
|
81
|
+
streaming:,
|
82
|
+
metadata: meta,
|
83
|
+
service: service_id,
|
84
|
+
method: method_name,
|
85
|
+
params: mapped_args
|
86
|
+
)
|
87
|
+
|
88
|
+
input_type = nil
|
89
|
+
output_type = nil
|
90
|
+
|
91
|
+
streamer = outputs.last
|
92
|
+
case streamer
|
93
|
+
when InputStream
|
94
|
+
input_type = streamer.resolved_type(self.class)
|
95
|
+
when OutputStream
|
96
|
+
output_type = streamer.resolved_type(self.class)
|
97
|
+
when InOutStream
|
98
|
+
input_type = streamer.resolved_input(self.class)
|
99
|
+
output_type = streamer.resolved_output(self.class)
|
100
|
+
end
|
101
|
+
|
102
|
+
resp = Responder.new(str, input_type, output_type)
|
103
|
+
|
104
|
+
str.write_data(BaseMessage.encode(req), end_stream: !streaming)
|
105
|
+
|
106
|
+
resp
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/arf/rpc/enum.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class Enum
|
6
|
+
def self.option(**kwargs)
|
7
|
+
@options ||= {}
|
8
|
+
kwargs.each { |k, v| @options[k.to_sym] = v }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.option_by_name(name)
|
12
|
+
@options ||= {}
|
13
|
+
@options[name.to_sym]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.option_by_value(value)
|
17
|
+
@options ||= {}
|
18
|
+
@options.find { _2 == value }&.first
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_reader :options
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.to_i(value)
|
26
|
+
case value
|
27
|
+
when Symbol, String
|
28
|
+
option_by_name(value) or raise(ArgumentError, "Invalid value #{value.inspect} for #{self}")
|
29
|
+
when Integer
|
30
|
+
option_by_value(value) or raise(ArgumentError, "Invalid value #{value.inspect} for #{self}")
|
31
|
+
value
|
32
|
+
else
|
33
|
+
raise ArgumentError, "Invalid value type #{value.class}. Expected Symbol, String or Integer."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.to_sym(value)
|
38
|
+
case value
|
39
|
+
when Symbol, String
|
40
|
+
value = value.to_sym
|
41
|
+
option_by_name(value) or raise(ArgumentError, "Invalid value #{value.inspect} for #{self}")
|
42
|
+
value
|
43
|
+
when Integer
|
44
|
+
option_by_value(value) or raise(ArgumentError, "Invalid value #{value.inspect} for #{self}")
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Invalid value type #{value.class}. Expected Symbol, String or Integer."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
MESSAGE_KIND_INVALID = 0x00
|
6
|
+
MESSAGE_KIND_REQUEST = 0x01
|
7
|
+
MESSAGE_KIND_RESPONSE = 0x02
|
8
|
+
MESSAGE_KIND_START_STREAM = 0x03
|
9
|
+
MESSAGE_KIND_STREAM_ITEM = 0x04
|
10
|
+
MESSAGE_KIND_STREAM_METADATA = 0x05
|
11
|
+
MESSAGE_KIND_END_STREAM = 0x06
|
12
|
+
MESSAGE_KIND_STREAM_ERROR = 0x07
|
13
|
+
|
14
|
+
MESSAGE_KIND_FROM_BYTE = {
|
15
|
+
MESSAGE_KIND_INVALID => :invalid,
|
16
|
+
MESSAGE_KIND_REQUEST => :request,
|
17
|
+
MESSAGE_KIND_RESPONSE => :response,
|
18
|
+
MESSAGE_KIND_START_STREAM => :start_stream,
|
19
|
+
MESSAGE_KIND_STREAM_ITEM => :stream_item,
|
20
|
+
MESSAGE_KIND_STREAM_METADATA => :stream_metadata,
|
21
|
+
MESSAGE_KIND_END_STREAM => :end_stream,
|
22
|
+
MESSAGE_KIND_STREAM_ERROR => :stream_error
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
MESSAGE_KIND_FROM_SYMBOL = MESSAGE_KIND_FROM_BYTE.to_a.to_h(&:reverse)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class Metadata < BaseMessage
|
6
|
+
def initialize(**kwargs)
|
7
|
+
super()
|
8
|
+
@pairs = {}
|
9
|
+
@dirty = false
|
10
|
+
@observer = Observer.new
|
11
|
+
kwargs.each { |k, v| set(k, v) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def attach_observer(obs)
|
15
|
+
@observer.attach_handler(obs)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(k, v) = @observer.modify { _add(k, v) }
|
19
|
+
|
20
|
+
def [](k) = @pairs[k]
|
21
|
+
def get(k) = @pairs[k]&.first
|
22
|
+
|
23
|
+
def []=(k, v)
|
24
|
+
@observer.modify { _add(k, v) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def set(k, v)
|
28
|
+
v = [v] unless v.is_a? Array
|
29
|
+
@observer.modify do
|
30
|
+
@pairs[k] = []
|
31
|
+
v.each { _add(k, _1) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def merge!(other)
|
36
|
+
@observer.modify do
|
37
|
+
other.each do |k, v|
|
38
|
+
@pairs[k] ||= []
|
39
|
+
@pairs[k].append(*v)
|
40
|
+
end
|
41
|
+
@dirty = true
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def replace!(other)
|
47
|
+
@observer.modify do
|
48
|
+
@pairs = {}
|
49
|
+
other.each do |k, v|
|
50
|
+
@pairs[k] ||= []
|
51
|
+
@pairs[k].append(*v)
|
52
|
+
end
|
53
|
+
@dirty = true
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def key?(k) = @pairs.key?(k.to_s)
|
59
|
+
alias has_key? key?
|
60
|
+
|
61
|
+
def each(&block) = tap { @pairs.each(&block) }
|
62
|
+
alias each_pair each
|
63
|
+
|
64
|
+
def keys = @pairs.keys
|
65
|
+
def each_key(&block) = tap { @pairs.keys(&block) }
|
66
|
+
|
67
|
+
def dirty? = @dirty
|
68
|
+
|
69
|
+
def encode
|
70
|
+
pairs = []
|
71
|
+
@pairs.each do |k, v|
|
72
|
+
v.each { pairs << [k, _1] }
|
73
|
+
end
|
74
|
+
keys = IO::Buffer.new
|
75
|
+
values = IO::Buffer.new
|
76
|
+
pairs.each do |p|
|
77
|
+
keys.write_raw(encode_string(p.first))
|
78
|
+
values.write_raw(encode_bytes(p.last))
|
79
|
+
end
|
80
|
+
|
81
|
+
@dirty = false
|
82
|
+
IO::Buffer.new
|
83
|
+
.write_raw(encode_uint16(pairs.length))
|
84
|
+
.write_raw(keys.string)
|
85
|
+
.write_raw(values.string)
|
86
|
+
.string
|
87
|
+
end
|
88
|
+
|
89
|
+
def decode(data)
|
90
|
+
len = decode_uint16(data)
|
91
|
+
keys = []
|
92
|
+
values = []
|
93
|
+
|
94
|
+
len.times { keys << decode_string(data) }
|
95
|
+
len.times { values << decode_bytes(data) }
|
96
|
+
|
97
|
+
@pairs = {}
|
98
|
+
keys.zip(values).each { |pair| _add(*pair) }
|
99
|
+
@dirty = false
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def _add(k, v)
|
107
|
+
k = k.to_s
|
108
|
+
v = case v
|
109
|
+
when String then v
|
110
|
+
when StringIO then v.string
|
111
|
+
else v.to_s
|
112
|
+
end
|
113
|
+
|
114
|
+
@pairs[k] ||= []
|
115
|
+
@pairs[k] << v
|
116
|
+
@dirty = true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class MethodMeta
|
6
|
+
Streamer = Arf::Types::Streamer
|
7
|
+
InOutStream = Arf::Types::InOutStream
|
8
|
+
|
9
|
+
ANY_STREAMER = ->(v) { v.is_a?(Streamer) || v.is_a?(InOutStream) }
|
10
|
+
NOT_STREAMER = ->(v) { !v.is_a?(Streamer) && !v.is_a?(InOutStream) }
|
11
|
+
|
12
|
+
def initialize(inputs, outputs)
|
13
|
+
@inputs = inputs || {}
|
14
|
+
@outputs = outputs || []
|
15
|
+
end
|
16
|
+
|
17
|
+
def output_stream = @outputs.find(&ANY_STREAMER)
|
18
|
+
def input_stream = @inputs.values.find(&ANY_STREAMER)
|
19
|
+
def output_stream? = !output_stream.nil?
|
20
|
+
def input_stream? = !input_stream.nil?
|
21
|
+
def output? = @outputs.any?(&NOT_STREAMER)
|
22
|
+
def inputs? = @inputs.values.any?(&NOT_STREAMER)
|
23
|
+
def output_types = @outputs.filter(&NOT_STREAMER)
|
24
|
+
|
25
|
+
def coerce_result(value, resolver)
|
26
|
+
return [] if value.nil?
|
27
|
+
|
28
|
+
[value].flatten.map.with_index do |v, idx|
|
29
|
+
expected_type = output_types[idx]
|
30
|
+
case expected_type
|
31
|
+
when String
|
32
|
+
Arf::Types.coerce_value(v, resolver.find_type(expected_type))
|
33
|
+
when Arf::Types::BaseType
|
34
|
+
expected_type.coerce(v)
|
35
|
+
else
|
36
|
+
Arf::Types.coerce_value(v, expected_type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class Request < BaseMessage
|
6
|
+
kind :request
|
7
|
+
has_streaming
|
8
|
+
has_metadata
|
9
|
+
attr_accessor :service, :method, :params
|
10
|
+
|
11
|
+
def encode
|
12
|
+
flags = 0x00
|
13
|
+
flags |= (0x01 << 0x00) if streaming?
|
14
|
+
|
15
|
+
params = @params.map { Proto.encode(_1) }
|
16
|
+
|
17
|
+
IO::Buffer.new
|
18
|
+
.write_raw(encode_string(@service))
|
19
|
+
.write_raw(encode_string(@method))
|
20
|
+
.write(flags)
|
21
|
+
.write_raw(@metadata.encode)
|
22
|
+
.write_raw(encode_uint16(params.length))
|
23
|
+
.write_raw(params.join)
|
24
|
+
.string
|
25
|
+
end
|
26
|
+
|
27
|
+
def decode(data)
|
28
|
+
@service = decode_string(data)
|
29
|
+
@method = decode_string(data)
|
30
|
+
flags = data.readbyte
|
31
|
+
@streaming = !flags.nobits?((0x01 << 0x00))
|
32
|
+
@metadata = Metadata.new.decode(data)
|
33
|
+
params_len = decode_uint16(data)
|
34
|
+
@params = []
|
35
|
+
params_len.times { @params << Proto.decode(data) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arf
|
4
|
+
module RPC
|
5
|
+
class Responder
|
6
|
+
def initialize(str, input_stream_type, output_stream_type)
|
7
|
+
@metadata = Metadata.new
|
8
|
+
@stream = str
|
9
|
+
|
10
|
+
@response = nil
|
11
|
+
@response_error = nil
|
12
|
+
@response_lock = Mutex.new
|
13
|
+
@response_cond = Thread::ConditionVariable.new
|
14
|
+
|
15
|
+
@input_stream_type = output_stream_type
|
16
|
+
@has_input_stream = !output_stream_type.nil?
|
17
|
+
@input_stream_started = false
|
18
|
+
@input_stream_error = nil
|
19
|
+
@input_stream_completed = false
|
20
|
+
@input_stream_items = Queue.new
|
21
|
+
@input_stream_closed_lock = Mutex.new
|
22
|
+
@input_stream_closed = false
|
23
|
+
|
24
|
+
@output_stream_type = input_stream_type
|
25
|
+
@has_output_stream = !input_stream_type.nil?
|
26
|
+
@output_stream_started_lock = Mutex.new
|
27
|
+
@output_stream_started = false
|
28
|
+
@output_stream_error = nil
|
29
|
+
@output_stream_closed_lock = Mutex.new
|
30
|
+
@output_stream_closed = false
|
31
|
+
|
32
|
+
str.attach_handler(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_data(value)
|
36
|
+
msg = BaseMessage.initialize_from(value)
|
37
|
+
case msg
|
38
|
+
when Response
|
39
|
+
@response_lock.synchronize do
|
40
|
+
@response = msg
|
41
|
+
@metadata.merge!(msg.metadata)
|
42
|
+
if @response.status == :ok
|
43
|
+
@params = msg.params
|
44
|
+
else
|
45
|
+
@response_error = Status::BadStatus.new(
|
46
|
+
@response.status,
|
47
|
+
@response.metadata.get("arf-status-description")
|
48
|
+
)
|
49
|
+
end
|
50
|
+
@response_cond.broadcast
|
51
|
+
end
|
52
|
+
|
53
|
+
when StartStream
|
54
|
+
@input_stream_started = true
|
55
|
+
|
56
|
+
when EndStream
|
57
|
+
@input_stream_completed = true
|
58
|
+
@input_stream_items.close
|
59
|
+
|
60
|
+
when StreamMetadata
|
61
|
+
@metadata.replace!(msg.metadata)
|
62
|
+
|
63
|
+
when StreamItem
|
64
|
+
return if @input_stream_completed
|
65
|
+
|
66
|
+
@input_stream_closed_lock.synchronize do
|
67
|
+
return if @input_stream_closed
|
68
|
+
end
|
69
|
+
@input_stream_items << msg.value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def push(value, **kwargs)
|
74
|
+
raise ArgumentError, "#push receives either a value or kwargs, not both." if value && !kwargs.empty?
|
75
|
+
|
76
|
+
raise RPC::NoStreamError, false unless @has_output_stream
|
77
|
+
raise @output_stream_error if @output_stream_error
|
78
|
+
|
79
|
+
# TODO: Warn? Error?
|
80
|
+
return if @output_stream_closed
|
81
|
+
|
82
|
+
@output_stream_closed_lock.synchronize do
|
83
|
+
return if @output_stream_closed
|
84
|
+
end
|
85
|
+
|
86
|
+
@output_stream_started_lock.synchronize do
|
87
|
+
next if @output_stream_started
|
88
|
+
|
89
|
+
@stream.write_data(BaseMessage.encode(StartStream.new))
|
90
|
+
@output_stream_started = true
|
91
|
+
end
|
92
|
+
|
93
|
+
@stream.write_data(BaseMessage.encode(StreamItem.new(value:)))
|
94
|
+
value
|
95
|
+
end
|
96
|
+
|
97
|
+
alias << push
|
98
|
+
|
99
|
+
def recv
|
100
|
+
raise RPC::NoStreamError, true unless @has_input_stream
|
101
|
+
raise @input_stream_error if @input_stream_error
|
102
|
+
|
103
|
+
@input_stream_items.pop
|
104
|
+
end
|
105
|
+
|
106
|
+
def each
|
107
|
+
loop do
|
108
|
+
item = recv
|
109
|
+
break if item.nil?
|
110
|
+
|
111
|
+
yield item
|
112
|
+
rescue StopIteration
|
113
|
+
break
|
114
|
+
end
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def close_send
|
119
|
+
return if @output_stream_closed
|
120
|
+
|
121
|
+
@output_stream_closed_lock.synchronize do
|
122
|
+
@output_stream_closed = true
|
123
|
+
@stream.write_data(BaseMessage.encode(EndStream.new))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def close_recv
|
128
|
+
return if @input_stream_closed
|
129
|
+
|
130
|
+
@input_stream_closed_lock.synchronize do
|
131
|
+
@input_stream_closed = true
|
132
|
+
@input_stream_items.close
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def _wait_response(throw_error: true)
|
137
|
+
raise @response_error if @response_error && throw_error
|
138
|
+
|
139
|
+
return if @response
|
140
|
+
|
141
|
+
catch :break_loop do
|
142
|
+
loop do
|
143
|
+
@response_lock.synchronize do
|
144
|
+
@response_cond.wait(@response_lock)
|
145
|
+
next if @response.nil?
|
146
|
+
|
147
|
+
throw :break_loop
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def params
|
154
|
+
_wait_response
|
155
|
+
normalize_response_params
|
156
|
+
end
|
157
|
+
|
158
|
+
def normalize_response_params
|
159
|
+
if @response.params.empty?
|
160
|
+
nil
|
161
|
+
elsif @response.params.length == 1
|
162
|
+
@response.params.first
|
163
|
+
else
|
164
|
+
@response.params
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def metadata
|
169
|
+
# It makes little sense to access metadata before a response is
|
170
|
+
# received. Given that:
|
171
|
+
_wait_response
|
172
|
+
|
173
|
+
@metadata
|
174
|
+
end
|
175
|
+
|
176
|
+
def status
|
177
|
+
_wait_response(throw_error: false)
|
178
|
+
@response.status
|
179
|
+
end
|
180
|
+
|
181
|
+
def success?
|
182
|
+
status == :ok
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|