rjr 0.19.1 → 0.19.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|