Class: RJR::Nodes::Web

Inherits:
RJR::Node show all
Defined in:
lib/rjr/nodes/web.rb

Overview

Web node definition, listen for and invoke json-rpc requests via web requests

Clients should specify the hostname / port when listening for requests and when invoking them.

note the RJR javascript client also supports sending / receiving json-rpc messages over http

Examples:

Listening for json-rpc requests over tcp

# initialize node
server = RJR::Nodes::Web.new :node_id => 'server', :host => 'localhost', :port => '7777'

# register rjr dispatchers (see RJR::Dispatcher)
server.dispatcher.handle('hello') do |name|
  "Hello #{name}!"
end

# listen, and block
server.listen
server.join

Invoking json-rpc requests over http using rjr

client = RJR::Nodes::Web.new :node_id => 'client'
puts client.invoke('http://localhost:7777', 'hello', 'mo')

Invoking json-rpc requests over http using curl

$ curl -X POST http://localhost:7777 -d '{"jsonrpc":"2.0","method":"hello","params":["mo"],"id":"123"}'
> {"jsonrpc":"2.0","id":"123","result":"Hello mo!"}

Constant Summary collapse

RJR_NODE_TYPE =
:web
PERSISTENT_NODE =
false

Instance Attribute Summary

Attributes inherited from RJR::Node

#dispatcher, #message_headers, #node_id

Instance Method Summary collapse

Methods inherited from RJR::Node

#clear_event_handlers, em, #halt, #join, #node_type, #on, #persistent?, persistent?, tp

Constructor Details

#initialize(args = {}) ⇒ Web

Web initializer

Parameters:

  • args (Hash) (defaults to: {})

    the options to create the tcp node with

Options Hash (args):

  • :host (String)

    the hostname/ip which to listen on

  • :port (Integer)

    the port which to listen on



104
105
106
107
108
# File 'lib/rjr/nodes/web.rb', line 104

def initialize(args = {})
   super(args)
   @host      = args[:host]
   @port      = args[:port]
end

Instance Method Details

#invoke(uri, rpc_method, *args) ⇒ Object

Instructs node to send rpc request, and wait for / return response

Implementation of RJR::Node#invoke

Do not invoke directly from em event loop or callback as will block the message subscription used to receive responses

Parameters:

  • uri (String)

    location of node to send request to, should be in format of hostname:port

  • rpc_method (String)

    json-rpc method to invoke on destination

  • args (Array)

    array of arguments to convert to json and invoke remote method wtih



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rjr/nodes/web.rb', line 153

def invoke(uri, rpc_method, *args)
  message = RequestMessage.new :method => rpc_method,
                               :args   => args,
                               :headers => @message_headers
  cb = lambda { |http|
    # TODO handle errors
    handle_message(http.response, http)
  }

  @@em.schedule do
    http = EventMachine::HttpRequest.new(uri).post :body => message.to_s,
                                                   :head => {'content-type' => 'application/json'}
    http.errback  &cb
    http.callback &cb
  end

  # will block until response message is received
  # TODO optional timeout for response ?
  result = wait_for_result(message)
  if result.size > 2
    raise Exception, result[2]
  end
  return result[1]
end

#listenObject

Instruct Node to start listening for and dispatching rpc requests

Implementation of RJR::Node#listen



135
136
137
138
139
140
# File 'lib/rjr/nodes/web.rb', line 135

def listen
  @@em.schedule do
    EventMachine::start_server(@host, @port, WebConnection, :rjr_node => self)
  end
  self
end

#notify(uri, rpc_method, *args) ⇒ Object

Instructs node to send rpc notification (immadiately returns / no response is generated)

Implementation of RJR::Node#notify

Parameters:

  • uri (String)

    location of node to send request to, should be in format of hostname:port

  • rpc_method (String)

    json-rpc method to invoke on destination

  • args (Array)

    array of arguments to convert to json and invoke remote method wtih



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/rjr/nodes/web.rb', line 186

def notify(uri, rpc_method, *args)
  # will block until message is published
  published_l = Mutex.new
  published_c = ConditionVariable.new

  invoked = false
  message = NotificationMessage.new :method => rpc_method,
                                    :args   => args,
                                    :headers => @message_headers
  cb = lambda { |arg| published_l.synchronize { invoked = true ; published_c.signal }}
  @@em.schedule do
    http = EventMachine::HttpRequest.new(uri).post :body => message.to_s,
                                                   :head => {'content-type' => 'application/json'}
    http.errback  &cb
    http.callback &cb
  end
  published_l.synchronize { published_c.wait published_l unless invoked }
  nil
end

#send_msg(data, connection) ⇒ Object

Send data using specified http connection

Implementation of RJR::Node#send_msg



117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/rjr/nodes/web.rb', line 117

def send_msg(data, connection)
  # we are assuming that since http connections
  # are not persistant, we should be sending a
  # response message here

  @@em.schedule  do
    resp = EventMachine::DelegatedHttpResponse.new(connection)
    #resp.status  = response.result.success ? 200 : 500
    resp.status = 200
    resp.content = data.to_s
    resp.content_type "application/json"
    resp.send_response
  end
end

#to_sObject



110
111
112
# File 'lib/rjr/nodes/web.rb', line 110

def to_s
  "RJR::Nodes::Web<#{@node_id},#{@host},#{@port}>"
end