msgpack-rpc 0.1.4 → 0.2.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.
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