msgpack-rpc 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/Rakefile +1 -1
  2. data/lib/msgpack/rpc.rb +479 -149
  3. data/test/msgpack_rpc_test.rb +18 -0
  4. metadata +7 -6
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ DESCRIPTION = "RPC library using MessagePack, a ainary-based efficient dat
17
17
  RUBYFORGE_PROJECT = "msgpack"
18
18
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
19
19
  BIN_FILES = %w( )
20
- VERS = "0.1.4"
20
+ VERS = "0.2.0"
21
21
 
22
22
  #REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
23
23
  REV = nil
data/lib/msgpack/rpc.rb CHANGED
@@ -40,11 +40,16 @@ class RemoteError < RPCError
40
40
  end
41
41
 
42
42
  class TimeoutError < Error
43
- def initialize
44
- super("request timed out")
43
+ def initialize(msg = "request timed out")
44
+ super
45
45
  end
46
46
  end
47
47
 
48
+ class ConnectError < TimeoutError
49
+ def initialize(msg = "connect failed")
50
+ super
51
+ end
52
+ end
48
53
 
49
54
  class Responder
50
55
  def initialize(socket, msgid)
@@ -53,7 +58,7 @@ class Responder
53
58
  end
54
59
 
55
60
  def result(retval, err = nil)
56
- @socket.send_response(@msgid, retval, err)
61
+ @socket.write RPCSocket.pack_response(@msgid, retval, err)
57
62
  end
58
63
 
59
64
  def error(err)
@@ -62,75 +67,141 @@ class Responder
62
67
  end
63
68
 
64
69
 
65
- REQUEST = 0
66
- RESPONSE = 1
67
- NOTIFY = 2
70
+ class Address
71
+ # +--+----+
72
+ # | 2| 4 |
73
+ # +--+----+
74
+ # port network byte order
75
+ # IPv4 address
76
+ #
77
+ # +--+----------------+
78
+ # | 2| 16 |
79
+ # +--+----------------+
80
+ # port network byte order
81
+ # IPv6 address
82
+ #
83
+
84
+ test = Socket.pack_sockaddr_in(0,'0.0.0.0')
85
+ if test[0] == "\0"[0] || test[1] == "\0"[0]
86
+ # Linux
87
+ IMPL_LINUX = true
88
+ else
89
+ # BSD
90
+ IMPL_LINUX = false
91
+ end
92
+
93
+ def initialize(host, port)
94
+ raw = Socket.pack_sockaddr_in(port, host)
95
+ if IMPL_LINUX
96
+ family = raw.unpack('S')[0]
97
+ else
98
+ family = raw.unpack('CC')[1]
99
+ end
100
+ if family == Socket::AF_INET
101
+ @serial = raw[2,6]
102
+ elsif family == Socket::AF_INET6
103
+ @serial = raw[2,2] + raw[8,16]
104
+ else
105
+ raise "Unknown address family: #{family}"
106
+ end
107
+ end
68
108
 
109
+ def host
110
+ unpack[0]
111
+ end
69
112
 
70
- module RPCSocket
71
- def session=(s)
72
- @session = s
73
- s.add_socket(self)
113
+ def port
114
+ unpack[1]
74
115
  end
75
116
 
76
- def on_message(msg)
77
- case msg[0]
78
- when REQUEST
79
- on_request(msg[1], msg[2], msg[3])
80
- when RESPONSE
81
- on_response(msg[1], msg[2], msg[3])
82
- when NOTIFY
83
- on_notify(msg[1], msg[2])
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]
84
133
  else
85
- raise RPCError.new("unknown message type #{msg[0]}")
134
+ addr = Socket.pack_sockaddr_in(0, '::')
135
+ addr[2,2] = raw[0,2]
136
+ addr[8,16] = raw[2,16]
86
137
  end
138
+ addr
87
139
  end
88
140
 
89
- def on_close
90
- return unless @session
91
- @session.on_close(self)
92
- @session = nil
93
- rescue
94
- nil
141
+ def self.parse(raw)
142
+ Socket.unpack_sockaddr_in(parse_sockaddr(raw)).reverse
95
143
  end
96
144
 
97
- def on_request(msgid, method, param)
98
- return unless @session
99
- @session.on_request(method, param, Responder.new(self,msgid))
145
+ def self.load(raw)
146
+ Address.new *parse(raw)
100
147
  end
101
148
 
102
- def on_notify(method, param)
103
- return unless @session
104
- @session.on_notify(method, param)
149
+ def dump
150
+ @serial
105
151
  end
106
152
 
107
- def on_response(msgid, error, result)
108
- return unless @session
109
- @session.on_response(msgid, error, result)
153
+ def to_msgpack(out = '')
154
+ @serial.to_msgpack(out)
110
155
  end
111
156
 
112
- def send_request(msgid, method, param)
113
- send_message [REQUEST, msgid, method, param]
157
+ def to_s
158
+ unpack.join(':')
114
159
  end
115
160
 
116
- def send_response(msgid, result, error)
117
- send_message [RESPONSE, msgid, error, result]
161
+ def to_a
162
+ unpack
118
163
  end
119
164
 
120
- def send_notify(method, param)
121
- send_message [NOTIFY, method, param]
165
+ def inspect
166
+ "#<#{self.class} #{to_s} @serial=#{@serial.inspect}>"
167
+ end
168
+
169
+
170
+ def eql?(o)
171
+ o.class == Address && dump.eql?(o.dump)
172
+ end
173
+
174
+ def hash
175
+ dump.hash
176
+ end
177
+
178
+ def ==(o)
179
+ eql?(o)
122
180
  end
123
181
  end
124
182
 
125
183
 
126
- class RevSocket < ::Rev::TCPSocket
127
- include RPCSocket
184
+ REQUEST = 0
185
+ RESPONSE = 1
186
+ NOTIFY = 2
187
+ INIT = 3
188
+
128
189
 
129
- def initialize(*args)
190
+ class RPCSocket < Rev::TCPSocket
191
+ def initialize(sock, session)
130
192
  @buffer = ''
131
193
  @nread = 0
132
194
  @mpac = MessagePack::Unpacker.new
133
- super
195
+ @s = session
196
+ super(sock)
197
+ end
198
+
199
+ def bind_session(s)
200
+ @s = s
201
+ end
202
+
203
+ def bound?
204
+ !@s.nil?
134
205
  end
135
206
 
136
207
  def on_read(data)
@@ -155,28 +226,96 @@ class RevSocket < ::Rev::TCPSocket
155
226
  end
156
227
  end
157
228
 
229
+ def on_message(msg)
230
+ case msg[0]
231
+ when REQUEST
232
+ on_request(msg[1], msg[2], msg[3])
233
+ when RESPONSE
234
+ on_response(msg[1], msg[2], msg[3])
235
+ when NOTIFY
236
+ on_notify(msg[1], msg[2])
237
+ when INIT
238
+ on_init(msg[1])
239
+ else
240
+ raise RPCError.new("unknown message type #{msg[0]}")
241
+ end
242
+ end
243
+
244
+ def on_connect
245
+ return unless @s
246
+ @s.on_connect(self)
247
+ end
248
+
249
+ def on_connect_failed
250
+ return unless @s
251
+ @s.on_connect_failed(self)
252
+ end
253
+
254
+ def on_close
255
+ return unless @s
256
+ @s.on_close(self)
257
+ @s = nil
258
+ rescue
259
+ nil
260
+ end
261
+
262
+ def on_request(msgid, method, param)
263
+ return unless @s
264
+ @s.on_request(method, param, Responder.new(self,msgid))
265
+ end
266
+
267
+ def on_notify(method, param)
268
+ return unless @s
269
+ @s.on_notify(method, param)
270
+ end
271
+
272
+ def on_response(msgid, error, result)
273
+ return unless @s
274
+ @s.on_response(msgid, error, result)
275
+ end
276
+
277
+ def on_init(msg)
278
+ # ignore
279
+ end
280
+
158
281
  def send_message(msg)
159
282
  write msg.to_msgpack
160
283
  end
284
+
285
+ def self.pack_request(msgid, method, param)
286
+ [REQUEST, msgid, method, param].to_msgpack
287
+ end
288
+
289
+ def self.pack_response(msgid, result, error)
290
+ [RESPONSE, msgid, error, result].to_msgpack
291
+ end
292
+
293
+ def self.pack_notify(method, param)
294
+ [NOTIFY, method, param].to_msgpack
295
+ end
296
+
297
+ def self.pack_init(msg)
298
+ [INIT, msg].to_msgpack
299
+ end
161
300
  end
162
301
 
163
302
 
164
- class ClientSession
303
+ class Session
165
304
 
166
305
  class BasicRequest
167
- def initialize(session, loop)
168
- @session = session
169
- @timeout = session.timeout
306
+ def initialize(s, loop)
307
+ @s = s
308
+ @timeout = s.timeout
170
309
  @loop = loop
171
310
  end
172
311
  attr_reader :loop
173
312
 
174
313
  def call(err, res)
175
- @session = nil
314
+ @s = nil
176
315
  end
177
316
 
178
317
  def join
179
- while @session
318
+ while @s
180
319
  @loop.run_once
181
320
  end
182
321
  self
@@ -193,8 +332,8 @@ class ClientSession
193
332
  end
194
333
 
195
334
  class AsyncRequest < BasicRequest
196
- def initialize(session, loop)
197
- super(session, loop)
335
+ def initialize(s, loop)
336
+ super(s, loop)
198
337
  @error = nil
199
338
  @result = nil
200
339
  end
@@ -203,13 +342,13 @@ class ClientSession
203
342
  def call(err, res)
204
343
  @error = err
205
344
  @result = res
206
- @session = nil
345
+ @s = nil
207
346
  end
208
347
  end
209
348
 
210
349
  class CallbackRequest < BasicRequest
211
- def initialize(session, loop, block)
212
- super(session, loop)
350
+ def initialize(s, loop, block)
351
+ super(s, loop)
213
352
  @block = block
214
353
  end
215
354
 
@@ -219,89 +358,164 @@ class ClientSession
219
358
  end
220
359
 
221
360
 
222
- def initialize(loop)
223
- @sock = nil
224
- @reqtable = {}
225
- @seqid = 0
361
+ def initialize(initmsg, target_addr, dispatcher, loop)
362
+ @initmsg = initmsg
363
+ @target_addr = target_addr
364
+ @dispatcher = dispatcher || NullDispatcher.new
226
365
  @loop = loop
227
- @timeout = 60 # FIXME default timeout time
366
+ @timeout = 10 # FIXME default timeout time
367
+ @reconnect = 5 # FIXME default reconnect limit
368
+ reset
369
+ end
370
+ attr_accessor :timeout, :reconnect
371
+
372
+ def address
373
+ @target_addr
228
374
  end
229
- attr_accessor :timeout
230
375
 
231
- def add_socket(sock)
232
- @sock = sock
376
+ def on_connect(sock)
377
+ @sockpool.push(sock)
378
+ sock.write @pending
379
+ @pending = ""
380
+ @connecting = 0
233
381
  end
234
382
 
383
+ def on_connect_failed(sock)
384
+ if @connecting < @reconnect
385
+ try_connect
386
+ @connecting += 1
387
+ else
388
+ @connecting = 0
389
+ @reqtable.reject! {|msgid, req|
390
+ begin
391
+ req.call ConnectError.new, nil
392
+ rescue
393
+ end
394
+ true
395
+ }
396
+ end
397
+ end
398
+
399
+
235
400
  def send(method, *args)
236
- send_real(method, args, AsyncRequest.new(self,@loop))
401
+ msgid = send_request(method, args)
402
+ @reqtable[msgid] = AsyncRequest.new(self, @loop)
237
403
  end
238
404
 
239
405
  def callback(method, *args, &block)
240
- send_real(method, args, CallbackRequest.new(self,@loop,block))
406
+ msgid = send_request(method, args)
407
+ @reqtable[msgid] = CallbackRequest.new(self, @loop, block)
241
408
  end
242
409
 
243
410
  def call(method, *args)
411
+ # FIXME if @reqtable.empty? optimize
244
412
  req = send(method, *args)
245
413
  req.join
246
414
  if req.error
247
- raise TimeoutError.new if req.error == :TimeoutError
415
+ raise req.error if req.error.is_a?(Error)
248
416
  raise RemoteError.new(req.error, req.result)
249
417
  end
250
418
  req.result
251
419
  end
252
420
 
253
421
  def notify(method, *args)
254
- notify_real(method, args)
422
+ send_notify(method, args)
423
+ end
424
+
425
+ def close
426
+ @sockpool.reject! {|sock|
427
+ sock.detach if sock.attached?
428
+ sock.close
429
+ true
430
+ }
431
+ reset
432
+ self
433
+ end
434
+
435
+ def step_timeout
436
+ reqs = []
437
+ @reqtable.reject! {|msgid, req|
438
+ if req.step_timeout
439
+ reqs.push(req)
440
+ end
441
+ }
442
+ reqs.each {|req|
443
+ begin
444
+ req.call TimeoutError.new, nil
445
+ rescue
446
+ end
447
+ }
448
+ !@reqtable.empty?
255
449
  end
256
450
 
257
451
 
258
452
  def on_response(msgid, error, result)
259
453
  if req = @reqtable.delete(msgid)
260
- req.call error, result
454
+ req.call(error, result)
261
455
  end
262
456
  end
263
457
 
264
- def on_notify(method, param)
265
- raise RPCError.new("unexpected notify message")
266
- end
267
-
268
458
  def on_request(method, param, res)
269
- raise RPCError.new("unexpected request message")
459
+ @dispatcher.dispatch_request(self, method, param, res)
270
460
  end
271
461
 
272
- def on_close(sock)
273
- @sock = nil
462
+ def on_notify(method, param)
463
+ @dispatcher.dispatch_notify(self, method, param)
274
464
  end
275
465
 
276
- def close
277
- @sock.close if @sock
466
+ def on_close(sock)
467
+ @sockpool.delete(sock)
278
468
  end
279
469
 
280
470
 
281
- def step_timeout
282
- reqs = []
283
- @reqtable.reject! {|msgid, req|
284
- if req.step_timeout
285
- reqs.push req
286
- end
287
- }
288
- reqs.each {|req| req.call :TimeoutError, nil }
471
+ private
472
+ def reset
473
+ @sockpool = []
474
+ @reqtable = {}
475
+ @seqid = 0
476
+ @pending = ""
477
+ @connecting = 0
289
478
  end
290
479
 
291
- private
292
- def send_real(method, param, req)
480
+ def send_request(method, param)
293
481
  method = method.to_s unless method.is_a?(Integer)
294
482
  msgid = @seqid
295
483
  @seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
296
- @sock.send_request msgid, method, param
297
- @reqtable[msgid] = req
484
+ send_data RPCSocket.pack_request(msgid, method, param)
485
+ msgid
298
486
  end
299
487
 
300
- def notify_real(method, param)
488
+ def send_notify(method, param)
301
489
  method = method.to_s unless method.is_a?(Integer)
302
- @sock.send_notify method, param
490
+ send_data RPCSocket.pack_notify(method, param)
303
491
  nil
304
492
  end
493
+
494
+ def send_data(msg)
495
+ unless @target_addr
496
+ raise RPCError.new("unexpected send request on server session")
497
+ end
498
+ if @sockpool.empty?
499
+ if @connecting == 0
500
+ try_connect
501
+ @connecting = 1
502
+ end
503
+ @pending << msg
504
+ else
505
+ # FIXME pesudo connection load balance
506
+ sock = @sockpool.first
507
+ sock.write msg
508
+ end
509
+ end
510
+
511
+ def try_connect
512
+ port, host = ::Socket.unpack_sockaddr_in(@target_addr.sockaddr)
513
+ sock = RPCSocket.connect(host, port, self) # async connect
514
+ if @initmsg
515
+ sock.write @initmsg
516
+ end
517
+ @loop.attach(sock)
518
+ end
305
519
  end
306
520
 
307
521
 
@@ -338,19 +552,25 @@ class AsyncResult
338
552
  end
339
553
 
340
554
 
341
- class ServerSession
555
+ class NullDispatcher
556
+ def dispatch_request(session, method, param, res)
557
+ raise RPCError.new("unexpected request message")
558
+ end
559
+
560
+ def dispatch_notify(session, method, param)
561
+ raise RPCError.new("unexpected notify message")
562
+ end
563
+ end
564
+
565
+ class ObjectDispatcher
342
566
  def initialize(obj, accept = obj.public_methods)
343
567
  @obj = obj
344
568
  @accept = accept.map {|m| m.is_a?(Integer) ? m : m.to_s}
345
569
  end
346
570
 
347
- def add_socket(sock)
348
- # do nothing
349
- end
350
-
351
- def on_request(method, param, res)
571
+ def dispatch_request(session, method, param, res)
352
572
  begin
353
- result = forward_method(method, param)
573
+ result = forward_method(session, method, param)
354
574
  rescue
355
575
  res.error($!.to_s)
356
576
  return
@@ -362,30 +582,23 @@ class ServerSession
362
582
  end
363
583
  end
364
584
 
365
- def on_notify(method, param)
366
- forward_method(method, param)
585
+ def dispatch_notify(session, method, param)
586
+ forward_method(session, method, param)
367
587
  rescue
368
588
  end
369
589
 
370
- def on_response(msgid, error, result)
371
- raise RPCError.new("unexpected response message")
372
- end
373
-
374
- def on_close(sock)
375
- # do nothing
376
- @sock = nil
377
- end
378
-
379
590
  private
380
- def forward_method(method, param)
591
+ def forward_method(session, method, param)
381
592
  unless @accept.include?(method)
382
593
  raise NoMethodError, "method `#{method}' is not accepted"
383
594
  end
384
- @obj.send(method, *param)
595
+ @obj.send(method, *param) { session }
385
596
  end
386
597
  end
387
598
 
388
- Loop = ::Rev::Loop
599
+
600
+ Loop = Rev::Loop
601
+
389
602
 
390
603
  module LoopUtil
391
604
  attr_reader :loop
@@ -404,11 +617,42 @@ module LoopUtil
404
617
  @loop.attach Timer.new(interval, repeating, &block)
405
618
  end
406
619
 
620
+ class TaskQueue < Rev::AsyncWatcher
621
+ def initialize
622
+ @queue = []
623
+ super
624
+ end
625
+
626
+ def push(task)
627
+ @queue.push(task)
628
+ signal
629
+ end
630
+
631
+ def on_signal
632
+ while task = @queue.shift
633
+ begin
634
+ task.call
635
+ rescue
636
+ end
637
+ end
638
+ end
639
+ end
640
+
641
+ def submit(task = nil, &block)
642
+ task ||= block
643
+ unless @queue
644
+ @queue = TaskQueue.new
645
+ @loop.attach(@queue)
646
+ end
647
+ @queue.push(task)
648
+ end
649
+
407
650
  def run
408
651
  @loop.run
409
652
  end
410
653
 
411
654
  def stop
655
+ @queue.detach if @queue && @queue.attached?
412
656
  @loop.stop
413
657
  # attach dummy timer
414
658
  @loop.attach Rev::TimerWatcher.new(0, false)
@@ -417,86 +661,172 @@ module LoopUtil
417
661
  end
418
662
 
419
663
 
420
- class Client
664
+ class Client < Session
421
665
  def initialize(host, port, loop = Loop.new)
422
666
  @loop = loop
423
667
  @host = host
424
668
  @port = port
425
- @rsock = RevSocket.connect(host, port)
426
- @s = ClientSession.new(loop)
427
- @rsock.session = @s
428
- loop.attach(@rsock)
429
- @timer = Timer.new(1, true) { @s.step_timeout }
669
+
670
+ target_addr = Address.new(host, port)
671
+ super(nil, target_addr, NullDispatcher.new, loop)
672
+
673
+ @timer = Timer.new(1, true) {
674
+ step_timeout
675
+ }
430
676
  loop.attach(@timer)
431
677
  end
432
678
  attr_reader :host, :port
433
679
 
680
+ def self.open(host, port, loop = Loop.new, &block)
681
+ cli = new(host, port, loop)
682
+ begin
683
+ block.call(cli)
684
+ ensure
685
+ cli.close
686
+ end
687
+ end
688
+
434
689
  def close
435
690
  @timer.detach if @timer.attached?
436
- @rsock.detach if @rsock.attached?
437
- @s.close
438
- nil
691
+ super
439
692
  end
440
693
 
441
- def send(method, *args)
442
- @s.send(method, *args)
443
- end
694
+ include LoopUtil
695
+ end
444
696
 
445
- def callback(method, *args, &block)
446
- @s.callback(method, *args, &block)
447
- end
448
697
 
449
- def call(method, *args)
450
- @s.call(method, *args)
698
+ class SessionPool
699
+ def initialize(loop = Loop.new)
700
+ @loop = loop
701
+ @spool = {}
702
+ @stimer = Timer.new(1, true, &method(:step_timeout))
703
+ loop.attach(@stimer)
451
704
  end
452
705
 
453
- def notify(method, *args)
454
- @s.notify(method, *args)
706
+ def get_session(host, port)
707
+ target_addr = Address.new(host, port)
708
+ @spool[target_addr] ||= create_session(target_addr)
455
709
  end
456
710
 
457
- def timeout
458
- @s.timeout
711
+ def close
712
+ @spool.reject! {|target_addr, s|
713
+ s.close
714
+ true
715
+ }
716
+ @stimer.detach if @stimer.attached?
717
+ nil
459
718
  end
460
719
 
461
- def timeout=(time)
462
- @s.timeout = time
720
+ include LoopUtil
721
+
722
+ protected
723
+ def create_session(target_addr)
724
+ Session.new(nil, target_addr, nil, @loop)
463
725
  end
464
726
 
465
- include LoopUtil
727
+ private
728
+ def step_timeout
729
+ @spool.each_pair {|target_addr, s|
730
+ s.step_timeout
731
+ }
732
+ end
466
733
  end
467
734
 
468
735
 
469
- class Server
470
- class Socket < RevSocket
471
- def initialize(*args)
472
- accept = args.pop
473
- obj = args.pop
474
- self.session = ServerSession.new(obj, accept)
475
- super(*args)
736
+ class Server < SessionPool
737
+ class Socket < RPCSocket
738
+ def initialize(sock, dispatcher, loop)
739
+ s = Session.new(nil, nil, dispatcher, loop)
740
+ super(sock, s)
476
741
  end
477
742
  end
478
743
 
479
744
  def initialize(loop = Loop.new)
480
- @loop = loop
481
- @socks = []
745
+ super(loop)
746
+ @lsocks = []
482
747
  end
483
748
 
484
749
  def listen(host, port, obj, accept = obj.public_methods)
485
- lsock = ::Rev::TCPServer.new(host, port, Server::Socket, obj, accept)
486
- @socks.push lsock
750
+ dispatcher = ObjectDispatcher.new(obj, accept)
751
+ lsock = Rev::TCPServer.new(host, port, Server::Socket, dispatcher, @loop)
752
+ @lsocks.push(lsock)
487
753
  @loop.attach(lsock)
488
754
  end
489
755
 
490
756
  def close
491
- @socks.reject! {|lsock|
757
+ @lsocks.reject! {|lsock|
492
758
  lsock.detach if lsock.attached?
493
759
  lsock.close
494
760
  true
495
761
  }
496
- nil
762
+ super
763
+ end
764
+ end
765
+
766
+
767
+ class Cluster < SessionPool
768
+ class Socket < RPCSocket
769
+ def initialize(sock, binder)
770
+ @binder = binder
771
+ super(sock, nil)
772
+ end
773
+
774
+ def on_message(msg)
775
+ if bound?
776
+ super
777
+ else
778
+ @binder.call(self, msg)
779
+ end
780
+ end
781
+ end
782
+
783
+ def initialize(host, port, loop = Loop.new)
784
+ super(loop)
785
+ @host = host
786
+ @port = port
787
+ @dispatcher = nil
788
+ self_addr = Address.new(host, port)
789
+ @initmsg = RPCSocket.pack_init(self_addr)
790
+ end
791
+ attr_reader :host, :port
792
+
793
+ def serve(obj, accept = obj.public_methods)
794
+ @dispatcher = ObjectDispatcher.new(obj, accept)
795
+ @lsock = Rev::TCPServer.new(host, port, Cluster::Socket, method(:lazy_bind))
796
+ @loop.attach(@lsock)
797
+ self
798
+ end
799
+
800
+ def close
801
+ if @lsock
802
+ @lsock.detach if @lsock.attached?
803
+ @lsock.close
804
+ end
805
+ super
497
806
  end
498
807
 
499
808
  include LoopUtil
809
+
810
+ protected
811
+ def create_session(target_addr)
812
+ Session.new(@initmsg, target_addr, @dispatcher, @loop)
813
+ end
814
+
815
+ private
816
+ def lazy_bind(sock, msg)
817
+ if msg[0] == INIT
818
+ # cluster
819
+ target_addr = Address.load(msg[1])
820
+ s = Session.new(@initmsg, target_addr, @dispatcher, @loop)
821
+ sock.bind_session(s)
822
+ @spool[target_addr] = s
823
+ else
824
+ # subsys
825
+ s = Session.new(nil, nil, @dispatcher, @loop)
826
+ sock.bind_session(s)
827
+ sock.on_message(msg)
828
+ end
829
+ end
500
830
  end
501
831
 
502
832
 
@@ -211,6 +211,24 @@ class MessagePackRPCTest < Test::Unit::TestCase
211
211
  end
212
212
 
213
213
 
214
+ def test_pool
215
+ svr, cli = start_server
216
+
217
+ sp = MessagePack::RPC::SessionPool.new
218
+ s = sp.get_session('127.0.0.1', cli.port)
219
+
220
+ result = s.call(:hello)
221
+ assert_equal(result, "ok")
222
+
223
+ result = s.call(:sum, 1, 2)
224
+ assert_equal(result, 3)
225
+
226
+ sp.close
227
+ cli.close
228
+ svr.stop
229
+ end
230
+
231
+
214
232
  def test_loop
215
233
  port = next_port
216
234
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msgpack-rpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - FURUHASHI Sadayuki
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-01 00:00:00 +09:00
12
+ date: 2009-12-05 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -48,11 +48,12 @@ files:
48
48
  - Rakefile
49
49
  - test/msgpack_rpc_test.rb
50
50
  - test/test_helper.rb
51
- - lib/msgpack
52
51
  - lib/msgpack/rpc.rb
53
52
  - AUTHORS
54
- has_rdoc: false
53
+ has_rdoc: true
55
54
  homepage: http://msgpack.rubyforge.org
55
+ licenses: []
56
+
56
57
  post_install_message:
57
58
  rdoc_options:
58
59
  - --title
@@ -84,9 +85,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
85
  requirements: []
85
86
 
86
87
  rubyforge_project: msgpack
87
- rubygems_version: 1.3.1
88
+ rubygems_version: 1.3.5
88
89
  signing_key:
89
- specification_version: 2
90
+ specification_version: 3
90
91
  summary: RPC library using MessagePack, a ainary-based efficient data interchange format.
91
92
  test_files:
92
93
  - test/test_helper.rb