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 SmartHash 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
-
#call(name, *args, **kwargs, &block) ⇒ Farcall::Promise
Call the remote party, non blocking, returns Promise instance to handle the remote return valy asynchronously (recommended way).
-
#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.
-
#remote ⇒ Farcall::Interface
Get the Interface 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
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/farcall/endpoint.rb', line 23 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 # @!visibility private def push_input 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.
19 20 21 |
# File 'lib/farcall/endpoint.rb', line 19 def provider @provider end |
Class Method Details
Instance Method Details
#call(name, *args, **kwargs, &block) ⇒ Farcall::Promise
Call the remote party, non blocking, returns Promise instance to handle the remote return valy asynchronously (recommended way).
Optionally the block could be provided that takes |error, result| parameters. Error must be nil or
SmartHash.new({'class' =>, 'text' => text [, data: {some_data}] })
if error is presented, the result is always the nil.
Usually, using #remote which returns Interface 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.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/farcall/endpoint.rb', line 98 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
74 75 76 77 78 |
# File 'lib/farcall/endpoint.rb', line 74 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)
173 174 175 |
# File 'lib/farcall/endpoint.rb', line 173 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
54 55 56 |
# File 'lib/farcall/endpoint.rb', line 54 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
59 60 61 |
# File 'lib/farcall/endpoint.rb', line 59 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.
159 160 161 |
# File 'lib/farcall/endpoint.rb', line 159 def on_remote_call &block @on_remote_call = block end |
#remote ⇒ Farcall::Interface
Get the Interface connnected to this endpoint. Any subsequent calls with return the same instance.
181 182 183 |
# File 'lib/farcall/endpoint.rb', line 181 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.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/farcall/endpoint.rb', line 124 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'], error['data']) end result end |