Class: EmFarcall::Endpoint

Inherits:
Object
  • Object
show all
Defined in:
lib/farcall/em_farcall.rb

Overview

Endpoint that run in the reactor thread of the EM. Eventmachine should run by the time of creation of the endpoint. All the methods can be called from any thread, not only EM’s reactor thread.

As the eventmachine callback paradigm is completely different from the threaded paradigm of the Farcall, that runs pretty well under JRuby and in multithreaded MRI, we provide compatible but different endpoint to run under EM.

Its main difference is that there is no sync_call, instead, calling remote commands from the endpoint and/ot interface can provide blocks that are called when the remote is executed.

The EM version of the endpoint works with any 2 EM:C:Channels.

Direct Known Subclasses

WsServerEndpoint

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_channel, output_channel, errback = nil, provider: nil) ⇒ Endpoint

Create new endpoint to work with input and output channels

Parameters:

  • input_channel (EM::Channel)
  • output_channel (EM::Channel)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/farcall/em_farcall.rb', line 40

def initialize(input_channel, output_channel, errback=nil, provider: nil)
  EM.schedule {
    @input, @output, @errback = input_channel, output_channel, errback
    @trace                    = false
    @in_serial                = @out_serial = 0
    @callbacks                = {}
    @handlers                 = {}
    @unnamed_handler          = -> (name, *args, **kwargs) {
      raise NoMethodError, "method does not exist: #{name}"
    }
    @input.subscribe { |data|
      process_input(data)
    }
    if provider
      @provider         = provider
      provider.endpoint = self
    end
  }
end

Instance Attribute Details

#providerObject

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.



63
64
65
# File 'lib/farcall/em_farcall.rb', line 63

def provider
  @provider
end

Instance Method Details

#call(name, *args, **kwargs, &block) ⇒ Promise

Call the remote method with specified name and arguments calling block when done. Returns immediately a Farcall::Promise instance which could be used to control remote procedure invocation result asynchronously and effective.

Also, if block is provided, it will be called when the remote will be called and possibly return some data. It receives single object paramter with two fields: result.error and result.result. It is also possible to use returned Farcall::Promise instance to set multiple callbacks with ease. Promise callbacks are called after the block.

‘result.error` is not nil when the remote raised error, then `error` and `error.text` are set accordingly.

if error is nil then result.result receives any return data from the remote method.

for example:

endpoint.call( 'some_func', 10, 20) { |done|
   if done.error
     puts "Remote error class: #{done.error[:class]}: #{done.error.text}"
   else
     puts "Remote returned #{done.result}"
}

Parameters:

  • name (String)

    remote method name

Returns:



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/farcall/em_farcall.rb', line 92

def call(name, *args, **kwargs, &block)
  promise = Farcall::Promise.new
  EM.schedule {
    @callbacks[@in_serial] = -> (result) {
      block.call(result) if block != nil
      if result.error
        promise.set_fail result.error
      else
        promise.set_success result.result
      end
    }
    send_block cmd: name, args: args, kwargs: kwargs
  }
  promise
end

#closeObject

Close the endpoint



109
110
111
# File 'lib/farcall/em_farcall.rb', line 109

def close
  super
end

#error(text) ⇒ Object

Report error via errback and the endpoint



114
115
116
117
118
119
120
# File 'lib/farcall/em_farcall.rb', line 114

def error text
  STDERR.puts "farcall ws server error #{text}"
  EM.schedule {
    @errback.call(text) if @errback
    close
  }
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.

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)



128
129
130
# File 'lib/farcall/em_farcall.rb', line 128

def on(name, &block)
  @handlers[name.to_s] = block
end

#on_command(&block) ⇒ Object

Process remote command. First parameter passed to the block is the method name, the rest are optional arguments of the call:

endpoint.on_command { |name, *args, **kwargs|
  if name == 'echo'
    { args: args, keyword_args: kwargs }
  else
    raise "unknown command"
  end
}

raising exceptions from the block cause farcall error to be returned back th the caller.



144
145
146
147
# File 'lib/farcall/em_farcall.rb', line 144

def on_command &block
  raise "unnamed handler should be present" unless block
  @unnamed_handler = block
end

#on_remote_call(&block) ⇒ Object

Same as #on_command (compatibilty method)



150
151
152
# File 'lib/farcall/em_farcall.rb', line 150

def on_remote_call &block
  on_command &block
end

#remoteObject

Get the Farcall::RemoteInterface connnected to this endpoint. Any subsequent calls with return the same instance.



156
157
158
# File 'lib/farcall/em_farcall.rb', line 156

def remote
  @remote ||= EmFarcall::Interface.new endpoint: self
end