arpie 0.0.6 → 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.
- data/.gitignore +4 -0
- data/.yardopts +1 -0
- data/{BINARY_SPEC → BINARY.rdoc} +73 -28
- data/Gemfile +8 -0
- data/LICENCE +15 -0
- data/PROTOCOLS.rdoc +46 -0
- data/README.rdoc +17 -0
- data/Rakefile +6 -114
- data/arpie.gemspec +26 -0
- data/examples/em.rb +18 -0
- data/lib/arpie.rb +2 -4
- data/lib/arpie/binary.rb +18 -4
- data/lib/arpie/binary/bytes_type.rb +7 -2
- data/lib/arpie/binary/fixed_type.rb +11 -4
- data/lib/arpie/binary/list_type.rb +2 -0
- data/lib/arpie/binary/pack_type.rb +20 -10
- data/lib/arpie/em.rb +48 -0
- data/lib/arpie/error.rb +2 -4
- data/lib/arpie/protocol.rb +7 -23
- data/lib/arpie/version.rb +3 -0
- data/spec/binary_spec.rb +113 -8
- data/spec/bytes_binary_type_spec.rb +16 -3
- data/spec/em_spec.rb +27 -0
- data/spec/examples_spec.rb +11 -0
- data/spec/fixed_binary_type_spec.rb +2 -2
- data/spec/list_binary_type_spec.rb +9 -0
- data/spec/protocol_merge_and_split_spec.rb +3 -3
- data/spec/protocol_spec.rb +20 -43
- data/spec/spec_helper.rb +13 -12
- metadata +74 -83
- data/COPYING +0 -15
- data/README +0 -167
- data/lib/arpie/client.rb +0 -195
- data/lib/arpie/proxy.rb +0 -143
- data/lib/arpie/server.rb +0 -157
- data/lib/arpie/xmlrpc.rb +0 -108
- data/spec/client_server_spec.rb +0 -107
- data/tools/benchmark.rb +0 -52
- data/tools/protocol_benchmark.rb +0 -42
data/COPYING
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
Copyright (C) 2008 Bernhard Stoeckner <elven@swordcoast.net> and contributors
|
2
|
-
|
3
|
-
This program is free software; you can redistribute it and/or modify
|
4
|
-
it under the terms of the GNU General Public License as published by
|
5
|
-
the Free Software Foundation; either version 2 of the License, or
|
6
|
-
(at your option) any later version.
|
7
|
-
|
8
|
-
This program is distributed in the hope that it will be useful,
|
9
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
-
GNU General Public License for more details.
|
12
|
-
|
13
|
-
You should have received a copy of the GNU General Public License along
|
14
|
-
with this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
data/README
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
= What's this?
|
2
|
-
|
3
|
-
Arpie is a end-to-end framework for sending protocol-encoded messages over arbitary
|
4
|
-
IO channels, including UNIX/TCP Sockets, Pipes, and pidgeon carriers (depending on
|
5
|
-
your implementation details).
|
6
|
-
|
7
|
-
Arpie also provides a robust replay-protected RPC framework.
|
8
|
-
|
9
|
-
The useful core of arpie is a protocol stack that can be used to read/split/assemble/write
|
10
|
-
any data stream, but is tailored for packeted streaming data.
|
11
|
-
|
12
|
-
The Arpie server uses one ruby-thread per client, the client runs entirely in the
|
13
|
-
calling thread; though an example implementation for evented callbacks is provided.
|
14
|
-
|
15
|
-
== Source Code
|
16
|
-
|
17
|
-
Source code is in git[http://git.swordcoast.net/?p=lib/ruby/arpie.git;a=summary].
|
18
|
-
|
19
|
-
You can contact me via email at elven@swordcoast.net.
|
20
|
-
|
21
|
-
arpie is available on the rubygems gem server - just do <tt>gem1.8 install arpie</tt>
|
22
|
-
to get the newest version.
|
23
|
-
|
24
|
-
|
25
|
-
== Simple, contrived example: A string reverse server
|
26
|
-
|
27
|
-
require 'rubygems'
|
28
|
-
require 'arpie'
|
29
|
-
require 'socket'
|
30
|
-
|
31
|
-
server = TCPServer.new(51210)
|
32
|
-
|
33
|
-
e = Arpie::Server.new(Arpie::MarshalProtocol.new, Arpie::SizedProtocol.new)
|
34
|
-
|
35
|
-
e.handle do |server, ep, msg|
|
36
|
-
ep.write_message msg.reverse
|
37
|
-
end
|
38
|
-
|
39
|
-
e.accept do
|
40
|
-
server.accept
|
41
|
-
end
|
42
|
-
|
43
|
-
c = Arpie::Client.new(Arpie::MarshalProtocol.new, Arpie::SizedProtocol.new)
|
44
|
-
c.connect do
|
45
|
-
TCPSocket.new("127.0.0.1", 51210)
|
46
|
-
end
|
47
|
-
|
48
|
-
c.write_message "hi"
|
49
|
-
puts c.read_message
|
50
|
-
# => "ih"
|
51
|
-
|
52
|
-
== Advanced, but still simple example: Using Proxy to access remote objects
|
53
|
-
|
54
|
-
require 'rubygems'
|
55
|
-
require 'arpie'
|
56
|
-
require 'socket'
|
57
|
-
|
58
|
-
class MyHandler
|
59
|
-
def reverse str
|
60
|
-
str.reverse
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
server = TCPServer.new(51210)
|
65
|
-
|
66
|
-
e = Arpie::ProxyServer.new(Arpie::MarshalProtocol.new, Arpie::SizedProtocol.new)
|
67
|
-
|
68
|
-
e.handle MyHandler.new
|
69
|
-
|
70
|
-
e.accept do
|
71
|
-
server.accept
|
72
|
-
end
|
73
|
-
|
74
|
-
p = Arpie::ProxyClient.new(Arpie::MarshalProtocol.new, Arpie::SizedProtocol.new)
|
75
|
-
p.connect do |transport|
|
76
|
-
TCPSocket.new("127.0.0.1", 51210)
|
77
|
-
end
|
78
|
-
|
79
|
-
puts p.reverse "hi"
|
80
|
-
# => "ih"
|
81
|
-
|
82
|
-
== Writing custom Protocols
|
83
|
-
|
84
|
-
You can use arpies Protocol layer to write your custom protocol parser/emitters.
|
85
|
-
Consider the following, again very contrived, example. You have a linebased wire format,
|
86
|
-
which sends regular object updates in multiple lines, each holding a property to be updated.
|
87
|
-
What objects get updated is not relevant to this example.
|
88
|
-
|
89
|
-
For this example, we'll be using the SeparatorProtocol already contained in protocols.rb as
|
90
|
-
a base.
|
91
|
-
|
92
|
-
class AssembleExample < Arpie::Protocol
|
93
|
-
|
94
|
-
def from binary
|
95
|
-
# The wire format is simply a collection of lines
|
96
|
-
# where the first one is a number containing the
|
97
|
-
# # of lines to expect.
|
98
|
-
assemble! binary do |binaries, meta|
|
99
|
-
binaries.size >= 1 or incomplete!
|
100
|
-
binaries.size - 1 >= binaries[0].to_i or incomplete!
|
101
|
-
|
102
|
-
# Here, you can wrap all collected updates in
|
103
|
-
# whatever format you want it to be. We're just
|
104
|
-
# "joining" them to be a single array.
|
105
|
-
binaries.shift
|
106
|
-
binaries
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def to object
|
111
|
-
yield object.size
|
112
|
-
object.each {|oo|
|
113
|
-
yield oo
|
114
|
-
}
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
p = Arpie::ProtocolChain.new(
|
119
|
-
AssembleExample.new,
|
120
|
-
Arpie::SeparatorProtocol.new
|
121
|
-
)
|
122
|
-
r, w = IO.pipe
|
123
|
-
|
124
|
-
p.write_message(w, %w{we want to be assembled})
|
125
|
-
|
126
|
-
p p.read_message(r)
|
127
|
-
# => ["we", "want", "to", "be", "assembled"]
|
128
|
-
|
129
|
-
== Replay protection
|
130
|
-
|
131
|
-
It can happen that a Client loses connection to a Server.
|
132
|
-
In that case, the Transport tries transparently reconnecting by simply
|
133
|
-
invoking the block again that was given to Client#connect.
|
134
|
-
See the Client accessors for modifying this behaviour.
|
135
|
-
|
136
|
-
It is assumed that each call, that is being placed, is atomic - eg, no
|
137
|
-
connection losses in between message send and receive; lost messages
|
138
|
-
will be retransmitted. Some Protocol classes provide support for replay
|
139
|
-
protection through in-band UUIDs; though it is not a requirement to implement it.
|
140
|
-
If a UUID is provided in the data stream, the Protocol will not call
|
141
|
-
the handler again for retransmissions, but instead reply with the old,
|
142
|
-
already evaluated value.
|
143
|
-
|
144
|
-
Not all protocols support UUIDs; those who do not offer no replay protection,
|
145
|
-
and special care has to be taken elsewhere.
|
146
|
-
|
147
|
-
All object-encoding protocols support UUIDs, including YAML and Marshal.
|
148
|
-
XMLRPC does not.
|
149
|
-
|
150
|
-
== Benchmarks
|
151
|
-
|
152
|
-
There is a benchmark script included in the git repository (and in the gem
|
153
|
-
under tools/). A sample output follows; your milage may vary.
|
154
|
-
|
155
|
-
user system total real
|
156
|
-
|
157
|
-
native DRb
|
158
|
-
1 0.000000 0.000000 0.000000 ( 0.000172)
|
159
|
-
1000 0.110000 0.010000 0.120000 ( 0.119767)
|
160
|
-
|
161
|
-
Arpie: proxied MarshalProtocol with replay protection through uuidtools
|
162
|
-
1 0.000000 0.000000 0.010000 ( 0.075373)
|
163
|
-
1000 0.530000 0.090000 0.600000 ( 0.608665)
|
164
|
-
|
165
|
-
Arpie: proxied MarshalProtocol without replay protection
|
166
|
-
1 0.000000 0.000000 0.000000 ( 0.000173)
|
167
|
-
1000 0.170000 0.020000 0.190000 ( 0.194649)
|
data/lib/arpie/client.rb
DELETED
@@ -1,195 +0,0 @@
|
|
1
|
-
module Arpie
|
2
|
-
|
3
|
-
# A Client is a connection manager, and acts as the
|
4
|
-
# glue between a user-defined medium (for example, a TCP
|
5
|
-
# socket), and a protocol, with automatic reconnecting
|
6
|
-
# and fault handling.
|
7
|
-
#
|
8
|
-
# See README for examples.
|
9
|
-
class Client
|
10
|
-
# The protocol chain used.
|
11
|
-
attr_reader :protocol
|
12
|
-
|
13
|
-
# How often should this Client retry a connection.
|
14
|
-
# 0 for never, greater than 0 for that many attempts,
|
15
|
-
# nil for infinite (default).
|
16
|
-
# Values other than nil will raise network exceptions
|
17
|
-
# to the caller.
|
18
|
-
attr_accessor :connect_retry
|
19
|
-
|
20
|
-
# How long should the caller sleep after each reconnect
|
21
|
-
# attempt. (default: 1.0). The default value is probably
|
22
|
-
# okay. Do not set this to 0; that will produce
|
23
|
-
# unnecessary load in case of network failure.
|
24
|
-
attr_accessor :connect_sleep
|
25
|
-
|
26
|
-
def initialize *protocols
|
27
|
-
@protocol = Arpie::ProtocolChain.new(*protocols)
|
28
|
-
@read_io = nil
|
29
|
-
@write_io = nil
|
30
|
-
@connector = lambda { raise ArgumentError, "No connector specified, cannot connect to Endpoint." }
|
31
|
-
@connect_retry = nil
|
32
|
-
@connect_sleep = 1.0
|
33
|
-
@on_error = lambda {|client, exception|
|
34
|
-
$stderr.puts "Error in Transport IO: #{exception.message.to_s}"
|
35
|
-
$stderr.puts exception.backtrace.join("\n")
|
36
|
-
$stderr.puts "Set Transport#on_error &block to override this."
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
|
-
# Provide a connector block, which will be called
|
41
|
-
# each time a connection is needed.
|
42
|
-
# Expectes an IO object.
|
43
|
-
# Alternatively, you can return a two-item array.
|
44
|
-
# To test something without involving any networking,
|
45
|
-
# simply run IO.pipe in this block.
|
46
|
-
# Set +connect_immediately+ to true to connect
|
47
|
-
# immediately, instead on the first message.
|
48
|
-
def connect connect_immediately = false, &connector
|
49
|
-
@connector = connector
|
50
|
-
_connect if connect_immediately
|
51
|
-
self
|
52
|
-
end
|
53
|
-
|
54
|
-
# Set an error handler. It will be called with two
|
55
|
-
# parameters, the client, and the exception that occured.
|
56
|
-
# Optional, and just for notification.
|
57
|
-
def on_error &handler #:yields: client, exception
|
58
|
-
@on_error = handler
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
|
-
# Send a message. Returns immediately.
|
63
|
-
def write_message message
|
64
|
-
io_retry do
|
65
|
-
@protocol.write_message(@write_io, message)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
alias_method :<<, :write_message
|
69
|
-
|
70
|
-
# Receive a message. Blocks until received.
|
71
|
-
def read_message
|
72
|
-
io_retry do
|
73
|
-
return @protocol.read_message(@read_io)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Execute the given block until all connection attempts
|
78
|
-
# have been exceeded.
|
79
|
-
# Yields self.
|
80
|
-
# You do not usually want to use this.
|
81
|
-
def io_retry &block
|
82
|
-
try = 0
|
83
|
-
|
84
|
-
begin
|
85
|
-
_connect
|
86
|
-
yield self
|
87
|
-
rescue IOError => e
|
88
|
-
try += 1
|
89
|
-
@on_error.call(self, e) if @on_error
|
90
|
-
p e
|
91
|
-
|
92
|
-
if @connect_retry == 0 || (@connect_retry && try > @connect_retry)
|
93
|
-
raise EOFError, "Cannot read from io: lost connection after #{try} attempts (#{e.message.to_s})"
|
94
|
-
end
|
95
|
-
|
96
|
-
sleep @connect_sleep
|
97
|
-
begin; @read_io.close if @read_io; rescue; end
|
98
|
-
@read_io = nil
|
99
|
-
begin; @write_io.close if @write_io; rescue; end
|
100
|
-
@write_io = nil
|
101
|
-
retry
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
def _connect
|
108
|
-
@read_io and return
|
109
|
-
@read_io, @write_io = @connector.call(self)
|
110
|
-
@protocol.reset
|
111
|
-
@write_io ||= @read_io
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# A simple pseudo event-based client, using a thread
|
116
|
-
# with a callback.
|
117
|
-
class EventedClient < Client
|
118
|
-
private :read_message
|
119
|
-
|
120
|
-
# Set a callback for incoming messages.
|
121
|
-
def handle &handler #:yields: client, message
|
122
|
-
@handler = handler
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
def _read_thread
|
128
|
-
loop do
|
129
|
-
io_retry do
|
130
|
-
message = read_message
|
131
|
-
@handler and @handler.call(self, message)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def _connect
|
137
|
-
super
|
138
|
-
@read_thread ||= Thread.new { _read_thread }
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
# A Client extension which provides a RPC-like
|
144
|
-
# interface. Used by ProxyClient.
|
145
|
-
class RPCClient < Client
|
146
|
-
private :read_message, :write_message
|
147
|
-
|
148
|
-
def initialize *protocols
|
149
|
-
super(*protocols)
|
150
|
-
|
151
|
-
@on_pre_call = lambda {|client, message| }
|
152
|
-
@on_post_call = lambda {|client, message, reply| }
|
153
|
-
end
|
154
|
-
|
155
|
-
# Callback that gets invoked before placing a call to the
|
156
|
-
# Server. You can stop the call from happening by raising
|
157
|
-
# an exception (which will be passed on to the caller).
|
158
|
-
def pre_call &handler #:yields: client, message
|
159
|
-
@on_pre_call = handler
|
160
|
-
self
|
161
|
-
end
|
162
|
-
|
163
|
-
# Callback that gets invoked after receiving an answer.
|
164
|
-
# You can raise an exception here; and it will be passed
|
165
|
-
# to the caller, instead of returning the value.
|
166
|
-
def post_call &handler #:yields: client, message, reply
|
167
|
-
@on_post_call = handler
|
168
|
-
self
|
169
|
-
end
|
170
|
-
|
171
|
-
|
172
|
-
# Send a message and receive a reply in a synchronous
|
173
|
-
# fashion. Will block until transmitted, or until
|
174
|
-
# all reconnect attempts failed.
|
175
|
-
def request message
|
176
|
-
reply = nil
|
177
|
-
|
178
|
-
@on_pre_call.call(self, message) if @on_pre_call
|
179
|
-
|
180
|
-
io_retry do
|
181
|
-
write_message(message)
|
182
|
-
reply = read_message
|
183
|
-
end
|
184
|
-
|
185
|
-
@on_post_call.call(self, message, reply) if @on_post_call
|
186
|
-
|
187
|
-
case reply
|
188
|
-
when Exception
|
189
|
-
raise reply
|
190
|
-
else
|
191
|
-
reply
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
data/lib/arpie/proxy.rb
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
require 'uuidtools'
|
2
|
-
|
3
|
-
module Arpie
|
4
|
-
|
5
|
-
# A Endpoint which supports arbitary objects as handlers,
|
6
|
-
# instead of a proc.
|
7
|
-
#
|
8
|
-
# Note that this will only export public instance method
|
9
|
-
# of the class as they are defined.
|
10
|
-
class ProxyServer < Server
|
11
|
-
|
12
|
-
# An array containing symbols of method names that the
|
13
|
-
# handler should be allowed to call. Defaults to
|
14
|
-
# all public instance methods the class defines (wysiwyg).
|
15
|
-
# Set this to nil to allow calling of ALL methods, but be
|
16
|
-
# warned of the security implications (instance_eval, ..).
|
17
|
-
attr_accessor :interface
|
18
|
-
|
19
|
-
# Set this to false to disable replay protection.
|
20
|
-
attr_accessor :uuid_tracking
|
21
|
-
|
22
|
-
# The maximum number of method call results to remember.
|
23
|
-
# Defaults to 100, which should be enough for everyone. ;)
|
24
|
-
attr_accessor :max_uuids
|
25
|
-
|
26
|
-
def initialize *va
|
27
|
-
super
|
28
|
-
@uuids = {}
|
29
|
-
@max_uuids = 100
|
30
|
-
@uuid_tracking = true
|
31
|
-
end
|
32
|
-
|
33
|
-
# Set a class handler. All public instance methods will be
|
34
|
-
# callable over RPC (with a Proxy object) (see attribute interface).
|
35
|
-
def handle handler
|
36
|
-
@handler = handler
|
37
|
-
@interface = handler.class.public_instance_methods(false).map {|x|
|
38
|
-
x.to_sym
|
39
|
-
}
|
40
|
-
self
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def _handle endpoint, message
|
46
|
-
if !@handler.respond_to?(message.meth.to_sym) ||
|
47
|
-
(@interface && !@interface.index(message.meth.to_sym))
|
48
|
-
endpoint.write_message NoMethodError.new("No such method: #{message.meth.inspect}")
|
49
|
-
return
|
50
|
-
end
|
51
|
-
|
52
|
-
begin
|
53
|
-
# Prune old serials. This can probably be optimized, but works well enough for now.
|
54
|
-
if @uuid_tracking && message.uuid
|
55
|
-
uuid, serial = * message.uuid
|
56
|
-
|
57
|
-
raise ArgumentError,
|
58
|
-
"Invalid UUID given, expect [uuid/64bit, serial/numeric]." unless
|
59
|
-
uuid.is_a?(Integer) && serial.is_a?(Integer)
|
60
|
-
|
61
|
-
# Limit to sane values.
|
62
|
-
uuid &= 0xffffffffffffffff
|
63
|
-
serial &= 0xffffffffffffffff
|
64
|
-
|
65
|
-
timestamps = @uuids.values.map {|v| v[0] }.sort
|
66
|
-
latest_timestamp = timestamps[-@max_uuids]
|
67
|
-
@uuids.reject! {|uuid, (time, value)|
|
68
|
-
time < latest_timestamp
|
69
|
-
} if latest_timestamp
|
70
|
-
|
71
|
-
endpoint.write_message((@uuids[message.uuid] ||=
|
72
|
-
[Time.now, @handler.send(message.meth, *message.argv)])[1])
|
73
|
-
|
74
|
-
else
|
75
|
-
endpoint.write_message @handler.send(message.meth, *message.argv)
|
76
|
-
end
|
77
|
-
rescue IOError
|
78
|
-
raise
|
79
|
-
|
80
|
-
rescue Exception => e
|
81
|
-
endpoint.write_message RuntimeError.new("Internal Error")
|
82
|
-
raise
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# A Proxy is a wrapper around a Client, which transparently tunnels
|
88
|
-
# method calls to the remote ProxyServer.
|
89
|
-
# Note that the methods of Client cannot be proxied.
|
90
|
-
class ProxyClient < RPCClient
|
91
|
-
attr_accessor :namespace
|
92
|
-
|
93
|
-
# Set to false to disable replay protection.
|
94
|
-
# Default is true.
|
95
|
-
attr_accessor :replay_protection
|
96
|
-
|
97
|
-
# The current serial for this transport.
|
98
|
-
attr_accessor :serial
|
99
|
-
|
100
|
-
# The generated uuid for this Client.
|
101
|
-
# nil if no call has been made yet.
|
102
|
-
attr_accessor :uuid
|
103
|
-
|
104
|
-
def initialize *protocols
|
105
|
-
super
|
106
|
-
@protocol, @namespace = protocol, ""
|
107
|
-
@serial = 0
|
108
|
-
@uuid_generator = lambda {|client, method, argv|
|
109
|
-
UUIDTools::UUID.random_create.to_i
|
110
|
-
}
|
111
|
-
@replay_protection = true
|
112
|
-
end
|
113
|
-
|
114
|
-
# Set up a new UUID generator for this proxy client.
|
115
|
-
# Make sure that this yields really random numbers.
|
116
|
-
# The default uses the uuidtools gem and is usually okay.
|
117
|
-
#
|
118
|
-
# This gets called exactly once for each created ProxyClient.
|
119
|
-
def uuid_generator &handler #:yields: client, method, argv
|
120
|
-
@uuid_generator = handler
|
121
|
-
self
|
122
|
-
end
|
123
|
-
|
124
|
-
def method_missing meth, *argv # :nodoc:
|
125
|
-
serial = nil
|
126
|
-
if @replay_protection
|
127
|
-
serial = [
|
128
|
-
@uuid ||= @uuid_generator.call(self, meth, argv),
|
129
|
-
@serial += 1
|
130
|
-
]
|
131
|
-
end
|
132
|
-
|
133
|
-
call = Arpie::RPCall.new(@namespace, meth, argv, serial)
|
134
|
-
ret = self.request(call)
|
135
|
-
case ret
|
136
|
-
when Exception
|
137
|
-
raise ret
|
138
|
-
else
|
139
|
-
ret
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|