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
-
#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
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 # @!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.
20 21 22 |
# File 'lib/farcall/endpoint.rb', line 20 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
Hashie::Mash.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.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/farcall/endpoint.rb', line 99 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)
174 175 176 |
# File 'lib/farcall/endpoint.rb', line 174 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.
160 161 162 |
# File 'lib/farcall/endpoint.rb', line 160 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.
182 183 184 |
# File 'lib/farcall/endpoint.rb', line 182 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.
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 151 |
# File 'lib/farcall/endpoint.rb', line 125 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 |