msgpack-rpc 0.2.0 → 0.3.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 (5) hide show
  1. data/NOTICE +4 -0
  2. data/README +1 -1
  3. data/lib/msgpack/rpc.rb +904 -287
  4. metadata +14 -27
  5. data/Rakefile +0 -132
data/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ MessagePack is developed by FURUHASHI Sadayuki, licensed under Apache License,
2
+ Version 2.0. The original software and related information is available at
3
+ http://msgpack.sourceforge.jp/.
4
+
data/README CHANGED
@@ -25,5 +25,5 @@
25
25
  == Copyright
26
26
 
27
27
  Author:: frsyuki <frsyuki@users.sourceforge.jp>
28
- Copyright:: Copyright (c) 2009 frsyuki
28
+ Copyright:: Copyright (c) 2010 frsyuki
29
29
  License:: Apache License, Version 2.0
data/lib/msgpack/rpc.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # MessagePack-RPC for Ruby
3
3
  #
4
- # Copyright (C) 2009 FURUHASHI Sadayuki
4
+ # Copyright (C) 2010 FURUHASHI Sadayuki
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
17
17
  #
18
18
  require 'msgpack'
19
19
  require 'rev'
20
+ require 'zlib'
20
21
 
21
22
  module MessagePack
22
23
  module RPC
@@ -51,20 +52,15 @@ class ConnectError < TimeoutError
51
52
  end
52
53
  end
53
54
 
54
- class Responder
55
- def initialize(socket, msgid)
56
- @socket = socket
57
- @msgid = msgid
58
- end
59
-
60
- def result(retval, err = nil)
61
- @socket.write RPCSocket.pack_response(@msgid, retval, err)
62
- end
63
55
 
64
- def error(err)
65
- result(nil, err)
66
- end
67
- end
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
68
64
 
69
65
 
70
66
  class Address
@@ -84,25 +80,29 @@ class Address
84
80
  test = Socket.pack_sockaddr_in(0,'0.0.0.0')
85
81
  if test[0] == "\0"[0] || test[1] == "\0"[0]
86
82
  # Linux
87
- IMPL_LINUX = true
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
88
94
  else
89
95
  # 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
96
+ def initialize(host, port)
97
+ raw = Socket.pack_sockaddr_in(port, host)
98
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}"
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
106
  end
107
107
  end
108
108
 
@@ -166,7 +166,6 @@ class Address
166
166
  "#<#{self.class} #{to_s} @serial=#{@serial.inspect}>"
167
167
  end
168
168
 
169
-
170
169
  def eql?(o)
171
170
  o.class == Address && dump.eql?(o.dump)
172
171
  end
@@ -181,235 +180,262 @@ class Address
181
180
  end
182
181
 
183
182
 
184
- REQUEST = 0
185
- RESPONSE = 1
186
- NOTIFY = 2
187
- INIT = 3
188
-
189
-
190
- class RPCSocket < Rev::TCPSocket
191
- def initialize(sock, session)
192
- @buffer = ''
193
- @nread = 0
194
- @mpac = MessagePack::Unpacker.new
195
- @s = session
196
- super(sock)
197
- end
198
-
199
- def bind_session(s)
183
+ class Future
184
+ def initialize(s, loop, block = nil)
200
185
  @s = s
186
+ @timeout = s.timeout
187
+ @loop = loop
188
+ @block = block
189
+ @error = nil
190
+ @result = nil
201
191
  end
192
+ attr_reader :loop
193
+ attr_accessor :result, :error
202
194
 
203
- def bound?
204
- !@s.nil?
195
+ def attach_callback(proc = nil, &block)
196
+ @block = proc || block
205
197
  end
206
198
 
207
- def on_read(data)
208
- @buffer << data
209
-
210
- while true
211
- @nread = @mpac.execute(@buffer, @nread)
212
-
213
- if @mpac.finished?
214
- msg = @mpac.data
215
-
216
- @mpac.reset
217
- @buffer.slice!(0, @nread)
218
- @nread = 0
219
-
220
- on_message(msg) # RPCSocket#on_message
221
-
222
- next unless @buffer.empty?
223
- end
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
224
207
 
225
- break
208
+ def join
209
+ while @s
210
+ @loop.run_once
226
211
  end
212
+ self
227
213
  end
228
214
 
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])
215
+ def step_timeout
216
+ if @timeout < 1
217
+ true
239
218
  else
240
- raise RPCError.new("unknown message type #{msg[0]}")
219
+ @timeout -= 1
220
+ false
241
221
  end
242
222
  end
223
+ end
243
224
 
244
- def on_connect
245
- return unless @s
246
- @s.on_connect(self)
247
- end
248
225
 
249
- def on_connect_failed
250
- return unless @s
251
- @s.on_connect_failed(self)
226
+ class Responder
227
+ def initialize(tran, msgid)
228
+ @tran = tran # send_message method is required
229
+ @msgid = msgid
252
230
  end
253
231
 
254
- def on_close
255
- return unless @s
256
- @s.on_close(self)
257
- @s = nil
258
- rescue
259
- nil
232
+ def result(retval, err = nil)
233
+ @tran.send_message [RESPONSE, @msgid, err, retval]
260
234
  end
261
235
 
262
- def on_request(msgid, method, param)
263
- return unless @s
264
- @s.on_request(method, param, Responder.new(self,msgid))
236
+ def error(err, retval = nil)
237
+ result(retval, err)
265
238
  end
239
+ end
266
240
 
267
- def on_notify(method, param)
268
- return unless @s
269
- @s.on_notify(method, param)
241
+
242
+ class ExchangeOption
243
+ def initialize(flags = 0)
244
+ @flags = flags
270
245
  end
271
246
 
272
- def on_response(msgid, error, result)
273
- return unless @s
274
- @s.on_response(msgid, error, result)
247
+ def get
248
+ @flags
275
249
  end
276
250
 
277
- def on_init(msg)
278
- # ignore
251
+ def deflate=(val)
252
+ val ? (@flags |= OPT_DEFLATE) : (@flags &= ~OPT_DEFLATE)
279
253
  end
280
254
 
281
- def send_message(msg)
282
- write msg.to_msgpack
255
+ def deflate?
256
+ @flags & OPT_DEFLATE != 0
283
257
  end
284
258
 
285
- def self.pack_request(msgid, method, param)
286
- [REQUEST, msgid, method, param].to_msgpack
259
+ def reset
260
+ @flags = 0
261
+ self
287
262
  end
288
263
 
289
- def self.pack_response(msgid, result, error)
290
- [RESPONSE, msgid, error, result].to_msgpack
264
+ def ==(o)
265
+ @flags == o.get
291
266
  end
292
267
 
293
- def self.pack_notify(method, param)
294
- [NOTIFY, method, param].to_msgpack
268
+ def to_msgpack(out = '')
269
+ @flags.to_msgpack(out)
295
270
  end
296
271
 
297
- def self.pack_init(msg)
298
- [INIT, msg].to_msgpack
272
+ def self.from_msgpack(obj)
273
+ @flags = obj
299
274
  end
300
275
  end
301
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
302
285
 
303
- class Session
286
+ def default?
287
+ @txopt.get == 0 && @rxopt.get == 0 && @rxproto.nil?
288
+ end
304
289
 
305
- class BasicRequest
306
- def initialize(s, loop)
307
- @s = s
308
- @timeout = s.timeout
309
- @loop = loop
310
- end
311
- attr_reader :loop
290
+ def reset
291
+ @txopt.reset
292
+ @rxopt.reset
293
+ #@rxproto = nil
294
+ #@rxaddr = nil
295
+ self
296
+ end
312
297
 
313
- def call(err, res)
314
- @s = nil
315
- end
298
+ def ==(o)
299
+ @txopt == o.txopt && @rxopt == o.rxopt # &&
300
+ #@rxproto == o.rxproto && @rxaddr == o.rxaddr
301
+ end
316
302
 
317
- def join
318
- while @s
319
- @loop.run_once
320
- end
321
- self
322
- end
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
323
326
 
324
- def step_timeout
325
- if @timeout < 1
326
- true
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
327
355
  else
328
- @timeout -= 1
329
- false
356
+ raise "unknown option #{x.inspect}"
330
357
  end
331
358
  end
332
359
  end
360
+ #attr_accessor :proto, :address
333
361
 
334
- class AsyncRequest < BasicRequest
335
- def initialize(s, loop)
336
- super(s, loop)
337
- @error = nil
338
- @result = nil
339
- end
340
- attr_accessor :result, :error
362
+ def reset
363
+ #@proto = PROTO_TCP
364
+ @address = nil
365
+ super
366
+ end
341
367
 
342
- def call(err, res)
343
- @error = err
344
- @result = res
345
- @s = nil
346
- end
368
+ def ==(o)
369
+ super(o) # && @proto = o.proto && @address = o.address
347
370
  end
348
371
 
349
- class CallbackRequest < BasicRequest
350
- def initialize(s, loop, block)
351
- super(s, loop)
352
- @block = block
353
- end
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
354
375
 
355
- def call(err, res)
356
- @block.call(err, res)
357
- end
358
- end
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
359
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
360
384
 
361
- def initialize(initmsg, target_addr, dispatcher, loop)
362
- @initmsg = initmsg
363
- @target_addr = target_addr
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
364
390
  @dispatcher = dispatcher || NullDispatcher.new
391
+ @dtopt = dtopt # default transport option
392
+ @dtran = create_transport(@dtopt) # default transport
365
393
  @loop = loop
394
+ @trans = []
395
+ @reqtable = {}
366
396
  @timeout = 10 # FIXME default timeout time
367
- @reconnect = 5 # FIXME default reconnect limit
368
397
  reset
369
398
  end
370
- attr_accessor :timeout, :reconnect
399
+ attr_reader :address, :self_address, :loop
400
+ attr_accessor :timeout
371
401
 
372
- def address
373
- @target_addr
402
+ def send(method, *args)
403
+ send_over(nil, method, *args)
374
404
  end
375
405
 
376
- def on_connect(sock)
377
- @sockpool.push(sock)
378
- sock.write @pending
379
- @pending = ""
380
- @connecting = 0
406
+ def callback(method, *args, &block)
407
+ callback_over(nil, method, *args, &block)
381
408
  end
382
409
 
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
410
+ def call(method, *args)
411
+ call_over(nil, method, *args)
397
412
  end
398
413
 
414
+ def notify(method, *args)
415
+ notify_over(nil, method, *args)
416
+ end
399
417
 
400
- def send(method, *args)
401
- msgid = send_request(method, args)
402
- @reqtable[msgid] = AsyncRequest.new(self, @loop)
418
+ def over(*args)
419
+ Over.new(self, TransportOption.new(*args))
403
420
  end
404
421
 
405
- def callback(method, *args, &block)
406
- msgid = send_request(method, args)
407
- @reqtable[msgid] = CallbackRequest.new(self, @loop, block)
422
+ def default_option
423
+ @dtopt.dup
408
424
  end
409
425
 
410
- def call(method, *args)
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)
411
437
  # FIXME if @reqtable.empty? optimize
412
- req = send(method, *args)
438
+ req = send_over(topt, method, *args)
413
439
  req.join
414
440
  if req.error
415
441
  raise req.error if req.error.is_a?(Error)
@@ -418,16 +444,17 @@ class Session
418
444
  req.result
419
445
  end
420
446
 
421
- def notify(method, *args)
422
- send_notify(method, args)
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)
423
453
  end
424
454
 
425
455
  def close
426
- @sockpool.reject! {|sock|
427
- sock.detach if sock.attached?
428
- sock.close
429
- true
430
- }
456
+ @dtran.close
457
+ @trans.each {|tran| tran.close }
431
458
  reset
432
459
  self
433
460
  end
@@ -448,18 +475,116 @@ class Session
448
475
  !@reqtable.empty?
449
476
  end
450
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
451
569
 
452
- def on_response(msgid, error, result)
570
+ def on_response(sock, msgid, error, result)
453
571
  if req = @reqtable.delete(msgid)
454
572
  req.call(error, result)
455
573
  end
456
574
  end
457
575
 
458
- def on_request(method, param, res)
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)
459
584
  @dispatcher.dispatch_request(self, method, param, res)
460
585
  end
461
586
 
462
- def on_notify(method, param)
587
+ def on_notify(sock, method, param)
463
588
  @dispatcher.dispatch_notify(self, method, param)
464
589
  end
465
590
 
@@ -467,57 +592,513 @@ class Session
467
592
  @sockpool.delete(sock)
468
593
  end
469
594
 
470
-
471
- private
472
595
  def reset
473
- @sockpool = []
474
596
  @reqtable = {}
475
597
  @seqid = 0
476
- @pending = ""
477
- @connecting = 0
478
598
  end
599
+ end
479
600
 
480
- def send_request(method, param)
481
- method = method.to_s unless method.is_a?(Integer)
482
- msgid = @seqid
483
- @seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
484
- send_data RPCSocket.pack_request(msgid, method, param)
485
- msgid
601
+
602
+ class BasicTransport
603
+ def initialize(session, topt)
604
+ @session = session
605
+ @option = topt
486
606
  end
487
607
 
488
- def send_notify(method, param)
489
- method = method.to_s unless method.is_a?(Integer)
490
- send_data RPCSocket.pack_notify(method, param)
491
- nil
608
+ def match?(topt)
609
+ @option == topt
492
610
  end
493
611
 
494
- def send_data(msg)
495
- unless @target_addr
496
- raise RPCError.new("unexpected send request on server session")
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
497
643
  end
644
+ end
645
+
646
+ def send_message(msg) # Transport interface
498
647
  if @sockpool.empty?
499
648
  if @connecting == 0
500
649
  try_connect
501
650
  @connecting = 1
502
651
  end
503
- @pending << msg
652
+ if @deflate
653
+ @pending << @deflate.deflate(msg.to_msgpack, Zlib::SYNC_FLUSH)
654
+ else
655
+ @pending << msg.to_msgpack
656
+ end
504
657
  else
505
658
  # FIXME pesudo connection load balance
506
659
  sock = @sockpool.first
507
- sock.write msg
660
+ sock.send_message(msg)
508
661
  end
509
662
  end
510
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
511
701
  def try_connect
512
- port, host = ::Socket.unpack_sockaddr_in(@target_addr.sockaddr)
513
- sock = RPCSocket.connect(host, port, self) # async 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
514
708
  if @initmsg
515
709
  sock.write @initmsg
516
710
  end
517
- @loop.attach(sock)
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
518
813
  end
519
814
  end
520
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
+
521
1102
 
522
1103
  class AsyncResult
523
1104
  def initialize
@@ -662,13 +1243,13 @@ end
662
1243
 
663
1244
 
664
1245
  class Client < Session
665
- def initialize(host, port, loop = Loop.new)
1246
+ def initialize(host, port, loop = Loop.new, dtopt = TransportOption.new)
666
1247
  @loop = loop
667
1248
  @host = host
668
1249
  @port = port
669
1250
 
670
- target_addr = Address.new(host, port)
671
- super(nil, target_addr, NullDispatcher.new, loop)
1251
+ addr = Address.new(host, port)
1252
+ super(addr, dtopt, NullDispatcher.new, nil, loop)
672
1253
 
673
1254
  @timer = Timer.new(1, true) {
674
1255
  step_timeout
@@ -677,8 +1258,8 @@ class Client < Session
677
1258
  end
678
1259
  attr_reader :host, :port
679
1260
 
680
- def self.open(host, port, loop = Loop.new, &block)
681
- cli = new(host, port, loop)
1261
+ def self.open(host, port, loop = Loop.new, dtopt = TransportOption.new, &block)
1262
+ cli = new(host, port, loop, dtopt)
682
1263
  begin
683
1264
  block.call(cli)
684
1265
  ensure
@@ -696,20 +1277,25 @@ end
696
1277
 
697
1278
 
698
1279
  class SessionPool
699
- def initialize(loop = Loop.new)
1280
+ def initialize(loop = Loop.new, dtopt = TransportOption.new)
700
1281
  @loop = loop
701
1282
  @spool = {}
702
1283
  @stimer = Timer.new(1, true, &method(:step_timeout))
1284
+ @dtopt = dtopt
703
1285
  loop.attach(@stimer)
704
1286
  end
705
1287
 
706
1288
  def get_session(host, port)
707
- target_addr = Address.new(host, port)
708
- @spool[target_addr] ||= create_session(target_addr)
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)
709
1295
  end
710
1296
 
711
1297
  def close
712
- @spool.reject! {|target_addr, s|
1298
+ @spool.reject! {|addr, s|
713
1299
  s.close
714
1300
  true
715
1301
  }
@@ -720,13 +1306,13 @@ class SessionPool
720
1306
  include LoopUtil
721
1307
 
722
1308
  protected
723
- def create_session(target_addr)
724
- Session.new(nil, target_addr, nil, @loop)
1309
+ def create_session(addr)
1310
+ Session.new(addr, @dtopt, nil, nil, @loop)
725
1311
  end
726
1312
 
727
1313
  private
728
1314
  def step_timeout
729
- @spool.each_pair {|target_addr, s|
1315
+ @spool.each_pair {|addr, s|
730
1316
  s.step_timeout
731
1317
  }
732
1318
  end
@@ -734,66 +1320,86 @@ end
734
1320
 
735
1321
 
736
1322
  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)
741
- end
1323
+ def initialize(loop = Loop.new)
1324
+ super(loop, TransportOption.new)
1325
+ @dispatcher = nil
1326
+ @listeners = []
742
1327
  end
743
1328
 
744
- def initialize(loop = Loop.new)
745
- super(loop)
746
- @lsocks = []
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
747
1339
  end
748
1340
 
749
- def listen(host, port, obj, accept = obj.public_methods)
750
- dispatcher = ObjectDispatcher.new(obj, accept)
751
- lsock = Rev::TCPServer.new(host, port, Server::Socket, dispatcher, @loop)
752
- @lsocks.push(lsock)
753
- @loop.attach(lsock)
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
754
1355
  end
755
1356
 
756
1357
  def close
757
- @lsocks.reject! {|lsock|
758
- lsock.detach if lsock.attached?
759
- lsock.close
1358
+ @listeners.reject! {|listener|
1359
+ listener.close
760
1360
  true
761
1361
  }
762
1362
  super
763
1363
  end
1364
+
1365
+ protected
1366
+ def create_session(addr)
1367
+ Session.new(addr, @dtopt, @dispatcher, nil, @loop)
1368
+ end
764
1369
  end
765
1370
 
766
1371
 
767
1372
  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)
1373
+ def initialize(host, port, loop = Loop.new, dtopt = TransportOption.new)
1374
+ super(loop, dtopt)
785
1375
  @host = host
786
1376
  @port = port
787
1377
  @dispatcher = nil
788
- self_addr = Address.new(host, port)
789
- @initmsg = RPCSocket.pack_init(self_addr)
1378
+ @self_addr = Address.new(host, port)
1379
+ @listeners = []
1380
+ listen(host, port) # FIXME obsolete?
790
1381
  end
791
1382
  attr_reader :host, :port
792
1383
 
793
1384
  def serve(obj, accept = obj.public_methods)
794
1385
  @dispatcher = ObjectDispatcher.new(obj, accept)
795
- @lsock = Rev::TCPServer.new(host, port, Cluster::Socket, method(:lazy_bind))
796
- @loop.attach(@lsock)
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)
797
1403
  self
798
1404
  end
799
1405
 
@@ -808,28 +1414,39 @@ class Cluster < SessionPool
808
1414
  include LoopUtil
809
1415
 
810
1416
  protected
811
- def create_session(target_addr)
812
- Session.new(@initmsg, target_addr, @dispatcher, @loop)
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)
813
1425
  end
814
1426
 
815
1427
  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)
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
828
1445
  end
829
1446
  end
830
1447
  end
831
1448
 
832
1449
 
833
- end # module RPC
834
- end # module MessagePack
1450
+ end
1451
+ end
835
1452