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)


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

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.



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

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:



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

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



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

def close
  super
end

#error(text) ⇒ Object

Report error via errback and the endpoint



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

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)



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

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.



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

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)



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

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.



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

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