rjr 0.19.1 → 0.19.2
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.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/Rakefile +0 -2
- data/examples/timeout.rb +23 -0
- data/lib/rjr/dispatcher.rb +1 -1
- data/lib/rjr/messages/intermediate.rb +50 -0
- data/lib/rjr/messages/notification.rb +9 -16
- data/lib/rjr/messages/request.rb +14 -20
- data/lib/rjr/messages/response.rb +19 -26
- data/lib/rjr/messages.rb +1 -0
- data/lib/rjr/node.rb +50 -34
- data/lib/rjr/nodes/amqp.rb +19 -3
- data/lib/rjr/nodes/local.rb +12 -5
- data/lib/rjr/nodes/tcp.rb +25 -12
- data/lib/rjr/nodes/web.rb +3 -2
- data/lib/rjr/request.rb +11 -1
- data/lib/rjr/util/json_parser.rb +47 -14
- data/lib/rjr/util/logger.rb +4 -2
- data/lib/rjr/version.rb +1 -1
- data/specs/args_spec.rb +2 -2
- data/specs/dispatcher_spec.rb +9 -9
- data/specs/em_adapter_spec.rb +3 -3
- data/specs/handles_methods_spec.rb +2 -2
- data/specs/json_parser_spec.rb +30 -4
- data/specs/messages/intermediate_spec.rb +58 -0
- data/specs/messages/notification_spec.rb +12 -13
- data/specs/messages/request_spec.rb +16 -16
- data/specs/messages/response_spec.rb +15 -14
- data/specs/node_spec.rb +79 -31
- data/specs/nodes/amqp_spec.rb +1 -1
- data/specs/nodes/local_spec.rb +2 -2
- data/specs/nodes/multi_spec.rb +1 -1
- data/specs/nodes/tcp_spec.rb +116 -27
- data/specs/nodes/web_spec.rb +1 -1
- data/specs/nodes/ws_spec.rb +1 -1
- data/specs/request_spec.rb +19 -0
- metadata +83 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67d23eb4f09f94c96a7d601c338b4d5088605c24
|
4
|
+
data.tar.gz: 53bbd5973ce99fa089c5d4bf560e2e9fe6c9005c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b8a199e88e55fd824cdabaeebf750cd234624ade0b9fc2acd9640aec729d5a3ab4339f5ef0769f707916a830f987d7a95c680e7e0ea07b4f526bd97b1394d3c
|
7
|
+
data.tar.gz: 55e17f0513fedef6f3e5dccae5673317bf5943988ae5d2146c7c2d76fa7aaee0ce003495c774ad3b623421efdff5127338d88cbf78792f3ecde9434dd9629f31
|
data/README.md
CHANGED
@@ -166,3 +166,6 @@ RJR as this is not standard JSON-RPC.
|
|
166
166
|
### Authors ###
|
167
167
|
* Mo Morsi <mo@morsi.org>
|
168
168
|
* Ladislav Smola <ladislav.smola@it-logica.cz>
|
169
|
+
* André Dieb Martins <andre.dieb@gmail.com>
|
170
|
+
* Eric Bakan <eric@ebakan.com>
|
171
|
+
* Jonas Collberg <jonas.collberg@gmail.com>
|
data/Rakefile
CHANGED
data/examples/timeout.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# A RJR timeout example
|
3
|
+
#
|
4
|
+
# Copyright (C) 2015 Mohammed Morsi <mo@morsi.org>
|
5
|
+
# Licensed under the Apache License, Version 2.0
|
6
|
+
|
7
|
+
require 'rjr/nodes/tcp'
|
8
|
+
|
9
|
+
server = RJR::Nodes::TCP.new :host => 'localhost', :port => 9789, :node_id => "server"
|
10
|
+
server.dispatcher.handle('method') { |i|
|
11
|
+
sleep 2
|
12
|
+
}
|
13
|
+
server.listen
|
14
|
+
|
15
|
+
client = RJR::Nodes::TCP.new :node_id => "client",
|
16
|
+
:host => 'localhost',
|
17
|
+
:port => 9666,
|
18
|
+
:timeout => 1 # causes error, change to 3 to wait for server response
|
19
|
+
|
20
|
+
client.invoke "jsonrpc://localhost:9789", "method", "Hello World"
|
21
|
+
# => exception
|
22
|
+
|
23
|
+
#client.join
|
data/lib/rjr/dispatcher.rb
CHANGED
@@ -152,7 +152,7 @@ class Dispatcher
|
|
152
152
|
request = Request.new args.merge(:rjr_handler => handler)
|
153
153
|
|
154
154
|
# set request environment
|
155
|
-
request.
|
155
|
+
request.set_env(environment) unless environment.nil?
|
156
156
|
|
157
157
|
begin
|
158
158
|
retval = request.handle
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# RJR Intermediate Message
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014-2015 Mohammed Morsi <mo@morsi.org>
|
4
|
+
# Licensed under the Apache License, Version 2.0
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
require 'rjr/util/json_parser'
|
8
|
+
|
9
|
+
module RJR
|
10
|
+
module Messages
|
11
|
+
|
12
|
+
# Intermediate representation of a JSON-RPC data containing
|
13
|
+
# extracted/parsed data which has not been analysed.
|
14
|
+
class Intermediate
|
15
|
+
# JSON from which data is extracted from
|
16
|
+
attr_accessor :json
|
17
|
+
|
18
|
+
# Data extracted from message
|
19
|
+
attr_accessor :data
|
20
|
+
|
21
|
+
def initialize(args = {})
|
22
|
+
@json = args[:json] || nil
|
23
|
+
@data = args[:data] || {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def keys
|
27
|
+
data.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](key)
|
31
|
+
data[key.to_s]
|
32
|
+
end
|
33
|
+
|
34
|
+
def has?(key)
|
35
|
+
data.key?(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.parse(json)
|
39
|
+
parsed = nil
|
40
|
+
|
41
|
+
#allow parsing errs to propagate up
|
42
|
+
parsed = JSONParser.parse(json)
|
43
|
+
|
44
|
+
self.new :json => json,
|
45
|
+
:data => parsed
|
46
|
+
end
|
47
|
+
|
48
|
+
end # class Intermediate
|
49
|
+
end # module Messages
|
50
|
+
end # module RJR
|
@@ -13,7 +13,7 @@ module Messages
|
|
13
13
|
# indicate the result should _not_ be returned
|
14
14
|
class Notification
|
15
15
|
# Message string received from the source
|
16
|
-
attr_accessor :
|
16
|
+
attr_accessor :message
|
17
17
|
|
18
18
|
# Method source is invoking on the destination
|
19
19
|
attr_accessor :jr_method
|
@@ -48,18 +48,17 @@ class Notification
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def parse_message(message)
|
51
|
-
@
|
52
|
-
|
53
|
-
@
|
54
|
-
@jr_args = notification['params']
|
51
|
+
@message = message
|
52
|
+
@jr_method = message['method']
|
53
|
+
@jr_args = message['params']
|
55
54
|
|
56
|
-
parse_headers(
|
55
|
+
parse_headers(message)
|
57
56
|
end
|
58
57
|
|
59
|
-
def parse_headers(
|
60
|
-
|
58
|
+
def parse_headers(message)
|
59
|
+
message.keys.select { |k|
|
61
60
|
!['jsonrpc', 'method', 'params'].include?(k)
|
62
|
-
}.each { |k| @headers[k] =
|
61
|
+
}.each { |k| @headers[k] = message[k] }
|
63
62
|
end
|
64
63
|
|
65
64
|
public
|
@@ -70,13 +69,7 @@ class Notification
|
|
70
69
|
# @param [String] message string message to check
|
71
70
|
# @return [true,false] indicating if message is a notification message
|
72
71
|
def self.is_notification_message?(message)
|
73
|
-
|
74
|
-
# FIXME log error
|
75
|
-
parsed = JSONParser.parse(message)
|
76
|
-
parsed.has_key?('method') && !parsed.has_key?('id')
|
77
|
-
rescue Exception => e
|
78
|
-
false
|
79
|
-
end
|
72
|
+
message.has?('method') && !message.has?('id')
|
80
73
|
end
|
81
74
|
|
82
75
|
# Convert notification message to json
|
data/lib/rjr/messages/request.rb
CHANGED
@@ -12,7 +12,7 @@ module Messages
|
|
12
12
|
# Message sent from client to server to invoke a JSON-RPC method
|
13
13
|
class Request
|
14
14
|
# Message string received from the source
|
15
|
-
attr_accessor :
|
15
|
+
attr_accessor :message
|
16
16
|
|
17
17
|
# Method source is invoking on the destination
|
18
18
|
attr_accessor :jr_method
|
@@ -51,35 +51,29 @@ class Request
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def parse_message(message)
|
54
|
-
@
|
55
|
-
|
56
|
-
@
|
57
|
-
@
|
58
|
-
@msg_id = request['id']
|
54
|
+
@message = message
|
55
|
+
@jr_method = message['method']
|
56
|
+
@jr_args = message['params']
|
57
|
+
@msg_id = message['id']
|
59
58
|
|
60
|
-
parse_headers(
|
59
|
+
parse_headers(message)
|
61
60
|
end
|
62
61
|
|
63
|
-
def parse_headers(
|
64
|
-
|
62
|
+
def parse_headers(message)
|
63
|
+
message.keys.select { |k|
|
65
64
|
!['jsonrpc', 'id', 'method', 'params'].include?(k)
|
66
|
-
}.each { |k| @headers[k] =
|
65
|
+
}.each { |k| @headers[k] = message[k] }
|
67
66
|
end
|
68
67
|
|
69
68
|
public
|
70
69
|
|
71
|
-
# Class helper to determine if the specified
|
72
|
-
# method request
|
73
|
-
#
|
70
|
+
# Class helper to determine if the specified message is a valid
|
71
|
+
# json-rpc method request message.
|
72
|
+
#
|
73
|
+
# @param [Message] message to check
|
74
74
|
# @return [true,false] indicating if message is request message
|
75
75
|
def self.is_request_message?(message)
|
76
|
-
|
77
|
-
# FIXME log error
|
78
|
-
parsed = JSONParser.parse(message)
|
79
|
-
parsed.has_key?('method') && parsed.has_key?('id')
|
80
|
-
rescue Exception => e
|
81
|
-
false
|
82
|
-
end
|
76
|
+
message.has?('method') && message.has?('id')
|
83
77
|
end
|
84
78
|
|
85
79
|
# Convert request message to json
|
@@ -13,7 +13,7 @@ module Messages
|
|
13
13
|
# Message sent from server to client in response to a JSON-RPC request
|
14
14
|
class Response
|
15
15
|
# Message string received from the source
|
16
|
-
attr_accessor :
|
16
|
+
attr_accessor :message
|
17
17
|
|
18
18
|
# ID of the message in accordance w/ json-rpc specification
|
19
19
|
attr_accessor :msg_id
|
@@ -49,54 +49,47 @@ class Response
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def parse_message(message)
|
52
|
-
@
|
53
|
-
|
54
|
-
@msg_id = response['id']
|
52
|
+
@message = message
|
53
|
+
@msg_id = message['id']
|
55
54
|
|
56
|
-
parse_result(
|
57
|
-
parse_headers(
|
55
|
+
parse_result(message)
|
56
|
+
parse_headers(message)
|
58
57
|
end
|
59
58
|
|
60
|
-
def parse_result(
|
59
|
+
def parse_result(message)
|
61
60
|
@result = Result.new
|
62
|
-
@result.success =
|
61
|
+
@result.success = message.has?('result')
|
63
62
|
@result.failed = !@result.success
|
64
63
|
|
65
64
|
if @result.success
|
66
|
-
@result.result =
|
65
|
+
@result.result = message['result']
|
67
66
|
|
68
|
-
elsif
|
69
|
-
@result.error_code =
|
70
|
-
@result.error_msg =
|
67
|
+
elsif message.has?('error')
|
68
|
+
@result.error_code = message['error']['code']
|
69
|
+
@result.error_msg = message['error']['message']
|
71
70
|
|
72
71
|
# TODO can we safely constantize this ?
|
73
|
-
@result.error_class =
|
72
|
+
@result.error_class = message['error']['class']
|
74
73
|
end
|
75
74
|
|
76
75
|
@result
|
77
76
|
end
|
78
77
|
|
79
|
-
def parse_headers(
|
80
|
-
|
78
|
+
def parse_headers(message)
|
79
|
+
message.keys.select { |k|
|
81
80
|
!['jsonrpc', 'id', 'method', 'result', 'error'].include?(k)
|
82
|
-
}.each { |k| @headers[k] =
|
81
|
+
}.each { |k| @headers[k] = message[k] }
|
83
82
|
end
|
84
83
|
|
85
84
|
public
|
86
85
|
|
87
|
-
# Class helper to determine if the specified string is a
|
88
|
-
# method response
|
86
|
+
# Class helper to determine if the specified string is a
|
87
|
+
# valid json-rpc method response
|
88
|
+
#
|
89
89
|
# @param [String] message string message to check
|
90
90
|
# @return [true,false] indicating if message is response message
|
91
91
|
def self.is_response_message?(message)
|
92
|
-
|
93
|
-
# FIXME log error
|
94
|
-
json = JSONParser.parse(message)
|
95
|
-
json.has_key?('result') || json.has_key?('error')
|
96
|
-
rescue Exception => e
|
97
|
-
puts e.to_s
|
98
|
-
false
|
99
|
-
end
|
92
|
+
message.has?('result') || message.has?('error')
|
100
93
|
end
|
101
94
|
|
102
95
|
def success_json
|
data/lib/rjr/messages.rb
CHANGED
data/lib/rjr/node.rb
CHANGED
@@ -104,9 +104,12 @@ class Node
|
|
104
104
|
clear_event_handlers
|
105
105
|
@response_lock = Mutex.new
|
106
106
|
@response_cv = ConditionVariable.new
|
107
|
+
@pending = {}
|
107
108
|
@responses = []
|
108
109
|
|
109
110
|
@node_id = args[:node_id]
|
111
|
+
@timeout = args[:timeout]
|
112
|
+
@wait_interval = args[:wait_interval] || 0.01
|
110
113
|
@dispatcher = args[:dispatcher] || RJR::Dispatcher.new
|
111
114
|
@message_headers = args.has_key?(:headers) ? {}.merge(args[:headers]) : {}
|
112
115
|
|
@@ -143,14 +146,20 @@ class Node
|
|
143
146
|
##################################################################
|
144
147
|
# Reset connection event handlers
|
145
148
|
def clear_event_handlers
|
146
|
-
@connection_event_handlers = {
|
149
|
+
@connection_event_handlers = {
|
150
|
+
:opened => [],
|
151
|
+
:closed => [],
|
152
|
+
:error => []
|
153
|
+
}
|
147
154
|
end
|
148
155
|
|
149
156
|
# Register connection event handler
|
150
|
-
# @param [:
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
157
|
+
# @param event [:opened, :closed, :error] the event to register the handler
|
158
|
+
# for
|
159
|
+
# @param handler [Callable] block param to be added to array of handlers
|
160
|
+
# that are called when event occurs
|
161
|
+
# @yield [Node, *args] self and event-specific *args are passed to each
|
162
|
+
# registered handler when event occurs
|
154
163
|
def on(event, &handler)
|
155
164
|
return unless @connection_event_handlers.keys.include?(event)
|
156
165
|
@connection_event_handlers[event] << handler
|
@@ -158,12 +167,11 @@ class Node
|
|
158
167
|
|
159
168
|
private
|
160
169
|
|
161
|
-
# Internal helper, run connection event handlers for specified event
|
162
|
-
|
170
|
+
# Internal helper, run connection event handlers for specified event, passing
|
171
|
+
# self and args to handler
|
172
|
+
def connection_event(event, *args)
|
163
173
|
return unless @connection_event_handlers.keys.include?(event)
|
164
|
-
@connection_event_handlers[event].each { |h|
|
165
|
-
h.call self
|
166
|
-
}
|
174
|
+
@connection_event_handlers[event].each { |h| h.call(self, *args) }
|
167
175
|
end
|
168
176
|
|
169
177
|
##################################################################
|
@@ -183,28 +191,36 @@ class Node
|
|
183
191
|
|
184
192
|
# Internal helper, handle message received
|
185
193
|
def handle_message(msg, connection = {})
|
186
|
-
|
187
|
-
|
194
|
+
intermediate = Messages::Intermediate.parse(msg)
|
195
|
+
|
196
|
+
if Messages::Request.is_request_message?(intermediate)
|
197
|
+
tp << ThreadPoolJob.new(intermediate) { |i|
|
198
|
+
handle_request(i, false, connection)
|
199
|
+
}
|
188
200
|
|
189
|
-
elsif Messages::Notification.is_notification_message?(
|
190
|
-
tp << ThreadPoolJob.new(
|
201
|
+
elsif Messages::Notification.is_notification_message?(intermediate)
|
202
|
+
tp << ThreadPoolJob.new(intermediate) { |i|
|
203
|
+
handle_request(i, true, connection)
|
204
|
+
}
|
191
205
|
|
192
|
-
elsif Messages::Response.is_response_message?(
|
193
|
-
handle_response(
|
206
|
+
elsif Messages::Response.is_response_message?(intermediate)
|
207
|
+
handle_response(intermediate)
|
194
208
|
|
195
209
|
end
|
210
|
+
|
211
|
+
intermediate
|
196
212
|
end
|
197
213
|
|
198
214
|
# Internal helper, handle request message received
|
199
|
-
def handle_request(
|
215
|
+
def handle_request(message, notification=false, connection={})
|
200
216
|
# get client for the specified connection
|
201
217
|
# TODO should grap port/ip immediately on connection and use that
|
202
218
|
client_port,client_ip = client_for(connection)
|
203
219
|
|
204
220
|
msg = notification ?
|
205
|
-
Messages::Notification.new(:message =>
|
221
|
+
Messages::Notification.new(:message => message,
|
206
222
|
:headers => @message_headers) :
|
207
|
-
Messages::Request.new(:message =>
|
223
|
+
Messages::Request.new(:message => message,
|
208
224
|
:headers => @message_headers)
|
209
225
|
|
210
226
|
callback = NodeCallback.new(:node => self,
|
@@ -233,8 +249,8 @@ class Node
|
|
233
249
|
end
|
234
250
|
|
235
251
|
# Internal helper, handle response message received
|
236
|
-
def handle_response(
|
237
|
-
msg = Messages::Response.new(:message =>
|
252
|
+
def handle_response(message)
|
253
|
+
msg = Messages::Response.new(:message => message,
|
238
254
|
:headers => self.message_headers)
|
239
255
|
res = err = nil
|
240
256
|
begin
|
@@ -254,25 +270,25 @@ class Node
|
|
254
270
|
# Internal helper, block until response matching message id is received
|
255
271
|
def wait_for_result(message)
|
256
272
|
res = nil
|
273
|
+
message_id = message.msg_id
|
274
|
+
@pending[message_id] = Time.now
|
257
275
|
while res.nil?
|
258
276
|
@response_lock.synchronize{
|
259
|
-
#
|
277
|
+
# Prune messages that timed out
|
278
|
+
if @timeout
|
279
|
+
now = Time.now
|
280
|
+
@pending.delete_if { |_, start_time| (now - start_time) > @timeout }
|
281
|
+
end
|
282
|
+
pending_ids = @pending.keys
|
283
|
+
raise Exception, 'Timed out' unless pending_ids.include? message_id
|
284
|
+
|
285
|
+
# Prune invalid responses
|
286
|
+
@responses.keep_if { |response| @pending.has_key? response.first }
|
260
287
|
res = @responses.find { |response| message.msg_id == response.first }
|
261
288
|
if !res.nil?
|
262
289
|
@responses.delete(res)
|
263
|
-
|
264
290
|
else
|
265
|
-
|
266
|
-
# may be deleted resulting in this sleeping indefinetly and a deadlock
|
267
|
-
|
268
|
-
# TODO wait for a finite # of seconds, record time we started waiting
|
269
|
-
# before while loop and on every iteration check to see if we've been
|
270
|
-
# waiting longer than an optional timeout. If so throw an error (also
|
271
|
-
# need mechanism to discard result if it comes in later).
|
272
|
-
# finite # of seconds we wait and optional timeout should be
|
273
|
-
# configurable on node class
|
274
|
-
@response_cv.wait @response_lock
|
275
|
-
|
291
|
+
@response_cv.wait @response_lock, @wait_interval
|
276
292
|
end
|
277
293
|
}
|
278
294
|
end
|
data/lib/rjr/nodes/amqp.rb
CHANGED
@@ -56,6 +56,17 @@ class AMQP < RJR::Node
|
|
56
56
|
|
57
57
|
private
|
58
58
|
|
59
|
+
def amqp_options
|
60
|
+
opts = {}
|
61
|
+
opts[:host] = @host if @host
|
62
|
+
opts[:port] = @port if @port
|
63
|
+
opts[:vhost] = @vhost if @vhost
|
64
|
+
opts[:user] = @user if @user
|
65
|
+
opts[:pass] = @pass if @pass
|
66
|
+
opts[:ssl] = @ssl if @ssl
|
67
|
+
opts
|
68
|
+
end
|
69
|
+
|
59
70
|
# Internal helper, initialize the amqp subsystem
|
60
71
|
def init_node(&on_init)
|
61
72
|
if !@conn.nil? && @conn.connected?
|
@@ -63,7 +74,7 @@ class AMQP < RJR::Node
|
|
63
74
|
return
|
64
75
|
end
|
65
76
|
|
66
|
-
@conn = ::AMQP.connect(
|
77
|
+
@conn = ::AMQP.connect(amqp_options) do |conn|
|
67
78
|
::AMQP.connection = conn # XXX not sure why this is needed but the amqp
|
68
79
|
# em interface won't shut down cleanly otherwise
|
69
80
|
|
@@ -117,12 +128,17 @@ class AMQP < RJR::Node
|
|
117
128
|
# @option args [String] :broker the amqp message broker which to connect to
|
118
129
|
def initialize(args = {})
|
119
130
|
super(args)
|
120
|
-
@
|
131
|
+
@host = args[:host] || args[:broker]
|
132
|
+
@port = args[:port]
|
133
|
+
@vhost = args[:vhost]
|
134
|
+
@user = args[:user] || args[:username]
|
135
|
+
@pass = args[:pass] || args[:password]
|
136
|
+
@ssl = args[:ssl]
|
121
137
|
@amqp_lock = Mutex.new
|
122
138
|
end
|
123
139
|
|
124
140
|
def to_s
|
125
|
-
"RJR::Nodes::AMQP<#{@node_id},#{@
|
141
|
+
"RJR::Nodes::AMQP<#{@node_id},#{@host},#{@port},#{@vhost},#{@queue_name}>"
|
126
142
|
end
|
127
143
|
|
128
144
|
# Publish a message using the amqp exchange
|
data/lib/rjr/nodes/local.rb
CHANGED
@@ -61,8 +61,9 @@ class Local < RJR::Node
|
|
61
61
|
# Implementation of RJR::Node#send_msg
|
62
62
|
def send_msg(msg, connection)
|
63
63
|
# ignore response message
|
64
|
-
|
65
|
-
|
64
|
+
inter = Messages::Intermediate.parse(msg)
|
65
|
+
unless Messages::Response.is_response_message?(inter)
|
66
|
+
launch_request(inter, true) # .join?
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
@@ -80,9 +81,15 @@ class Local < RJR::Node
|
|
80
81
|
# (or close to it, globals will still be available, but locks will
|
81
82
|
# not be locally held, etc)
|
82
83
|
def launch_request(req, notification)
|
83
|
-
Thread.new(req,notification) { |req,notification|
|
84
|
-
|
85
|
-
|
84
|
+
Thread.new(req, notification) { |req, notification|
|
85
|
+
inter = req.is_a?(Messages::Intermediate) ? req :
|
86
|
+
Messages::Intermediate.parse(req)
|
87
|
+
res = handle_request(inter, notification, nil)
|
88
|
+
|
89
|
+
unless res.nil?
|
90
|
+
inter = Messages::Intermediate.parse(res.to_s)
|
91
|
+
handle_response(inter)
|
92
|
+
end
|
86
93
|
}
|
87
94
|
end
|
88
95
|
|
data/lib/rjr/nodes/tcp.rb
CHANGED
@@ -33,6 +33,11 @@ class TCPConnection < EventMachine::Connection
|
|
33
33
|
|
34
34
|
@send_lock = Mutex.new
|
35
35
|
@data = ""
|
36
|
+
@rjr_node.add_connection(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def post_init
|
40
|
+
@rjr_node.send(:connection_event, :opened, self)
|
36
41
|
end
|
37
42
|
|
38
43
|
# EventMachine::Connection#receive_data callback, handle request / response messages
|
@@ -54,6 +59,10 @@ class TCPConnection < EventMachine::Connection
|
|
54
59
|
}
|
55
60
|
end
|
56
61
|
|
62
|
+
def unbind
|
63
|
+
@rjr_node.remove_connection(self)
|
64
|
+
@rjr_node.send(:connection_event, :closed, self)
|
65
|
+
end
|
57
66
|
end
|
58
67
|
|
59
68
|
# TCP node definition, listen for and invoke json-rpc requests via TCP sockets
|
@@ -89,18 +98,8 @@ class TCP < RJR::Node
|
|
89
98
|
# Internal helper, initialize new client
|
90
99
|
def init_client(args={}, &on_init)
|
91
100
|
host,port = args[:host], args[:port]
|
92
|
-
connection =
|
93
|
-
|
94
|
-
connection = @connections.find { |c|
|
95
|
-
port == c.port && host == c.host
|
96
|
-
}
|
97
|
-
if connection.nil?
|
98
|
-
connection =
|
99
|
-
EventMachine::connect host, port,
|
100
|
-
TCPConnection, args
|
101
|
-
@connections << connection
|
102
|
-
end
|
103
|
-
}
|
101
|
+
connection = @connections.find { |c| port == c.port && host == c.host }
|
102
|
+
connection ||= EventMachine::connect(host, port, TCPConnection, args)
|
104
103
|
on_init.call(connection) # TODO move to tcpnode event ?
|
105
104
|
end
|
106
105
|
|
@@ -140,6 +139,20 @@ class TCP < RJR::Node
|
|
140
139
|
self
|
141
140
|
end
|
142
141
|
|
142
|
+
# Called by TCPConnection::initialize
|
143
|
+
def add_connection(connection)
|
144
|
+
@connections_lock.synchronize do
|
145
|
+
connections << connection
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Called by TCPConnection::unbind
|
150
|
+
def remove_connection(connection)
|
151
|
+
@connections_lock.synchronize do
|
152
|
+
connections.delete(connection)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
143
156
|
# Instructs node to send rpc request, and wait for / return response.
|
144
157
|
#
|
145
158
|
# Implementation of RJR::Node#invoke
|
data/lib/rjr/nodes/web.rb
CHANGED
@@ -52,12 +52,13 @@ class WebConnection < EventMachine::Connection
|
|
52
52
|
def process_http_request
|
53
53
|
# TODO support http protocols other than POST
|
54
54
|
msg = @http_post_content.nil? ? '' : @http_post_content
|
55
|
-
@rjr_node.send(:handle_message, msg, self) # XXX private method
|
55
|
+
inter = @rjr_node.send(:handle_message, msg, self) # XXX private method
|
56
56
|
|
57
57
|
# XXX we still have to send a response back to client to satisfy
|
58
58
|
# the http standard, even if this is a notification. handle_message
|
59
59
|
# does not do this.
|
60
|
-
|
60
|
+
notification = Messages::Notification.is_notification_message?(inter)
|
61
|
+
@rjr_node.send_msg "", self if notification
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
data/lib/rjr/request.rb
CHANGED
@@ -50,6 +50,9 @@ class Request
|
|
50
50
|
# ID of node which request came in on
|
51
51
|
attr_accessor :rjr_node_id
|
52
52
|
|
53
|
+
# Environment handler will be run in
|
54
|
+
attr_accessor :rjr_env
|
55
|
+
|
53
56
|
# Actual proc registered to handle request
|
54
57
|
attr_accessor :rjr_handler
|
55
58
|
|
@@ -73,7 +76,14 @@ class Request
|
|
73
76
|
@rjr_handler = args[:rjr_handler]
|
74
77
|
|
75
78
|
@rjr_args = Arguments.new :args => @rjr_method_args
|
76
|
-
@
|
79
|
+
@rjr_env = nil
|
80
|
+
@result = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
# Set the environment by extending Request instance with the specified module
|
84
|
+
def set_env(env)
|
85
|
+
@rjr_env = env
|
86
|
+
self.extend(env)
|
77
87
|
end
|
78
88
|
|
79
89
|
# Invoke the request by calling the registered handler with the registered
|