msgpack-rpc 0.2.0 → 0.3.0

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