msgpack-rpc 0.3.0 → 0.4.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/NOTICE +5 -1
- data/lib/msgpack/rpc.rb +144 -1430
- data/lib/msgpack/rpc/address.rb +144 -0
- data/lib/msgpack/rpc/client.rb +80 -0
- data/lib/msgpack/rpc/dispatcher.rb +111 -0
- data/lib/msgpack/rpc/exception.rb +53 -0
- data/lib/msgpack/rpc/future.rb +116 -0
- data/lib/msgpack/rpc/loop.rb +87 -0
- data/lib/msgpack/rpc/message.rb +31 -0
- data/lib/msgpack/rpc/server.rb +111 -0
- data/lib/msgpack/rpc/session.rb +157 -0
- data/lib/msgpack/rpc/session_pool.rb +91 -0
- data/lib/msgpack/rpc/transport/base.rb +48 -0
- data/lib/msgpack/rpc/transport/tcp.rb +242 -0
- data/lib/msgpack/rpc/transport/udp.rb +192 -0
- data/lib/msgpack/rpc/transport/unix.rb +165 -0
- data/test/test_helper.rb +2 -2
- metadata +17 -3
data/NOTICE
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
MessagePack-RPC for Ruby is developed by FURUHASHI Sadayuki, licensed under
|
2
|
+
Apache License, Version 2.0. The original software and related information
|
3
|
+
is available at http://msgpack.sourceforge.net/.
|
4
|
+
|
1
5
|
MessagePack is developed by FURUHASHI Sadayuki, licensed under Apache License,
|
2
6
|
Version 2.0. The original software and related information is available at
|
3
|
-
http://msgpack.sourceforge.
|
7
|
+
http://msgpack.sourceforge.net/.
|
4
8
|
|
data/lib/msgpack/rpc.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# MessagePack-RPC for Ruby
|
2
|
+
# MessagePack-RPC for Ruby TCP transport
|
3
3
|
#
|
4
4
|
# Copyright (C) 2010 FURUHASHI Sadayuki
|
5
5
|
#
|
@@ -15,1438 +15,152 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
-
|
19
|
-
require 'rev'
|
20
|
-
require 'zlib'
|
18
|
+
module MessagePack #:nodoc:
|
21
19
|
|
22
|
-
|
20
|
+
# MessagePack-RPC is an inter-process messaging library that uses
|
21
|
+
# MessagePack for object serialization. The goal of the project is
|
22
|
+
# providing fast and scalable messaging system for server, client
|
23
|
+
# and cluster applications.
|
24
|
+
#
|
25
|
+
# == Client API
|
26
|
+
#
|
27
|
+
# MessagePack::RPC::Client and MessagePack::RPC::SessionPool are for RPC clients.
|
28
|
+
#
|
29
|
+
# === Simple usage
|
30
|
+
# Client is subclass of Session. Use Session#call method to call remote methods.
|
31
|
+
#
|
32
|
+
# require 'msgpack/rpc' # gem install msgpack-rpc
|
33
|
+
#
|
34
|
+
# client = MessagePack::RPC::Client.new('127.0.0.1', 18800)
|
35
|
+
#
|
36
|
+
# result = client.call(:methodName, arg1, arg2, arg3)
|
37
|
+
#
|
38
|
+
# === Asynchronous call
|
39
|
+
# Use Session#call_async method to call remote methods asynchronously. It returns a Future. Use Future#get or Future#attach_callback to get actual result.
|
40
|
+
#
|
41
|
+
# require 'msgpack/rpc' # gem install msgpack-rpc
|
42
|
+
#
|
43
|
+
# client = MessagePack::RPC::Client.new('127.0.0.1', 18800)
|
44
|
+
#
|
45
|
+
# future1 = client.call(:method1, arg1) # call two methods concurrently
|
46
|
+
# future2 = client.call(:method2, arg1)
|
47
|
+
#
|
48
|
+
# result1 = future1.get
|
49
|
+
# result2 = future2.get
|
50
|
+
#
|
51
|
+
# === Connection pooling
|
52
|
+
#
|
53
|
+
# SessionPool#get_session returns a Session. It pools created session and enables you to reuse established connections.
|
54
|
+
#
|
55
|
+
#
|
56
|
+
# == Server API
|
57
|
+
#
|
58
|
+
# MessagePack::RPC::Server is for RPC servers.
|
59
|
+
#
|
60
|
+
# === Simple usage
|
61
|
+
#
|
62
|
+
# The public methods of handler class becomes callbale.
|
63
|
+
#
|
64
|
+
# require 'msgpack/rpc' # gem install msgpack-rpc
|
65
|
+
#
|
66
|
+
# class MyHandler
|
67
|
+
# def methodName(arg1, arg2, arg3)
|
68
|
+
# puts "received"
|
69
|
+
# return "return result."
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# server = MessagePack::RPC::Server.new
|
74
|
+
# server.listen('0.0.0.0', 18800, MyHandler.new)
|
75
|
+
# server.run
|
76
|
+
#
|
77
|
+
# === Advance return
|
78
|
+
#
|
79
|
+
# In the handler method, you can use *yield* to send the result without returning.
|
80
|
+
#
|
81
|
+
# class MyHandler
|
82
|
+
# def method1(arg1)
|
83
|
+
# yield("return result.")
|
84
|
+
# puts "you can do something after returning the result"
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# === Delayed return
|
89
|
+
#
|
90
|
+
# You can use AsyncResult to return results later.
|
91
|
+
#
|
92
|
+
# class MyHandler
|
93
|
+
# def method2(arg1)
|
94
|
+
# as = MessagePack::RPC::AsyncResult.new
|
95
|
+
# Thread.new do
|
96
|
+
# sleep 10 # return result 10 seconds later.
|
97
|
+
# as.result("return result.")
|
98
|
+
# end
|
99
|
+
# return as
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
#
|
104
|
+
# You can receive and send any objects that can be serialized by MessagePack.
|
105
|
+
# This means that the objects required to implement *to_msgpack(out = '')* method.
|
106
|
+
#
|
107
|
+
#
|
108
|
+
# == Transports
|
109
|
+
#
|
110
|
+
# You can use UDP and UNIX domain sockets instead of TCP.
|
111
|
+
#
|
112
|
+
# === For clients
|
113
|
+
#
|
114
|
+
# For clients, use MessagePack::RPC::UDPTransport or MessagePack::RPC::UNIXTransport.
|
115
|
+
#
|
116
|
+
# require 'msgpack/rpc' # gem install msgpack-rpc
|
117
|
+
# require 'msgpack/rpc/transport/udp'
|
118
|
+
#
|
119
|
+
# transport = MessagePack::RPC::UDPTransport.new
|
120
|
+
# address = MessagePack::RPC::Address.new('127.0.0.1', 18800)
|
121
|
+
# client = MessagePack::RPC::Client.new(transport, address)
|
122
|
+
#
|
123
|
+
# result = client.call(:methodName, arg1, arg2, arg3)
|
124
|
+
#
|
125
|
+
# === For servers
|
126
|
+
#
|
127
|
+
# For servers, use MessagePack::RPC::UDPServerTransport or MessagePack::RPC::UNIXServerTransport.
|
128
|
+
#
|
129
|
+
# require 'msgpack/rpc' # gem install msgpack-rpc
|
130
|
+
# require 'msgpack/rpc/transport/udp'
|
131
|
+
#
|
132
|
+
# class MyHandler
|
133
|
+
# def methodName(arg1, arg2, arg3)
|
134
|
+
# puts "received"
|
135
|
+
# return "return result."
|
136
|
+
# end
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# address = MessagePack::RPC::Address.new('0.0.0.0', 18800)
|
140
|
+
# listener = MessagePack::RPC::UDPServerTransport.new(address)
|
141
|
+
# server = MessagePack::RPC::Server.new
|
142
|
+
# server.listen(listener, MyHandler.new)
|
143
|
+
# server.run
|
144
|
+
#
|
145
|
+
#
|
23
146
|
module RPC
|
24
|
-
|
25
|
-
|
26
|
-
class Error < StandardError
|
27
|
-
end
|
28
|
-
|
29
|
-
class RPCError < Error
|
30
|
-
def initialize(msg)
|
31
|
-
super(msg)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class RemoteError < RPCError
|
36
|
-
def initialize(msg, result = nil)
|
37
|
-
super(msg)
|
38
|
-
@result = result
|
39
|
-
end
|
40
|
-
attr_reader :result
|
41
|
-
end
|
42
|
-
|
43
|
-
class TimeoutError < Error
|
44
|
-
def initialize(msg = "request timed out")
|
45
|
-
super
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class ConnectError < TimeoutError
|
50
|
-
def initialize(msg = "connect failed")
|
51
|
-
super
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
REQUEST = 0 # [0, msgid, method, param]
|
57
|
-
RESPONSE = 1 # [1, msgid, error, result]
|
58
|
-
NOTIFY = 2 # [2, method, param]
|
59
|
-
SESSION = 3 # [3, addr]
|
60
|
-
OPTION = 4 # [4, txopt, rxopt] #[, rxproto, rxaddr]
|
61
|
-
OPT_DEFLATE = 0b00000001
|
62
|
-
#PROTO_TCP = 0
|
63
|
-
#PROTO_UDP = 1
|
64
|
-
|
65
|
-
|
66
|
-
class Address
|
67
|
-
# +--+----+
|
68
|
-
# | 2| 4 |
|
69
|
-
# +--+----+
|
70
|
-
# port network byte order
|
71
|
-
# IPv4 address
|
72
|
-
#
|
73
|
-
# +--+----------------+
|
74
|
-
# | 2| 16 |
|
75
|
-
# +--+----------------+
|
76
|
-
# port network byte order
|
77
|
-
# IPv6 address
|
78
|
-
#
|
79
|
-
|
80
|
-
test = Socket.pack_sockaddr_in(0,'0.0.0.0')
|
81
|
-
if test[0] == "\0"[0] || test[1] == "\0"[0]
|
82
|
-
# Linux
|
83
|
-
def initialize(host, port)
|
84
|
-
raw = Socket.pack_sockaddr_in(port, host)
|
85
|
-
family = raw.unpack('S')[0]
|
86
|
-
if family == Socket::AF_INET
|
87
|
-
@serial = raw[2,6]
|
88
|
-
elsif family == Socket::AF_INET6
|
89
|
-
@serial = raw[2,2] + raw[8,16]
|
90
|
-
else
|
91
|
-
raise "Unknown address family: #{family}"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
else
|
95
|
-
# BSD
|
96
|
-
def initialize(host, port)
|
97
|
-
raw = Socket.pack_sockaddr_in(port, host)
|
98
|
-
family = raw.unpack('CC')[1]
|
99
|
-
if family == Socket::AF_INET
|
100
|
-
@serial = raw[2,6]
|
101
|
-
elsif family == Socket::AF_INET6
|
102
|
-
@serial = raw[2,2] + raw[8,16]
|
103
|
-
else
|
104
|
-
raise "Unknown address family: #{family}"
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def host
|
110
|
-
unpack[0]
|
111
|
-
end
|
112
|
-
|
113
|
-
def port
|
114
|
-
unpack[1]
|
115
|
-
end
|
116
|
-
|
117
|
-
def connectable?
|
118
|
-
port != 0
|
119
|
-
end
|
120
|
-
|
121
|
-
def sockaddr
|
122
|
-
Address.parse_sockaddr(@serial)
|
123
|
-
end
|
124
|
-
|
125
|
-
def unpack
|
126
|
-
Address.parse(@serial)
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.parse_sockaddr(raw)
|
130
|
-
if raw.length == 6
|
131
|
-
addr = Socket.pack_sockaddr_in(0, '0.0.0.0')
|
132
|
-
addr[2,6] = raw[0,6]
|
133
|
-
else
|
134
|
-
addr = Socket.pack_sockaddr_in(0, '::')
|
135
|
-
addr[2,2] = raw[0,2]
|
136
|
-
addr[8,16] = raw[2,16]
|
137
|
-
end
|
138
|
-
addr
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.parse(raw)
|
142
|
-
Socket.unpack_sockaddr_in(parse_sockaddr(raw)).reverse
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.load(raw)
|
146
|
-
Address.new *parse(raw)
|
147
|
-
end
|
148
|
-
|
149
|
-
def dump
|
150
|
-
@serial
|
151
|
-
end
|
152
|
-
|
153
|
-
def to_msgpack(out = '')
|
154
|
-
@serial.to_msgpack(out)
|
155
|
-
end
|
156
|
-
|
157
|
-
def to_s
|
158
|
-
unpack.join(':')
|
159
|
-
end
|
160
|
-
|
161
|
-
def to_a
|
162
|
-
unpack
|
163
|
-
end
|
164
|
-
|
165
|
-
def inspect
|
166
|
-
"#<#{self.class} #{to_s} @serial=#{@serial.inspect}>"
|
167
|
-
end
|
168
|
-
|
169
|
-
def eql?(o)
|
170
|
-
o.class == Address && dump.eql?(o.dump)
|
171
|
-
end
|
172
|
-
|
173
|
-
def hash
|
174
|
-
dump.hash
|
175
|
-
end
|
176
|
-
|
177
|
-
def ==(o)
|
178
|
-
eql?(o)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
|
-
class Future
|
184
|
-
def initialize(s, loop, block = nil)
|
185
|
-
@s = s
|
186
|
-
@timeout = s.timeout
|
187
|
-
@loop = loop
|
188
|
-
@block = block
|
189
|
-
@error = nil
|
190
|
-
@result = nil
|
191
|
-
end
|
192
|
-
attr_reader :loop
|
193
|
-
attr_accessor :result, :error
|
194
|
-
|
195
|
-
def attach_callback(proc = nil, &block)
|
196
|
-
@block = proc || block
|
197
|
-
end
|
198
|
-
|
199
|
-
def call(err, res)
|
200
|
-
@error = err
|
201
|
-
@result = res
|
202
|
-
if @block
|
203
|
-
@block.call(err, res)
|
204
|
-
end
|
205
|
-
@s = nil
|
206
|
-
end
|
207
|
-
|
208
|
-
def join
|
209
|
-
while @s
|
210
|
-
@loop.run_once
|
211
|
-
end
|
212
|
-
self
|
213
|
-
end
|
214
|
-
|
215
|
-
def step_timeout
|
216
|
-
if @timeout < 1
|
217
|
-
true
|
218
|
-
else
|
219
|
-
@timeout -= 1
|
220
|
-
false
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
|
226
|
-
class Responder
|
227
|
-
def initialize(tran, msgid)
|
228
|
-
@tran = tran # send_message method is required
|
229
|
-
@msgid = msgid
|
230
|
-
end
|
231
|
-
|
232
|
-
def result(retval, err = nil)
|
233
|
-
@tran.send_message [RESPONSE, @msgid, err, retval]
|
234
|
-
end
|
235
|
-
|
236
|
-
def error(err, retval = nil)
|
237
|
-
result(retval, err)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
|
242
|
-
class ExchangeOption
|
243
|
-
def initialize(flags = 0)
|
244
|
-
@flags = flags
|
245
|
-
end
|
246
|
-
|
247
|
-
def get
|
248
|
-
@flags
|
249
|
-
end
|
250
|
-
|
251
|
-
def deflate=(val)
|
252
|
-
val ? (@flags |= OPT_DEFLATE) : (@flags &= ~OPT_DEFLATE)
|
253
|
-
end
|
254
|
-
|
255
|
-
def deflate?
|
256
|
-
@flags & OPT_DEFLATE != 0
|
257
|
-
end
|
258
|
-
|
259
|
-
def reset
|
260
|
-
@flags = 0
|
261
|
-
self
|
262
|
-
end
|
263
|
-
|
264
|
-
def ==(o)
|
265
|
-
@flags == o.get
|
266
|
-
end
|
267
|
-
|
268
|
-
def to_msgpack(out = '')
|
269
|
-
@flags.to_msgpack(out)
|
270
|
-
end
|
271
|
-
|
272
|
-
def self.from_msgpack(obj)
|
273
|
-
@flags = obj
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
class StreamOption
|
278
|
-
def initialize(txopt = ExchangeOption.new, rxopt = ExchangeOption.new) #, rxproto = nil, rxaddr = nil)
|
279
|
-
@txopt = txopt
|
280
|
-
@rxopt = rxopt
|
281
|
-
#@rxproto = rxproto # nil or PROTO_TCP or PROTO_UDP
|
282
|
-
#@rxaddr = rxaddr # nil or address
|
283
|
-
end
|
284
|
-
attr_accessor :txopt, :rxopt #, :rxproto, :rxaddr
|
285
|
-
|
286
|
-
def default?
|
287
|
-
@txopt.get == 0 && @rxopt.get == 0 && @rxproto.nil?
|
288
|
-
end
|
289
|
-
|
290
|
-
def reset
|
291
|
-
@txopt.reset
|
292
|
-
@rxopt.reset
|
293
|
-
#@rxproto = nil
|
294
|
-
#@rxaddr = nil
|
295
|
-
self
|
296
|
-
end
|
297
|
-
|
298
|
-
def ==(o)
|
299
|
-
@txopt == o.txopt && @rxopt == o.rxopt # &&
|
300
|
-
#@rxproto == o.rxproto && @rxaddr == o.rxaddr
|
301
|
-
end
|
302
|
-
|
303
|
-
def to_msgpack(out = '')
|
304
|
-
array = [OPTION, @txopt, @rxopt]
|
305
|
-
#if @rxproto
|
306
|
-
# array << @rxproto
|
307
|
-
# if @rxaddr
|
308
|
-
# array << @rxaddr
|
309
|
-
# end
|
310
|
-
#end
|
311
|
-
array.to_msgpack(out)
|
312
|
-
end
|
313
|
-
|
314
|
-
def self.from_msgpack(obj)
|
315
|
-
txopt = ExchangeOption.new(obj[1] || 0)
|
316
|
-
rxopt = ExchangeOption.new(obj[2] || 0)
|
317
|
-
#if obj[3]
|
318
|
-
# rxproto = obj[3]
|
319
|
-
# if obj[4]
|
320
|
-
# rxaddr = Address.load(obj[4])
|
321
|
-
# end
|
322
|
-
#end
|
323
|
-
StreamOption.new(txopt, rxopt) #, rxproto, rxaddr)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
class TransportOption < StreamOption
|
328
|
-
def initialize(*args)
|
329
|
-
super()
|
330
|
-
#@proto = PROTO_TCP
|
331
|
-
#@address = nil
|
332
|
-
args.each do |x|
|
333
|
-
case x
|
334
|
-
#when :tx_tcp, :tcp
|
335
|
-
# @proto = PROTO_TCP
|
336
|
-
#when :tx_udp, :udp
|
337
|
-
# @proto = PROTO_UDP
|
338
|
-
#when :rx_tcp
|
339
|
-
# @rxproto = PROTO_TCP
|
340
|
-
#when :rx_udp
|
341
|
-
# @rxproto = PROTO_UDP
|
342
|
-
when :deflate
|
343
|
-
@txopt.deflate = true
|
344
|
-
@rxopt.deflate = true
|
345
|
-
when :tx_deflate
|
346
|
-
@txopt.deflate = true
|
347
|
-
when :rx_deflate
|
348
|
-
@rxopt.deflate = true
|
349
|
-
#when PROTO_TCP
|
350
|
-
# @proto = PROTO_TCP
|
351
|
-
#when PROTO_UDP
|
352
|
-
# @proto = PROTO_UDP
|
353
|
-
#when Address
|
354
|
-
# @rxaddr = x
|
355
|
-
else
|
356
|
-
raise "unknown option #{x.inspect}"
|
357
|
-
end
|
358
|
-
end
|
359
|
-
end
|
360
|
-
#attr_accessor :proto, :address
|
361
|
-
|
362
|
-
def reset
|
363
|
-
#@proto = PROTO_TCP
|
364
|
-
@address = nil
|
365
|
-
super
|
366
|
-
end
|
367
|
-
|
368
|
-
def ==(o)
|
369
|
-
super(o) # && @proto = o.proto && @address = o.address
|
370
|
-
end
|
371
|
-
|
372
|
-
#def deflate(val = true) txopt.deflate = va; rxopt.deflate = va; self end
|
373
|
-
#def rx_deflate(val = true) @rxopt.deflate = val; self; end
|
374
|
-
#def tx_deflate(val = true) @txopt.deflate = val; self; end
|
375
|
-
|
376
|
-
#def tcp; @proto = PROTO_TCP; self; end
|
377
|
-
#def tx_tcp; @proto = PROTO_TCP; self; end
|
378
|
-
#def rx_tcp; @rxproto = PROTO_TCP; self; end
|
379
|
-
|
380
|
-
#def udp; @proto = PROTO_UDP; self; end
|
381
|
-
#def rx_udp; @proto = PROTO_UDP; self; end
|
382
|
-
#def rx_udp; @rxproto = PROTO_UDP; self; end
|
383
|
-
end
|
384
|
-
|
385
|
-
|
386
|
-
class Session
|
387
|
-
def initialize(to_addr, dtopt, dispatcher, self_addr, loop)
|
388
|
-
@address = to_addr # destination address
|
389
|
-
@self_address = self_addr # self session identifier
|
390
|
-
@dispatcher = dispatcher || NullDispatcher.new
|
391
|
-
@dtopt = dtopt # default transport option
|
392
|
-
@dtran = create_transport(@dtopt) # default transport
|
393
|
-
@loop = loop
|
394
|
-
@trans = []
|
395
|
-
@reqtable = {}
|
396
|
-
@timeout = 10 # FIXME default timeout time
|
397
|
-
reset
|
398
|
-
end
|
399
|
-
attr_reader :address, :self_address, :loop
|
400
|
-
attr_accessor :timeout
|
401
|
-
|
402
|
-
def send(method, *args)
|
403
|
-
send_over(nil, method, *args)
|
404
|
-
end
|
405
|
-
|
406
|
-
def callback(method, *args, &block)
|
407
|
-
callback_over(nil, method, *args, &block)
|
408
|
-
end
|
409
|
-
|
410
|
-
def call(method, *args)
|
411
|
-
call_over(nil, method, *args)
|
412
|
-
end
|
413
|
-
|
414
|
-
def notify(method, *args)
|
415
|
-
notify_over(nil, method, *args)
|
416
|
-
end
|
417
|
-
|
418
|
-
def over(*args)
|
419
|
-
Over.new(self, TransportOption.new(*args))
|
420
|
-
end
|
421
|
-
|
422
|
-
def default_option
|
423
|
-
@dtopt.dup
|
424
|
-
end
|
425
|
-
|
426
|
-
def send_over(topt, method, *args)
|
427
|
-
msgid = send_request(topt, method, args)
|
428
|
-
@reqtable[msgid] = Future.new(self, @loop)
|
429
|
-
end
|
430
|
-
|
431
|
-
def callback_over(topt, method, *args, &block)
|
432
|
-
msgid = send_request(topt, method, args)
|
433
|
-
@reqtable[msgid] = Future.new(self, @loop, block)
|
434
|
-
end
|
435
|
-
|
436
|
-
def call_over(topt, method, *args)
|
437
|
-
# FIXME if @reqtable.empty? optimize
|
438
|
-
req = send_over(topt, method, *args)
|
439
|
-
req.join
|
440
|
-
if req.error
|
441
|
-
raise req.error if req.error.is_a?(Error)
|
442
|
-
raise RemoteError.new(req.error, req.result)
|
443
|
-
end
|
444
|
-
req.result
|
445
|
-
end
|
446
|
-
|
447
|
-
def notify_over(topt, method, *args)
|
448
|
-
send_notify(topt, method, args)
|
449
|
-
end
|
450
|
-
|
451
|
-
def send_message_over(topt, msg) # for Over#send_message
|
452
|
-
get_transport(topt).send_message(msg)
|
453
|
-
end
|
454
|
-
|
455
|
-
def close
|
456
|
-
@dtran.close
|
457
|
-
@trans.each {|tran| tran.close }
|
458
|
-
reset
|
459
|
-
self
|
460
|
-
end
|
461
|
-
|
462
|
-
def step_timeout
|
463
|
-
reqs = []
|
464
|
-
@reqtable.reject! {|msgid, req|
|
465
|
-
if req.step_timeout
|
466
|
-
reqs.push(req)
|
467
|
-
end
|
468
|
-
}
|
469
|
-
reqs.each {|req|
|
470
|
-
begin
|
471
|
-
req.call TimeoutError.new, nil
|
472
|
-
rescue
|
473
|
-
end
|
474
|
-
}
|
475
|
-
!@reqtable.empty?
|
476
|
-
end
|
477
|
-
|
478
|
-
def on_message(sock, msg) # Session interface
|
479
|
-
case msg[0]
|
480
|
-
when REQUEST
|
481
|
-
on_request(sock, msg[1], msg[2], msg[3])
|
482
|
-
when RESPONSE
|
483
|
-
on_response(sock, msg[1], msg[2], msg[3])
|
484
|
-
when NOTIFY
|
485
|
-
on_notify(sock, msg[1], msg[2])
|
486
|
-
when SESSION
|
487
|
-
# ignore because session is already bound
|
488
|
-
else
|
489
|
-
raise RPCError.new("unknown message type #{msg[0]}")
|
490
|
-
end
|
491
|
-
end
|
492
|
-
|
493
|
-
def on_connect_failed
|
494
|
-
@reqtable.reject! {|msgid, req|
|
495
|
-
begin
|
496
|
-
req.call ConnectError.new, nil
|
497
|
-
rescue
|
498
|
-
end
|
499
|
-
true
|
500
|
-
}
|
501
|
-
# FIXME reset?
|
502
|
-
end
|
503
|
-
|
504
|
-
private
|
505
|
-
def create_transport(topt)
|
506
|
-
TCPTransport.new(self, topt)
|
507
|
-
end
|
508
|
-
|
509
|
-
def get_transport(topt)
|
510
|
-
if topt.nil? || @dtran.match?(topt)
|
511
|
-
return @dtran
|
512
|
-
end
|
513
|
-
if tran = @trans.find {|f| f.match?(topt) }
|
514
|
-
return tran
|
515
|
-
end
|
516
|
-
tran = create_transport(topt)
|
517
|
-
@trans.push(tran)
|
518
|
-
tran
|
519
|
-
end
|
520
|
-
|
521
|
-
class Over
|
522
|
-
def initialize(session, topt)
|
523
|
-
@session = session
|
524
|
-
@topt = topt
|
525
|
-
end
|
526
|
-
|
527
|
-
def send(method, *args)
|
528
|
-
@session.send_over(@topt, method, *args)
|
529
|
-
end
|
530
|
-
|
531
|
-
def callback(method, *args, &block)
|
532
|
-
@session.callback_over(@topt, method, *args, &block)
|
533
|
-
end
|
534
|
-
|
535
|
-
def call(method, *args)
|
536
|
-
@session.call_over(@topt, method, *args)
|
537
|
-
end
|
538
|
-
|
539
|
-
def notify(method, *args)
|
540
|
-
@session.notify_over(@topt, method, *args)
|
541
|
-
end
|
542
|
-
|
543
|
-
def send_message(msg) # Transport interface for Responder
|
544
|
-
@session.send_message_over(@topt, msg)
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
def send_notify(topt, method, param)
|
549
|
-
unless @address
|
550
|
-
raise RPCError.new("unexpected send request on server session")
|
551
|
-
end
|
552
|
-
method = method.to_s unless method.is_a?(Integer)
|
553
|
-
tran = get_transport(topt)
|
554
|
-
tran.send_message([NOTIFY, method, param])
|
555
|
-
end
|
556
|
-
|
557
|
-
def send_request(topt, method, param)
|
558
|
-
unless @address
|
559
|
-
raise RPCError.new("unexpected send request on server session")
|
560
|
-
end
|
561
|
-
method = method.to_s unless method.is_a?(Integer)
|
562
|
-
tran = get_transport(topt)
|
563
|
-
msgid = @seqid
|
564
|
-
@seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
|
565
|
-
@reqtable[msgid] = Future.new(self, @loop)
|
566
|
-
tran.send_message([REQUEST, msgid, method, param])
|
567
|
-
msgid
|
568
|
-
end
|
569
|
-
|
570
|
-
def on_response(sock, msgid, error, result)
|
571
|
-
if req = @reqtable.delete(msgid)
|
572
|
-
req.call(error, result)
|
573
|
-
end
|
574
|
-
end
|
575
|
-
|
576
|
-
def on_request(sock, msgid, method, param)
|
577
|
-
#if sock.option.rxproto
|
578
|
-
# #if @address
|
579
|
-
# tran = Over.new(self, sock.option)
|
580
|
-
#else
|
581
|
-
tran = sock
|
582
|
-
#end
|
583
|
-
res = Responder.new(tran, msgid)
|
584
|
-
@dispatcher.dispatch_request(self, method, param, res)
|
585
|
-
end
|
586
|
-
|
587
|
-
def on_notify(sock, method, param)
|
588
|
-
@dispatcher.dispatch_notify(self, method, param)
|
589
|
-
end
|
590
|
-
|
591
|
-
def on_close(sock)
|
592
|
-
@sockpool.delete(sock)
|
593
|
-
end
|
594
|
-
|
595
|
-
def reset
|
596
|
-
@reqtable = {}
|
597
|
-
@seqid = 0
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
|
602
|
-
class BasicTransport
|
603
|
-
def initialize(session, topt)
|
604
|
-
@session = session
|
605
|
-
@option = topt
|
606
|
-
end
|
607
|
-
|
608
|
-
def match?(topt)
|
609
|
-
@option == topt
|
610
|
-
end
|
611
|
-
|
612
|
-
#def close; end
|
613
|
-
|
614
|
-
protected
|
615
|
-
def get_address
|
616
|
-
#@option.address || @session.address
|
617
|
-
@session.address
|
618
|
-
end
|
619
|
-
end
|
620
|
-
|
621
|
-
class TCPTransport < BasicTransport
|
622
|
-
def initialize(session, topt)
|
623
|
-
super(session, topt)
|
624
|
-
|
625
|
-
@pending = ""
|
626
|
-
@sockpool = []
|
627
|
-
@connecting = 0
|
628
|
-
@reconnect = 5 # FIXME default reconnect limit
|
629
|
-
|
630
|
-
@initmsg = ""
|
631
|
-
if session.self_address
|
632
|
-
@initmsg << [SESSION, session.self_address].to_msgpack
|
633
|
-
end
|
634
|
-
unless topt.default?
|
635
|
-
@initmsg << topt.to_msgpack
|
636
|
-
end
|
637
|
-
@initmsg = nil if @initmsg.empty?
|
638
|
-
|
639
|
-
if topt.txopt.deflate?
|
640
|
-
@deflate = Zlib::Deflate.new
|
641
|
-
else
|
642
|
-
@deflate = nil
|
643
|
-
end
|
644
|
-
end
|
645
|
-
|
646
|
-
def send_message(msg) # Transport interface
|
647
|
-
if @sockpool.empty?
|
648
|
-
if @connecting == 0
|
649
|
-
try_connect
|
650
|
-
@connecting = 1
|
651
|
-
end
|
652
|
-
if @deflate
|
653
|
-
@pending << @deflate.deflate(msg.to_msgpack, Zlib::SYNC_FLUSH)
|
654
|
-
else
|
655
|
-
@pending << msg.to_msgpack
|
656
|
-
end
|
657
|
-
else
|
658
|
-
# FIXME pesudo connection load balance
|
659
|
-
sock = @sockpool.first
|
660
|
-
sock.send_message(msg)
|
661
|
-
end
|
662
|
-
end
|
663
|
-
|
664
|
-
def close # Transport interface
|
665
|
-
@sockpool.reject! {|sock|
|
666
|
-
sock.detach if sock.attached?
|
667
|
-
sock.close
|
668
|
-
true
|
669
|
-
}
|
670
|
-
@sockpool = []
|
671
|
-
@connecting = 0
|
672
|
-
@pending = ""
|
673
|
-
@deflate.reset if @deflate
|
674
|
-
self
|
675
|
-
end
|
676
|
-
|
677
|
-
def on_connect(sock)
|
678
|
-
@sockpool.push(sock)
|
679
|
-
sock.send_pending(@pending, @deflate)
|
680
|
-
@pending = ""
|
681
|
-
@deflate = Zlib::Deflate.new if @deflate
|
682
|
-
@connecting = 0
|
683
|
-
end
|
684
|
-
|
685
|
-
def on_connect_failed(sock)
|
686
|
-
if @connecting < @reconnect
|
687
|
-
try_connect
|
688
|
-
@connecting += 1
|
689
|
-
else
|
690
|
-
@connecting = 0
|
691
|
-
@pending = ""
|
692
|
-
@session.on_connect_failed
|
693
|
-
end
|
694
|
-
end
|
695
|
-
|
696
|
-
def on_close(sock)
|
697
|
-
@sockpool.delete(sock)
|
698
|
-
end
|
699
|
-
|
700
|
-
private
|
701
|
-
def try_connect
|
702
|
-
addr = get_address
|
703
|
-
if addr.nil?
|
704
|
-
return # FIXME raise?
|
705
|
-
end
|
706
|
-
host, port = *addr
|
707
|
-
sock = ActiveSocket.connect(host, port, self, @option, @session) # async connect
|
708
|
-
if @initmsg
|
709
|
-
sock.write @initmsg
|
710
|
-
end
|
711
|
-
@session.loop.attach(sock)
|
712
|
-
end
|
713
|
-
end
|
714
|
-
|
715
|
-
class TCPTransport::Socket < Rev::TCPSocket
|
716
|
-
def initialize(sock, session)
|
717
|
-
@buffer = ''
|
718
|
-
@nread = 0
|
719
|
-
@mpac = MessagePack::Unpacker.new
|
720
|
-
@deflate = nil
|
721
|
-
@inflate = nil
|
722
|
-
@s = session
|
723
|
-
super(sock)
|
724
|
-
end
|
725
|
-
|
726
|
-
def session
|
727
|
-
@s
|
728
|
-
end
|
729
|
-
|
730
|
-
def on_read(data)
|
731
|
-
if @inflate
|
732
|
-
data = @inflate.inflate(data)
|
733
|
-
return if data.empty?
|
734
|
-
end
|
735
|
-
@buffer << data
|
736
|
-
|
737
|
-
while true
|
738
|
-
@nread = @mpac.execute(@buffer, @nread)
|
739
|
-
if @mpac.finished?
|
740
|
-
msg = @mpac.data
|
741
|
-
@mpac.reset
|
742
|
-
@buffer.slice!(0, @nread)
|
743
|
-
@nread = 0
|
744
|
-
on_message(msg)
|
745
|
-
next unless @buffer.empty?
|
746
|
-
end
|
747
|
-
break
|
748
|
-
end
|
749
|
-
end
|
750
|
-
|
751
|
-
def on_message(msg)
|
752
|
-
return unless @s
|
753
|
-
@s.on_message(self, msg)
|
754
|
-
end
|
755
|
-
|
756
|
-
def on_close
|
757
|
-
@deflate.close if @deflate
|
758
|
-
@inflate.close if @inflate
|
759
|
-
end
|
760
|
-
|
761
|
-
def send_message(msg) # Transport interface
|
762
|
-
if @deflate
|
763
|
-
data = @deflate.deflate(msg.to_msgpack, Zlib::SYNC_FLUSH)
|
764
|
-
else
|
765
|
-
data = msg.to_msgpack
|
766
|
-
end
|
767
|
-
write data
|
768
|
-
end
|
769
|
-
end
|
770
|
-
|
771
|
-
class TCPTransport::ActiveSocket < TCPTransport::Socket
|
772
|
-
def initialize(sock, tran, topt, session)
|
773
|
-
super(sock, session)
|
774
|
-
@tran = tran
|
775
|
-
set_option(topt)
|
776
|
-
end
|
777
|
-
|
778
|
-
def on_connect
|
779
|
-
return unless @tran
|
780
|
-
@tran.on_connect(self)
|
781
|
-
end
|
782
|
-
|
783
|
-
def on_connect_failed
|
784
|
-
return unless @tran
|
785
|
-
@tran.on_connect_failed(self)
|
786
|
-
end
|
787
|
-
|
788
|
-
def on_close
|
789
|
-
return unless @tran
|
790
|
-
@tran.on_close(self)
|
791
|
-
@tran = nil
|
792
|
-
@s = nil
|
793
|
-
rescue
|
794
|
-
nil
|
795
|
-
ensure
|
796
|
-
super
|
797
|
-
end
|
798
|
-
|
799
|
-
def send_pending(data, z)
|
800
|
-
write data
|
801
|
-
@deflate = z
|
802
|
-
end
|
803
|
-
|
804
|
-
private
|
805
|
-
def set_option(sopt) # stream option
|
806
|
-
if sopt.txopt.deflate?
|
807
|
-
@deflate = Zlib::Deflate.new
|
808
|
-
end
|
809
|
-
if sopt.rxopt.deflate?
|
810
|
-
@inflate = Zlib::Inflate.new
|
811
|
-
#@buffer = @inflate.inflate(@buffer) unless @buffer.empty?
|
812
|
-
end
|
813
|
-
end
|
814
|
-
end
|
815
|
-
|
816
|
-
class TCPTransport::PassiveSocket < TCPTransport::Socket
|
817
|
-
def initialize(sock, create_session)
|
818
|
-
super(sock, create_session.call)
|
819
|
-
@option = TransportOption.new # active option (reversed)
|
820
|
-
end
|
821
|
-
|
822
|
-
attr_reader :option # for Session#on_request
|
823
|
-
|
824
|
-
def rebind(session)
|
825
|
-
@s = session
|
826
|
-
end
|
827
|
-
|
828
|
-
def on_message(msg)
|
829
|
-
if msg[0] == OPTION
|
830
|
-
sopt = StreamOption.from_msgpack(msg)
|
831
|
-
set_option(sopt)
|
832
|
-
return
|
833
|
-
end
|
834
|
-
super(msg)
|
835
|
-
end
|
836
|
-
|
837
|
-
private
|
838
|
-
def set_option(sopt)
|
839
|
-
if sopt.txopt.deflate?
|
840
|
-
@inflate = Zlib::Inflate.new
|
841
|
-
@buffer = @inflate.inflate(@buffer) unless @buffer.empty?
|
842
|
-
end
|
843
|
-
if sopt.rxopt.deflate?
|
844
|
-
@deflate = Zlib::Deflate.new
|
845
|
-
end
|
846
|
-
# rx-tx reverse
|
847
|
-
@option = TransportOption.new
|
848
|
-
@option.txopt = sopt.rxopt
|
849
|
-
@option.rxopt = sopt.txopt
|
850
|
-
#@option.proto = sopt.rxproto || PROTO_TCP
|
851
|
-
#@option.address = sopt.rxaddr
|
852
|
-
end
|
853
|
-
end
|
854
|
-
|
855
|
-
class TCPTransport::Listener
|
856
|
-
def initialize(host, port, &create_session)
|
857
|
-
@lsock = Rev::TCPServer.new(host, port, TCPTransport::PassiveSocket, create_session)
|
858
|
-
end
|
859
|
-
|
860
|
-
def activate(loop)
|
861
|
-
loop.attach(@lsock)
|
862
|
-
end
|
863
|
-
|
864
|
-
def close
|
865
|
-
@lsock.detach if @lsock.attached?
|
866
|
-
@lsock.close
|
867
|
-
end
|
868
|
-
end
|
869
|
-
|
870
|
-
|
871
|
-
=begin
|
872
|
-
class UDPTransport < BasicTransport
|
873
|
-
def initialize(session, topt)
|
874
|
-
super(session, topt)
|
875
|
-
|
876
|
-
initmsg = ""
|
877
|
-
if session.self_address
|
878
|
-
initmsg << [SESSION, session.self_address].to_msgpack
|
879
|
-
end
|
880
|
-
unless topt.default?
|
881
|
-
initmsg << topt.to_msgpack
|
882
|
-
end
|
883
|
-
initmsg = nil if initmsg.empty?
|
884
|
-
|
885
|
-
sock = UDPSocket.new
|
886
|
-
@addr = get_address
|
887
|
-
@asock = ActiveSocket.new(sock, initmsg, topt, session)
|
888
|
-
end
|
889
|
-
|
890
|
-
def send_message(msg) # Transport interface
|
891
|
-
@asock.send_message_to(msg, @addr)
|
892
|
-
end
|
893
|
-
|
894
|
-
def close
|
895
|
-
@sock.close
|
896
|
-
@deflate.close if @deflate
|
897
|
-
end
|
898
|
-
end
|
899
|
-
|
900
|
-
class UDPTransport::Socket < Rev::IO
|
901
|
-
def initialize(sock, create_session)
|
902
|
-
@sock = sock
|
903
|
-
@mpac = MessagePack::Unpacker.new
|
904
|
-
@create_session = create_session
|
905
|
-
super(sock)
|
906
|
-
end
|
907
|
-
|
908
|
-
def on_readable
|
909
|
-
begin
|
910
|
-
buffer, from = @sock.recvfrom(65536)
|
911
|
-
rescue Errno::EAGAIN
|
912
|
-
return
|
913
|
-
rescue Errno::EINTR
|
914
|
-
return
|
915
|
-
end
|
916
|
-
# addr = Address.from_sockaddr(from) FIXME
|
917
|
-
on_recv(buffer, addr)
|
918
|
-
end
|
919
|
-
|
920
|
-
def on_message(rc, msg)
|
921
|
-
return unless @s
|
922
|
-
@s.on_message(rc, msg)
|
923
|
-
end
|
924
|
-
|
925
|
-
def send_message_with(initmsg, msg, deflate, addr)
|
926
|
-
if deflate
|
927
|
-
d2 = deflate.deflate(msg.to_msgpack, Zlib::SYNC_FLUSH)
|
928
|
-
else
|
929
|
-
d2 = msg.to_msgpack
|
930
|
-
end
|
931
|
-
if initmsg
|
932
|
-
data = d2
|
933
|
-
else
|
934
|
-
data = initmsg.dup
|
935
|
-
data << d2
|
936
|
-
end
|
937
|
-
@sock.sendto(data, 0, addr.sockaddr)
|
938
|
-
end
|
939
|
-
end
|
940
|
-
|
941
|
-
class UDPTransport::ActiveSocket < UDPTransport::Socket
|
942
|
-
def initialize(sock, initmsg, topt, session)
|
943
|
-
@sock = sock
|
944
|
-
super(sock)
|
945
|
-
if topt.txopt.deflate?
|
946
|
-
@deflate = Zlib::Deflate.new
|
947
|
-
else
|
948
|
-
@deflate = nil
|
949
|
-
end
|
950
|
-
@initmsg = initmsg
|
951
|
-
@s = session
|
952
|
-
end
|
953
|
-
|
954
|
-
def on_recv(data, addr)
|
955
|
-
rc = ReturnContext.new(self, addr)
|
956
|
-
if @inflate
|
957
|
-
data = @inflate.inflate(data)
|
958
|
-
@inflate.finish
|
959
|
-
return if data.empty?
|
960
|
-
end
|
961
|
-
nread = 0
|
962
|
-
while true
|
963
|
-
nread = @mpac.execute(data, nread)
|
964
|
-
if @mpac.finished?
|
965
|
-
msg = @mpac.data
|
966
|
-
@mpac.reset
|
967
|
-
data.slice!(0, nread)
|
968
|
-
nread = 0
|
969
|
-
on_message(rc, msg)
|
970
|
-
next unless data.empty?
|
971
|
-
else
|
972
|
-
@mpac.reset
|
973
|
-
end
|
974
|
-
break
|
975
|
-
end
|
976
|
-
end
|
977
|
-
|
978
|
-
def send_message_to(msg, addr)
|
979
|
-
send_message_with(@initmsg, msg, @deflate, addr)
|
980
|
-
end
|
981
|
-
|
982
|
-
private
|
983
|
-
class ReturnContext
|
984
|
-
def initialize(asock, addr)
|
985
|
-
@asock = asock
|
986
|
-
@addr = addr
|
987
|
-
end
|
988
|
-
|
989
|
-
def send_message(msg) # Transport interface
|
990
|
-
@asock.send_message_to(msg, @addr)
|
991
|
-
end
|
992
|
-
end
|
993
|
-
end
|
994
|
-
|
995
|
-
class UDPTransport::PassiveSocket < UDPTransport::Socket
|
996
|
-
def initialize(sock, create_session)
|
997
|
-
super(sock)
|
998
|
-
@create_session = create_session
|
999
|
-
@inflate = LazyInflate.new
|
1000
|
-
@deflate = LazyInflate.new
|
1001
|
-
end
|
1002
|
-
|
1003
|
-
def on_recv(data, addr)
|
1004
|
-
rc = PassiveReturnContext.new(self, addr)
|
1005
|
-
nread = 0
|
1006
|
-
while true
|
1007
|
-
nread = @mpac.execute(data, nread)
|
1008
|
-
if @mpac.finished?
|
1009
|
-
msg = @mpac.data
|
1010
|
-
@mpac.reset
|
1011
|
-
data.slice!(0, nread)
|
1012
|
-
nread = 0
|
1013
|
-
data = on_message(data, rc, msg)
|
1014
|
-
next unless data.empty?
|
1015
|
-
else
|
1016
|
-
@mpac.reset
|
1017
|
-
end
|
1018
|
-
break
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
def on_message(data, rc, msg)
|
1023
|
-
if msg[0] == OPTION
|
1024
|
-
sopt = StreamOption.from_msgpack(msg)
|
1025
|
-
return set_option(data, rc, sopt)
|
1026
|
-
end
|
1027
|
-
super(rc, msg)
|
1028
|
-
end
|
1029
|
-
|
1030
|
-
attr_reader :deflate # for ReturnContext#send_message
|
1031
|
-
|
1032
|
-
private
|
1033
|
-
class ReturnContext
|
1034
|
-
def initialize(psock, addr)
|
1035
|
-
@psock = psock
|
1036
|
-
@addr = addr
|
1037
|
-
@option = TransportOption.new
|
1038
|
-
end
|
1039
|
-
attr_accessor :option
|
1040
|
-
|
1041
|
-
def send_message(msg) # Transport interface
|
1042
|
-
if @option.txopt.deflate?
|
1043
|
-
deflate = @psock.deflate.get
|
1044
|
-
else
|
1045
|
-
deflate = nil
|
1046
|
-
end
|
1047
|
-
@psock.send_message_with(nil, msg, deflate, @addr)
|
1048
|
-
end
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
class LazyDeflate
|
1052
|
-
def initialize
|
1053
|
-
@deflate = nil
|
1054
|
-
end
|
1055
|
-
def get
|
1056
|
-
@deflate ||= Zlib::Deflate.new
|
1057
|
-
end
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
class LazyInflate
|
1061
|
-
def initialize
|
1062
|
-
@inflate = nil
|
1063
|
-
end
|
1064
|
-
def get
|
1065
|
-
@inflate ||= Zlib::Inflate.new
|
1066
|
-
end
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
def set_option(data, rc, sopt)
|
1070
|
-
if sopt.txopt.deflate?
|
1071
|
-
inflate = @inflate.get
|
1072
|
-
data = inflate.inflate(data)
|
1073
|
-
@inflate.finish
|
1074
|
-
end
|
1075
|
-
# rx-tx reverse
|
1076
|
-
rc.option.reset
|
1077
|
-
rc.option.txopt = sopt.rxopt
|
1078
|
-
rc.option.proto = sopt.rxproto || PROTO_UDP
|
1079
|
-
rc.option.address = sopt.rxaddr
|
1080
|
-
data
|
1081
|
-
end
|
1082
|
-
end
|
1083
|
-
|
1084
|
-
class UDPTransport::Listener
|
1085
|
-
def initialize(host, port, &create_session)
|
1086
|
-
@sock = UDPSocket.new
|
1087
|
-
@sock.bind(host, port)
|
1088
|
-
@psock = PassiveSocket.new(@sock, &create_session)
|
1089
|
-
end
|
1090
|
-
|
1091
|
-
def activate(loop)
|
1092
|
-
loop.attach(@psock)
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
def close
|
1096
|
-
@psock.detach if @psock.attached?
|
1097
|
-
@psock.close
|
1098
|
-
end
|
1099
|
-
end
|
1100
|
-
=end
|
1101
|
-
|
1102
|
-
|
1103
|
-
class AsyncResult
|
1104
|
-
def initialize
|
1105
|
-
@responder = nil
|
1106
|
-
@sent = false
|
1107
|
-
end
|
1108
|
-
|
1109
|
-
def result(retval, err = nil)
|
1110
|
-
unless @sent
|
1111
|
-
if @responder
|
1112
|
-
@responder.result(retval, err)
|
1113
|
-
else
|
1114
|
-
@result = [retval, err]
|
1115
|
-
end
|
1116
|
-
@sent = true
|
1117
|
-
end
|
1118
|
-
nil
|
1119
|
-
end
|
1120
|
-
|
1121
|
-
def error(err)
|
1122
|
-
result(nil, err)
|
1123
|
-
nil
|
1124
|
-
end
|
1125
|
-
|
1126
|
-
def responder=(res)
|
1127
|
-
@responder = res
|
1128
|
-
if @sent && @result
|
1129
|
-
@responder.result(*@result)
|
1130
|
-
@result = nil
|
1131
|
-
end
|
1132
|
-
end
|
1133
|
-
end
|
1134
|
-
|
1135
|
-
|
1136
|
-
class NullDispatcher
|
1137
|
-
def dispatch_request(session, method, param, res)
|
1138
|
-
raise RPCError.new("unexpected request message")
|
1139
|
-
end
|
1140
|
-
|
1141
|
-
def dispatch_notify(session, method, param)
|
1142
|
-
raise RPCError.new("unexpected notify message")
|
1143
|
-
end
|
1144
|
-
end
|
1145
|
-
|
1146
|
-
class ObjectDispatcher
|
1147
|
-
def initialize(obj, accept = obj.public_methods)
|
1148
|
-
@obj = obj
|
1149
|
-
@accept = accept.map {|m| m.is_a?(Integer) ? m : m.to_s}
|
1150
|
-
end
|
1151
|
-
|
1152
|
-
def dispatch_request(session, method, param, res)
|
1153
|
-
begin
|
1154
|
-
result = forward_method(session, method, param)
|
1155
|
-
rescue
|
1156
|
-
res.error($!.to_s)
|
1157
|
-
return
|
1158
|
-
end
|
1159
|
-
if result.is_a?(AsyncResult)
|
1160
|
-
result.responder = res
|
1161
|
-
else
|
1162
|
-
res.result(result)
|
1163
|
-
end
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
def dispatch_notify(session, method, param)
|
1167
|
-
forward_method(session, method, param)
|
1168
|
-
rescue
|
1169
|
-
end
|
1170
|
-
|
1171
|
-
private
|
1172
|
-
def forward_method(session, method, param)
|
1173
|
-
unless @accept.include?(method)
|
1174
|
-
raise NoMethodError, "method `#{method}' is not accepted"
|
1175
|
-
end
|
1176
|
-
@obj.send(method, *param) { session }
|
1177
|
-
end
|
1178
|
-
end
|
1179
|
-
|
1180
|
-
|
1181
|
-
Loop = Rev::Loop
|
1182
|
-
|
1183
|
-
|
1184
|
-
module LoopUtil
|
1185
|
-
attr_reader :loop
|
1186
|
-
|
1187
|
-
class Timer < Rev::TimerWatcher
|
1188
|
-
def initialize(interval, repeating, &block)
|
1189
|
-
@block = block
|
1190
|
-
super(interval, repeating)
|
1191
|
-
end
|
1192
|
-
def on_timer
|
1193
|
-
@block.call
|
1194
|
-
end
|
1195
|
-
end
|
1196
|
-
|
1197
|
-
def start_timer(interval, repeating, &block)
|
1198
|
-
@loop.attach Timer.new(interval, repeating, &block)
|
1199
|
-
end
|
1200
|
-
|
1201
|
-
class TaskQueue < Rev::AsyncWatcher
|
1202
|
-
def initialize
|
1203
|
-
@queue = []
|
1204
|
-
super
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
def push(task)
|
1208
|
-
@queue.push(task)
|
1209
|
-
signal
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
def on_signal
|
1213
|
-
while task = @queue.shift
|
1214
|
-
begin
|
1215
|
-
task.call
|
1216
|
-
rescue
|
1217
|
-
end
|
1218
|
-
end
|
1219
|
-
end
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
def submit(task = nil, &block)
|
1223
|
-
task ||= block
|
1224
|
-
unless @queue
|
1225
|
-
@queue = TaskQueue.new
|
1226
|
-
@loop.attach(@queue)
|
1227
|
-
end
|
1228
|
-
@queue.push(task)
|
1229
|
-
end
|
1230
|
-
|
1231
|
-
def run
|
1232
|
-
@loop.run
|
1233
|
-
end
|
1234
|
-
|
1235
|
-
def stop
|
1236
|
-
@queue.detach if @queue && @queue.attached?
|
1237
|
-
@loop.stop
|
1238
|
-
# attach dummy timer
|
1239
|
-
@loop.attach Rev::TimerWatcher.new(0, false)
|
1240
|
-
nil
|
1241
|
-
end
|
1242
|
-
end
|
1243
|
-
|
1244
|
-
|
1245
|
-
class Client < Session
|
1246
|
-
def initialize(host, port, loop = Loop.new, dtopt = TransportOption.new)
|
1247
|
-
@loop = loop
|
1248
|
-
@host = host
|
1249
|
-
@port = port
|
1250
|
-
|
1251
|
-
addr = Address.new(host, port)
|
1252
|
-
super(addr, dtopt, NullDispatcher.new, nil, loop)
|
1253
|
-
|
1254
|
-
@timer = Timer.new(1, true) {
|
1255
|
-
step_timeout
|
1256
|
-
}
|
1257
|
-
loop.attach(@timer)
|
1258
|
-
end
|
1259
|
-
attr_reader :host, :port
|
1260
|
-
|
1261
|
-
def self.open(host, port, loop = Loop.new, dtopt = TransportOption.new, &block)
|
1262
|
-
cli = new(host, port, loop, dtopt)
|
1263
|
-
begin
|
1264
|
-
block.call(cli)
|
1265
|
-
ensure
|
1266
|
-
cli.close
|
1267
|
-
end
|
1268
|
-
end
|
1269
|
-
|
1270
|
-
def close
|
1271
|
-
@timer.detach if @timer.attached?
|
1272
|
-
super
|
1273
|
-
end
|
1274
|
-
|
1275
|
-
include LoopUtil
|
1276
|
-
end
|
1277
|
-
|
1278
|
-
|
1279
|
-
class SessionPool
|
1280
|
-
def initialize(loop = Loop.new, dtopt = TransportOption.new)
|
1281
|
-
@loop = loop
|
1282
|
-
@spool = {}
|
1283
|
-
@stimer = Timer.new(1, true, &method(:step_timeout))
|
1284
|
-
@dtopt = dtopt
|
1285
|
-
loop.attach(@stimer)
|
1286
|
-
end
|
1287
|
-
|
1288
|
-
def get_session(host, port)
|
1289
|
-
addr = Address.new(host, port)
|
1290
|
-
get_session_addr(addr)
|
1291
|
-
end
|
1292
|
-
|
1293
|
-
def get_session_addr(addr)
|
1294
|
-
@spool[addr] ||= create_session(addr)
|
1295
|
-
end
|
1296
|
-
|
1297
|
-
def close
|
1298
|
-
@spool.reject! {|addr, s|
|
1299
|
-
s.close
|
1300
|
-
true
|
1301
|
-
}
|
1302
|
-
@stimer.detach if @stimer.attached?
|
1303
|
-
nil
|
1304
|
-
end
|
1305
|
-
|
1306
|
-
include LoopUtil
|
1307
|
-
|
1308
|
-
protected
|
1309
|
-
def create_session(addr)
|
1310
|
-
Session.new(addr, @dtopt, nil, nil, @loop)
|
1311
|
-
end
|
1312
|
-
|
1313
|
-
private
|
1314
|
-
def step_timeout
|
1315
|
-
@spool.each_pair {|addr, s|
|
1316
|
-
s.step_timeout
|
1317
|
-
}
|
1318
|
-
end
|
1319
147
|
end
|
1320
148
|
|
149
|
+
end # module MessagePack
|
1321
150
|
|
1322
|
-
class Server < SessionPool
|
1323
|
-
def initialize(loop = Loop.new)
|
1324
|
-
super(loop, TransportOption.new)
|
1325
|
-
@dispatcher = nil
|
1326
|
-
@listeners = []
|
1327
|
-
end
|
1328
|
-
|
1329
|
-
def serve(obj, accept = obj.public_methods)
|
1330
|
-
@dispatcher = ObjectDispatcher.new(obj, accept)
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
def listen(host, port, obj = nil, accept = obj.public_methods)
|
1334
|
-
unless obj.nil?
|
1335
|
-
serve(obj, accept)
|
1336
|
-
end
|
1337
|
-
listen_real(host, port)
|
1338
|
-
self
|
1339
|
-
end
|
1340
|
-
|
1341
|
-
def listen_real(host, port) #, proto = PROTO_TCP)
|
1342
|
-
creator = Proc.new { create_session(nil) }
|
1343
|
-
#case proto
|
1344
|
-
#when PROTO_TCP, :tcp
|
1345
|
-
# listener = TCPTransport::Listener.new(host, port, &creator)
|
1346
|
-
#when PROTO_UDP, :udp
|
1347
|
-
# listener = UDPTransport::Listener.new(host, port, &creator)
|
1348
|
-
#else
|
1349
|
-
# raise "unknown option: #{proto.inspect}"
|
1350
|
-
#end
|
1351
|
-
listener = TCPTransport::Listener.new(host, port, &creator)
|
1352
|
-
@listeners.push(listener)
|
1353
|
-
listener.activate(@loop)
|
1354
|
-
self
|
1355
|
-
end
|
1356
|
-
|
1357
|
-
def close
|
1358
|
-
@listeners.reject! {|listener|
|
1359
|
-
listener.close
|
1360
|
-
true
|
1361
|
-
}
|
1362
|
-
super
|
1363
|
-
end
|
1364
|
-
|
1365
|
-
protected
|
1366
|
-
def create_session(addr)
|
1367
|
-
Session.new(addr, @dtopt, @dispatcher, nil, @loop)
|
1368
|
-
end
|
1369
|
-
end
|
1370
|
-
|
1371
|
-
|
1372
|
-
class Cluster < SessionPool
|
1373
|
-
def initialize(host, port, loop = Loop.new, dtopt = TransportOption.new)
|
1374
|
-
super(loop, dtopt)
|
1375
|
-
@host = host
|
1376
|
-
@port = port
|
1377
|
-
@dispatcher = nil
|
1378
|
-
@self_addr = Address.new(host, port)
|
1379
|
-
@listeners = []
|
1380
|
-
listen(host, port) # FIXME obsolete?
|
1381
|
-
end
|
1382
|
-
attr_reader :host, :port
|
1383
|
-
|
1384
|
-
def serve(obj, accept = obj.public_methods)
|
1385
|
-
@dispatcher = ObjectDispatcher.new(obj, accept)
|
1386
|
-
self
|
1387
|
-
end
|
1388
|
-
|
1389
|
-
def listen(host, port) #, proto = PROTO_TCP)
|
1390
|
-
lz = LazyBinder.new(self)
|
1391
|
-
creator = Proc.new { lz }
|
1392
|
-
#case proto
|
1393
|
-
#when PROTO_TCP, :tcp
|
1394
|
-
# listener = TCPTransport::Listener.new(host, port, &creator)
|
1395
|
-
#when PROTO_UDP, :udp
|
1396
|
-
# listener = UDPTransport::Listener.new(host, port, &creator)
|
1397
|
-
#else
|
1398
|
-
# raise "unknown option: #{proto.inspect}"
|
1399
|
-
#end
|
1400
|
-
listener = TCPTransport::Listener.new(host, port, &creator)
|
1401
|
-
@listeners.push(listener)
|
1402
|
-
listener.activate(@loop)
|
1403
|
-
self
|
1404
|
-
end
|
1405
|
-
|
1406
|
-
def close
|
1407
|
-
if @lsock
|
1408
|
-
@lsock.detach if @lsock.attached?
|
1409
|
-
@lsock.close
|
1410
|
-
end
|
1411
|
-
super
|
1412
|
-
end
|
1413
|
-
|
1414
|
-
include LoopUtil
|
1415
|
-
|
1416
|
-
protected
|
1417
|
-
def create_session(addr)
|
1418
|
-
Session.new(addr, @dtopt, @dispatcher, @self_addr, @loop)
|
1419
|
-
end
|
1420
|
-
|
1421
|
-
public
|
1422
|
-
def create_server_session
|
1423
|
-
# FIXME
|
1424
|
-
Session.new(nil, @dtopt, @dispatcher, @self_addr, @loop)
|
1425
|
-
end
|
1426
|
-
|
1427
|
-
private
|
1428
|
-
class LazyBinder < Session
|
1429
|
-
def initialize(cluster)
|
1430
|
-
@cluster = cluster
|
1431
|
-
end
|
1432
|
-
|
1433
|
-
def on_message(sock, msg) # Session interface
|
1434
|
-
if msg[0] == SESSION
|
1435
|
-
# cluster
|
1436
|
-
addr = Address.load(msg[1])
|
1437
|
-
session = @cluster.get_session_addr(addr)
|
1438
|
-
sock.rebind(session)
|
1439
|
-
else
|
1440
|
-
# subsys
|
1441
|
-
session = @cluster.create_server_session
|
1442
|
-
sock.rebind(session)
|
1443
|
-
sock.on_message(msg)
|
1444
|
-
end
|
1445
|
-
end
|
1446
|
-
end
|
1447
|
-
end
|
1448
|
-
|
1449
|
-
|
1450
|
-
end
|
1451
|
-
end
|
1452
151
|
|
152
|
+
require 'msgpack'
|
153
|
+
require 'socket'
|
154
|
+
require 'rev'
|
155
|
+
require 'msgpack/rpc/address'
|
156
|
+
require 'msgpack/rpc/message'
|
157
|
+
require 'msgpack/rpc/exception'
|
158
|
+
require 'msgpack/rpc/loop'
|
159
|
+
require 'msgpack/rpc/future'
|
160
|
+
require 'msgpack/rpc/session'
|
161
|
+
require 'msgpack/rpc/session_pool'
|
162
|
+
require 'msgpack/rpc/dispatcher'
|
163
|
+
require 'msgpack/rpc/client'
|
164
|
+
require 'msgpack/rpc/server'
|
165
|
+
require 'msgpack/rpc/transport/base'
|
166
|
+
require 'msgpack/rpc/transport/tcp'
|