rjr 0.18.2 → 0.19.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,147 @@
|
|
1
|
+
require 'rjr/request'
|
2
|
+
|
3
|
+
module RJR
|
4
|
+
describe Request do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "sets rjr method" do
|
7
|
+
request = Request.new :rjr_method => 'foobar'
|
8
|
+
request.rjr_method.should == 'foobar'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "sets rjr method args" do
|
12
|
+
args = ['a', 'r', 'g']
|
13
|
+
request = Request.new :rjr_method_args => args
|
14
|
+
request.rjr_method_args.should == args
|
15
|
+
end
|
16
|
+
|
17
|
+
it "sets rjr headers" do
|
18
|
+
headers = {:h => :s}
|
19
|
+
request = Request.new :rjr_headers => headers
|
20
|
+
request.rjr_headers.should == headers
|
21
|
+
end
|
22
|
+
|
23
|
+
it "sets client ip" do
|
24
|
+
request = Request.new :rjr_client_ip => '127.0.0.1'
|
25
|
+
request.rjr_client_ip.should == '127.0.0.1'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "sets client port" do
|
29
|
+
request = Request.new :rjr_client_port => 1234
|
30
|
+
request.rjr_client_port.should == 1234
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sets callback" do
|
34
|
+
request = Request.new :rjr_callback => :cb
|
35
|
+
request.rjr_callback.should == :cb
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets node" do
|
39
|
+
request = Request.new :rjr_node => :node
|
40
|
+
request.rjr_node.should == :node
|
41
|
+
end
|
42
|
+
|
43
|
+
it "sets node id" do
|
44
|
+
request = Request.new :rjr_node_id => :node_id
|
45
|
+
request.rjr_node_id.should == :node_id
|
46
|
+
end
|
47
|
+
|
48
|
+
it "node type" do
|
49
|
+
request = Request.new :rjr_node_type => :node_type
|
50
|
+
request.rjr_node_type.should == :node_type
|
51
|
+
end
|
52
|
+
|
53
|
+
it "rjr handler" do
|
54
|
+
request = Request.new :rjr_handler => :handler
|
55
|
+
request.rjr_handler.should == :handler
|
56
|
+
end
|
57
|
+
|
58
|
+
it "initialies new RJR::Arguments object from argument list" do
|
59
|
+
args = ['a', 'r', 'g']
|
60
|
+
request = Request.new :rjr_method_args => args
|
61
|
+
request.rjr_method_args.should == args
|
62
|
+
request.rjr_args.should be_an_instance_of(Arguments)
|
63
|
+
request.rjr_args.args.should == args
|
64
|
+
end
|
65
|
+
|
66
|
+
it "sets default result to nil" do
|
67
|
+
Request.new.result.should be_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#handle" do
|
72
|
+
it "invokes the registered handler with args" do
|
73
|
+
received = nil
|
74
|
+
handler = proc { |arg| received = arg }
|
75
|
+
request = Request.new :rjr_handler => handler,
|
76
|
+
:rjr_method_args => ['foo']
|
77
|
+
request.handle
|
78
|
+
received.should == 'foo'
|
79
|
+
end
|
80
|
+
|
81
|
+
it "invokes registered handler in request contenxt" do
|
82
|
+
received = nil
|
83
|
+
handler = proc { |arg| received = @var }
|
84
|
+
|
85
|
+
request = Request.new :rjr_handler => handler
|
86
|
+
request.instance_variable_set(:@var, 'foo')
|
87
|
+
request.handle
|
88
|
+
received.should == 'foo'
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns the handler return value" do
|
92
|
+
handler = proc { |arg| 42 }
|
93
|
+
request = Request.new :rjr_handler => handler
|
94
|
+
request.handle.should == 42
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#to_json" do
|
99
|
+
it "returns the request in json format" do
|
100
|
+
request = Request.new :rjr_method => 'foobar',
|
101
|
+
:rjr_method_args => [:a, :b],
|
102
|
+
:rjr_headers => { :header1 => :val1 },
|
103
|
+
:rjr_node_type => :local,
|
104
|
+
:rjr_node_id => :loc1
|
105
|
+
j = request.to_json
|
106
|
+
j.should include('"json_class":"RJR::Request"')
|
107
|
+
j.should include('"rjr_method":"foobar"')
|
108
|
+
j.should include('"rjr_method_args":["a","b"]')
|
109
|
+
j.should include('"rjr_headers":{"header1":"val1"}')
|
110
|
+
j.should include('"rjr_node_type":"local"')
|
111
|
+
j.should include('"rjr_node_id":"loc1"')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "includes the result in the json" do
|
115
|
+
request = Request.new
|
116
|
+
result = RJR::Result.new :result => 42,
|
117
|
+
:error_code => 123,
|
118
|
+
:error_msg => 'error occurred',
|
119
|
+
:error_class => 'ArgumentError'
|
120
|
+
request.result = result
|
121
|
+
|
122
|
+
j = request.to_json
|
123
|
+
j.should include('"result":42')
|
124
|
+
j.should include('"error_code":123')
|
125
|
+
j.should include('"error_msg":"error occurred"')
|
126
|
+
j.should include('"error_class":"ArgumentError"')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "#json_create" do
|
131
|
+
it "returns a new request from json" do
|
132
|
+
j = '{"json_class":"RJR::Request","data":{"request":{"rjr_method":"foobar","rjr_method_args":["a","b"],"rjr_headers":{"foo":"bar"},"rjr_node_type":"local","rjr_node_id":"loc1"},"result":{"result":42,"error_code":null,"error_msg":null,"error_class":null}}}'
|
133
|
+
request = JSON.parse(j, :create_additions => true)
|
134
|
+
|
135
|
+
request.should be_an_instance_of(RJR::Request)
|
136
|
+
request.rjr_method.should == 'foobar'
|
137
|
+
request.rjr_method_args.should == ['a', 'b']
|
138
|
+
request.rjr_headers.should == { 'foo' => 'bar' }
|
139
|
+
request.rjr_node_type.should == 'local'
|
140
|
+
request.rjr_node_id.should == 'loc1'
|
141
|
+
|
142
|
+
request.result.should be_an_instance_of(RJR::Result)
|
143
|
+
request.result.result.should == 42
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end # describe Request
|
147
|
+
end # module RJR
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'rjr/result'
|
2
|
+
|
3
|
+
module RJR
|
4
|
+
describe Result do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "initializes default attributes" do
|
7
|
+
result = Result.new
|
8
|
+
result.result.should be_nil
|
9
|
+
result.error_code.should be_nil
|
10
|
+
result.error_msg.should be_nil
|
11
|
+
result.error_class.should be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "stores result" do
|
15
|
+
result = Result.new :result => 'foobar'
|
16
|
+
result.result.should == 'foobar'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "stores error" do
|
20
|
+
result = Result.new :error_code => 123, :error_msg => 'abc',
|
21
|
+
:error_class => ArgumentError
|
22
|
+
result.error_code.should == 123
|
23
|
+
result.error_msg.should == 'abc'
|
24
|
+
result.error_class.should == ArgumentError
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when an error code is not specified" do
|
28
|
+
it "should be marked as successful" do
|
29
|
+
result = Result.new
|
30
|
+
result.success.should == true
|
31
|
+
result.failed.should == false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when an error code is specified" do
|
36
|
+
it "should be marked as failed" do
|
37
|
+
result = Result.new :error_code => 123
|
38
|
+
result.success.should == false
|
39
|
+
result.failed.should == true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end # describe #initialize
|
43
|
+
|
44
|
+
describe "#==" do
|
45
|
+
context "all fields are equal" do
|
46
|
+
it "returns true" do
|
47
|
+
Result.new.should == Result.new
|
48
|
+
Result.new(:result => 1).should == Result.new(:result => 1)
|
49
|
+
Result.new(:error_code => 50).should == Result.new(:error_code => 50)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "'success' is different" do
|
54
|
+
it "returns false" do
|
55
|
+
r1 = Result.new
|
56
|
+
r2 = Result.new
|
57
|
+
r1.success = true
|
58
|
+
r2.success = false
|
59
|
+
r1.should_not == r2
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "'failed' is different" do
|
64
|
+
it "returns false" do
|
65
|
+
r1 = Result.new
|
66
|
+
r2 = Result.new
|
67
|
+
r1.failed = true
|
68
|
+
r2.failed = false
|
69
|
+
r1.should_not == r2
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "'result' is different" do
|
74
|
+
it "returns false" do
|
75
|
+
r1 = Result.new
|
76
|
+
r2 = Result.new
|
77
|
+
r1.result = 1
|
78
|
+
r2.result = 2
|
79
|
+
r1.should_not == r2
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "'error_code' is different" do
|
84
|
+
it "returns false" do
|
85
|
+
r1 = Result.new
|
86
|
+
r2 = Result.new
|
87
|
+
r1.error_code = 1
|
88
|
+
r2.error_code = 2
|
89
|
+
r1.should_not == r2
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "'error_msg' is different" do
|
94
|
+
it "returns false" do
|
95
|
+
r1 = Result.new
|
96
|
+
r2 = Result.new
|
97
|
+
r1.error_msg = 'something'
|
98
|
+
r2.error_msg = 'bad'
|
99
|
+
r1.should_not == r2
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "'error_class' is different" do
|
104
|
+
it "returns false" do
|
105
|
+
r1 = Result.new
|
106
|
+
r2 = Result.new
|
107
|
+
r1.error_class = 'something'
|
108
|
+
r2.error_class = 'bad'
|
109
|
+
r1.should_not == r2
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end # describe #==
|
113
|
+
|
114
|
+
describe "#invalid_request" do
|
115
|
+
it "is an instance of result" do
|
116
|
+
Result.invalid_request.should be_an_instance_of(Result)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "has error code -32600" do
|
120
|
+
Result.invalid_request.error_code.should == -32600
|
121
|
+
end
|
122
|
+
|
123
|
+
it "has error message 'Invalid Request'" do
|
124
|
+
Result.invalid_request.error_msg.should == "Invalid Request"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#method_not_found" do
|
129
|
+
it "is an instance of result" do
|
130
|
+
Result.method_not_found('foobar').should be_an_instance_of(Result)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "has error code -32602" do
|
134
|
+
Result.method_not_found('foobar').error_code.should == -32602
|
135
|
+
end
|
136
|
+
|
137
|
+
it "has error message 'Method '<name>' not found'" do
|
138
|
+
Result.method_not_found('foobar').error_msg.should ==
|
139
|
+
"Method 'foobar' not found"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end # describe Result
|
144
|
+
end # module RJR
|
data/specs/thread_pool_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rjr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mo Morsi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -68,17 +68,27 @@ files:
|
|
68
68
|
- examples/local.rb
|
69
69
|
- examples/complete.rb
|
70
70
|
- examples/amqp.rb
|
71
|
+
- examples/structured_server.rb
|
71
72
|
- examples/client.rb
|
72
73
|
- examples/unix.rb
|
73
|
-
- lib/rjr/
|
74
|
-
- lib/rjr/
|
75
|
-
- lib/rjr/
|
76
|
-
- lib/rjr/
|
74
|
+
- lib/rjr/node_callback.rb
|
75
|
+
- lib/rjr/messages/compressed.rb
|
76
|
+
- lib/rjr/messages/response.rb
|
77
|
+
- lib/rjr/messages/request.rb
|
78
|
+
- lib/rjr/messages/notification.rb
|
79
|
+
- lib/rjr/messages.rb
|
77
80
|
- lib/rjr/version.rb
|
78
81
|
- lib/rjr/node.rb
|
79
82
|
- lib/rjr/common.rb
|
80
|
-
- lib/rjr/
|
81
|
-
- lib/rjr/
|
83
|
+
- lib/rjr/util/logger.rb
|
84
|
+
- lib/rjr/util/em_adapter.rb
|
85
|
+
- lib/rjr/util/handles_methods.rb
|
86
|
+
- lib/rjr/util/inspect.rb
|
87
|
+
- lib/rjr/util/has_messages.rb
|
88
|
+
- lib/rjr/util/thread_pool.rb
|
89
|
+
- lib/rjr/util/json_parser.rb
|
90
|
+
- lib/rjr/util/args.rb
|
91
|
+
- lib/rjr/request.rb
|
82
92
|
- lib/rjr/nodes/web.rb
|
83
93
|
- lib/rjr/nodes/udp.rb
|
84
94
|
- lib/rjr/nodes/tcp.rb
|
@@ -94,6 +104,8 @@ files:
|
|
94
104
|
- lib/rjr/nodes/unix.rb
|
95
105
|
- lib/rjr/nodes/missing.rb
|
96
106
|
- lib/rjr/nodes/multi.rb
|
107
|
+
- lib/rjr/core_ext.rb
|
108
|
+
- lib/rjr/result.rb
|
97
109
|
- lib/rjr/dispatcher.rb
|
98
110
|
- site/index.html
|
99
111
|
- site/jquery-latest.js
|
@@ -102,8 +114,18 @@ files:
|
|
102
114
|
- LICENSE
|
103
115
|
- Rakefile
|
104
116
|
- README.md
|
117
|
+
- specs/json_parser_spec.rb
|
118
|
+
- specs/messages/response_spec.rb
|
119
|
+
- specs/messages/request_spec.rb
|
120
|
+
- specs/messages/notification_spec.rb
|
105
121
|
- specs/dispatcher_spec.rb
|
122
|
+
- specs/handles_methods_spec.rb
|
123
|
+
- specs/has_messages_spec.rb
|
106
124
|
- specs/node_spec.rb
|
125
|
+
- specs/args_spec.rb
|
126
|
+
- specs/request_spec.rb
|
127
|
+
- specs/node_callbacks_spec.rb
|
128
|
+
- specs/result_spec.rb
|
107
129
|
- specs/nodes/unix_spec.rb
|
108
130
|
- specs/nodes/multi_spec.rb
|
109
131
|
- specs/nodes/tcp_spec.rb
|
@@ -114,7 +136,6 @@ files:
|
|
114
136
|
- specs/nodes/easy_spec.rb
|
115
137
|
- specs/inspect_spec.rb
|
116
138
|
- specs/thread_pool_spec.rb
|
117
|
-
- specs/message_spec.rb
|
118
139
|
- specs/em_adapter_spec.rb
|
119
140
|
- bin/rjr-server
|
120
141
|
- bin/rjr-client
|
@@ -148,13 +169,23 @@ requirements:
|
|
148
169
|
- The eventmachine_httpserver and em-http-request gems are needed to use the web node
|
149
170
|
- The em-websocket and em-websocket-client gems are needed to use the web socket node
|
150
171
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.0.
|
172
|
+
rubygems_version: 2.0.14
|
152
173
|
signing_key:
|
153
174
|
specification_version: 4
|
154
175
|
summary: JSON RPC server and client library over amqp, websockets, http, etc
|
155
176
|
test_files:
|
177
|
+
- specs/json_parser_spec.rb
|
178
|
+
- specs/messages/response_spec.rb
|
179
|
+
- specs/messages/request_spec.rb
|
180
|
+
- specs/messages/notification_spec.rb
|
156
181
|
- specs/dispatcher_spec.rb
|
182
|
+
- specs/handles_methods_spec.rb
|
183
|
+
- specs/has_messages_spec.rb
|
157
184
|
- specs/node_spec.rb
|
185
|
+
- specs/args_spec.rb
|
186
|
+
- specs/request_spec.rb
|
187
|
+
- specs/node_callbacks_spec.rb
|
188
|
+
- specs/result_spec.rb
|
158
189
|
- specs/nodes/unix_spec.rb
|
159
190
|
- specs/nodes/multi_spec.rb
|
160
191
|
- specs/nodes/tcp_spec.rb
|
@@ -165,6 +196,5 @@ test_files:
|
|
165
196
|
- specs/nodes/easy_spec.rb
|
166
197
|
- specs/inspect_spec.rb
|
167
198
|
- specs/thread_pool_spec.rb
|
168
|
-
- specs/message_spec.rb
|
169
199
|
- specs/em_adapter_spec.rb
|
170
200
|
has_rdoc:
|
data/lib/rjr/errors.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# RJR Errors
|
2
|
-
#
|
3
|
-
# Copyright (C) 2012 Mohammed Morsi <mo@morsi.org>
|
4
|
-
# Licensed under the Apache License, Version 2.0
|
5
|
-
|
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.
|
11
|
-
module Errors
|
12
|
-
|
13
|
-
# Catches all Errors constants and define new RuntimeError subclass
|
14
|
-
def self.const_missing(error_name) # :nodoc:
|
15
|
-
if error_name.to_s =~ /Error\z/
|
16
|
-
const_set(error_name, Class.new(RuntimeError))
|
17
|
-
else
|
18
|
-
super
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
data/lib/rjr/message.rb
DELETED
@@ -1,351 +0,0 @@
|
|
1
|
-
# RJR Message
|
2
|
-
#
|
3
|
-
# Representations of json-rpc messages in accordance with the standard
|
4
|
-
#
|
5
|
-
# Copyright (C) 2012-2013 Mohammed Morsi <mo@morsi.org>
|
6
|
-
# Licensed under the Apache License, Version 2.0
|
7
|
-
|
8
|
-
require 'json'
|
9
|
-
require 'rjr/common'
|
10
|
-
|
11
|
-
module RJR
|
12
|
-
|
13
|
-
# Message sent from client to server to invoke a json-rpc method
|
14
|
-
class RequestMessage
|
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
|
-
# ID of the message in accordance w/ json-rpc specification
|
25
|
-
attr_accessor :msg_id
|
26
|
-
|
27
|
-
# Optional headers to add to json outside of standard json-rpc request
|
28
|
-
attr_accessor :headers
|
29
|
-
|
30
|
-
# RJR Request Message initializer
|
31
|
-
#
|
32
|
-
# This should be invoked with one of two argument sets. If creating a new message
|
33
|
-
# to send to the server, specify :method, :args, and :headers to include in the message
|
34
|
-
# (message id will be autogenerated). If handling an new request message sent from the
|
35
|
-
# client, simply specify :message and optionally any additional headers (they will
|
36
|
-
# be merged with the headers contained in the message)
|
37
|
-
#
|
38
|
-
# @param [Hash] args options to set on request
|
39
|
-
# @option args [String] :message json string received from sender
|
40
|
-
# @option args [Hash] :headers optional headers to set in request and subsequent messages
|
41
|
-
# @option args [String] :method method to invoke on server
|
42
|
-
# @option args [Array<Object>] :args to pass to server method, all must be convertable to/from json
|
43
|
-
def initialize(args = {})
|
44
|
-
if args.has_key?(:message)
|
45
|
-
begin
|
46
|
-
@json_message = args[:message]
|
47
|
-
request = RJR.parse_json(@json_message)
|
48
|
-
@jr_method = request['method']
|
49
|
-
@jr_args = request['params']
|
50
|
-
@msg_id = request['id']
|
51
|
-
@headers = args.has_key?(:headers) ? {}.merge!(args[:headers]) : {}
|
52
|
-
|
53
|
-
request.keys.select { |k|
|
54
|
-
!['jsonrpc', 'id', 'method', 'params'].include?(k)
|
55
|
-
}.each { |k| @headers[k] = request[k] }
|
56
|
-
|
57
|
-
rescue Exception => e
|
58
|
-
#puts "Exception Parsing Request #{e}"
|
59
|
-
raise e
|
60
|
-
end
|
61
|
-
|
62
|
-
elsif args.has_key?(:method)
|
63
|
-
@jr_method = args[:method]
|
64
|
-
@jr_args = args[:args]
|
65
|
-
@headers = args[:headers]
|
66
|
-
@msg_id = gen_uuid
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
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 = RJR.parse_json(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 string json format
|
86
|
-
def to_s
|
87
|
-
request = { 'jsonrpc' => '2.0',
|
88
|
-
'method' => @jr_method,
|
89
|
-
'params' => @jr_args }
|
90
|
-
request['id'] = @msg_id unless @msg_id.nil?
|
91
|
-
request.merge!(@headers) unless @headers.nil?
|
92
|
-
request.to_json.to_s
|
93
|
-
end
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
# Message sent from server to client in response to json-rpc request message
|
98
|
-
class ResponseMessage
|
99
|
-
# Message string received from the source
|
100
|
-
attr_accessor :json_message
|
101
|
-
|
102
|
-
# ID of the message in accordance w/ json-rpc specification
|
103
|
-
attr_accessor :msg_id
|
104
|
-
|
105
|
-
# Result encapsulated in the response message
|
106
|
-
# @see RJR::Result
|
107
|
-
attr_accessor :result
|
108
|
-
|
109
|
-
# Optional headers to add to json outside of standard json-rpc request
|
110
|
-
attr_accessor :headers
|
111
|
-
|
112
|
-
# ResponseMessage initializer
|
113
|
-
#
|
114
|
-
# This should be invoked with one of two argument sets. If creating a new message
|
115
|
-
# to send to the client, specify :id, :result, and :headers to include in the message.
|
116
|
-
# If handling an new request message sent from the client, simply specify :message
|
117
|
-
# and optionally any additional headers (they will be merged with the headers contained
|
118
|
-
# in the message)
|
119
|
-
#
|
120
|
-
# @param [Hash] args options to set on request
|
121
|
-
# @option args [String] :message json string received from sender
|
122
|
-
# @option args [Hash] :headers optional headers to set in request and subsequent messages
|
123
|
-
# @option args [String] :id id to set in response message, should be same as that in received message
|
124
|
-
# @option args [RJR::Result] :result result of json-rpc method invocation
|
125
|
-
def initialize(args = {})
|
126
|
-
if args.has_key?(:message)
|
127
|
-
@json_message = args[:message]
|
128
|
-
response = RJR.parse_json(@json_message)
|
129
|
-
@msg_id = response['id']
|
130
|
-
@result = Result.new
|
131
|
-
@result.success = response.has_key?('result')
|
132
|
-
@result.failed = !response.has_key?('result')
|
133
|
-
@headers = args.has_key?(:headers) ? {}.merge!(args[:headers]) : {}
|
134
|
-
|
135
|
-
if @result.success
|
136
|
-
@result.result = response['result']
|
137
|
-
|
138
|
-
elsif response.has_key?('error')
|
139
|
-
@result.error_code = response['error']['code']
|
140
|
-
@result.error_msg = response['error']['message']
|
141
|
-
@result.error_class = response['error']['class'] # TODO safely constantize this ?
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
response.keys.select { |k|
|
146
|
-
!['jsonrpc', 'id', 'result', 'error'].include?(k)
|
147
|
-
}.each { |k| @headers[k] = response[k] }
|
148
|
-
|
149
|
-
elsif args.has_key?(:result)
|
150
|
-
@msg_id = args[:id]
|
151
|
-
@result = args[:result]
|
152
|
-
@headers = args[:headers]
|
153
|
-
|
154
|
-
#else
|
155
|
-
# raise ArgumentError, "must specify :message or :result"
|
156
|
-
|
157
|
-
end
|
158
|
-
|
159
|
-
end
|
160
|
-
|
161
|
-
# Class helper to determine if the specified string is a valid json-rpc
|
162
|
-
# method response
|
163
|
-
# @param [String] message string message to check
|
164
|
-
# @return [true,false] indicating if message is response message
|
165
|
-
def self.is_response_message?(message)
|
166
|
-
begin
|
167
|
-
json = RJR.parse_json(message)
|
168
|
-
json.has_key?('result') || json.has_key?('error')
|
169
|
-
rescue Exception => e
|
170
|
-
# FIXME log error
|
171
|
-
puts e.to_s
|
172
|
-
false
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
# Convert request message to string json format
|
177
|
-
def to_s
|
178
|
-
s = ''
|
179
|
-
if result.success
|
180
|
-
s = {'jsonrpc' => '2.0',
|
181
|
-
'id' => @msg_id,
|
182
|
-
'result' => @result.result}
|
183
|
-
|
184
|
-
else
|
185
|
-
s = {'jsonrpc' => '2.0',
|
186
|
-
'id' => @msg_id,
|
187
|
-
'error' => { 'code' => @result.error_code,
|
188
|
-
'message' => @result.error_msg,
|
189
|
-
'class' => @result.error_class}}
|
190
|
-
end
|
191
|
-
|
192
|
-
s.merge! @headers unless headers.nil?
|
193
|
-
return s.to_json.to_s
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
# Message sent to a jsonrpc node to invoke a rpc method but
|
198
|
-
# indicate the result should _not_ be returned
|
199
|
-
class NotificationMessage
|
200
|
-
# Message string received from the source
|
201
|
-
attr_accessor :json_message
|
202
|
-
|
203
|
-
# Method source is invoking on the destination
|
204
|
-
attr_accessor :jr_method
|
205
|
-
|
206
|
-
# Arguments source is passing to destination method
|
207
|
-
attr_accessor :jr_args
|
208
|
-
|
209
|
-
# Optional headers to add to json outside of standard json-rpc request
|
210
|
-
attr_accessor :headers
|
211
|
-
|
212
|
-
# RJR Notification Message initializer
|
213
|
-
#
|
214
|
-
# This should be invoked with one of two argument sets. If creating a new message
|
215
|
-
# to send to the server, specify :method, :args, and :headers to include in the message
|
216
|
-
# If handling an new request message sent from the client, simply specify :message and
|
217
|
-
# optionally any additional headers (they will be merged with the headers contained in
|
218
|
-
# the message)
|
219
|
-
#
|
220
|
-
# No message id will be generated in accordance w/ the jsonrpc standard
|
221
|
-
#
|
222
|
-
# @param [Hash] args options to set on request
|
223
|
-
# @option args [String] :message json string received from sender
|
224
|
-
# @option args [Hash] :headers optional headers to set in request and subsequent messages
|
225
|
-
# @option args [String] :method method to invoke on server
|
226
|
-
# @option args [Array<Object>] :args to pass to server method, all must be convertable to/from json
|
227
|
-
def initialize(args = {})
|
228
|
-
if args.has_key?(:message)
|
229
|
-
begin
|
230
|
-
@json_message = args[:message]
|
231
|
-
notification = RJR.parse_json(@json_message)
|
232
|
-
@jr_method = notification['method']
|
233
|
-
@jr_args = notification['params']
|
234
|
-
@headers = args.has_key?(:headers) ? {}.merge!(args[:headers]) : {}
|
235
|
-
|
236
|
-
notification.keys.select { |k|
|
237
|
-
!['jsonrpc', 'method', 'params'].include?(k)
|
238
|
-
}.each { |k| @headers[k] = notification[k] }
|
239
|
-
|
240
|
-
rescue Exception => e
|
241
|
-
#puts "Exception Parsing Notification #{e}"
|
242
|
-
raise e
|
243
|
-
end
|
244
|
-
|
245
|
-
elsif args.has_key?(:method)
|
246
|
-
@jr_method = args[:method]
|
247
|
-
@jr_args = args[:args]
|
248
|
-
@headers = args[:headers]
|
249
|
-
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
# Class helper to determine if the specified string is a valid json-rpc
|
254
|
-
# notification
|
255
|
-
#
|
256
|
-
# @param [String] message string message to check
|
257
|
-
# @return [true,false] indicating if message is a notification message
|
258
|
-
def self.is_notification_message?(message)
|
259
|
-
begin
|
260
|
-
# FIXME log error
|
261
|
-
parsed = RJR.parse_json(message)
|
262
|
-
parsed.has_key?('method') && !parsed.has_key?('id')
|
263
|
-
rescue Exception => e
|
264
|
-
false
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
# Convert notification message to string json format
|
269
|
-
def to_s
|
270
|
-
notification = { 'jsonrpc' => '2.0',
|
271
|
-
'method' => @jr_method,
|
272
|
-
'params' => @jr_args }
|
273
|
-
notification.merge!(@headers) unless @headers.nil?
|
274
|
-
notification.to_json.to_s
|
275
|
-
end
|
276
|
-
|
277
|
-
end
|
278
|
-
|
279
|
-
# Helper utilities for messages
|
280
|
-
class MessageUtil
|
281
|
-
# Retrieve and return a single json message from a data string.
|
282
|
-
#
|
283
|
-
# Returns the message and remaining portion of the data string,
|
284
|
-
# if message is found, else nil
|
285
|
-
#
|
286
|
-
# XXX really don't like having to do this, but a quick solution
|
287
|
-
# to the issue of multiple messages appearing in one tcp data packet.
|
288
|
-
#
|
289
|
-
# TODO efficiency can probably be optimized
|
290
|
-
# in the case closing '}' hasn't arrived yet
|
291
|
-
def self.retrieve_json(data)
|
292
|
-
return nil if data.nil? || data.empty?
|
293
|
-
start = 0
|
294
|
-
start += 1 until start == data.length || data[start].chr == '{'
|
295
|
-
on = mi = 0
|
296
|
-
start.upto(data.length - 1).each { |i|
|
297
|
-
if data[i].chr == '{'
|
298
|
-
on += 1
|
299
|
-
elsif data[i].chr == '}'
|
300
|
-
on -= 1
|
301
|
-
end
|
302
|
-
|
303
|
-
if on == 0
|
304
|
-
mi = i
|
305
|
-
break
|
306
|
-
end
|
307
|
-
}
|
308
|
-
|
309
|
-
return nil if mi == 0
|
310
|
-
return data[start..mi], data[(mi+1)..-1]
|
311
|
-
end
|
312
|
-
|
313
|
-
# Mechanism to register / retrieve preformatted message
|
314
|
-
#
|
315
|
-
# @param [Symbol] id id of message to get / set
|
316
|
-
# @param [String] msg optional preformatted message to store
|
317
|
-
# @return [String] json rpc message
|
318
|
-
def self.message(id, msg=nil)
|
319
|
-
@rjr_messages ||= {}
|
320
|
-
@rjr_messages[id] = msg unless msg.nil?
|
321
|
-
@rjr_messages[id]
|
322
|
-
end
|
323
|
-
|
324
|
-
# Clear preformatted messages
|
325
|
-
def self.clear
|
326
|
-
@rjr_messages = {}
|
327
|
-
end
|
328
|
-
|
329
|
-
# Return random message from registry.
|
330
|
-
#
|
331
|
-
# Optionally specify the transport which the message must accept
|
332
|
-
# (TODO turn this into a generic selection callback)
|
333
|
-
def self.rand_msg(transport = nil)
|
334
|
-
@rjr_messages ||= {}
|
335
|
-
messages = @rjr_messages.select { |mid,m| m[:transports].nil? || transport.nil? ||
|
336
|
-
m[:transports].include?(transport) }
|
337
|
-
messages[messages.keys[rand(messages.keys.size)]]
|
338
|
-
end
|
339
|
-
|
340
|
-
end # MessageUtil
|
341
|
-
|
342
|
-
# Module providing helper methods for messages
|
343
|
-
module MessageMixins
|
344
|
-
|
345
|
-
# Wrapper around MessageUtil.message
|
346
|
-
def define_message(name, &bl)
|
347
|
-
MessageUtil.message(name, bl.call)
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
end
|