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 +9 -0
- data/Manifest.txt +1 -0
- data/README.txt +22 -12
- data/lib/emdrb/emdrb.rb +296 -73
- data/lib/emdrb/unix.rb +93 -0
- data/lib/emdrb/version.rb +2 -2
- data/spec/drbserver.rb +35 -1
- data/spec/server_spec.rb +6 -1
- metadata +3 -2
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
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
|
-
|
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
|
-
*
|
23
|
-
*
|
24
|
-
*
|
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
|
-
|
39
|
+
following releases.
|
30
40
|
|
31
41
|
== SYNOPSIS:
|
32
42
|
|
33
|
-
EMDRb basically reopens several classes
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
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
|
-
|
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
|
-
|
465
|
-
|
466
|
-
|
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
|
-
|
563
|
-
|
564
|
-
|
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
|
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 =
|
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
|
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
|
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.
|
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-
|
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
|