class RJR::Nodes::Web
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
@example 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
@example Invoking json-rpc requests over http using rjr
client = RJR::Nodes::Web.new :node_id => 'client' puts client.invoke('http://localhost:7777', 'hello', 'mo')
@example 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!"}
Web
socket node definition, listen for and invoke json-rpc requests via web sockets
Clients should specify the hostname / port when listening for and invoking requests.
note the RJR
javascript client also supports sending / receiving json-rpc messages over web sockets
@example Listening for json-rpc requests over tcp
# initialize node server = RJR::Nodes::WS.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
@example Invoking json-rpc requests over web sockets using rjr
client = RJR::Nodes::WS.new :node_id => 'client' puts client.invoke_request('ws://localhost:7777', 'hello', 'mo')
Constants
- INDIRECT_NODE
- PERSISTENT_NODE
- RJR_NODE_TYPE
Public Class Methods
Web
initializer @param [Hash] args the options to create the tcp node with @option args [String] :host the hostname/ip which to listen on @option args [Integer] :port the port which to listen on
RJR::Node::new
# File lib/rjr/nodes/web.rb, line 106 def initialize(args = {}) super(args) @host = args[:host] @port = args[:port] end
Public Instance Methods
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
@param [String] uri location of node to send request to, should be
in format of http://hostname:port
@param [String] rpc_method json-rpc method to invoke on destination @param [Array] args array of arguments to convert to json and invoke remote method wtih
# File lib/rjr/nodes/web.rb, line 155 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 fail result[2] end return result[1] end
Instruct Node
to start listening for and dispatching rpc requests
Implementation of RJR::Node#listen
# File lib/rjr/nodes/web.rb, line 137 def listen @@em.schedule do EventMachine::start_server(@host, @port, WebConnection, :rjr_node => self) end self end
# File lib/rjr/nodes/missing.rb, line 14 def method_missing(method_id, *args, &bl) raise "rjr node #{node_id} is missing a dependency - cannot invoke #{method_id}" end
Instructs node to send rpc notification (immadiately returns / no response is generated)
Implementation of RJR::Node#notify
@param [String] uri location of node to send request to, should be
in format of http://hostname:port
@param [String] rpc_method json-rpc method to invoke on destination @param [Array] args array of arguments to convert to json and invoke remote method wtih
# File lib/rjr/nodes/web.rb, line 188 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 data using specified http connection
Implementation of RJR::Node#send_msg
# File lib/rjr/nodes/web.rb, line 119 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
# File lib/rjr/nodes/web.rb, line 112 def to_s "RJR::Nodes::Web<#{@node_id},#{@host},#{@port}>" end
Private Instance Methods
Internal helper initialize new client
# File lib/rjr/nodes/ws.rb, line 63 def init_client(uri, &on_init) connection = nil @connections_lock.synchronize { connection = @connections.find { |c| c.url == uri } if connection.nil? connection = EventMachine::WebSocketClient.connect(uri) connection.callback do on_init.call(connection) end @connections << connection # TODO sleep until connected? else on_init.call(connection) end } connection end