rjr 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +144 -0
- data/Rakefile +5 -5
- data/bin/rjr-server +2 -1
- data/lib/rjr.rb +3 -0
- data/lib/rjr/amqp_node.rb +103 -52
- data/lib/rjr/common.rb +19 -3
- data/lib/rjr/dispatcher.rb +103 -7
- data/lib/rjr/errors.rb +5 -3
- data/lib/rjr/local_node.rb +38 -12
- data/lib/rjr/message.rb +56 -1
- data/lib/rjr/multi_node.rb +31 -4
- data/lib/rjr/node.rb +57 -8
- data/lib/rjr/tcp_node.rb +65 -11
- data/lib/rjr/thread_pool.rb +33 -9
- data/lib/rjr/web_node.rb +72 -20
- data/lib/rjr/ws_node.rb +54 -12
- metadata +35 -2
- data/README.rdoc +0 -73
data/lib/rjr/dispatcher.rb
CHANGED
@@ -1,25 +1,50 @@
|
|
1
1
|
# RJR Request / Response Dispatcher
|
2
2
|
#
|
3
|
+
# Representation of a json-rpc request, response and mechanisms which to
|
4
|
+
# register methods to handle requests and return responses
|
5
|
+
#
|
3
6
|
# Copyright (C) 2012 Mohammed Morsi <mo@morsi.org>
|
4
7
|
# Licensed under the Apache License, Version 2.0
|
5
8
|
|
6
|
-
# establish client connection w/ specified args and invoke block w/
|
7
|
-
# newly created client, returning it after block terminates
|
8
|
-
|
9
9
|
require 'rjr/common'
|
10
10
|
|
11
11
|
module RJR
|
12
12
|
|
13
|
+
# JSON-RPC request representation
|
13
14
|
class Request
|
15
|
+
# name of the method which request is for
|
14
16
|
attr_accessor :method
|
17
|
+
|
18
|
+
# array of arguments which to pass to the rpc method handler
|
15
19
|
attr_accessor :method_args
|
20
|
+
|
21
|
+
# hash of keys/values corresponding to optional headers received as part of of the request
|
16
22
|
attr_accessor :headers
|
23
|
+
|
24
|
+
# callback through which additional requests may be invoked
|
17
25
|
attr_accessor :rjr_callback
|
26
|
+
|
27
|
+
# type of the rjr node which request was received on
|
18
28
|
attr_accessor :rjr_node_type
|
29
|
+
|
30
|
+
# id of the rjr node which request was received on
|
19
31
|
attr_accessor :rjr_node_id
|
20
32
|
|
33
|
+
# callable object registered to the specified method which to invoke request on with arguments
|
21
34
|
attr_accessor :handler
|
22
35
|
|
36
|
+
# RJR request intializer
|
37
|
+
# @param [Hash] args options to set on request
|
38
|
+
# @option args [String] :method name of the method which request is for
|
39
|
+
# @option args [Array] :method_args array of arguments which to pass to the rpc method handler
|
40
|
+
# @option args [Hash] :headers hash of keys/values corresponding to optional headers received as part of of the request
|
41
|
+
# @option args [String] :client_ip ip address of client which invoked the request (if applicable)
|
42
|
+
# @option args [String] :client_port port of client which invoked the request (if applicable)
|
43
|
+
# @option args [RJR::Callback] :rjr_callback callback through which additional requests may be invoked
|
44
|
+
# @option args [RJR::Node] :rjr_node rjr node which request was received on
|
45
|
+
# @option args [String] :rjr_node_id id of the rjr node which request was received on
|
46
|
+
# @option args [Symbol] :rjr_node_type type of the rjr node which request was received on
|
47
|
+
# @option args [Callable] :handler callable object registered to the specified method which to invoke request on with arguments
|
23
48
|
def initialize(args = {})
|
24
49
|
@method = args[:method]
|
25
50
|
@method_args = args[:method_args]
|
@@ -33,6 +58,8 @@ class Request
|
|
33
58
|
@handler = args[:handler]
|
34
59
|
end
|
35
60
|
|
61
|
+
# Actually invoke the request by calling the registered handler with the specified
|
62
|
+
# method parameters in the local scope
|
36
63
|
def handle
|
37
64
|
RJR::Logger.info "Dispatching '#{@method}' request with parameters (#{@method_args.join(',')}) on #{@rjr_node_type}-node(#{@rjr_node_id})"
|
38
65
|
retval = instance_exec(*@method_args, &@handler)
|
@@ -41,14 +68,32 @@ class Request
|
|
41
68
|
end
|
42
69
|
end
|
43
70
|
|
71
|
+
# JSON-RPC result representation
|
44
72
|
class Result
|
73
|
+
# boolean indicating if request was successfully invoked
|
45
74
|
attr_accessor :success
|
75
|
+
|
76
|
+
# boolean indicating if request was not successfully invoked
|
46
77
|
attr_accessor :failed
|
78
|
+
|
79
|
+
# return value of the json-rpc call if successful
|
47
80
|
attr_accessor :result
|
81
|
+
|
82
|
+
# code corresponding to json-rpc error if problem occured during request invocation
|
48
83
|
attr_accessor :error_code
|
84
|
+
|
85
|
+
# message corresponding to json-rpc error if problem occured during request invocation
|
49
86
|
attr_accessor :error_msg
|
87
|
+
|
88
|
+
# class of error raised (if any) during request invocation (this is extra metadata beyond standard json-rpc)
|
50
89
|
attr_accessor :error_class
|
51
90
|
|
91
|
+
# RJR result intializer
|
92
|
+
# @param [Hash] args options to set on result
|
93
|
+
# @option args [Object] :result result of json-rpc method handler if successfully returned
|
94
|
+
# @option args [Integer] :error_code code corresponding to json-rpc error if problem occured during request invocation
|
95
|
+
# @option args [String] :error_msg message corresponding to json-rpc error if problem occured during request invocation
|
96
|
+
# @option args [Class] :error_class class of error raised (if any) during request invocation (this is extra metadata beyond standard json-rpc)
|
52
97
|
def initialize(args = {})
|
53
98
|
@result = nil
|
54
99
|
@error_code = nil
|
@@ -70,6 +115,8 @@ class Result
|
|
70
115
|
end
|
71
116
|
end
|
72
117
|
|
118
|
+
# Compare Result against other result, returning true if both correspond
|
119
|
+
# to equivalent json-rpc results else false
|
73
120
|
def ==(other)
|
74
121
|
@success == other.success &&
|
75
122
|
@failed == other.failed &&
|
@@ -79,17 +126,20 @@ class Result
|
|
79
126
|
@error_class == other.error_class
|
80
127
|
end
|
81
128
|
|
129
|
+
# Convert Response to human consumable string
|
82
130
|
def to_s
|
83
131
|
"#{@success} #{@result} #{@error_code} #{@error_msg} #{@error_class}"
|
84
132
|
end
|
85
133
|
|
86
134
|
######### Specific request types
|
87
135
|
|
136
|
+
# JSON-RPC -32600 / Invalid Request
|
88
137
|
def self.invalid_request
|
89
138
|
return Result.new(:error_code => -32600,
|
90
139
|
:error_msg => ' Invalid Request')
|
91
140
|
end
|
92
141
|
|
142
|
+
# JSON-RPC -32602 / Method not found
|
93
143
|
def self.method_not_found(name)
|
94
144
|
return Result.new(:error_code => -32602,
|
95
145
|
:error_msg => "Method '#{name}' not found")
|
@@ -97,15 +147,33 @@ class Result
|
|
97
147
|
|
98
148
|
end
|
99
149
|
|
150
|
+
# Association between json-rpc method name and registered handler to
|
151
|
+
# be invoked on new requests.
|
152
|
+
#
|
153
|
+
# When invoked, creates new {RJR::Request} object with specified request
|
154
|
+
# params and uses it to invoke handler in its context. Formats and returns
|
155
|
+
# return of operation
|
100
156
|
class Handler
|
101
157
|
attr_accessor :method_name
|
102
158
|
attr_accessor :handler_proc
|
103
159
|
|
160
|
+
# RJR::Handler intializer
|
161
|
+
# @param [Hash] args options to set on handler
|
162
|
+
# @option args [String] :method name of json-rpc method to which handler is bound
|
163
|
+
# @option args [Callable] :handle callable object which to bind to method name
|
104
164
|
def initialize(args = {})
|
105
165
|
@method_name = args[:method]
|
106
166
|
@handler_proc = args[:handler]
|
107
167
|
end
|
108
168
|
|
169
|
+
# Handle new json-rpc request to registered method.
|
170
|
+
#
|
171
|
+
# Creates new {RJR::Request} with the local method name and handler and the
|
172
|
+
# arguments received as part of the request. Uses it to invoke handler and
|
173
|
+
# creates and returns new {RJR::Result} encapsulating the return value if
|
174
|
+
# successful or error code/message/class if not.
|
175
|
+
#
|
176
|
+
# If invalid method_name is specified returns a json-rpc 'Method not found'
|
109
177
|
def handle(args = {})
|
110
178
|
return Result.method_not_found(args[:missing_name]) if @method_name.nil?
|
111
179
|
|
@@ -126,13 +194,39 @@ class Handler
|
|
126
194
|
end
|
127
195
|
end
|
128
196
|
|
197
|
+
# Primary RJR JSON-RPC method dispatcher interface.
|
198
|
+
#
|
199
|
+
# Provides class methods which to register global handlers to json-rpc methods and
|
200
|
+
# to handle requests and responses.
|
129
201
|
class Dispatcher
|
130
|
-
#
|
202
|
+
# Clear all registered json-rpc handlers
|
131
203
|
def self.init_handlers
|
132
204
|
@@handlers = {}
|
133
205
|
end
|
134
206
|
|
135
|
-
#
|
207
|
+
# Register a handler for the specified method(s)
|
208
|
+
#
|
209
|
+
# *WARNING* Do not invoke 'return' in registered handlers as these are blocks and *not* lambdas
|
210
|
+
# (see {http://stackoverflow.com/questions/626/when-to-use-lambda-when-to-use-proc-new Ruby Lambdas vs Procs})
|
211
|
+
#
|
212
|
+
# If specifying a single method name pass in a string, else pass in an array of strings.
|
213
|
+
# The block argument will be used as the method handler and will be invoked when
|
214
|
+
# json-rpc requests are received corresponding to the method name(s)
|
215
|
+
# @param [String,Array<String>] method_names one or more string method names
|
216
|
+
# @param [Hash] args options to initialize handler with, current unused
|
217
|
+
# @param [Callable] handler block to invoke when json-rpc requests to method are received
|
218
|
+
#
|
219
|
+
# @example
|
220
|
+
# RJR::Dispatcher.add_handler("hello_world") {
|
221
|
+
# "hello world"
|
222
|
+
# }
|
223
|
+
#
|
224
|
+
# RJR::Dispatcher.add_handler(["echo", "ECHO"]) { |val|
|
225
|
+
# val
|
226
|
+
# }
|
227
|
+
#
|
228
|
+
# # TODO define yard macros to construct documentation for a rjr based api
|
229
|
+
# from calls to add_handler
|
136
230
|
def self.add_handler(method_names, args = {}, &handler)
|
137
231
|
method_names = Array(method_names) unless method_names.is_a?(Array)
|
138
232
|
@@handlers ||= {}
|
@@ -142,7 +236,8 @@ class Dispatcher
|
|
142
236
|
}
|
143
237
|
end
|
144
238
|
|
145
|
-
# Helper to
|
239
|
+
# Helper used by RJR nodes to dispatch requests received via transports to
|
240
|
+
# registered handlers.
|
146
241
|
def self.dispatch_request(method_name, args = {})
|
147
242
|
@@handlers ||= {}
|
148
243
|
handler = @@handlers[method_name]
|
@@ -155,7 +250,8 @@ class Dispatcher
|
|
155
250
|
return handler.handle args
|
156
251
|
end
|
157
252
|
|
158
|
-
# Helper to handle
|
253
|
+
# Helper used by RJR nodes to handle responses received from rjr requests
|
254
|
+
# (returns return-value of method handler or raises error)
|
159
255
|
def self.handle_response(result)
|
160
256
|
unless result.success
|
161
257
|
#if result.error_class
|
data/lib/rjr/errors.rb
CHANGED
@@ -3,12 +3,14 @@
|
|
3
3
|
# Copyright (C) 2012 Mohammed Morsi <mo@morsi.org>
|
4
4
|
# Licensed under the Apache License, Version 2.0
|
5
5
|
|
6
|
-
# establish client connection w/ specified args and invoke block w/
|
7
|
-
# newly created client, returning it after block terminates
|
8
|
-
|
9
6
|
module RJR
|
7
|
+
|
8
|
+
# The RJR::Errors module provides a mechanism to dynamically create errors
|
9
|
+
# on demand as they are needed. At some point this will go away / be replaced
|
10
|
+
# with a more rigidly / fixed defined error heirarchy.
|
10
11
|
module Errors
|
11
12
|
|
13
|
+
# Catches all Errors constants and define new RuntimeError subclass
|
12
14
|
def self.const_missing(error_name) # :nodoc:
|
13
15
|
if error_name.to_s =~ /Error\z/
|
14
16
|
const_set(error_name, Class.new(RuntimeError))
|
data/lib/rjr/local_node.rb
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
# RJR Local Endpoint
|
2
2
|
#
|
3
|
+
# Implements the RJR::Node interface to satisty JSON-RPC requests via local method calls
|
4
|
+
#
|
3
5
|
# Copyright (C) 2012 Mohammed Morsi <mo@morsi.org>
|
4
6
|
# Licensed under the Apache License, Version 2.0
|
5
7
|
|
6
|
-
# establish client connection w/ specified args and invoke block w/
|
7
|
-
# newly created client, returning it after block terminates
|
8
|
-
|
9
8
|
require 'rjr/node'
|
10
9
|
require 'rjr/message'
|
11
10
|
|
12
11
|
module RJR
|
13
12
|
|
14
|
-
# Local
|
15
|
-
# send data back to client via local handlers
|
13
|
+
# Local node callback interface, used to invoke local json-rpc method handlers
|
16
14
|
class LocalNodeCallback
|
15
|
+
# LocalNodeCallback initializer
|
16
|
+
# @param [Hash] args the options to create the local node callback with
|
17
|
+
# @option args [LocalNode] :node local node used to send/receive messages
|
17
18
|
def initialize(args = {})
|
18
19
|
@node = args[:node]
|
19
20
|
end
|
20
21
|
|
22
|
+
# Implementation of {RJR::NodeCallback#invoke}
|
21
23
|
def invoke(callback_method, *data)
|
22
24
|
# TODO any exceptions from handler will propagate here, surround w/ begin/rescue block
|
23
25
|
@node.invoke_request(callback_method, *data)
|
@@ -25,34 +27,58 @@ class LocalNodeCallback
|
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
|
-
# Local node definition,
|
29
|
-
# requests via local handlers
|
30
|
+
# Local node definition, implements the {RJR::Node} interface to
|
31
|
+
# listen for and invoke json-rpc requests via local handlers
|
32
|
+
#
|
33
|
+
# This is useful for situations in which you would like to invoke registered
|
34
|
+
# json-rpc handlers locally, enforcing the same constraints as
|
35
|
+
# you would on a json-rpc request coming in remotely.
|
36
|
+
#
|
37
|
+
# @example Listening for and dispatching json-rpc requests locally
|
38
|
+
# RJR::Dispatcher.add_handler('hello') { |name|
|
39
|
+
# @rjr_node_type == :local ? "Hello superuser #{name}" : "Hello #{name}!"
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# # initialize node and invoke request
|
43
|
+
# node = RJR::LocalNode.new :node_id => 'node'
|
44
|
+
# node.invoke_request('hello', 'mo')
|
45
|
+
#
|
30
46
|
class LocalNode < RJR::Node
|
31
47
|
RJR_NODE_TYPE = :local
|
32
48
|
|
33
|
-
#
|
49
|
+
# allows clients to override the node type for the local node
|
34
50
|
attr_accessor :node_type
|
35
51
|
|
36
|
-
#
|
52
|
+
# LocalNode initializer
|
53
|
+
# @param [Hash] args the options to create the local node with
|
37
54
|
def initialize(args = {})
|
38
55
|
super(args)
|
39
56
|
@node_type = RJR_NODE_TYPE
|
40
57
|
end
|
41
58
|
|
42
59
|
# register connection event handler,
|
43
|
-
#
|
44
|
-
#
|
60
|
+
# *note* Until we support manual disconnections of the local node, we don't have to do anything here
|
61
|
+
#
|
62
|
+
# @param [:error, :close] event the event to register the handler for
|
63
|
+
# @param [Callable] handler block param to be added to array of handlers that are called when event occurs
|
64
|
+
# @yield [LocalNode] self is passed to each registered handler when event occurs
|
45
65
|
def on(event, &handler)
|
46
66
|
# TODO raise error (for the time being)?
|
47
67
|
end
|
48
68
|
|
49
69
|
# Instruct Node to start listening for and dispatching rpc requests
|
70
|
+
#
|
71
|
+
# Currently does nothing as method handlers can be invoked directly upon invoke_request
|
50
72
|
def listen
|
51
73
|
em_run do
|
52
74
|
end
|
53
75
|
end
|
54
76
|
|
55
|
-
# Instructs node to send rpc request, and wait for
|
77
|
+
# Instructs node to send rpc request, and wait for and return response
|
78
|
+
# @param [String] rpc_method json-rpc method to invoke on destination
|
79
|
+
# @param [Array] args array of arguments to convert to json and invoke remote method wtih
|
80
|
+
# @return [Object] the json result retrieved from destination converted to a ruby object
|
81
|
+
# @raise [Exception] if the destination raises an exception, it will be converted to json and re-raised here
|
56
82
|
def invoke_request(rpc_method, *args)
|
57
83
|
0.upto(args.size).each { |i| args[i] = args[i].to_s if args[i].is_a?(Symbol) }
|
58
84
|
message = RequestMessage.new :method => rpc_method,
|
data/lib/rjr/message.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# RJR Message
|
2
2
|
#
|
3
|
+
# Representations of json-rpc messages in accordance with the standard
|
4
|
+
#
|
3
5
|
# Copyright (C) 2012 Mohammed Morsi <mo@morsi.org>
|
4
6
|
# Licensed under the Apache License, Version 2.0
|
5
7
|
|
@@ -18,12 +20,34 @@ class RequestMessage
|
|
18
20
|
Array.new(16) {|x| rand(0xff) }
|
19
21
|
end
|
20
22
|
|
23
|
+
# Message string received from the source
|
21
24
|
attr_accessor :json_message
|
25
|
+
|
26
|
+
# Method source is invoking on the destination
|
22
27
|
attr_accessor :jr_method
|
28
|
+
|
29
|
+
# Arguments source is passing to destination method
|
23
30
|
attr_accessor :jr_args
|
31
|
+
|
32
|
+
# ID of the message in accordance w/ json-rpc specification
|
24
33
|
attr_accessor :msg_id
|
34
|
+
|
35
|
+
# Optional headers to add to json outside of standard json-rpc request
|
25
36
|
attr_accessor :headers
|
26
37
|
|
38
|
+
# RJR Request Message initializer
|
39
|
+
#
|
40
|
+
# This should be invoked with one of two argument sets. If creating a new message
|
41
|
+
# to send to the server, specify :method, :args, and :headers to include in the message
|
42
|
+
# (message id will be autogenerated). If handling an new request message sent from the
|
43
|
+
# client, simply specify :message and optionally any additional headers (they will
|
44
|
+
# be merged with the headers contained in the message)
|
45
|
+
#
|
46
|
+
# @param [Hash] args options to set on request
|
47
|
+
# @option args [String] :message json string received from sender
|
48
|
+
# @option args [Hash] :headers optional headers to set in request and subsequent messages
|
49
|
+
# @option args [String] :method method to invoke on server
|
50
|
+
# @option args [Array<Object>] :args to pass to server method, all must be convertable to/from json
|
27
51
|
def initialize(args = {})
|
28
52
|
if args.has_key?(:message)
|
29
53
|
begin
|
@@ -52,6 +76,10 @@ class RequestMessage
|
|
52
76
|
end
|
53
77
|
end
|
54
78
|
|
79
|
+
# Class helper to determine if the specified string is a valid json-rpc
|
80
|
+
# method request
|
81
|
+
# @param [String] message string message to check
|
82
|
+
# @return [true,false] indicating if message is request message
|
55
83
|
def self.is_request_message?(message)
|
56
84
|
begin
|
57
85
|
# TODO log error
|
@@ -61,6 +89,7 @@ class RequestMessage
|
|
61
89
|
end
|
62
90
|
end
|
63
91
|
|
92
|
+
# Convert request message to string json format
|
64
93
|
def to_s
|
65
94
|
request = { 'jsonrpc' => '2.0',
|
66
95
|
'method' => @jr_method,
|
@@ -72,13 +101,34 @@ class RequestMessage
|
|
72
101
|
|
73
102
|
end
|
74
103
|
|
75
|
-
# Message sent from server to client in response to request message
|
104
|
+
# Message sent from server to client in response to json-rpc request message
|
76
105
|
class ResponseMessage
|
106
|
+
# Message string received from the source
|
77
107
|
attr_accessor :json_message
|
108
|
+
|
109
|
+
# ID of the message in accordance w/ json-rpc specification
|
78
110
|
attr_accessor :msg_id
|
111
|
+
|
112
|
+
# Result encapsulated in the response message
|
113
|
+
# @see RJR::Result
|
79
114
|
attr_accessor :result
|
115
|
+
|
116
|
+
# Optional headers to add to json outside of standard json-rpc request
|
80
117
|
attr_accessor :headers
|
81
118
|
|
119
|
+
# ResponseMessage initializer
|
120
|
+
#
|
121
|
+
# This should be invoked with one of two argument sets. If creating a new message
|
122
|
+
# to send to the client, specify :id, :result, and :headers to include in the message.
|
123
|
+
# If handling an new request message sent from the client, simply specify :message
|
124
|
+
# and optionally any additional headers (they will be merged with the headers contained
|
125
|
+
# in the message)
|
126
|
+
#
|
127
|
+
# @param [Hash] args options to set on request
|
128
|
+
# @option args [String] :message json string received from sender
|
129
|
+
# @option args [Hash] :headers optional headers to set in request and subsequent messages
|
130
|
+
# @option args [String] :id id to set in response message, should be same as that in received message
|
131
|
+
# @option args [RJR::Result] :result result of json-rpc method invocation
|
82
132
|
def initialize(args = {})
|
83
133
|
if args.has_key?(:message)
|
84
134
|
response = JSON.parse(args[:message])
|
@@ -115,6 +165,10 @@ class ResponseMessage
|
|
115
165
|
|
116
166
|
end
|
117
167
|
|
168
|
+
# Class helper to determine if the specified string is a valid json-rpc
|
169
|
+
# method response
|
170
|
+
# @param [String] message string message to check
|
171
|
+
# @return [true,false] indicating if message is response message
|
118
172
|
def self.is_response_message?(message)
|
119
173
|
begin
|
120
174
|
json = JSON.parse(message)
|
@@ -125,6 +179,7 @@ class ResponseMessage
|
|
125
179
|
end
|
126
180
|
end
|
127
181
|
|
182
|
+
# Convert request message to string json format
|
128
183
|
def to_s
|
129
184
|
s = ''
|
130
185
|
if result.success
|
data/lib/rjr/multi_node.rb
CHANGED
@@ -1,30 +1,57 @@
|
|
1
1
|
# RJR MultiNode Endpoint
|
2
2
|
#
|
3
|
+
# Implements the RJR::Node interface to satisty JSON-RPC requests over multiple protocols
|
4
|
+
#
|
3
5
|
# Copyright (C) 2012 Mohammed Morsi <mo@morsi.org>
|
4
6
|
# Licensed under the Apache License, Version 2.0
|
5
7
|
|
6
|
-
# establish client connection w/ specified args and invoke block w/
|
7
|
-
# newly created client, returning it after block terminates
|
8
|
-
|
9
8
|
require 'eventmachine'
|
10
9
|
require 'rjr/node'
|
11
10
|
require 'rjr/message'
|
12
11
|
|
13
12
|
module RJR
|
14
13
|
|
14
|
+
# Multiple node definition, allows a developer to easily multiplex transport
|
15
|
+
# mechanisms to serve JSON-RPC requests over.
|
16
|
+
#
|
17
|
+
# @example Listening for json-rpc requests over amqp, tcp, http, and websockets
|
18
|
+
# # register rjr dispatchers (see RJR::Dispatcher)
|
19
|
+
# RJR::Dispatcher.add_handler('hello') { |name|
|
20
|
+
# # optionally use @rjr_node_type to handle different transport types
|
21
|
+
# "Hello #{name}!"
|
22
|
+
# }
|
23
|
+
#
|
24
|
+
# amqp_server = RJR::TCPNode.new :node_id => 'amqp_server', :broker => 'localhost'
|
25
|
+
# tcp_server = RJR::TCPNode.new :node_id => 'tcp_server', :host => 'localhost', :port => '7777'
|
26
|
+
# web_server = RJR::WebNode.new :node_id => 'tcp_server', :host => 'localhost', :port => '80'
|
27
|
+
# ws_server = RJR::WebNode.new :node_id => 'tcp_server', :host => 'localhost', :port => '8080'
|
28
|
+
#
|
29
|
+
# server = RJR::MultiNode.new :node_id => 'server',
|
30
|
+
# :nodes => [amqp_server, tcp_server, web_server, ws_server]
|
31
|
+
# server.listen
|
32
|
+
# server.join
|
33
|
+
#
|
34
|
+
# # invoke requests as you normally would via any protocol
|
35
|
+
#
|
15
36
|
class MultiNode < RJR::Node
|
16
|
-
#
|
37
|
+
# MultiNode initializer
|
38
|
+
# @param [Hash] args the options to create the tcp node with
|
39
|
+
# @option args [Array<RJR::Node>] :nodes array of nodes to use to listen to new requests on
|
17
40
|
def initialize(args = {})
|
18
41
|
super(args)
|
19
42
|
@nodes = args[:nodes]
|
20
43
|
end
|
21
44
|
|
45
|
+
# Add node to multinode
|
46
|
+
# @param [RJR::Node] node the node to add
|
22
47
|
def <<(node)
|
23
48
|
@nodes << node
|
24
49
|
end
|
25
50
|
|
26
51
|
|
27
52
|
# Instruct Node to start listening for and dispatching rpc requests
|
53
|
+
#
|
54
|
+
# Implementation of {RJR::Node#listen}
|
28
55
|
def listen
|
29
56
|
@nodes.each { |node|
|
30
57
|
node.listen
|