ccrpc 0.3.1 → 0.5.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.md +12 -9
- data/ccrpc.gemspec +1 -0
- data/lib/ccrpc/escape.rb +1 -1
- data/lib/ccrpc/rpc_connection.rb +196 -58
- data/lib/ccrpc/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +26 -24
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3f1a9ac22e449534ede2f1d3f94efcc11becf3d65d7e868ce1f6334f580ba54
|
4
|
+
data.tar.gz: 70a5849b9f6594090a5069b13d566b39cf53baf69bf5ee743ead1fa56d7bd1a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31e497800794295aafed95c1f75b8d2cc866aff6255d94914f0377eb04d7ad3a0009da355bc6f240466a25cd5131de46a56d8845c345f4a67b8896303e79a5e2
|
7
|
+
data.tar.gz: c457015d25201324c856a7fea9b0bc3ccdc0b5a1f9819f7c0758e45f27f3cf4c732b4028fa3e8f9af955a2e14319bde9c6ff6da9e3a3cae09b3cc560e8109520
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.md
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
# Ccrpc - A
|
1
|
+
# Ccrpc - A minimalist RPC library for Ruby
|
2
2
|
|
3
3
|
Features:
|
4
|
-
|
5
|
-
*
|
4
|
+
|
5
|
+
* Simple human readable wire protocol and optionally a faster binary protocol
|
6
|
+
* Works on arbitrary IO like objects (Pipes, Sockets, STDIN, STDOUT, OpenSSL) even Windows CR/LF converting IOs
|
6
7
|
* No object definitions - only plain string transfers (so no issues with undefined classes or garbage collection like in DRb)
|
7
8
|
* Each call transfers a function name and a list of parameters in form of a Hash<String=>String>
|
8
9
|
* Each response equally transfers a list of parameters
|
9
|
-
* Similar to closures, it's possible to respond to a particular call as a call_back
|
10
|
-
* Fully asynchronous, either by use of multiple threads or by using lazy_answers
|
10
|
+
* Similar to closures, it's possible to respond to a particular call as a `call_back`
|
11
|
+
* Fully asynchronous, either by use of multiple threads or by using `lazy_answers`, so that arbitrary calls in both directions can be mixed simultaneously without blocking each other
|
11
12
|
* Fully thread safe, but doesn't use additional internal threads
|
12
|
-
* Each call_back arrives in the thread of the caller
|
13
|
+
* Each `call_back` arrives in the thread of the caller
|
13
14
|
* Only dedicated functions can be called (not arbitrary as in DRb)
|
14
15
|
* No dependencies
|
15
16
|
|
@@ -72,7 +73,7 @@ The following example invokes the call in the opposite direction, from the subpr
|
|
72
73
|
require 'ccrpc'
|
73
74
|
# Create the receiver side of the connection
|
74
75
|
# Use a copy of STDOUT because...
|
75
|
-
rpc = Ccrpc::RpcConnection.new(STDIN, STDOUT.dup)
|
76
|
+
rpc = Ccrpc::RpcConnection.new(STDIN.binmode, STDOUT.dup.binmode)
|
76
77
|
# .. STDOUT is now redirected to STDERR, so that pp prints to STDERR
|
77
78
|
STDOUT.reopen(STDERR)
|
78
79
|
# Call function "hello" with param {"who" => "world"}
|
@@ -84,10 +85,10 @@ The following example invokes the call in the opposite direction, from the subpr
|
|
84
85
|
tf.write(code)
|
85
86
|
tf.flush
|
86
87
|
# Execute the temp file in a subprocess
|
87
|
-
io = IO.popen(['ruby', tf.path], "
|
88
|
+
io = IO.popen(['ruby', tf.path], "wb+")
|
88
89
|
|
89
90
|
# Create the caller side of the connection
|
90
|
-
rpc = Ccrpc::RpcConnection.new(io, io)
|
91
|
+
rpc = Ccrpc::RpcConnection.new(io, io, protocol: :binary)
|
91
92
|
# Wait for calls
|
92
93
|
rpc.call do |call|
|
93
94
|
# Print the received call data to STDERR
|
@@ -98,6 +99,8 @@ The following example invokes the call in the opposite direction, from the subpr
|
|
98
99
|
# call returns when the IO is closed by the subprocess
|
99
100
|
```
|
100
101
|
|
102
|
+
Full API documentation is here: https://rubydoc.info/gems/ccrpc
|
103
|
+
|
101
104
|
|
102
105
|
## Development
|
103
106
|
|
data/ccrpc.gemspec
CHANGED
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/ccrpc"
|
16
17
|
|
17
18
|
# Specify which files should be added to the gem when it is released.
|
18
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
data/lib/ccrpc/escape.rb
CHANGED
@@ -5,7 +5,7 @@ module Ccrpc
|
|
5
5
|
module Escape
|
6
6
|
def self.escape(data)
|
7
7
|
data = data.b if data.frozen? || data.encoding != Encoding::BINARY
|
8
|
-
data.gsub(/([\a\r\n\t\\])/n){ "\\x" + $1.
|
8
|
+
data.gsub(/([\a\r\n\t\\])/n){ "\\x" + $1.unpack1("H2") }
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.unescape(data)
|
data/lib/ccrpc/rpc_connection.rb
CHANGED
@@ -76,20 +76,43 @@ class RpcConnection
|
|
76
76
|
end
|
77
77
|
|
78
78
|
CallbackReceiver = Struct.new :meth, :callbacks
|
79
|
+
ReceivedCallData = Struct.new :cbfunc, :id, :recv_id
|
79
80
|
|
81
|
+
# The kind of +IO+ object used to receive calls and answers. Set by {initialize}.
|
80
82
|
attr_accessor :read_io
|
83
|
+
# The kind of +IO+ object used to send calls and answers. Set by {initialize}.
|
81
84
|
attr_accessor :write_io
|
82
85
|
|
83
86
|
# Create a RPC connection
|
84
87
|
#
|
85
88
|
# @param [IO] read_io readable IO object for reception of data
|
86
89
|
# @param [IO] write_io writable IO object for transmission of data
|
87
|
-
# @param [Boolean] lazy_answers Enable or disable lazy results.
|
88
|
-
|
90
|
+
# @param [Boolean] lazy_answers Enable or disable lazy results.
|
91
|
+
# If enabled the return value of #call is always a Ccrpc::Promise object.
|
92
|
+
# It behaves like an ordinary +nil+ or Hash object, but the actual IO blocking operation is delayed to the first method call on the Promise object.
|
93
|
+
# See {#call} for more description.
|
94
|
+
# @param [Symbol] protocol Select the protocol which is used to send calls.
|
95
|
+
# * The +:text+ protocol is the classic default.
|
96
|
+
# * The +:binary+ protocol is faster, but not so readable for human.
|
97
|
+
# * The +:prefer_binary+ is the same as :binary, but with an initial round-trip to check that the other end is binary-capable (means ccrpc >= 0.5).
|
98
|
+
# The protocol used to receive calls is selected by the *protocol* option on the other end.
|
99
|
+
# A connection could use different protocols for both directions, although this has no advantage.
|
100
|
+
def initialize(read_io, write_io, lazy_answers: false, protocol: :text)
|
89
101
|
super()
|
90
102
|
|
91
103
|
@read_io = read_io
|
92
104
|
@write_io = write_io
|
105
|
+
@read_binary = false
|
106
|
+
@write_binary = case protocol
|
107
|
+
when :binary
|
108
|
+
true
|
109
|
+
when :text, :only_text # only_text is to simulate ccrpc-0.4.0 peer
|
110
|
+
false
|
111
|
+
when :prefer_binary
|
112
|
+
nil
|
113
|
+
else
|
114
|
+
raise ArgumentError, "invalid protocol: #{protocol.inspect}"
|
115
|
+
end
|
93
116
|
if lazy_answers
|
94
117
|
require 'ccrpc/lazy'
|
95
118
|
alias maybe_lazy do_lazy
|
@@ -101,27 +124,100 @@ class RpcConnection
|
|
101
124
|
@write_io.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
102
125
|
end
|
103
126
|
|
104
|
-
# A random number as start call ID is not technically required, but makes transferred data more readable.
|
105
|
-
@id = rand(1000)
|
106
127
|
@id_mutex = Mutex.new
|
107
128
|
@read_mutex = Mutex.new
|
108
129
|
@write_mutex = Mutex.new
|
109
130
|
@answers = {}
|
110
131
|
@receivers = {}
|
111
132
|
@answers_mutex = Mutex.new
|
133
|
+
@proto_ack_mutex = Mutex.new
|
112
134
|
@new_answer = ConditionVariable.new
|
113
135
|
|
114
136
|
@read_enum = Enumerator.new do |y|
|
115
137
|
begin
|
116
138
|
while @read_enum
|
117
|
-
|
118
|
-
|
119
|
-
|
139
|
+
if @read_binary
|
140
|
+
t = @read_io.read(1)&.getbyte(0)
|
141
|
+
# p @read_io=>t
|
142
|
+
case t
|
143
|
+
when 1
|
144
|
+
keysize, valsize = @read_io.read(8).unpack("NN")
|
145
|
+
key = @read_io.read(keysize).force_encoding(Encoding::UTF_8)
|
146
|
+
value = @read_io.read(valsize).force_encoding(Encoding::UTF_8)
|
147
|
+
y << [key, value]
|
148
|
+
when 2
|
149
|
+
id, funcsize = @read_io.read(8).unpack("NN")
|
150
|
+
func = @read_io.read(funcsize)
|
151
|
+
y << ReceivedCallData.new(func.force_encoding(Encoding::UTF_8), id)
|
152
|
+
when 3
|
153
|
+
id, recv_id, funcsize = @read_io.read(12).unpack("NNN")
|
154
|
+
func = @read_io.read(funcsize)
|
155
|
+
y << ReceivedCallData.new(func.force_encoding(Encoding::UTF_8), id, recv_id)
|
156
|
+
when 4
|
157
|
+
id = @read_io.read(4).unpack1("N")
|
158
|
+
y << id
|
159
|
+
when 79 # "O"
|
160
|
+
l = @read_io.read(6)
|
161
|
+
unless l == "\tK\n\a1\n"
|
162
|
+
raise InvalidResponse, "invalid binary response #{l.inspect}"
|
163
|
+
end
|
164
|
+
y << ["O", "K"]
|
165
|
+
y << 1
|
166
|
+
|
167
|
+
when NilClass
|
168
|
+
# connection closed
|
169
|
+
break
|
170
|
+
|
171
|
+
else
|
172
|
+
raise InvalidResponse, "invalid binary response #{t.inspect}"
|
173
|
+
end
|
174
|
+
|
175
|
+
else
|
176
|
+
|
177
|
+
l = @read_io.gets&.force_encoding(Encoding::BINARY)
|
178
|
+
# p @read_io=>l
|
179
|
+
case
|
180
|
+
when l=="\r\0\a1\n" && protocol != :only_text
|
181
|
+
@read_binary = true
|
182
|
+
when l=="\r\1\a1\n" && protocol != :only_text
|
183
|
+
@read_binary = true
|
184
|
+
send_answer({O: :K}, 1)
|
185
|
+
|
186
|
+
when l=~/\A([^\t\a\n]+)\t(.*?)\r?\n\z/mn
|
187
|
+
# received key/value pair used for either callback parameters or return values
|
188
|
+
y << [Escape.unescape($1).force_encoding(Encoding::UTF_8), Escape.unescape($2.force_encoding(Encoding::UTF_8))]
|
189
|
+
|
190
|
+
when l=~/\A([^\t\a\n]+)(?:\a(\d+))?(?:\a(\d+))?\r?\n\z/mn
|
191
|
+
# received callback
|
192
|
+
y << ReceivedCallData.new(Escape.unescape($1.force_encoding(Encoding::UTF_8)), $2&.to_i, $3&.to_i)
|
193
|
+
|
194
|
+
when l=~/\A\a(\d+)\r?\n\z/mn
|
195
|
+
# received return event
|
196
|
+
y << $1.to_i
|
197
|
+
|
198
|
+
when l.nil?
|
199
|
+
# connection closed
|
200
|
+
break
|
201
|
+
|
202
|
+
else
|
203
|
+
raise InvalidResponse, "invalid text response #{l.inspect}"
|
204
|
+
end
|
205
|
+
end
|
120
206
|
end
|
121
207
|
rescue => err
|
122
208
|
y << err
|
123
209
|
end
|
124
210
|
end
|
211
|
+
|
212
|
+
if @write_binary == true # immediate binary mode
|
213
|
+
# Use ID 1 for proto change request to have a fixed string over the wire
|
214
|
+
register_call("\r", 1)
|
215
|
+
@write_io.write "\r\0\a1\n"
|
216
|
+
@write_io.flush
|
217
|
+
end
|
218
|
+
|
219
|
+
# A random number as start call ID is not technically required, but makes transferred data more readable.
|
220
|
+
@id = rand(1000) + 1
|
125
221
|
end
|
126
222
|
|
127
223
|
private def do_lazy(&block)
|
@@ -131,11 +227,11 @@ class RpcConnection
|
|
131
227
|
yield
|
132
228
|
end
|
133
229
|
|
134
|
-
# Disable reception of data from the read_io object.
|
230
|
+
# Disable reception of data from the {read_io} object.
|
135
231
|
#
|
136
|
-
# This function doesn't close the IO objects.
|
232
|
+
# This function doesn't close the +IO+ objects.
|
137
233
|
# A waiting reception is not aborted by this call.
|
138
|
-
# It can be aborted by calling IO#close on the underlying read_io and write_io objects.
|
234
|
+
# It can be aborted by calling +IO#close+ on the underlying {read_io} and {write_io} objects.
|
139
235
|
def detach
|
140
236
|
@read_enum = nil
|
141
237
|
end
|
@@ -143,9 +239,9 @@ class RpcConnection
|
|
143
239
|
# Do a RPC call and/or wait for a RPC call from the other side.
|
144
240
|
#
|
145
241
|
# {#call} must be called with either a function name (and optional parameters) or with a block or with both.
|
146
|
-
# If
|
147
|
-
# If
|
148
|
-
# If
|
242
|
+
# * If called with a function name, the block on the other end of the RPC connection is called with that function name.
|
243
|
+
# * If called with a block only, than it receives these kind of calls, which are called anonymous callbacks.
|
244
|
+
# * If called with a function name and a block, then the RPC function on the other side is called and it is possible to call back to this dedicated block by invoking {Call#call_back} .
|
149
245
|
#
|
150
246
|
# @param func [String, Symbol] The RPC function to be called on the other side.
|
151
247
|
# The other side must wait for calls through {#call} without arguments but with a block.
|
@@ -160,10 +256,11 @@ class RpcConnection
|
|
160
256
|
# @return [Hash] Received answer parameters.
|
161
257
|
# @return [Promise] Received answer parameters enveloped by a Promise.
|
162
258
|
# This type of answers can be enabled by +RpcConnection#new(lazy_answers: true)+
|
163
|
-
# The Promise object is returned as soon as the RPC call is sent, but before waiting for the corresponding answer.
|
259
|
+
# The Promise object is returned as soon as the RPC call is sent and a callback receiver is registered, but before waiting for the corresponding answer.
|
164
260
|
# This way several calls can be send in parallel without using threads.
|
165
|
-
# As soon as
|
166
|
-
#
|
261
|
+
# As soon as any method is called on the Promise object, this method is blocked until the RPC answer was received.
|
262
|
+
# When the RPC answer has been received, the Promise object then behaves like an ordinary Hash object or +nil+ in case of connection end.
|
263
|
+
# It is recommended to use +Promise#itself+ to trigger explicit waiting for call answers or callbacks (although any other method triggers waiting as well).
|
167
264
|
# @return [NilClass] Waiting for further answers was stopped gracefully by either returning +[hash, true]+ from the block or because the connection was closed.
|
168
265
|
def call(func=nil, params={}, &block)
|
169
266
|
call_intern(func, params, &block)
|
@@ -171,22 +268,24 @@ class RpcConnection
|
|
171
268
|
|
172
269
|
protected
|
173
270
|
|
174
|
-
def
|
175
|
-
id
|
271
|
+
def register_call(func, id, &block)
|
272
|
+
id ||= next_id if func
|
176
273
|
|
177
274
|
@answers_mutex.synchronize do
|
178
|
-
@receivers[id] = CallbackReceiver.new(block_given? ? nil : caller[
|
275
|
+
@receivers[id] = CallbackReceiver.new(block_given? ? nil : caller[4], [])
|
179
276
|
end
|
277
|
+
id
|
278
|
+
end
|
180
279
|
|
181
|
-
|
182
|
-
|
183
|
-
pr = proc do
|
280
|
+
def wait_for_return(id, &block)
|
281
|
+
maybe_lazy do
|
184
282
|
@answers_mutex.synchronize do
|
185
283
|
res = loop do
|
186
284
|
# Is a callback pending for this thread?
|
187
285
|
if cb=@receivers[id].callbacks.shift
|
188
286
|
@answers_mutex.unlock
|
189
287
|
begin
|
288
|
+
# invoke the user block
|
190
289
|
rets, exit = yield(cb)
|
191
290
|
if rets
|
192
291
|
cb.answer = rets
|
@@ -223,7 +322,12 @@ class RpcConnection
|
|
223
322
|
res
|
224
323
|
end
|
225
324
|
end
|
226
|
-
|
325
|
+
end
|
326
|
+
|
327
|
+
def call_intern(func, params={}, recv_id=nil, &block)
|
328
|
+
id = register_call(func, nil, &block)
|
329
|
+
send_call(func, params, id, recv_id) if func
|
330
|
+
wait_for_return(id, &block)
|
227
331
|
end
|
228
332
|
|
229
333
|
def next_id
|
@@ -232,70 +336,103 @@ class RpcConnection
|
|
232
336
|
end
|
233
337
|
end
|
234
338
|
|
235
|
-
def
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
339
|
+
def wait_for_proto_ack
|
340
|
+
@proto_ack_mutex.synchronize do
|
341
|
+
if @write_binary.nil? # acknowledge text/binary mode
|
342
|
+
register_call("\r", 1)
|
343
|
+
@write_mutex.synchronize do
|
344
|
+
@write_io.write "\r\1\a1\n"
|
345
|
+
@write_io.flush
|
346
|
+
end
|
347
|
+
# wait until protocol is acknowledged
|
348
|
+
res = wait_for_return(1)
|
349
|
+
if res == {"O" => "K"}
|
350
|
+
@write_binary = true
|
351
|
+
else
|
352
|
+
@write_binary = false
|
244
353
|
end
|
245
354
|
end
|
246
|
-
to_send << Escape.escape(func.to_s) << "\a#{id}"
|
247
|
-
to_send << "\a#{recv_id}" if recv_id
|
248
|
-
@write_io.write(to_send << "\n")
|
249
355
|
end
|
250
|
-
@write_io.flush
|
251
|
-
after_write
|
252
356
|
end
|
253
357
|
|
254
|
-
def
|
358
|
+
def send_call_or_answer(params)
|
255
359
|
to_send = String.new
|
256
360
|
@write_mutex.synchronize do
|
257
|
-
|
258
|
-
|
259
|
-
|
361
|
+
params.compact.each do |key, value|
|
362
|
+
if @write_binary
|
363
|
+
k = key.to_s
|
364
|
+
v = value.to_s
|
365
|
+
to_send << [1, k.bytesize, v.bytesize, k, v].pack("CNNa*a*")
|
366
|
+
else
|
367
|
+
to_send << Escape.escape(key.to_s) << "\t" <<
|
368
|
+
Escape.escape(value.to_s) << "\n"
|
369
|
+
end
|
260
370
|
if to_send.bytesize > 9999
|
261
371
|
@write_io.write to_send
|
262
372
|
to_send = String.new
|
263
373
|
end
|
264
374
|
end
|
265
|
-
to_send
|
266
|
-
@write_io.write(to_send
|
375
|
+
yield(to_send)
|
376
|
+
@write_io.write(to_send)
|
377
|
+
@write_io.flush
|
267
378
|
end
|
268
|
-
@write_io.flush
|
269
379
|
after_write
|
270
380
|
end
|
271
381
|
|
382
|
+
def send_call(func, params, id, recv_id)
|
383
|
+
wait_for_proto_ack unless recv_id
|
384
|
+
send_call_or_answer(params) do |to_send|
|
385
|
+
if @write_binary
|
386
|
+
f = func.to_s
|
387
|
+
if recv_id
|
388
|
+
to_send << [3, id, recv_id, f.bytesize, f].pack("CNNNa*")
|
389
|
+
else
|
390
|
+
to_send << [2, id, f.bytesize, f].pack("CNNa*")
|
391
|
+
end
|
392
|
+
else
|
393
|
+
to_send << Escape.escape(func.to_s) << "\a#{id}"
|
394
|
+
to_send << "\a#{recv_id}" if recv_id
|
395
|
+
to_send << "\n"
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def send_answer(answer, id)
|
401
|
+
send_call_or_answer(answer) do |to_send|
|
402
|
+
if @write_binary
|
403
|
+
to_send << [4, id].pack("CN")
|
404
|
+
else
|
405
|
+
to_send << "\a#{id}" if id
|
406
|
+
to_send << "\n"
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
272
411
|
def receive_answers
|
273
412
|
rets = {}
|
274
413
|
(@read_enum || raise(ConnectionDetached, "connection already detached")).each do |l|
|
275
414
|
case l
|
276
415
|
when Exception
|
277
416
|
raise l
|
278
|
-
when /\A([^\t\a\n]+)\t(.*?)\r?\n\z/mn
|
279
|
-
# received key/value pair used for either callback parameters or return values
|
280
|
-
rets[Escape.unescape($1).force_encoding(Encoding::UTF_8)] ||= Escape.unescape($2.force_encoding(Encoding::UTF_8))
|
281
417
|
|
282
|
-
when
|
283
|
-
|
284
|
-
cbfunc, id, recv_id = $1, $2&.to_i, $3&.to_i
|
418
|
+
when Array
|
419
|
+
rets[l[0]] ||= l[1]
|
285
420
|
|
286
|
-
|
421
|
+
when ReceivedCallData
|
422
|
+
# received callback
|
423
|
+
callback = Call.new(self, l.cbfunc.to_sym, rets, l.id)
|
287
424
|
|
288
425
|
@answers_mutex.synchronize do
|
289
|
-
receiver = @receivers[recv_id]
|
426
|
+
receiver = @receivers[l.recv_id]
|
290
427
|
|
291
428
|
if !receiver
|
292
|
-
if recv_id
|
293
|
-
raise NoCallbackDefined, "call_back to #{cbfunc.inspect} was received, but corresponding call returned already"
|
429
|
+
if l.recv_id
|
430
|
+
raise NoCallbackDefined, "call_back to #{l.cbfunc.inspect} was received, but corresponding call returned already"
|
294
431
|
else
|
295
|
-
raise NoCallbackDefined, "call to #{cbfunc.inspect} was received, but there is no #{self.class}#call running"
|
432
|
+
raise NoCallbackDefined, "call to #{l.cbfunc.inspect} was received, but there is no #{self.class}#call running"
|
296
433
|
end
|
297
434
|
elsif meth=receiver.meth
|
298
|
-
raise NoCallbackDefined, "call_back to #{cbfunc.inspect} was received, but corresponding call was called without a block in #{meth}"
|
435
|
+
raise NoCallbackDefined, "call_back to #{l.cbfunc.inspect} was received, but corresponding call was called without a block in #{meth}"
|
299
436
|
end
|
300
437
|
|
301
438
|
receiver.callbacks << callback
|
@@ -303,9 +440,10 @@ class RpcConnection
|
|
303
440
|
end
|
304
441
|
return
|
305
442
|
|
306
|
-
when
|
443
|
+
when Integer
|
307
444
|
# received return event
|
308
|
-
id =
|
445
|
+
id = l
|
446
|
+
|
309
447
|
@answers_mutex.synchronize do
|
310
448
|
@answers[id] = rets
|
311
449
|
@new_answer.broadcast
|
data/lib/ccrpc/version.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,35 +1,38 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ccrpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Kanis
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain:
|
11
10
|
- |
|
12
11
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
12
|
+
MIIEBDCCAmygAwIBAgIBAzANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
|
13
|
+
L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yNDEyMjkxOTU2NTZaFw0yNTEy
|
14
|
+
MjkxOTU2NTZaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
|
15
|
+
PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
|
16
|
+
mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
|
17
|
+
eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
|
18
|
+
8nBMvR0mHo77kIkapHc26UzVq/G0nKLfDsIHXVylto3PjzOumjG6GhmFN4r3cP6e
|
19
|
+
SDfl1FSeRYVpt4kmQULz/zdSaOH3AjAq7PM2Z91iGwQvoUXMANH2v89OWjQO/NHe
|
20
|
+
JMNDFsmHK/6Ji4Kk48Z3TyscHQnipAID5GhS1oD21/WePdj7GhmbF5gBzkV5uepd
|
21
|
+
eJQPgWGwrQW/Z2oPjRuJrRofzWfrMWqbOahj9uth6WSxhNexUtbjk6P8emmXOJi5
|
22
|
+
chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
|
23
|
+
9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjOTA3MAkG
|
24
|
+
A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQ4h1tIyvdUWtMI739xMzTR
|
25
|
+
7EfMFzANBgkqhkiG9w0BAQsFAAOCAYEAoZZWzNV2XXaoSmvyamSSN+Wt/Ia+DNrU
|
26
|
+
2pc3kMEqykH6l1WiVPszr6HavQ//2I2UcSRSS5AGDdiSXcfyFmHtMBdtJHhTPcn7
|
27
|
+
4DLliB0szpvwG+ltGD8PI8eWkLaTQeFzs+0QCTavgKV+Zw56Q0J5zZvHHUMrLkUD
|
28
|
+
qhwKjdTdkrRTn9Sqi0BrIRRZGTUDdrt8qoWm35aES5arKZzytgrRD/kXfFW2LCg0
|
29
|
+
FzgTKibR4/3g8ph94kQLg/D2SMlVPkQ3ECi036mZxDC2n8V6u3rDkG5923wmrRZB
|
30
|
+
J6cqz475Q8HYORQCB68OPzkWMfC7mBo3vpSsIqRoNs1FE4FJu4FGwZG8fBSrDC4H
|
31
|
+
bZe+GtyS3e2SMjgT65zp35gLO9I7MquzYN9P6V2u1iBpTycchk5z9R1ghxzZSBT8
|
32
|
+
DrkJ9tVlPQtJB0LqT0tvBap4upnwT1xYq721b5dwH6AF4Pi6iz/dc5vnq1/MH8bV
|
33
|
+
8VbbBzzeE7MsvgkP3sHlLmY8PtuyViJ8
|
31
34
|
-----END CERTIFICATE-----
|
32
|
-
date:
|
35
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
33
36
|
dependencies: []
|
34
37
|
description: Simple bidirectional and thread safe RPC protocol. Works on arbitrary
|
35
38
|
Ruby IO objects.
|
@@ -60,7 +63,7 @@ licenses:
|
|
60
63
|
- MIT
|
61
64
|
metadata:
|
62
65
|
homepage_uri: https://github.com/larskanis/ccrpc
|
63
|
-
|
66
|
+
documentation_uri: https://rubydoc.info/gems/ccrpc
|
64
67
|
rdoc_options: []
|
65
68
|
require_paths:
|
66
69
|
- lib
|
@@ -75,8 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
78
|
- !ruby/object:Gem::Version
|
76
79
|
version: '0'
|
77
80
|
requirements: []
|
78
|
-
rubygems_version: 3.
|
79
|
-
signing_key:
|
81
|
+
rubygems_version: 3.6.9
|
80
82
|
specification_version: 4
|
81
83
|
summary: Simple bidirectional RPC protocol
|
82
84
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|