rjr 0.18.2 → 0.19.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -0
  3. data/bin/rjr-client +16 -9
  4. data/bin/rjr-server +2 -1
  5. data/examples/client.rb +21 -19
  6. data/examples/server.rb +1 -1
  7. data/examples/structured_server.rb +1 -0
  8. data/examples/tcp.rb +1 -0
  9. data/lib/rjr/common.rb +1 -226
  10. data/lib/rjr/core_ext.rb +63 -0
  11. data/lib/rjr/dispatcher.rb +75 -219
  12. data/lib/rjr/messages.rb +8 -0
  13. data/lib/rjr/messages/compressed.rb +264 -0
  14. data/lib/rjr/messages/notification.rb +95 -0
  15. data/lib/rjr/messages/request.rb +99 -0
  16. data/lib/rjr/messages/response.rb +128 -0
  17. data/lib/rjr/node.rb +100 -97
  18. data/lib/rjr/node_callback.rb +43 -0
  19. data/lib/rjr/nodes/amqp.rb +12 -11
  20. data/lib/rjr/nodes/easy.rb +4 -4
  21. data/lib/rjr/nodes/local.rb +13 -12
  22. data/lib/rjr/nodes/multi.rb +1 -1
  23. data/lib/rjr/nodes/tcp.rb +15 -13
  24. data/lib/rjr/nodes/template.rb +4 -4
  25. data/lib/rjr/nodes/unix.rb +15 -13
  26. data/lib/rjr/nodes/web.rb +15 -14
  27. data/lib/rjr/nodes/ws.rb +12 -11
  28. data/lib/rjr/request.rb +128 -0
  29. data/lib/rjr/result.rb +75 -0
  30. data/lib/rjr/util/args.rb +145 -0
  31. data/lib/rjr/{em_adapter.rb → util/em_adapter.rb} +0 -0
  32. data/lib/rjr/util/handles_methods.rb +115 -0
  33. data/lib/rjr/util/has_messages.rb +50 -0
  34. data/lib/rjr/{inspect.rb → util/inspect.rb} +1 -1
  35. data/lib/rjr/util/json_parser.rb +101 -0
  36. data/lib/rjr/util/logger.rb +128 -0
  37. data/lib/rjr/{thread_pool.rb → util/thread_pool.rb} +2 -0
  38. data/lib/rjr/version.rb +1 -1
  39. data/site/jrw.js +1 -1
  40. data/specs/args_spec.rb +144 -0
  41. data/specs/dispatcher_spec.rb +399 -211
  42. data/specs/em_adapter_spec.rb +31 -18
  43. data/specs/handles_methods_spec.rb +154 -0
  44. data/specs/has_messages_spec.rb +54 -0
  45. data/specs/inspect_spec.rb +1 -1
  46. data/specs/json_parser_spec.rb +169 -0
  47. data/specs/messages/notification_spec.rb +59 -0
  48. data/specs/messages/request_spec.rb +66 -0
  49. data/specs/messages/response_spec.rb +94 -0
  50. data/specs/node_callbacks_spec.rb +47 -0
  51. data/specs/node_spec.rb +465 -56
  52. data/specs/request_spec.rb +147 -0
  53. data/specs/result_spec.rb +144 -0
  54. data/specs/thread_pool_spec.rb +1 -1
  55. metadata +41 -11
  56. data/lib/rjr/errors.rb +0 -23
  57. data/lib/rjr/message.rb +0 -351
  58. data/lib/rjr/semaphore.rb +0 -58
  59. data/specs/message_spec.rb +0 -229
@@ -1,181 +1,17 @@
1
- # RJR Request / Response Dispatcher
1
+ # RJR Dispatcher
2
2
  #
3
- # Representation of a json-rpc request, response and mechanisms which to
4
- # register methods to handle requests and return responses
3
+ # Mechanisms which to register methods to handle requests
4
+ # and return responses
5
5
  #
6
- # Copyright (C) 2012-2013 Mohammed Morsi <mo@morsi.org>
6
+ # Copyright (C) 2012-2014 Mohammed Morsi <mo@morsi.org>
7
7
  # Licensed under the Apache License, Version 2.0
8
8
 
9
- require 'json'
10
- require 'rjr/common'
9
+ require 'rjr/request'
10
+ require 'rjr/result'
11
+ require 'rjr/util/logger'
11
12
 
12
13
  module RJR
13
14
 
14
- # JSON-RPC result representation
15
- class Result
16
- # Boolean indicating if request was successfully invoked
17
- attr_accessor :success
18
-
19
- # Boolean indicating if request failed in some manner
20
- attr_accessor :failed
21
-
22
- # Return value of the json-rpc call if successful
23
- attr_accessor :result
24
-
25
- # Code corresponding to json-rpc error if problem occured during request invocation
26
- attr_accessor :error_code
27
-
28
- # Message corresponding to json-rpc error if problem occured during request invocation
29
- attr_accessor :error_msg
30
-
31
- # Class of error raised (if any) during request invocation (this is extra metadata beyond standard json-rpc)
32
- attr_accessor :error_class
33
-
34
- # RJR result intializer
35
- # @param [Hash] args options to set on result
36
- # @option args [Object] :result result of json-rpc method handler if successfully returned
37
- # @option args [Integer] :error_code code corresponding to json-rpc error if problem occured during request invocation
38
- # @option args [String] :error_msg message corresponding to json-rpc error if problem occured during request invocation
39
- # @option args [Class] :error_class class of error raised (if any) during request invocation (this is extra metadata beyond standard json-rpc)
40
- def initialize(args = {})
41
- @result = args[:result] || args['result']
42
- @error_code = args[:error_code] || args['error_code']
43
- @error_msg = args[:error_msg] || args['error_msg']
44
- @error_class = args[:error_class] || args['error_class']
45
-
46
- @success = @error_code.nil?
47
- @failed = !@error_code.nil?
48
- end
49
-
50
- # Compare Result against other result, returning true if both correspond
51
- # to equivalent json-rpc results else false
52
- def ==(other)
53
- @success == other.success &&
54
- @failed == other.failed &&
55
- @result == other.result &&
56
- @error_code == other.error_code &&
57
- @error_msg == other.error_msg &&
58
- @error_class == other.error_class
59
- end
60
-
61
- # Convert Response to human consumable string
62
- def to_s
63
- "#{@success} #{@result} #{@error_code} #{@error_msg} #{@error_class}"
64
- end
65
-
66
- ######### Specific request types
67
-
68
- # JSON-RPC -32600 / Invalid Request
69
- def self.invalid_request
70
- return Result.new(:error_code => -32600,
71
- :error_msg => ' Invalid Request')
72
- end
73
-
74
- # JSON-RPC -32602 / Method not found
75
- def self.method_not_found(name)
76
- return Result.new(:error_code => -32602,
77
- :error_msg => "Method '#{name}' not found")
78
- end
79
- end
80
-
81
- # JSON-RPC request representation.
82
- #
83
- # Registered request handlers will be invoked in the context of
84
- # instances of this class, meaning all member variables will be available
85
- # for use in the handler.
86
- class Request
87
- # Result of the request operation, set by dispatcher
88
- attr_accessor :result
89
-
90
- # Method which request is for
91
- attr_accessor :rjr_method
92
-
93
- # Arguments be passed to method
94
- attr_accessor :rjr_method_args
95
-
96
- # Headers which came w/ request
97
- attr_accessor :rjr_headers
98
-
99
- # Type of node which request came in on
100
- attr_accessor :rjr_node_type
101
-
102
- # ID of node which request came in on
103
- attr_accessor :rjr_node_id
104
-
105
- # RJR Request initializer
106
- # @param [Hash] args options to set on request
107
- # @option args [String] :rjr_method name of the method which request is for
108
- # @option args [Array] :rjr_method_args array of arguments which to pass to the rpc method handler
109
- # @option args [Hash] :rjr_headers hash of keys/values corresponding to optional headers received as part of of the request
110
- # @option args [String] :rjr_client_ip ip address of client which invoked the request (if applicable)
111
- # @option args [String] :rjr_client_port port of client which invoked the request (if applicable)
112
- # @option args [RJR::Callback] :rjr_callback callback through which requests/notifications can be sent to remote node
113
- # @option args [RJR::Node] :rjr_node rjr node which request was received on
114
- # @option args [String] :rjr_node_id id of the rjr node which request was received on
115
- # @option args [Symbol] :rjr_node_type type of the rjr node which request was received on
116
- # @option args [Callable] :rjr_handler callable object registered to the specified method which to invoke request on with arguments
117
- def initialize(args = {})
118
- @rjr_method = args[:rjr_method] || args['rjr_method']
119
- @rjr_method_args = args[:rjr_method_args] || args['rjr_method_args'] || []
120
- @rjr_headers = args[:rjr_headers] || args['rjr_headers']
121
-
122
- @rjr_client_ip = args[:rjr_client_ip]
123
- @rjr_client_port = args[:rjr_client_port]
124
-
125
- @rjr_callback = args[:rjr_callback]
126
- @rjr_node = args[:rjr_node]
127
- @rjr_node_id = args[:rjr_node_id] || args['rjr_node_id']
128
- @rjr_node_type = args[:rjr_node_type] || args['rjr_node_type']
129
-
130
- @rjr_handler = args[:rjr_handler]
131
-
132
- @result = nil
133
- end
134
-
135
- # Invoke the request by calling the registered handler with the registered
136
- # method parameters in the local scope
137
- def handle
138
- node_sig = "#{@rjr_node_id}(#{@rjr_node_type})"
139
- method_sig = "#{@rjr_method}(#{@rjr_method_args.join(',')})"
140
-
141
- RJR::Logger.info "#{node_sig}->#{method_sig}"
142
-
143
- retval = instance_exec(*@rjr_method_args, &@rjr_handler)
144
-
145
- RJR::Logger.info \
146
- "#{node_sig}<-#{method_sig}<-#{retval.nil? ? "nil" : retval}"
147
-
148
- return retval
149
- end
150
-
151
- # Convert request to json representation and return it
152
- def to_json(*a)
153
- {
154
- 'json_class' => self.class.name,
155
- 'data' =>
156
- {:request => { :rjr_method => @rjr_method,
157
- :rjr_method_args => @rjr_method_args,
158
- :rjr_headers => @rjr_headers,
159
- :rjr_node_type => @rjr_node_type,
160
- :rjr_node_id => @rjr_node_id },
161
-
162
- :result => { :result => @result.result,
163
- :error_code => @result.error_code,
164
- :error_msg => @result.error_msg,
165
- :error_class => @result.error_class } }
166
- }.to_json(*a)
167
- end
168
-
169
- # Create new request from json representation
170
- def self.json_create(o)
171
- result = Result.new(o['data']['result'])
172
- request = Request.new(o['data']['request'])
173
- request.result = result
174
- return request
175
- end
176
-
177
- end
178
-
179
15
  # Primary RJR JSON-RPC method dispatcher.
180
16
  class Dispatcher
181
17
  # Registered json-rpc request signatures and corresponding handlers
@@ -188,7 +24,14 @@ class Dispatcher
188
24
  attr_accessor :keep_requests
189
25
 
190
26
  # Requests which have been dispatched
191
- def requests ; @requests_lock.synchronize { Array.new(@requests) } ; end
27
+ def requests
28
+ @requests_lock.synchronize { Array.new(@requests) }
29
+ end
30
+
31
+ # Store request if configured to do so
32
+ def store_request(request)
33
+ @requests_lock.synchronize { @requests << request } if @keep_requests
34
+ end
192
35
 
193
36
  # RJR::Dispatcher intializer
194
37
  def initialize(args = {})
@@ -226,8 +69,8 @@ class Dispatcher
226
69
  # Register json-rpc handler with dispatcher
227
70
  #
228
71
  # @param [String,Regex] signature request signature to match
229
- # @param [Callable] callable callable object which to bind to signature
230
- # @param [Callable] &bl block parameter will be set to callback if specified
72
+ # @param [Callable] callback callable object which to bind to signature
73
+ # @param [Callable] bl block parameter will be set to callback if specified
231
74
  # @return self
232
75
  def handle(signature, callback = nil, &bl)
233
76
  if signature.is_a?(Array)
@@ -239,16 +82,28 @@ class Dispatcher
239
82
  self
240
83
  end
241
84
 
85
+ # Return handler for specified method.
86
+ #
87
+ # Currently we match method name string or regex against signature
88
+ # @param [String] rjr_method string rjr method to match
89
+ # @return [Callable, nil] callback proc registered to handle rjr_method
90
+ # or nil if not found
91
+ def handler_for(rjr_method)
92
+ # look for exact match first
93
+ handler = @handlers.find { |k,v| k == rjr_method }
94
+
95
+ # if not found try to match regex's
96
+ handler ||= @handlers.find { |k,v| k.is_a?(Regexp) && (k =~ rjr_method) }
97
+
98
+ handler.nil? ? nil : handler.last
99
+ end
100
+
242
101
  # Return boolean indicating if dispatcher can handle method
243
102
  #
244
- # @param [String] string rjr method to match
103
+ # @param [String] rjr_method string rjr method to match
245
104
  # @return [true,false] indicating if requests to specified method will be matched
246
105
  def handles?(rjr_method)
247
- !@handlers.find { |k,v|
248
- k.is_a?(String) ?
249
- k == rjr_method :
250
- k =~ rjr_method
251
- }.nil?
106
+ !handler_for(rjr_method).nil?
252
107
  end
253
108
 
254
109
  # Register environment to run json-rpc handler w/ dispatcher.
@@ -257,7 +112,7 @@ class Dispatcher
257
112
  # will extend before executing handler
258
113
  #
259
114
  # @param [String,Regex] signature request signature to match
260
- # @param [Module] module which to extend requests with
115
+ # @param [Module] environment module which to extend requests with
261
116
  # @return self
262
117
  def env(signature, environment)
263
118
  if signature.is_a?(Array)
@@ -268,51 +123,52 @@ class Dispatcher
268
123
  self
269
124
  end
270
125
 
126
+ # Return the environment registered for the specified method
127
+ def env_for(rjr_method)
128
+ # look for exact match first
129
+ env = @environments.find { |k,v| k == rjr_method }
130
+
131
+ # if not found try to match regex's
132
+ env ||= @environments.find { |k,v| k.is_a?(Regexp) && (k =~ rjr_method) }
133
+
134
+ env.nil? ? nil : env.last
135
+ end
136
+
271
137
  # Dispatch received request. (used internally by nodes).
272
138
  #
273
139
  # Arguments should include :rjr_method and other parameters
274
140
  # required to construct a valid Request instance
275
141
  def dispatch(args = {})
276
- # currently we match method name string or regex against signature
277
- # TODO not using concurrent access protection, assumes all handlers are registered
278
- # before first dispatch occurs
279
- handler = @handlers.find { |k,v|
280
- k.is_a?(String) ?
281
- k == args[:rjr_method] :
282
- k =~ args[:rjr_method] }
283
-
284
- # TODO currently just using last environment that matches,
285
- # allow multiple environments to be used?
286
- environment = @environments.keys.select { |k|
287
- k.is_a?(String) ?
288
- k == args[:rjr_method] :
289
- k =~ args[:rjr_method]
290
- }.last
291
-
292
- return Result.method_not_found(args[:rjr_method]) if handler.nil?
293
-
294
- # TODO compare arity of handler to number of method_args passed in
295
- request = Request.new args.merge(:rjr_handler => handler.last)
296
-
297
- # set request environment
298
- request.extend(@environments[environment]) unless environment.nil?
299
-
300
- begin
301
- retval = request.handle
302
- request.result = Result.new(:result => retval)
303
-
304
- rescue Exception => e
305
- RJR::Logger.warn ["Exception Raised in #{args[:rjr_method]} handler #{e}"] +
306
- e.backtrace
307
- request.result =
308
- Result.new(:error_code => -32000,
309
- :error_msg => e.to_s,
310
- :error_class => e.class)
142
+ rjr_method = args[:rjr_method]
311
143
 
312
- end
144
+ # *note* not using concurrent access protection,
145
+ # assumes all handlers/enviroments are registered
146
+ # before first dispatch occurs
147
+ handler = handler_for(rjr_method)
148
+ environment = env_for(rjr_method)
149
+
150
+ return Result.method_not_found(rjr_method) if handler.nil?
151
+
152
+ request = Request.new args.merge(:rjr_handler => handler)
153
+
154
+ # set request environment
155
+ request.extend(environment) unless environment.nil?
156
+
157
+ begin
158
+ retval = request.handle
159
+ request.result = Result.new(:result => retval)
160
+
161
+ rescue Exception => e
162
+ warning = "Exception Raised in #{rjr_method} handler #{e}"
163
+ RJR::Logger.warn [warning] + e.backtrace
164
+
165
+ request.result = Result.new(:error_code => -32000,
166
+ :error_msg => e.to_s,
167
+ :error_class => e.class)
168
+ end
313
169
 
314
- @requests_lock.synchronize { @requests << request } if @keep_requests
315
- return request.result
170
+ store_request request
171
+ return request.result
316
172
  end
317
173
 
318
174
  # Handle responses received from rjr requests. (used internally by nodes)
@@ -0,0 +1,8 @@
1
+ # RJR Messages
2
+ #
3
+ # Copyright (C) 2014 Mohammed Morsi <mo@morsi.org>
4
+ # Licensed under the Apache License, Version 2.0
5
+
6
+ require 'rjr/messages/request'
7
+ require 'rjr/messages/response'
8
+ require 'rjr/messages/notification'
@@ -0,0 +1,264 @@
1
+ # RJR Compressed Messages
2
+ #
3
+ # *Note* this module is still expiremental
4
+ #
5
+ # Copyright (C) 2014 Mohammed Morsi <mo@morsi.org>
6
+ # Licensed under the Apache License, Version 2.0
7
+
8
+ # TODO split up into seperate modules
9
+ # (under lib/rjr/messages/compressed/ w/ this file including all)
10
+
11
+ require 'zlib'
12
+ require 'base64'
13
+
14
+ require 'rjr/messages'
15
+
16
+ module RJR
17
+ module Messages
18
+ # Make backups of original class references
19
+ module Uncompressed
20
+ Request = RJR::Messages::Request
21
+ Response = RJR::Messages::Response
22
+ Notification = RJR::Messages::Notification
23
+ end
24
+
25
+ # Subclass original message classes w/ versions that first
26
+ # check for compressed messages before dispatching to superclass
27
+ module Compressed
28
+ class Request < Uncompressed::Request
29
+ COMPRESSED = true
30
+
31
+ def initialize(args = {})
32
+ parse_args(args)
33
+ end
34
+
35
+ private
36
+
37
+ def parse_args(args)
38
+ args = Hash[args]
39
+ if args[:message]
40
+ message = args.delete(:message)
41
+ parse_message(message, args)
42
+ else
43
+ super(args)
44
+ end
45
+ end
46
+
47
+ def parse_message(message, args={})
48
+ @json_message = message
49
+ request = JSONParser.parse(@json_message)
50
+
51
+ if request.has_key?('m')
52
+ decoded = Base64.decode64(request['p'])
53
+ inflated = Zlib::Inflate.inflate(decoded)
54
+ converted = JSONParser.parse(inflated)
55
+
56
+ parse_args({:method => request['m'],
57
+ :id => request['i'],
58
+ :args => converted}.merge(args))
59
+
60
+ else
61
+ parse_args({:method => request['method'],
62
+ :args => request['params'],
63
+ :id => request['id']}.merge(args))
64
+ end
65
+ end
66
+
67
+ public
68
+
69
+ def self.is_compressed_request_message?(message)
70
+ begin
71
+ parsed = JSONParser.parse(message)
72
+ parsed.has_key?('m') && parsed.has_key?('i')
73
+ rescue Exception => e
74
+ false
75
+ end
76
+ end
77
+
78
+ def self.is_request_message?(message)
79
+ is_compressed_request_message?(message) || super(message)
80
+ end
81
+
82
+ def to_json(*a)
83
+ deflated = Zlib::Deflate.deflate(@jr_args.to_json.to_s)
84
+ encoded = Base64.encode64(deflated)
85
+
86
+ {'j' => 2.0,
87
+ 'i' => @msg_id,
88
+ 'm' => @jr_method,
89
+ 'p' => encoded}.merge(@headers).to_json(*a)
90
+ end
91
+ end
92
+
93
+ class Response < Uncompressed::Response
94
+ def initialize(args = {})
95
+ parse_args(args)
96
+ end
97
+
98
+ private
99
+
100
+ def parse_args(args)
101
+ args = Hash[args]
102
+ @request = args[:request]
103
+
104
+ if args[:message]
105
+ message = args.delete(:message)
106
+ parse_message(message, args)
107
+ else
108
+ super(args)
109
+ end
110
+ end
111
+
112
+ def parse_message(message, args={})
113
+ @json_message = message
114
+ response = JSONParser.parse(@json_message)
115
+
116
+ if response.has_key?('r') || response.has_key?('e')
117
+ result = parse_compressed_result(response)
118
+ parse_args({:id => response['i'],
119
+ :result => result}.merge(args))
120
+
121
+ else
122
+ result = parse_result(response)
123
+ parse_args({:id => response['id'],
124
+ :result => result}.merge(args))
125
+ end
126
+ end
127
+
128
+ def parse_compressed_result(response)
129
+ @result = Result.new
130
+ @result.success = response.has_key?('r')
131
+ @result.failed = !@result.success
132
+
133
+ if @result.success
134
+ decoded = Base64.decode64(response['r'])
135
+ inflated = Zlib::Inflate.inflate(decoded)
136
+ converted = JSONParser.parse(inflated).first
137
+ @result.result = converted
138
+
139
+ elsif response.has_key?('e')
140
+ @result.error_code = response['e']['co']
141
+ @result.error_msg = response['e']['m']
142
+ @result.error_class = response['e']['cl']
143
+ end
144
+
145
+ @result
146
+ end
147
+
148
+ public
149
+
150
+ def has_compressed_request?
151
+ !!@request && @request.class.const_defined?(:COMPRESSED)
152
+ end
153
+
154
+ def has_uncompressed_request?
155
+ !!@request && !@request.class.const_defined?(:COMPRESSED)
156
+ end
157
+
158
+ def self.is_compressed_response_message?(message)
159
+ begin
160
+ json = JSONParser.parse(message)
161
+ json.has_key?('r') || json.has_key?('e')
162
+ rescue Exception => e
163
+ puts e.to_s
164
+ false
165
+ end
166
+ end
167
+
168
+ def self.is_response_message?(message)
169
+ is_compressed_response_message?(message) || super(message)
170
+ end
171
+
172
+ def compressed_success_json
173
+ # XXX encapsulate in array & extract above so as to
174
+ # guarantee to be able to be parsable JSON
175
+ deflated = Zlib::Deflate.deflate([@result.result].to_json.to_s)
176
+ encoded = Base64.encode64(deflated)
177
+ {'r' => encoded}
178
+ end
179
+
180
+ def compressed_error_json
181
+ {'e' => {'co' => @result.error_code,
182
+ 'm' => @result.error_msg,
183
+ 'cl' => @result.error_class}}
184
+ end
185
+
186
+ def to_json(*a)
187
+ return super(*a) if has_uncompressed_request?
188
+
189
+ result_json = @result.success ?
190
+ compressed_success_json : compressed_error_json
191
+
192
+ response = {'j' => 2.0,
193
+ 'i' => @msg_id}.merge(@headers).
194
+ merge(result_json).to_json(*a)
195
+ end
196
+ end
197
+
198
+ class Notification < Uncompressed::Notification
199
+ def initialize(args = {})
200
+ parse_args(args)
201
+ end
202
+
203
+ private
204
+
205
+ def parse_args(args)
206
+ args = Hash[args]
207
+ if args[:message]
208
+ message = args.delete(:message)
209
+ parse_message(message, args)
210
+ else
211
+ super(args)
212
+ end
213
+ end
214
+
215
+ def parse_message(message, args={})
216
+ @json_message = message
217
+ request = JSONParser.parse(@json_message)
218
+
219
+ if request.has_key?('m')
220
+ decoded = Base64.decode64(request['p'])
221
+ inflated = Zlib::Inflate.inflate(decoded)
222
+ converted = JSONParser.parse(inflated)
223
+ parse_args({:method => request['m'],
224
+ :args => converted}.merge(args))
225
+
226
+ else
227
+ parse_args({:method => request['method'],
228
+ :args => request['params']}.merge(args))
229
+ end
230
+ end
231
+
232
+ public
233
+
234
+ def self.is_compressed_notification_message?(message)
235
+ begin
236
+ parsed = JSONParser.parse(message)
237
+ parsed.has_key?('m') && !parsed.has_key?('i')
238
+ rescue Exception => e
239
+ false
240
+ end
241
+ end
242
+
243
+ def self.is_notification_message?(message)
244
+ is_compressed_notification_message?(message) || super(message)
245
+ end
246
+
247
+ def to_json(*a)
248
+ deflated = Zlib::Deflate.deflate(@jr_args.to_json.to_s)
249
+ encoded = Base64.encode64(deflated)
250
+
251
+ {'j' => 2.0,
252
+ 'm' => @jr_method,
253
+ 'p' => encoded}.merge(@headers).to_json(*a)
254
+ end
255
+ end
256
+ end
257
+
258
+ # Override original classes w/ subclasses
259
+ Request = Compressed::Request
260
+ Response = Compressed::Response
261
+ Notification = Compressed::Notification
262
+
263
+ end # module Messages
264
+ end # module RJR