msgpack-rpc 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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'