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 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.jp/.
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
- require 'msgpack'
19
- require 'rev'
20
- require 'zlib'
18
+ module MessagePack #:nodoc:
21
19
 
22
- module MessagePack
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'