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.
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