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,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
|