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

Instance Attribute Summary

Attributes inherited from RJR::Node

#dispatcher, #message_headers, #node_id

Instance Method Summary collapse

Methods inherited from RJR::Node

em, #halt, #join, #node_type, #on, 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



101
102
103
104
105
# File 'lib/rjr/nodes/web.rb', line 101

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



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

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



132
133
134
135
136
137
# File 'lib/rjr/nodes/web.rb', line 132

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



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

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



114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rjr/nodes/web.rb', line 114

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



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

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