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

sh> 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
INDIRECT_NODE =
false

Instance Attribute Summary

Attributes inherited from RJR::Node

#connection_event_handlers, #dispatcher, #message_headers, #node_id

Instance Method Summary collapse

Methods inherited from RJR::Node

#clear_event_handlers, em, #em, #halt, #indirect?, indirect?, #join, #node_type, #on, persistent?, #persistent?, tp, #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



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

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



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

def invoke(uri, rpc_method, *args)
  message = Messages::Request.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



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

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



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

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

  invoked = false
  message = Messages::Notification.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



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

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



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

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