lib/rexec/connection.rb in rexec-1.2.6 vs lib/rexec/connection.rb in rexec-1.3.0
- old
+ new
@@ -2,13 +2,66 @@
# Released under the MIT license. Please see LICENSE.txt for license details.
# This class is as small and independant as possible as it will get sent to clients for execution.
require 'thread'
+require 'monitor'
module RExec
+
+ # A wrapper for sending method invocations over a Connection
+ class Invocation
+ def initialize(name, arguments)
+ @name = name
+ @arguments = arguments
+ end
+ def apply(object)
+ object.send(@name, *@arguments)
+ end
+
+ class Result
+ def initialize(value)
+ @value = value
+ end
+
+ attr :value
+ end
+ end
+
+ # A proxy class to create and send Invocation objects via a Connection, and receive a result.
+ class Proxy
+ def initialize(connection)
+ @connection = connection
+
+ @method_mutex = Mutex.new
+ end
+
+ def method_missing(name, *arguments)
+ invocation = Invocation.new(name, arguments)
+ result = nil
+
+ # Connection provides no transaction support. This means that
+ # if multiple threads are sending and receiving arbirary objects
+ # via the connection, the Proxy object may fail due to out of
+ # line objects.
+ @method_mutex.synchronize do
+ # Send the invocation.
+ @connection.send_object(invocation)
+
+ # Wait for the result.
+ result = @connection.receive_object
+ end
+
+ if Invocation::Result === result
+ return result.value
+ else
+ raise InvalidResponse.new("Invalid response received: #{result}")
+ end
+ end
+ end
+
# This class represents an abstract connection to another ruby process. The interface does not impose
# any structure on the way this communication link works, except for the fact you can send and receive
# objects. You can implement whatever kind of idiom you need for communication on top of this library.
#
# Depending on how you set things up, this could connect to a local ruby process, or a remote ruby process
@@ -42,12 +95,21 @@
@error = error
@receive_mutex = Mutex.new
@send_mutex = Mutex.new
+
+ @proxy = Proxy.new(self)
+ @handler = nil
end
+ # The object that will handle remote proxy invocations.
+ attr :handler, true
+
+ # The proxy object that will dispatch RPCs.
+ attr :proxy
+
# The pipe used for reading data
def input
@input
end
@@ -87,10 +149,15 @@
@running = false
return
end
begin
- yield object
+ if @handler && Invocation === object
+ result = object.apply(@handler)
+ send_object(Invocation::Result.new(result))
+ else
+ yield object
+ end
rescue Exception => ex
send_object(ex)
end
end
end