rjr 0.18.2 → 0.19.1
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/Rakefile +2 -0
- data/bin/rjr-client +16 -9
- data/bin/rjr-server +2 -1
- data/examples/client.rb +21 -19
- data/examples/server.rb +1 -1
- data/examples/structured_server.rb +1 -0
- data/examples/tcp.rb +1 -0
- data/lib/rjr/common.rb +1 -226
- data/lib/rjr/core_ext.rb +63 -0
- data/lib/rjr/dispatcher.rb +75 -219
- data/lib/rjr/messages.rb +8 -0
- data/lib/rjr/messages/compressed.rb +264 -0
- data/lib/rjr/messages/notification.rb +95 -0
- data/lib/rjr/messages/request.rb +99 -0
- data/lib/rjr/messages/response.rb +128 -0
- data/lib/rjr/node.rb +100 -97
- data/lib/rjr/node_callback.rb +43 -0
- data/lib/rjr/nodes/amqp.rb +12 -11
- data/lib/rjr/nodes/easy.rb +4 -4
- data/lib/rjr/nodes/local.rb +13 -12
- data/lib/rjr/nodes/multi.rb +1 -1
- data/lib/rjr/nodes/tcp.rb +15 -13
- data/lib/rjr/nodes/template.rb +4 -4
- data/lib/rjr/nodes/unix.rb +15 -13
- data/lib/rjr/nodes/web.rb +15 -14
- data/lib/rjr/nodes/ws.rb +12 -11
- data/lib/rjr/request.rb +128 -0
- data/lib/rjr/result.rb +75 -0
- data/lib/rjr/util/args.rb +145 -0
- data/lib/rjr/{em_adapter.rb → util/em_adapter.rb} +0 -0
- data/lib/rjr/util/handles_methods.rb +115 -0
- data/lib/rjr/util/has_messages.rb +50 -0
- data/lib/rjr/{inspect.rb → util/inspect.rb} +1 -1
- data/lib/rjr/util/json_parser.rb +101 -0
- data/lib/rjr/util/logger.rb +128 -0
- data/lib/rjr/{thread_pool.rb → util/thread_pool.rb} +2 -0
- data/lib/rjr/version.rb +1 -1
- data/site/jrw.js +1 -1
- data/specs/args_spec.rb +144 -0
- data/specs/dispatcher_spec.rb +399 -211
- data/specs/em_adapter_spec.rb +31 -18
- data/specs/handles_methods_spec.rb +154 -0
- data/specs/has_messages_spec.rb +54 -0
- data/specs/inspect_spec.rb +1 -1
- data/specs/json_parser_spec.rb +169 -0
- data/specs/messages/notification_spec.rb +59 -0
- data/specs/messages/request_spec.rb +66 -0
- data/specs/messages/response_spec.rb +94 -0
- data/specs/node_callbacks_spec.rb +47 -0
- data/specs/node_spec.rb +465 -56
- data/specs/request_spec.rb +147 -0
- data/specs/result_spec.rb +144 -0
- data/specs/thread_pool_spec.rb +1 -1
- metadata +41 -11
- data/lib/rjr/errors.rb +0 -23
- data/lib/rjr/message.rb +0 -351
- data/lib/rjr/semaphore.rb +0 -58
- data/specs/message_spec.rb +0 -229
@@ -0,0 +1,95 @@
|
|
1
|
+
# RJR Notification Message
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012-2014 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
|
+
# Message sent to a JSON-RPC server to invoke a rpc method but
|
13
|
+
# indicate the result should _not_ be returned
|
14
|
+
class Notification
|
15
|
+
# Message string received from the source
|
16
|
+
attr_accessor :json_message
|
17
|
+
|
18
|
+
# Method source is invoking on the destination
|
19
|
+
attr_accessor :jr_method
|
20
|
+
|
21
|
+
# Arguments source is passing to destination method
|
22
|
+
attr_accessor :jr_args
|
23
|
+
|
24
|
+
# Optional headers to add to json outside of standard json-rpc request
|
25
|
+
attr_accessor :headers
|
26
|
+
|
27
|
+
# RJR Notification Message initializer
|
28
|
+
#
|
29
|
+
# No message id will be generated in accordance w/ the jsonrpc standard
|
30
|
+
#
|
31
|
+
# @param [Hash] args options to set on request
|
32
|
+
# @option args [String] :message json string received from sender
|
33
|
+
# @option args [Hash] :headers optional headers to set in request and subsequent messages
|
34
|
+
# @option args [String] :method method to invoke on server
|
35
|
+
# @option args [Array<Object>] :args to pass to server method, all must be convertable to/from json
|
36
|
+
def initialize(args = {})
|
37
|
+
parse_args(args)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def parse_args(args)
|
43
|
+
@jr_method = args[:method]
|
44
|
+
@jr_args = args[:args] || []
|
45
|
+
@headers = args[:headers] || {}
|
46
|
+
|
47
|
+
parse_message(args[:message]) if args.has_key?(:message)
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_message(message)
|
51
|
+
@json_message = message
|
52
|
+
notification = JSONParser.parse(@json_message)
|
53
|
+
@jr_method = notification['method']
|
54
|
+
@jr_args = notification['params']
|
55
|
+
|
56
|
+
parse_headers(notification)
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_headers(notification)
|
60
|
+
notification.keys.select { |k|
|
61
|
+
!['jsonrpc', 'method', 'params'].include?(k)
|
62
|
+
}.each { |k| @headers[k] = notification[k] }
|
63
|
+
end
|
64
|
+
|
65
|
+
public
|
66
|
+
|
67
|
+
# Class helper to determine if the specified string is a valid json-rpc
|
68
|
+
# notification
|
69
|
+
#
|
70
|
+
# @param [String] message string message to check
|
71
|
+
# @return [true,false] indicating if message is a notification message
|
72
|
+
def self.is_notification_message?(message)
|
73
|
+
begin
|
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
|
80
|
+
end
|
81
|
+
|
82
|
+
# Convert notification message to json
|
83
|
+
def to_json(*a)
|
84
|
+
{'jsonrpc' => '2.0',
|
85
|
+
'method' => @jr_method,
|
86
|
+
'params' => @jr_args}.merge(@headers).to_json(*a)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Convert request to string format
|
90
|
+
def to_s
|
91
|
+
to_json.to_s
|
92
|
+
end
|
93
|
+
end # class Notification
|
94
|
+
end # module Messages
|
95
|
+
end # module RJR
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# RJR Request Message
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012-2014 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
|
+
# Message sent from client to server to invoke a JSON-RPC method
|
13
|
+
class Request
|
14
|
+
# Message string received from the source
|
15
|
+
attr_accessor :json_message
|
16
|
+
|
17
|
+
# Method source is invoking on the destination
|
18
|
+
attr_accessor :jr_method
|
19
|
+
|
20
|
+
# Arguments source is passing to destination method
|
21
|
+
attr_accessor :jr_args
|
22
|
+
|
23
|
+
# ID of the message in accordance w/ json-rpc specification
|
24
|
+
attr_accessor :msg_id
|
25
|
+
|
26
|
+
# Optional headers to add to json outside of standard json-rpc request
|
27
|
+
attr_accessor :headers
|
28
|
+
|
29
|
+
# RJR Request Message initializer
|
30
|
+
#
|
31
|
+
# @param [Hash] args options to set on request
|
32
|
+
# @option args [String] :message json string received from sender
|
33
|
+
# @option args [Hash] :headers optional headers to set in request
|
34
|
+
# and subsequent messages
|
35
|
+
# @option args [String] :method method to invoke on server
|
36
|
+
# @option args [Array<Object>] :args to pass to server method, all
|
37
|
+
# must be convertable to/from json
|
38
|
+
def initialize(args = {})
|
39
|
+
parse_args(args)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parse_args(args)
|
45
|
+
@jr_method = args[:method]
|
46
|
+
@jr_args = args[:args] || []
|
47
|
+
@headers = args[:headers] || {}
|
48
|
+
@msg_id = args[:id] || gen_uuid
|
49
|
+
|
50
|
+
parse_message(args[:message]) if args.has_key?(:message)
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_message(message)
|
54
|
+
@json_message = message
|
55
|
+
request = JSONParser.parse(@json_message)
|
56
|
+
@jr_method = request['method']
|
57
|
+
@jr_args = request['params']
|
58
|
+
@msg_id = request['id']
|
59
|
+
|
60
|
+
parse_headers(request)
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_headers(request)
|
64
|
+
request.keys.select { |k|
|
65
|
+
!['jsonrpc', 'id', 'method', 'params'].include?(k)
|
66
|
+
}.each { |k| @headers[k] = request[k] }
|
67
|
+
end
|
68
|
+
|
69
|
+
public
|
70
|
+
|
71
|
+
# Class helper to determine if the specified string is a valid json-rpc
|
72
|
+
# method request
|
73
|
+
# @param [String] message string message to check
|
74
|
+
# @return [true,false] indicating if message is request message
|
75
|
+
def self.is_request_message?(message)
|
76
|
+
begin
|
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
|
83
|
+
end
|
84
|
+
|
85
|
+
# Convert request message to json
|
86
|
+
def to_json(*a)
|
87
|
+
{'jsonrpc' => '2.0',
|
88
|
+
'id' => @msg_id,
|
89
|
+
'method' => @jr_method,
|
90
|
+
'params' => @jr_args}.merge(@headers).to_json(*a)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Convert request to string format
|
94
|
+
def to_s
|
95
|
+
to_json.to_s
|
96
|
+
end
|
97
|
+
end # class Request
|
98
|
+
end # module Messages
|
99
|
+
end # module RJR
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# RJR Response Message
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012-2014 Mohammed Morsi <mo@morsi.org>
|
4
|
+
# Licensed under the Apache License, Version 2.0
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
require 'rjr/result'
|
8
|
+
require 'rjr/util/json_parser'
|
9
|
+
|
10
|
+
module RJR
|
11
|
+
module Messages
|
12
|
+
|
13
|
+
# Message sent from server to client in response to a JSON-RPC request
|
14
|
+
class Response
|
15
|
+
# Message string received from the source
|
16
|
+
attr_accessor :json_message
|
17
|
+
|
18
|
+
# ID of the message in accordance w/ json-rpc specification
|
19
|
+
attr_accessor :msg_id
|
20
|
+
|
21
|
+
# Result encapsulated in the response message
|
22
|
+
# @see RJR::Result
|
23
|
+
attr_accessor :result
|
24
|
+
|
25
|
+
# Optional headers to add to json outside of standard json-rpc request
|
26
|
+
attr_accessor :headers
|
27
|
+
|
28
|
+
# ResponseMessage initializer
|
29
|
+
#
|
30
|
+
# @param [Hash] args options to set on request
|
31
|
+
# @option args [String] :message json string received from sender
|
32
|
+
# @option args [Hash] :headers optional headers to set in request
|
33
|
+
# and subsequent messages
|
34
|
+
# @option args [String] :id id to set in response message, should
|
35
|
+
# be same as that in received message
|
36
|
+
# @option args [RJR::Result] :result result of json-rpc method invocation
|
37
|
+
def initialize(args = {})
|
38
|
+
parse_args(args)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def parse_args(args)
|
44
|
+
@msg_id = args[:id]
|
45
|
+
@result = args[:result]
|
46
|
+
@headers = args[:headers] || {}
|
47
|
+
|
48
|
+
parse_message(args[:message]) if args.has_key?(:message)
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_message(message)
|
52
|
+
@json_message = message
|
53
|
+
response = JSONParser.parse(@json_message)
|
54
|
+
@msg_id = response['id']
|
55
|
+
|
56
|
+
parse_result(response)
|
57
|
+
parse_headers(response)
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_result(response)
|
61
|
+
@result = Result.new
|
62
|
+
@result.success = response.has_key?('result')
|
63
|
+
@result.failed = !@result.success
|
64
|
+
|
65
|
+
if @result.success
|
66
|
+
@result.result = response['result']
|
67
|
+
|
68
|
+
elsif response.has_key?('error')
|
69
|
+
@result.error_code = response['error']['code']
|
70
|
+
@result.error_msg = response['error']['message']
|
71
|
+
|
72
|
+
# TODO can we safely constantize this ?
|
73
|
+
@result.error_class = response['error']['class']
|
74
|
+
end
|
75
|
+
|
76
|
+
@result
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_headers(request)
|
80
|
+
request.keys.select { |k|
|
81
|
+
!['jsonrpc', 'id', 'method', 'result', 'error'].include?(k)
|
82
|
+
}.each { |k| @headers[k] = request[k] }
|
83
|
+
end
|
84
|
+
|
85
|
+
public
|
86
|
+
|
87
|
+
# Class helper to determine if the specified string is a valid json-rpc
|
88
|
+
# method response
|
89
|
+
# @param [String] message string message to check
|
90
|
+
# @return [true,false] indicating if message is response message
|
91
|
+
def self.is_response_message?(message)
|
92
|
+
begin
|
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
|
100
|
+
end
|
101
|
+
|
102
|
+
def success_json
|
103
|
+
{'result' => @result.result}
|
104
|
+
end
|
105
|
+
|
106
|
+
def error_json
|
107
|
+
{'error' => {'code' => @result.error_code,
|
108
|
+
'message' => @result.error_msg,
|
109
|
+
'class' => @result.error_class}}
|
110
|
+
end
|
111
|
+
|
112
|
+
# Convert request message to json
|
113
|
+
def to_json(*a)
|
114
|
+
result_json = @result.success ? success_json : error_json
|
115
|
+
|
116
|
+
{'jsonrpc' => '2.0',
|
117
|
+
'id' => @msg_id}.merge(@headers).
|
118
|
+
merge(result_json).to_json(*a)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Convert request to string format
|
122
|
+
def to_s
|
123
|
+
to_json.to_s
|
124
|
+
end
|
125
|
+
|
126
|
+
end # class Response
|
127
|
+
end # module Messages
|
128
|
+
end # module RJR
|
data/lib/rjr/node.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
# RJR Base Node Interface
|
2
2
|
#
|
3
|
-
# Copyright (C) 2012-
|
3
|
+
# Copyright (C) 2012-2014 Mohammed Morsi <mo@morsi.org>
|
4
4
|
# Licensed under the Apache License, Version 2.0
|
5
5
|
|
6
|
-
require 'thread'
|
7
6
|
require 'socket'
|
8
|
-
require 'rjr/
|
9
|
-
require 'rjr/message'
|
7
|
+
require 'rjr/messages'
|
10
8
|
require 'rjr/dispatcher'
|
11
|
-
require 'rjr/em_adapter'
|
12
|
-
require 'rjr/thread_pool'
|
9
|
+
require 'rjr/util/em_adapter'
|
10
|
+
require 'rjr/util/thread_pool'
|
11
|
+
require 'rjr/node_callback'
|
13
12
|
|
14
13
|
module RJR
|
15
14
|
|
@@ -21,7 +20,8 @@ module RJR
|
|
21
20
|
# Each subclass should define
|
22
21
|
# * RJR_NODE_TYPE - unique id of the transport
|
23
22
|
# * listen method - begin listening for new requests and return
|
24
|
-
# * send_message(msg, connection) - send message using the specified connection
|
23
|
+
# * send_message(msg, connection) - send message using the specified connection
|
24
|
+
# (transport dependent)
|
25
25
|
# * invoke - establish connection, send message, and wait for / return result
|
26
26
|
# * notify - establish connection, send message, and immediately return
|
27
27
|
#
|
@@ -44,12 +44,21 @@ class Node
|
|
44
44
|
# Dispatcher to use to satisfy requests
|
45
45
|
attr_accessor :dispatcher
|
46
46
|
|
47
|
+
# Handlers for various connection events
|
48
|
+
attr_reader :connection_event_handlers
|
49
|
+
|
47
50
|
class <<self
|
48
51
|
# Bool indiciting if this node is persistent
|
49
52
|
def persistent?
|
50
53
|
self.const_defined?(:PERSISTENT_NODE) &&
|
51
54
|
self.const_get(:PERSISTENT_NODE)
|
52
55
|
end
|
56
|
+
|
57
|
+
# Bool indiciting if this node is indirect
|
58
|
+
def indirect?
|
59
|
+
self.const_defined?(:INDIRECT_NODE) &&
|
60
|
+
self.const_get(:INDIRECT_NODE)
|
61
|
+
end
|
53
62
|
end
|
54
63
|
|
55
64
|
# Bool indicating if this node class is persistent
|
@@ -57,20 +66,39 @@ class Node
|
|
57
66
|
self.class.persistent?
|
58
67
|
end
|
59
68
|
|
69
|
+
# Bool indicating if this node class is indirect
|
70
|
+
def indirect?
|
71
|
+
self.class.indirect?
|
72
|
+
end
|
73
|
+
|
60
74
|
# alias of RJR_NODE_TYPE
|
61
75
|
def node_type
|
62
|
-
self.class
|
76
|
+
self.class.const_defined?(:RJR_NODE_TYPE) ?
|
77
|
+
self.class.const_get(:RJR_NODE_TYPE) : nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.em
|
81
|
+
defined?(@@em) ? @@em : nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def em
|
85
|
+
self.class.em
|
63
86
|
end
|
64
87
|
|
65
|
-
|
66
|
-
|
67
|
-
|
88
|
+
def self.tp
|
89
|
+
defined?(@@tp) ? @@tp : nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def tp
|
93
|
+
self.class.tp
|
94
|
+
end
|
68
95
|
|
69
96
|
# RJR::Node initializer
|
70
97
|
#
|
71
98
|
# @param [Hash] args options to set on request
|
72
99
|
# @option args [String] :node_id unique id of the node
|
73
|
-
# @option args [Hash<String,String>] :headers optional headers to set
|
100
|
+
# @option args [Hash<String,String>] :headers optional headers to set
|
101
|
+
# on all json-rpc messages
|
74
102
|
# @option args [Dispatcher] :dispatcher dispatcher to assign to the node
|
75
103
|
def initialize(args = {})
|
76
104
|
clear_event_handlers
|
@@ -86,28 +114,29 @@ class Node
|
|
86
114
|
@@em ||= EMAdapter.new
|
87
115
|
|
88
116
|
# will do nothing if already started
|
89
|
-
|
90
|
-
|
117
|
+
tp.start
|
118
|
+
em.start
|
91
119
|
end
|
92
120
|
|
93
|
-
# Block until the eventmachine reactor and thread pool have both
|
121
|
+
# Block until the eventmachine reactor and thread pool have both
|
122
|
+
# completed running.
|
94
123
|
#
|
95
124
|
# @return self
|
96
125
|
def join
|
97
|
-
|
98
|
-
|
126
|
+
tp.join
|
127
|
+
em.join
|
99
128
|
self
|
100
129
|
end
|
101
130
|
|
102
131
|
# Immediately terminate the node
|
103
132
|
#
|
104
|
-
# *Warning* this does what it says it does. All running threads,
|
105
|
-
# jobs are immediately killed
|
133
|
+
# *Warning* this does what it says it does. All running threads,
|
134
|
+
# and reactor jobs are immediately killed
|
106
135
|
#
|
107
136
|
# @return self
|
108
137
|
def halt
|
109
|
-
|
110
|
-
|
138
|
+
em.stop_event_loop
|
139
|
+
tp.stop
|
111
140
|
self
|
112
141
|
end
|
113
142
|
|
@@ -119,36 +148,48 @@ class Node
|
|
119
148
|
|
120
149
|
# Register connection event handler
|
121
150
|
# @param [:error, :close] event the event to register the handler for
|
122
|
-
# @param [Callable] handler block param to be added to array of handlers
|
151
|
+
# @param [Callable] handler block param to be added to array of handlers
|
152
|
+
# that are called when event occurs
|
123
153
|
# @yield [Node] self is passed to each registered handler when event occurs
|
124
154
|
def on(event, &handler)
|
125
|
-
|
126
|
-
|
127
|
-
end
|
155
|
+
return unless @connection_event_handlers.keys.include?(event)
|
156
|
+
@connection_event_handlers[event] << handler
|
128
157
|
end
|
129
158
|
|
130
159
|
private
|
131
160
|
|
132
161
|
# Internal helper, run connection event handlers for specified event
|
133
162
|
def connection_event(event)
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
163
|
+
return unless @connection_event_handlers.keys.include?(event)
|
164
|
+
@connection_event_handlers[event].each { |h|
|
165
|
+
h.call self
|
166
|
+
}
|
139
167
|
end
|
140
168
|
|
141
169
|
##################################################################
|
142
170
|
|
171
|
+
# Internal helper, extract client info from connection
|
172
|
+
def client_for(connection)
|
173
|
+
# skip if an indirect node type or local
|
174
|
+
return nil, nil if self.indirect? || self.node_type == :local
|
175
|
+
|
176
|
+
begin
|
177
|
+
return Socket.unpack_sockaddr_in(connection.get_peername)
|
178
|
+
rescue Exception=>e
|
179
|
+
end
|
180
|
+
|
181
|
+
return nil, nil
|
182
|
+
end
|
183
|
+
|
143
184
|
# Internal helper, handle message received
|
144
185
|
def handle_message(msg, connection = {})
|
145
|
-
if
|
146
|
-
|
186
|
+
if Messages::Request.is_request_message?(msg)
|
187
|
+
tp << ThreadPoolJob.new(msg) { |m| handle_request(m, false, connection) }
|
147
188
|
|
148
|
-
elsif
|
149
|
-
|
189
|
+
elsif Messages::Notification.is_notification_message?(msg)
|
190
|
+
tp << ThreadPoolJob.new(msg) { |m| handle_request(m, true, connection) }
|
150
191
|
|
151
|
-
elsif
|
192
|
+
elsif Messages::Response.is_response_message?(msg)
|
152
193
|
handle_response(msg)
|
153
194
|
|
154
195
|
end
|
@@ -158,39 +199,32 @@ class Node
|
|
158
199
|
def handle_request(data, notification=false, connection={})
|
159
200
|
# get client for the specified connection
|
160
201
|
# TODO should grap port/ip immediately on connection and use that
|
161
|
-
client_port,client_ip =
|
162
|
-
begin
|
163
|
-
# XXX skip if an 'indirect' node type or local
|
164
|
-
unless [:amqp, :local].include?(self.class::RJR_NODE_TYPE)
|
165
|
-
client_port, client_ip =
|
166
|
-
Socket.unpack_sockaddr_in(connection.get_peername)
|
167
|
-
end
|
168
|
-
rescue Exception=>e
|
169
|
-
end
|
202
|
+
client_port,client_ip = client_for(connection)
|
170
203
|
|
171
204
|
msg = notification ?
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
205
|
+
Messages::Notification.new(:message => data,
|
206
|
+
:headers => @message_headers) :
|
207
|
+
Messages::Request.new(:message => data,
|
208
|
+
:headers => @message_headers)
|
209
|
+
|
210
|
+
callback = NodeCallback.new(:node => self,
|
211
|
+
:connection => connection)
|
212
|
+
|
213
|
+
result = @dispatcher.dispatch(:rjr_method => msg.jr_method,
|
214
|
+
:rjr_method_args => msg.jr_args,
|
215
|
+
:rjr_headers => msg.headers,
|
216
|
+
:rjr_client_ip => client_ip,
|
217
|
+
:rjr_client_port => client_port,
|
218
|
+
:rjr_node => self,
|
219
|
+
:rjr_node_id => node_id,
|
220
|
+
:rjr_node_type => self.node_type,
|
221
|
+
:rjr_callback => callback)
|
189
222
|
|
190
223
|
unless notification
|
191
|
-
response =
|
192
|
-
|
193
|
-
|
224
|
+
response = Messages::Response.new(:id => msg.msg_id,
|
225
|
+
:result => result,
|
226
|
+
:headers => msg.headers,
|
227
|
+
:request => msg)
|
194
228
|
self.send_msg(response.to_s, connection)
|
195
229
|
return response
|
196
230
|
end
|
@@ -200,7 +234,8 @@ class Node
|
|
200
234
|
|
201
235
|
# Internal helper, handle response message received
|
202
236
|
def handle_response(data)
|
203
|
-
msg =
|
237
|
+
msg = Messages::Response.new(:message => data,
|
238
|
+
:headers => self.message_headers)
|
204
239
|
res = err = nil
|
205
240
|
begin
|
206
241
|
res = @dispatcher.handle_response(msg.result)
|
@@ -243,37 +278,5 @@ class Node
|
|
243
278
|
end
|
244
279
|
return res
|
245
280
|
end
|
246
|
-
|
247
281
|
end # class Node
|
248
|
-
|
249
|
-
# Node callback interface, used to invoke json-rpc methods
|
250
|
-
# against a remote node via node connection previously established
|
251
|
-
#
|
252
|
-
# After a node sends a json-rpc request to another, the either node may send
|
253
|
-
# additional requests to each other via the connection already established until
|
254
|
-
# it is closed on either end
|
255
|
-
class NodeCallback
|
256
|
-
|
257
|
-
# NodeCallback initializer
|
258
|
-
# @param [Hash] args the options to create the node callback with
|
259
|
-
# @option args [node] :node node used to send messages
|
260
|
-
# @option args [connection] :connection connection to be used in channel selection
|
261
|
-
def initialize(args = {})
|
262
|
-
@node = args[:node]
|
263
|
-
@connection = args[:connection]
|
264
|
-
end
|
265
|
-
|
266
|
-
def notify(callback_method, *data)
|
267
|
-
# XXX return if node type does not support
|
268
|
-
# pesistent conntections (throw err instead?)
|
269
|
-
return if @node.class::RJR_NODE_TYPE == :web
|
270
|
-
|
271
|
-
msg = NotificationMessage.new :method => callback_method,
|
272
|
-
:args => data, :headers => @node.message_headers
|
273
|
-
|
274
|
-
# TODO surround w/ begin/rescue block incase of socket errors / raise RJR::ConnectionError
|
275
|
-
@node.send_msg msg.to_s, @connection
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
282
|
end # module RJR
|