Class: Farcall::Endpoint
- Inherits:
-
Object
- Object
- Farcall::Endpoint
- Defined in:
- lib/farcall/endpoint.rb
Overview
The protocol endpoint. Takes some transport and implements Farcall protocol over it. You can use it direcly or with Farcall::RemoteInterface and Farcall::LocalProvider helper classes.
Note that the returned data is converted to Hashie::Mash primarily for the sake of :key vs. ‘key’ ambigity that otherwise might appear depending on the transport encoding protocol. Anyway it is better than ruby hash ;)
Endpoint class is thread-safe.
Instance Attribute Summary collapse
-
#provider ⇒ Object
Set or get provider instance.
Class Method Summary collapse
Instance Method Summary collapse
-
#abort(reason, exception = nil) ⇒ Object
:nodoc:.
-
#call(name, *args, **kwargs, &block) ⇒ Farcall::Promise
Call remote party.
-
#close ⇒ Object
Close endpoint and connected transport.
-
#initialize(transport, init_proc = nil) ⇒ Endpoint
constructor
Create endpoint connected to some transport.
-
#on(name, &block) ⇒ Object
Set handler to perform the named command.
-
#on_abort(&proc) ⇒ Object
The provided block will be called if endpoint functioning will be aborted.
-
#on_close(&block) ⇒ Object
Add the close handler.
-
#on_remote_call(&block) ⇒ Object
(also: #on_command)
Process remote commands.
- #push_input(data) ⇒ Object
-
#remote ⇒ Object
Get the Farcall::RemoteInterface connnected to this endpoint.
-
#sync_call(name, *args, **kwargs) ⇒ Object
Call the remote party and wait for the return.
Constructor Details
#initialize(transport, init_proc = nil) ⇒ Endpoint
Create endpoint connected to some transport
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/farcall/endpoint.rb', line 24 def initialize(transport, init_proc=nil) @transport = transport @in_serial = @out_serial = 0 @send_lock = Mutex.new @receive_lock = Mutex.new @handlers = {} @waiting = {} init_proc.call(self) if init_proc def push_input data p 'me -- pusj!', data @in_buffer << data drain end @transport.on_data_received = -> (data) { begin _received(data) rescue abort :format_error, $! end } end |
Instance Attribute Details
#provider ⇒ Object
Set or get provider instance. When provider is set, its public methods are called by the remote and any possible exception are passed back to caller party. You can use any ruby class instance everything will work, operators, indexes[] and like.
20 21 22 |
# File 'lib/farcall/endpoint.rb', line 20 def provider @provider end |
Class Method Details
Instance Method Details
#abort(reason, exception = nil) ⇒ Object
:nodoc:
65 66 67 68 69 70 71 72 |
# File 'lib/farcall/endpoint.rb', line 65 def abort reason, exception = nil puts "*** Abort: reason #{reason || exception.to_s}" @abort_hadnler and @abort_hadnler.call reason, exception if exception raise exception end close end |
#call(name, *args, **kwargs, &block) ⇒ Farcall::Promise
Call remote party. Retruns immediately. When remote party answers, calls the specified block if present. The block should take |error, result| parameters. If result’s content hashes or result itself are instances of th Hashie::Mash. Error could be nil or {‘class’ =>, ‘text’ => } Hashie::Mash hash. result is always nil if error is presented.
Usually, using Farcall::Endpoint#interface or Farcall::RemoteInterface is more effective rather than this low-level method.
The returned Promise instance let add any number of callbacks on commend execution, success or failure.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/farcall/endpoint.rb', line 94 def call(name, *args, **kwargs, &block) promise = Farcall::Promise.new @send_lock.synchronize { @waiting[@out_serial] = -> (error, result) { block.call(error, result) if block if error promise.set_fail error else promise.set_success result end } _send(cmd: name.to_s, args: args, kwargs: kwargs) } promise end |
#close ⇒ Object
Close endpoint and connected transport
75 76 77 78 79 |
# File 'lib/farcall/endpoint.rb', line 75 def close @transport.close @transport = nil @close_handler and @close_handler.call end |
#on(name, &block) ⇒ Object
Set handler to perform the named command. Block will be called when the remote party calls with parameters passed from the remote. The block returned value will be passed back to the caller.
The provider if set is calling instead.
If the block raises the exception it will be reported to the caller as an error (depending on it’s platofrm, will raise exception on its end or report error)
169 170 171 |
# File 'lib/farcall/endpoint.rb', line 169 def on(name, &block) @handlers[name.to_s] = block end |
#on_abort(&proc) ⇒ Object
The provided block will be called if endpoint functioning will be aborted. The block should take |reason, exception| parameters - latter could be nil
55 56 57 |
# File 'lib/farcall/endpoint.rb', line 55 def on_abort &proc @abort_hadnler = proc end |
#on_close(&block) ⇒ Object
Add the close handler. Specified block will be called when the endpoint is been closed
60 61 62 |
# File 'lib/farcall/endpoint.rb', line 60 def on_close &block @close_handler = block end |
#on_remote_call(&block) ⇒ Object Also known as: on_command
Process remote commands. Provided block will be executed on every remote command taking parameters |name, args, kwargs|. Whatever block returns will be passed to a calling party. The same any exception that the block might raise would be send back to caller.
this block will be called onlly of there wes no ‘provider` specified and no #on handler set for the command being executed.
155 156 157 |
# File 'lib/farcall/endpoint.rb', line 155 def on_remote_call &block @on_remote_call = block end |
#push_input(data) ⇒ Object
34 35 36 37 38 |
# File 'lib/farcall/endpoint.rb', line 34 def push_input data p 'me -- pusj!', data @in_buffer << data drain end |
#remote ⇒ Object
Get the Farcall::RemoteInterface connnected to this endpoint. Any subsequent calls with return the same instance.
176 177 178 |
# File 'lib/farcall/endpoint.rb', line 176 def remote @remote ||= Farcall::Interface.new endpoint: self end |
#sync_call(name, *args, **kwargs) ⇒ Object
Call the remote party and wait for the return.
It is desirable to use Farcall::Endpoint#interface or Farcall::RemoteInterface rather than this low-level method.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/farcall/endpoint.rb', line 120 def sync_call(name, *args, **kwargs) mutex = Mutex.new resource = ConditionVariable.new error = nil result = nil calling_thread = Thread.current mutex.synchronize { same_thread = false call(name, *args, **kwargs) { |e, r| error, result = e, r # Absolutly stupid wait for self situation # When single thread is used to send and receive # - often happens in test environments if calling_thread == Thread.current same_thread = true else resource.signal end } same_thread or resource.wait(mutex) } if error raise Farcall::RemoteError.new(error['class'], error['text']) end result end |