emdrb 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.
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.3.0 / 2009-01-27
2
+
3
+ * Added provisions for DRb servers to have methods which are
4
+ aware of EventMachine.
5
+ * Made internal changes so that other transports can be more easily supported.
6
+ * Unix domain socket transport added.
7
+ * Connection closing and stop_service are made to work.
8
+ * Added support for standard DRb ACLs.
9
+
1
10
  == 0.2.0 / 2009-01-23
2
11
 
3
12
  * DRb client implementation, including asynchronous calls.
data/Manifest.txt CHANGED
@@ -6,6 +6,7 @@ README.txt
6
6
  Rakefile
7
7
  lib/emdrb.rb
8
8
  lib/emdrb/emdrb.rb
9
+ lib/emdrb/unix.rb
9
10
  lib/emdrb/version.rb
10
11
  spec/client_spec.rb
11
12
  spec/drbserver.rb
data/README.txt CHANGED
@@ -16,25 +16,35 @@ that uses traditional Ruby sockets. This should at the very least
16
16
  play better with other programs that have an EventMachine event loop,
17
17
  and hopefully provide somewhat better scalability.
18
18
 
19
- Obviously, this is a quick and dirty release, just to get something
20
- out there, and of course it has a number of limitations:
19
+ EMDRb already supports the following features of the standard DRb:
21
20
 
22
- * No SSL support.
23
- * No support for ACLs.
24
- * No support for DRb over Unix domain sockets.
21
+ * Clients and servers over TCP/IP
22
+ * Clients and servers over Unix domain sockets
23
+ * Standard distributed Ruby ACLs
24
+
25
+ It also has the following extensions, which derive from its basis in
26
+ EventMachine:
27
+
28
+ * Client-side asynchronous method calls
29
+ * EventMachine-aware server methods capable of asynchrony.
30
+
31
+ It is, however, not yet a complete replacement for the standard DRb:
32
+
33
+ * No SSL support. To support this fully, EventMachine needs to have
34
+ more comprehensive SSL/TLS support.
25
35
  * RSpec tests are very basic, and need a lot more comprehensive work.
26
36
  * Many standard configuration options for DRb still unsupported
27
37
 
28
38
  These and many other problems are scheduled to be addressed in the
29
- next release.
39
+ following releases.
30
40
 
31
41
  == SYNOPSIS:
32
42
 
33
- EMDRb basically reopens several classes and adds methods and overrides
34
- some methods in the basic distributed Ruby implementation to make it
35
- use EventMachine's infrastructure instead of the normal networking
36
- layer. One could do the following, which is practically identical to
37
- one of the examples for distributed Ruby:
43
+ EMDRb basically reopens several classes, adds methods, and overrides other
44
+ methods in the basic distributed Ruby implementation to make it use
45
+ EventMachine's infrastructure instead of the traditional Ruby networking
46
+ code. One could do the following, which is practically identical to one
47
+ of the examples for distributed Ruby:
38
48
 
39
49
  require 'emdrb'
40
50
 
@@ -96,5 +106,5 @@ Copyright © 2008, 2009 Rafael R. Sevilla. You can redistribute it
96
106
  and/or modify it under the same terms as Ruby. Please see the file
97
107
  COPYING for more details.
98
108
 
99
- $Id: README.txt 63 2009-01-23 09:15:55Z dido $
109
+ $Id: README.txt 81 2009-01-29 04:46:14Z dido $
100
110
 
data/lib/emdrb/emdrb.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # Homepage:: http://emdrb.rubyforge.org/
5
5
  # License:: GNU General Public License / Ruby License
6
6
  #
7
- # $Id: emdrb.rb 49 2009-01-23 08:51:47Z dido $
7
+ # $Id: emdrb.rb 78 2009-01-29 04:21:25Z dido $
8
8
  #
9
9
  #----------------------------------------------------------------------------
10
10
  #
@@ -28,6 +28,44 @@ module DRb
28
28
  DEFAULT_LOAD_LIMIT = 256 * 102400
29
29
  DEFAULT_SAFE_LEVEL = 0
30
30
 
31
+ ##
32
+ # The DRbEMSafe module allows the designation of certain methods as
33
+ # 'deferrable methods' which are run from within the event loop rather
34
+ # than within a thread. It gives one the ability to circumvent the
35
+ # sugaring and black magic that EMDRb does in order to provide the
36
+ # complete illusion that remote objects are the same as local ones,
37
+ # most especially with respect to blocks. This may also provide more
38
+ # performance if one is using a method that itself makes use of
39
+ # Deferrables to accomplish the job.
40
+ #
41
+ module DRbEMSafe
42
+ module ClassMethods
43
+ ##
44
+ # Mark the method as a deferrable method. Such a method must
45
+ # accept two arguments, an array of parameters and a block
46
+ # (usually nil). The method must always return a Deferrable
47
+ # which should be set to success with the result of the method
48
+ # when the method is done, and failed with the exception object
49
+ # if the method failed. The block, if any, is a DRbObject that
50
+ # should be invoked by send_async(:call). Using a direct call
51
+ # on the DRbObject will most likely result in a threading
52
+ # deadlock since deferrable methods are invoked from the main
53
+ # thread!
54
+ def deferrable_method(method_name)
55
+ @deferrable_methods ||= {}
56
+ @deferrable_methods[method_name] = true
57
+ end
58
+
59
+ def deferrable_method?(method_name)
60
+ return(@deferrable_methods.has_key?(method_name))
61
+ end
62
+ end
63
+
64
+ def self.included(base)
65
+ base.extend(ClassMethods)
66
+ end
67
+ end
68
+
31
69
  ##
32
70
  # Common protocol elements for distributed Ruby, used by both the
33
71
  # client and server.
@@ -132,6 +170,11 @@ module DRb
132
170
  # The safe level for this connection.
133
171
  attr_accessor :safe_level
134
172
 
173
+ ##
174
+ # The peer address for this connection.
175
+ attr_accessor :peer_addr
176
+
177
+
135
178
  ##
136
179
  # The post initialization process sets up the default load
137
180
  # and argument length limits, the idconv object, the initial
@@ -145,7 +188,7 @@ module DRb
145
188
  @state = :ref
146
189
  @msgbuffer = ""
147
190
  @request = {}
148
- @server = @argv = @argc = nil
191
+ @peer_addr = @server = @argv = @argc = nil
149
192
  end
150
193
 
151
194
  private
@@ -188,7 +231,6 @@ module DRb
188
231
  end
189
232
  end
190
233
  rescue
191
- p $!
192
234
  EventMachine::next_tick do
193
235
  df.set_deferred_status(:failed, $!)
194
236
  end
@@ -265,6 +307,14 @@ module DRb
265
307
  #
266
308
  def perform
267
309
  @server.check_insecure_method(@request[:ro], @request[:msg])
310
+ if @request[:ro].kind_of?(DRbEMSafe) &&
311
+ @request[:ro].class.deferrable_method?(@request[:msg])
312
+ # A deferrable method will return an actual Deferrable that we
313
+ # can use instead.
314
+ return(@request[:ro].__send__(@request[:msg],
315
+ @request[:argv],
316
+ @request[:block]))
317
+ end
268
318
  return((@request[:block]) ? perform_with_block : perform_without_block)
269
319
  end
270
320
 
@@ -346,6 +396,210 @@ module DRb
346
396
 
347
397
  end
348
398
 
399
+ ##
400
+ # The default DRb transport, which performs communication over a TCP
401
+ # socket. These protocol objects are used in a different way from the
402
+ # way they are used internally by the standard DRb. In the standard
403
+ # DRb, open_server is a class method. Here, it is an instance method
404
+ # that is called when the server object is started.
405
+ class DRbTCPSocket
406
+ private
407
+
408
+ def self.host_inaddr_any(host)
409
+ infos = Socket::getaddrinfo(host, nil,
410
+ Socket::AF_UNSPEC,
411
+ Socket::SOCK_STREAM,
412
+ 0,
413
+ Socket::AI_PASSIVE)
414
+ family = infos.collect { |af, *_| af }.uniq
415
+ case family
416
+ when ['AF_INET']
417
+ return("0.0.0.0")
418
+ when ['AF_INET6']
419
+ return("::")
420
+ else
421
+ raise "Unknown network class"
422
+ end
423
+ end
424
+
425
+ public
426
+
427
+ attr_reader :uri
428
+ attr_reader :option
429
+
430
+ def initialize(uri, config={})
431
+ @uri = (uri.nil?) ? 'druby://:0' : uri
432
+ @host, @port, @option = self.class.parse_uri(@uri)
433
+ @host.untaint
434
+ @port.untaint
435
+ @config = config
436
+ @acl = config[:tcp_acl]
437
+ if @host.size == 0
438
+ @host = self.class.getservername
439
+ @connhost = self.class.host_inaddr_any(@host)
440
+ end
441
+ end
442
+
443
+ ##
444
+ # This method starts a TCP server using EventMachine.
445
+ def start_server(prot)
446
+ # If start_server is called several times, only the one started
447
+ # server will be made.
448
+ if @conndesc
449
+ return(@conndesc)
450
+ end
451
+ @conndesc = EventMachine::start_server(@host, @port, prot) do |conn|
452
+ # Obtain the address of the peer, and check it against
453
+ # any ACLs that might have been specified.
454
+ peeraddr = Socket.unpack_sockaddr_in(conn.get_peername)[1]
455
+ @config[:reverse_dns] = true
456
+ if @config[:reverse_dns]
457
+ a = Socket.gethostbyname(peeraddr)
458
+ peeraddr = begin
459
+ [Socket.gethostbyaddr(a[3], a[2])[0], peeraddr]
460
+ rescue
461
+ [nil, peeraddr]
462
+ end
463
+ else
464
+ peeraddr = [nil, peeraddr]
465
+ end
466
+ conn.peer_addr = [nil, nil] + peeraddr
467
+
468
+ if block_given?
469
+ yield conn
470
+ end
471
+
472
+ if @acl && !@acl.allow_addr?(conn.peer_addr)
473
+ conn.close_connection
474
+ end
475
+
476
+ end
477
+ # NOTE: This is an undocumented method in EventMachine. Revise
478
+ # as necessary when we receive feedback from the EventMachine
479
+ # developers on the canonical way to determine the real port number
480
+ # if port 0 was specified in start_server.
481
+ addr = Socket.unpack_sockaddr_in(EventMachine.get_sockname(@conndesc))
482
+ @port = addr[0] if @port == 0
483
+ @uri = "druby://#{@host}:#{@port}"
484
+ return(@conndesc)
485
+ end
486
+
487
+ ##
488
+ # This method makes a client connection using EventMachine
489
+ def client_connect(prot)
490
+ EventMachine.connect(@host, @port, prot) do |c|
491
+ if block_given?
492
+ yield c
493
+ end
494
+ end
495
+ end
496
+
497
+
498
+ ##
499
+ # This method closes a server that has been started using this
500
+ # protocol object instance.
501
+ def stop_server
502
+ if @conndesc
503
+ @conndesc = nil
504
+ if EventMachine::reactor_running?
505
+ EventMachine::stop_server(@conndesc)
506
+ end
507
+ end
508
+ end
509
+ end
510
+
511
+ ##
512
+ # Module managing the underlying network transport(s) used by EMDRb.
513
+ # This is analogous to the DRbProtocol module used by the original
514
+ # DRb. The network transport classes must define the following
515
+ # class method:
516
+ #
517
+ # [uri_option(uri, config)] Take a URI, possibly containing an option
518
+ # component (e.g. a trailing '?param=val'),
519
+ # and return a [uri, option] tuple.
520
+ #
521
+ # A network transport class is instantiated whenever an EMDRb client
522
+ # or server starts operation, provided with the URI and any configuration
523
+ # options. The transport initialize method should raise a DRbBadScheme
524
+ # exception if the URI is invalid. This is how the DRbTransport module
525
+ # determines which transport implementation serves a particular URI.
526
+ #
527
+ # The transport class instance must provide the following methods:
528
+ #
529
+ # [start_server(prot)] Open a server listening at the URI specified when
530
+ # the transport instance was created using the
531
+ # protocol handler module or class +prot+. A block
532
+ # passed here will be called whenever a connection is
533
+ # made to the server, just after the post_init method
534
+ # of the handler is called.
535
+ # [client_connect(prot)] Open a client connection to the URI specified when
536
+ # the when the transport instance was created, using
537
+ # the protocol handler module or class +prot+. A
538
+ # block passed here will be called when the
539
+ # connection has been initiated, just after the
540
+ # post_init method of the handler is called.
541
+ # [stop_server] Stop a server that was started with start_server.
542
+ #
543
+ module DRbTransport
544
+ @transports = [DRbTCPSocket]
545
+
546
+ def add_transport(tr)
547
+ @transports.push(tr)
548
+ end
549
+ module_function :add_transport
550
+
551
+ ##
552
+ # Rather than open_server, EMDRb uses this protocol factory method
553
+ # to create a protocol object instance that DRbServer and DRbClient
554
+ # can use later on when they want to connect.
555
+ def factory(uri, config, first=true)
556
+ @transports.each do |t|
557
+ begin
558
+ return(t.new(uri, config))
559
+ rescue DRbBadScheme
560
+ end
561
+ end
562
+ if first && (config[:auto_load] != false)
563
+ auto_load(uri, config)
564
+ return factory(uri, config, false)
565
+ end
566
+ raise DRbBadURI, 'can\'t parse uri:' + uri
567
+ end
568
+ module_function :factory
569
+
570
+ ##
571
+ # Parse +uri+ into a [uri, option] pair.
572
+ #
573
+ # The DRbTransport module asks each registered transport class in turn to
574
+ # try to parse the URI. Each transport signals that it does not handle
575
+ # that URI by raising a DRbBadScheme error. If no transport recognizes
576
+ # the URI, then a DRbBadURI error is raised.
577
+ def uri_option(uri, config, first=true)
578
+ @transports.each do |t|
579
+ begin
580
+ uri, opt = t.uri_option(uri, config)
581
+ # opt = nil if opt == ''
582
+ return uri, opt
583
+ rescue DRbBadScheme
584
+ end
585
+ end
586
+ if first && (config[:auto_load] != false)
587
+ auto_load(uri, config)
588
+ return uri_option(uri, config, false)
589
+ end
590
+ raise DRbBadURI, 'can\'t parse uri:' + uri
591
+ end
592
+ module_function :uri_option
593
+
594
+ def auto_load(uri, config) # :nodoc:
595
+ if uri =~ /^drb([a-z0-9]+):/
596
+ require("emdrb/#{$1}") rescue nil
597
+ end
598
+ end
599
+ module_function :auto_load
600
+
601
+ end
602
+
349
603
  ##
350
604
  # Class representing a drb server instance. This subclasses DRb::DRbServer
351
605
  # for brevity. DRbServer instances are normally created indirectly using
@@ -362,8 +616,8 @@ module DRb
362
616
  }
363
617
  end
364
618
 
365
- @uri = (uri.nil?) ? "druby://:0" : uri
366
619
  @config = self.class.make_config(config)
620
+ @protocol = DRbTransport.factory(uri, config)
367
621
  @front = front
368
622
  @idconv = @config[:idconv]
369
623
  @safe_level = @config[:safe_level]
@@ -372,43 +626,12 @@ module DRb
372
626
  end
373
627
  end
374
628
 
375
- private
376
-
377
- def self.host_inaddr_any
378
- host = Socket::gethostname
379
- begin
380
- host = Socket::gethostbyname(host)[0]
381
- rescue
382
- host = "localhost"
383
- end
384
- infos = Socket::getaddrinfo(host, nil,
385
- Socket::AF_UNSPEC,
386
- Socket::SOCK_STREAM,
387
- 0,
388
- Socket::AI_PASSIVE)
389
- family = infos.collect { |af, *_| af }.uniq
390
- case family
391
- when ['AF_INET']
392
- return("0.0.0.0")
393
- when ['AF_INET6']
394
- return("::")
395
- else
396
- raise "Unknown network class"
397
- end
398
- end
399
-
400
- public
401
-
402
629
  ##
403
630
  # Start a DRb server from within an event loop.
404
631
  #
405
632
  def start_drb_server
406
633
  @thread = Thread.current
407
- host, port, opt = DRb::parse_uri_drb(@uri)
408
- if host.size == 0
409
- host = self.class.host_inaddr_any
410
- end
411
- r = EventMachine::start_server(host, port, DRbServerProtocol) do |conn|
634
+ @protocol.start_server(DRbServerProtocol) do |conn|
412
635
  Thread.current['DRb'] = { 'client' => conn, 'server' => self }
413
636
  conn.front = @front
414
637
  conn.load_limit = @config[:load_limit]
@@ -417,31 +640,22 @@ module DRb
417
640
  conn.server = self
418
641
  conn.safe_level = self.safe_level
419
642
  end
420
- # NOTE: This is an undocumented method in EventMachine. Revise
421
- # as necessary when we receive feedback from the EventMachine
422
- # developers on the canonical way to determine the real port number
423
- # if port 0 was specified in start_server.
424
- addr = Socket.unpack_sockaddr_in(EventMachine.get_sockname(r))
425
- port = addr[0] if port == 0
426
- @uri = "druby://#{host}:#{port}"
643
+ @uri = @protocol.uri
427
644
  end
428
645
 
429
- end
430
-
431
- def parse_uri_drb(uri)
432
- if uri =~ /^druby:\/\/(.*?):(\d+)(\?(.*))?$/
433
- host = $1
434
- port = $2.to_i
435
- option = $4
436
- [host, port, option]
437
- else
438
- unless uri =~ /^druby:/
439
- raise DRb::DRbBadScheme.new(uri)
646
+ ##
647
+ # Stop this server.
648
+ def stop_service
649
+ DRb.remove_server(self)
650
+ if Thread.current['DRb'] && Thread.current['DRb']['server'] == self
651
+ Thread.current['DRb']['stop_service'] = true
652
+ else
653
+ @thread.kill
440
654
  end
441
- raise DRb::DRbBadURI.new('can\'t parse uri:' + uri)
655
+ @protocol.stop_server
442
656
  end
657
+
443
658
  end
444
- module_function :parse_uri_drb
445
659
 
446
660
  @eventloop = nil
447
661
 
@@ -451,29 +665,41 @@ module DRb
451
665
  def start_drbserver(uri=nil, front=nil, config=nil)
452
666
  serv = DRbServer.new(uri, front, config)
453
667
  serv.start_drb_server
668
+ DRb.regist_server(serv)
454
669
  return(serv)
455
670
  end
456
671
  module_function :start_drbserver
457
672
 
458
- ##
459
- # This start_service emulates DRb#start_service.
460
- #
461
- def start_service(uri=nil, front=nil, config=nil)
673
+ def start_evloop
462
674
  unless EventMachine::reactor_running?
463
675
  @eventloop = Thread.new do
464
- EventMachine::run do
465
- # Start an empty event loop. The DRb server(s) will be started
466
- # by EM#next_tick calls.
676
+ begin
677
+ EventMachine::run do
678
+ # Start an empty event loop. The DRb server(s) will be started
679
+ # by EM#next_tick calls.
680
+ end
681
+ ensure
682
+ # close all servers if the event loop ends for whatever reason
683
+ @server.each do |uri,srv|
684
+ srv.stop_service
685
+ end
467
686
  end
468
687
  end
469
688
  end
689
+ end
690
+ module_function :start_evloop
691
+
692
+ ##
693
+ # This start_service emulates DRb#start_service.
694
+ #
695
+ def start_service(uri=nil, front=nil, config=nil)
696
+ DRb.start_evloop
470
697
  queue = Queue.new
471
698
  EventMachine::next_tick do
472
699
  queue << self.start_drbserver(uri, front, config)
473
700
  end
474
701
  serv = queue.shift
475
702
  @primary_server = serv
476
- DRb.regist_server(serv)
477
703
  return(serv)
478
704
  end
479
705
  module_function :start_service
@@ -544,9 +770,8 @@ module DRb
544
770
  @ref = nil
545
771
  if obj.nil?
546
772
  return if uri.nil?
547
- @uri = uri
548
- ref = nil
549
- @host, @port, @opt = DRb::parse_uri_drb(@uri)
773
+ @uri, option = DRbTransport.uri_option(uri, DRb.config)
774
+ @ref = DRbURIOption.new(option) unless option.nil?
550
775
  else
551
776
  @uri = uri ? uri : (DRb.uri rescue nil)
552
777
  @ref = obj ? DRb.to_id(obj) : nil
@@ -559,10 +784,9 @@ module DRb
559
784
  # callbacks can be attached.
560
785
  def send_async(msg_id, *a, &b)
561
786
  df = EventMachine::DefaultDeferrable.new
562
- if @host.nil? || @port.nil?
563
- @host, @port, @opt = DRb::parse_uri_drb(@uri)
564
- end
565
- EventMachine.connect(@host, @port, DRbClientProtocol) do |c|
787
+ @protocol ||= DRbTransport.factory(@uri, DRb.config)
788
+
789
+ @protocol.client_connect(DRbClientProtocol) do |c|
566
790
  c.ref = self
567
791
  c.msg_id = msg_id
568
792
  c.args = a
@@ -575,7 +799,7 @@ module DRb
575
799
  ##
576
800
  # Route method calls to the referenced object. This synchronizes
577
801
  # an asynchronous call by using a Queue to synchronize the DRb
578
- # event thread with the calling thread, so use of this mechanism,
802
+ # event thread with the calling thread, so use of this mechanism
579
803
  # to make method calls within an event loop will thus result in a
580
804
  # threading deadlock! Use the send_async method if you want to
581
805
  # use EMDRb from within an event loop.
@@ -604,5 +828,4 @@ module DRb
604
828
  end
605
829
 
606
830
  end
607
-
608
831
  end
data/lib/emdrb/unix.rb ADDED
@@ -0,0 +1,93 @@
1
+ #
2
+ # Author:: Rafael R. Sevilla (mailto:dido@imperium.ph)
3
+ # Copyright:: Copyright © 2008, 2009 Rafael R. Sevilla
4
+ # Homepage:: http://emdrb.rubyforge.org/
5
+ # License:: GNU General Public License / Ruby License
6
+ #
7
+ # $Id: emdrb.rb 72 2009-01-28 09:53:08Z dido $
8
+ #
9
+ #----------------------------------------------------------------------------
10
+ #
11
+ # Copyright © 2008, 2009 Rafael Sevilla
12
+ # This file is part of EMDRb
13
+ #
14
+ # This program is free software; you can redistribute it and/or modify
15
+ # it under the terms of either: 1) the GNU General Public License
16
+ # as published by the Free Software Foundation; either version 2 of the
17
+ # License, or (at your option) any later version; or 2) Ruby's License.
18
+ #
19
+ # See the file COPYING for complete licensing information.
20
+ #----------------------------------------------------------------------------
21
+ #
22
+ require 'drb/unix'
23
+
24
+ module DRb
25
+
26
+ ##
27
+ # Unix domain socket transport
28
+ class DRbUNIXSocket < DRbTCPSocket
29
+ public
30
+
31
+ def initialize(uri, config={})
32
+ @uri = (uri.nil?) ? 'drbunix:' : uri
33
+ @filename, @option = self.class.parse_uri(@uri)
34
+ @filename.untaint
35
+ @port.untaint
36
+ @config = config
37
+ @acl = nil
38
+ end
39
+
40
+ def start_server(prot)
41
+ if @conndesc
42
+ return(@conndesc)
43
+ end
44
+
45
+ lock = nil
46
+ if @filename.nil?
47
+ tmpdir = Dir::tmpdir
48
+ n = 0
49
+ while true
50
+ begin
51
+ tmpname = sprintf('%s/druby%d.%d', tmpdir, $$, n)
52
+ lock = tmpname + '.lock'
53
+ unless File.exist?(tmpname) or File.exist?(lock)
54
+ Dir.mkdir(lock)
55
+ @filename = tmpname
56
+ break
57
+ end
58
+ rescue
59
+ raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try
60
+ #sleep(1)
61
+ end
62
+ n += 1
63
+ end
64
+ end
65
+
66
+ @conndesc = EventMachine::start_unix_domain_server(@filename,
67
+ prot) do |conn|
68
+ if block_given?
69
+ yield conn
70
+ end
71
+ end
72
+
73
+ if lock
74
+ Dir.rmdir(lock)
75
+ end
76
+ end
77
+
78
+ def client_connect(prot)
79
+ EventMachine.connect_unix_domain(@filename, prot) do |c|
80
+ if block_given?
81
+ yield c
82
+ end
83
+ end
84
+ end
85
+
86
+ def stop_server
87
+ super
88
+ File.unlink(@filename)
89
+ end
90
+ end
91
+
92
+ DRbTransport.add_transport(DRbUNIXSocket)
93
+ end
data/lib/emdrb/version.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # Homepage:: http://emdrb.rubyforge.org/
5
5
  # License:: GNU Lesser General Public License / Ruby License
6
6
  #
7
- # $Id: version.rb 57 2009-01-23 09:07:54Z dido $
7
+ # $Id: version.rb 68 2009-01-27 07:26:59Z dido $
8
8
  #
9
9
  #----------------------------------------------------------------------------
10
10
  #
@@ -25,7 +25,7 @@ module EMDRb
25
25
  module Version
26
26
 
27
27
  MAJOR = 0
28
- MINOR = 2
28
+ MINOR = 3
29
29
  TINY = 0
30
30
 
31
31
  # The version of EMDRb in use.
data/spec/drbserver.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # Homepage:: http://emdrb.rubyforge.org/
5
5
  # License:: GNU General Public License / Ruby License
6
6
  #
7
- # $Id: drbserver.rb 46 2009-01-23 08:10:42Z dido $
7
+ # $Id: drbserver.rb 66 2009-01-27 07:25:23Z dido $
8
8
  #
9
9
  #----------------------------------------------------------------------------
10
10
  #
@@ -72,6 +72,40 @@ class TestServer
72
72
  end
73
73
  end
74
74
 
75
+ if ARGV[0] == "emdrb"
76
+ class TestServer
77
+ include DRb::DRbEMSafe
78
+ include EventMachine::Deferrable
79
+
80
+ deferrable_method :block_df
81
+
82
+ ##
83
+ # Simple example of a deferrable method structured as a state
84
+ # machine.
85
+ def block_df(args, block, state={:index => 0, :retval => 0 })
86
+ if state[:index] >= args.length
87
+ self.set_deferred_status(:succeeded, state[:retval])
88
+ return(self)
89
+ end
90
+
91
+ df = block.send_async(:call, args[state[:index]])
92
+ df.callback do |succ,result|
93
+ if succ
94
+ state[:retval] += result
95
+ state[:index] += 1
96
+ EventMachine::next_tick do
97
+ self.block_df(args, block, state)
98
+ end
99
+ else
100
+ self.set_deferred_status(:failed, res)
101
+ end
102
+ end
103
+ df.errback do |res|
104
+ end
105
+ return(self)
106
+ end
107
+ end
108
+ end
75
109
 
76
110
 
77
111
  DRb.start_service("druby://:12345", TestServer.new)
data/spec/server_spec.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # Homepage:: http://emdrb.rubyforge.org/
5
5
  # License:: GNU General Public License / Ruby License
6
6
  #
7
- # $Id: server_spec.rb 48 2009-01-23 08:48:43Z dido $
7
+ # $Id: server_spec.rb 65 2009-01-27 07:24:53Z dido $
8
8
  #
9
9
  #----------------------------------------------------------------------------
10
10
  #
@@ -48,4 +48,9 @@ describe "EMDRb Server" do
48
48
  @obj.sum(1,2,3,4,5).should == 15
49
49
  end
50
50
 
51
+ it "should use deferrable methods correctly" do
52
+ res = @obj.block_df(1,2,3,4,5) { |x| x }
53
+ res.should == 15
54
+ end
55
+
51
56
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emdrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dido@imperium.ph
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-23 00:00:00 +08:00
12
+ date: 2009-01-29 00:00:00 +08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -31,6 +31,7 @@ files:
31
31
  - Rakefile
32
32
  - lib/emdrb.rb
33
33
  - lib/emdrb/emdrb.rb
34
+ - lib/emdrb/unix.rb
34
35
  - lib/emdrb/version.rb
35
36
  - spec/client_spec.rb
36
37
  - spec/drbserver.rb