qrpc 0.4.0 → 0.9.0

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 (44) hide show
  1. data/CHANGES.txt +9 -6
  2. data/Gemfile +10 -4
  3. data/Gemfile.lock +34 -12
  4. data/LICENSE.txt +1 -1
  5. data/README.md +92 -25
  6. data/Rakefile +2 -1
  7. data/TODO.md +1 -3
  8. data/VERSION +1 -1
  9. data/lib/qrpc/client.rb +13 -5
  10. data/lib/qrpc/client/dispatcher.rb +66 -50
  11. data/lib/qrpc/client/exception.rb +8 -37
  12. data/lib/qrpc/client/job.rb +49 -16
  13. data/lib/qrpc/general.rb +61 -1
  14. data/lib/qrpc/generator/object-id.rb +43 -0
  15. data/lib/qrpc/generator/uuid.rb +43 -0
  16. data/lib/qrpc/locator.rb +11 -85
  17. data/lib/qrpc/locator/em-jack.rb +160 -0
  18. data/lib/qrpc/locator/evented-queue.rb +101 -0
  19. data/lib/qrpc/protocol/abstract.rb +119 -0
  20. data/lib/qrpc/protocol/abstract/error.rb +54 -0
  21. data/lib/qrpc/protocol/abstract/object.rb +81 -0
  22. data/lib/qrpc/protocol/abstract/request.rb +126 -0
  23. data/lib/qrpc/protocol/abstract/response.rb +103 -0
  24. data/lib/qrpc/protocol/json-rpc.rb +32 -0
  25. data/lib/qrpc/protocol/json-rpc/error.rb +71 -0
  26. data/lib/qrpc/protocol/json-rpc/native/exception-data.rb +247 -0
  27. data/lib/qrpc/protocol/json-rpc/native/qrpc-object.rb +137 -0
  28. data/lib/qrpc/protocol/json-rpc/request.rb +140 -0
  29. data/lib/qrpc/protocol/json-rpc/response.rb +146 -0
  30. data/lib/qrpc/protocol/object.rb +32 -0
  31. data/lib/qrpc/protocol/object/error.rb +46 -0
  32. data/lib/qrpc/protocol/object/request.rb +111 -0
  33. data/lib/qrpc/protocol/object/response.rb +93 -0
  34. data/lib/qrpc/server.rb +63 -48
  35. data/lib/qrpc/server/dispatcher.rb +5 -107
  36. data/lib/qrpc/server/job.rb +69 -19
  37. data/qrpc.gemspec +55 -19
  38. data/test-both.rb +85 -0
  39. data/test-client.rb +36 -8
  40. data/test-server.rb +17 -12
  41. metadata +181 -31
  42. data/lib/qrpc/protocol/exception-data.rb +0 -227
  43. data/lib/qrpc/protocol/qrpc-object.rb +0 -103
  44. data/lib/qrpc/protocol/request.rb +0 -46
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ # (c) 2012 Martin Kozák (martinkozak@martinkozak.net)
3
+
4
+ require "qrpc/general"
5
+ require "qrpc/protocol/abstract/error"
6
+
7
+ ##
8
+ # General QRPC module.
9
+ #
10
+
11
+ module QRPC
12
+
13
+ ##
14
+ # Protocols helper module.
15
+ # @since 0.9.0
16
+ #
17
+
18
+ module Protocol
19
+
20
+ ##
21
+ # Object protocol implementation.
22
+ # @since 0.9.0
23
+ #
24
+
25
+ class Object
26
+
27
+ ##
28
+ # Object error implementation.
29
+ # @since 0.9.0
30
+ #
31
+
32
+ class Error < QRPC::Protocol::Abstract::Error
33
+
34
+ ##
35
+ # Serializes object to the resultant form.
36
+ # @return [Error] serialized form
37
+ #
38
+
39
+ def serialize
40
+ self
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,111 @@
1
+ # encoding: utf-8
2
+ # (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
3
+
4
+ require "qrpc/general"
5
+ require "qrpc/protocol/abstract/request"
6
+
7
+ ##
8
+ # General QRPC module.
9
+ #
10
+
11
+ module QRPC
12
+
13
+ ##
14
+ # Protocols helper module.
15
+ # @since 0.9.0
16
+ #
17
+
18
+ module Protocol
19
+
20
+ ##
21
+ # Object protocol implementation.
22
+ # @since 0.9.0
23
+ #
24
+
25
+ class Object
26
+
27
+ ##
28
+ # Object request implementation.
29
+ # @since 0.9.0
30
+ #
31
+
32
+ class Request < QRPC::Protocol::Abstract::Request
33
+
34
+ ##
35
+ # Parses the data for new object.
36
+ #
37
+ # @param [String] raw raw data
38
+ # @return [Request] new request according to data
39
+ #
40
+
41
+ def self.parse(raw)
42
+ self::new(raw.options)
43
+ end
44
+
45
+ ##
46
+ # Serializes object to the resultant form.
47
+ # @return [Request] serialized form
48
+ #
49
+
50
+ def serialize
51
+ self
52
+ end
53
+
54
+ ##
55
+ # Returns ID of the request.
56
+ # @return [Object] request ID
57
+ #
58
+
59
+ def id
60
+ @options.id
61
+ end
62
+
63
+ ##
64
+ # Returns method identifier of the request.
65
+ # @return [Symbol]
66
+ #
67
+
68
+ def method
69
+ @options[:method]
70
+ end
71
+
72
+ ##
73
+ # Returns method params of the request.
74
+ # @return [Array]
75
+ #
76
+
77
+ def params
78
+ @options.arguments
79
+ end
80
+
81
+ ##
82
+ # Returns the QRPC request priority.
83
+ # @return [Integer]
84
+ #
85
+
86
+ def priority
87
+ @options.priority
88
+ end
89
+
90
+ ##
91
+ # Returns the QRPC request client identifier.
92
+ # @return [Object]
93
+ #
94
+
95
+ def client
96
+ @options.client_id.to_s
97
+ end
98
+
99
+ ##
100
+ # Indicates, job is notification.
101
+ # @return [Boolean]
102
+ #
103
+
104
+ def notification?
105
+ @options.notification
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,93 @@
1
+ # encoding: utf-8
2
+ # (c) 2012 Martin Kozák (martinkozak@martinkozak.net)
3
+
4
+ require "qrpc/general"
5
+ require "qrpc/protocol/abstract/response"
6
+
7
+ ##
8
+ # General QRPC module.
9
+ #
10
+
11
+ module QRPC
12
+
13
+ ##
14
+ # Protocols helper module.
15
+ # @since 0.9.0
16
+ #
17
+
18
+ module Protocol
19
+
20
+ ##
21
+ # Object protocol implementation.
22
+ # @since 0.9.0
23
+ #
24
+
25
+ class Object
26
+
27
+ ##
28
+ # Object response implementation.
29
+ # @since 0.9.0
30
+ #
31
+
32
+ class Response < QRPC::Protocol::Abstract::Response
33
+
34
+ ##
35
+ # Parses the data for new object.
36
+ #
37
+ # @param [String] raw raw data
38
+ # @return [Response] new request according to data
39
+ #
40
+
41
+ def self.parse(raw)
42
+ self::new(raw.options)
43
+ end
44
+
45
+ ##
46
+ # Serializes object to the resultant form.
47
+ # @return [Response] serialized form
48
+ #
49
+
50
+ def serialize
51
+ self
52
+ end
53
+
54
+ ##
55
+ # Returns ID of the response.
56
+ # @return [Object] response ID
57
+ #
58
+
59
+ def id
60
+ @options.request.id
61
+ end
62
+
63
+ ##
64
+ # Indicates, error state of the response.
65
+ # @return [Boolean] error indication
66
+ #
67
+
68
+ def error?
69
+ not self.error.nil?
70
+ end
71
+
72
+ ##
73
+ # Returns response error.
74
+ # @return [Exception] error object
75
+ #
76
+
77
+ def error
78
+ @options.error
79
+ end
80
+
81
+ ##
82
+ # Returns response result.
83
+ # @return [Object] response result
84
+ #
85
+
86
+ def result
87
+ @options.result
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+ end
data/lib/qrpc/server.rb CHANGED
@@ -1,11 +1,15 @@
1
1
  # encoding: utf-8
2
- require "qrpc/general"
3
- require "qrpc/server/job"
4
- require "qrpc/server/dispatcher"
5
- require "qrpc/locator"
2
+ # (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
3
+
6
4
  require "qrpc/protocol/qrpc-object"
7
- require "em-jack"
5
+ require "qrpc/server/dispatcher"
6
+ require "qrpc/server/job"
7
+ require "qrpc/general"
8
+
9
+ require "hash-utils/hash" # >= 0.1.0
8
10
  require "eventmachine"
11
+ require "em-batch"
12
+ require "em-jack"
9
13
  require "base64"
10
14
 
11
15
  ##
@@ -95,6 +99,20 @@ module QRPC
95
99
 
96
100
  @output_used
97
101
 
102
+ ##
103
+ # Holds protocol instance.
104
+ # @since 0.9.0
105
+ #
106
+
107
+ @protocol
108
+
109
+ ##
110
+ # Indicates API methods synchronicity.
111
+ # @since 0.4.0
112
+ #
113
+
114
+ @synchronicity
115
+
98
116
  ##
99
117
  # Holds servers for finalizing.
100
118
  #
@@ -103,11 +121,16 @@ module QRPC
103
121
 
104
122
  ##
105
123
  # Constructor.
124
+ #
106
125
  # @param [Object] api some object which will be used as RPC API
126
+ # @param [Symbol] synchronicity API methods synchronicity
127
+ # @param [QRPC::Protocol::Abstract] protocol a protocol handling instance
107
128
  #
108
129
 
109
- def initialize(api)
130
+ def initialize(api, synchronicity = :synchronous, protocol = QRPC::default_protocol)
110
131
  @api = api
132
+ @protocol = protocol
133
+ @synchronicity = synchronicity
111
134
  @output_name_cache = { }
112
135
 
113
136
  # Destructor
@@ -132,9 +155,9 @@ module QRPC
132
155
 
133
156
  def finalize!
134
157
  if not @input_queue.nil?
135
- @input_queue.watch("default") do
136
- @input_queue.ignore(@input_name.to_s) do
137
- @input_queue.close
158
+ @input_queue.subscribe("default") do
159
+ @input_queue.unsubscribe(@input_name.to_s) do
160
+ @input_queue.close!
138
161
  end
139
162
  end
140
163
  end
@@ -171,58 +194,52 @@ module QRPC
171
194
 
172
195
  def start_listening(locator, opts = { })
173
196
  @locator = locator
174
- @dispatcher = QRPC::Server::Dispatcher::new(opts[:max_jobs])
175
-
197
+ @dispatcher = QRPC::Server::Dispatcher::new
198
+
176
199
  # Cache cleaning dispatcher
177
- EM.add_periodic_timer(20) do
200
+ EM::add_periodic_timer(20) do
178
201
  @output_name_cache.clear
179
202
  end
180
-
203
+
181
204
  # Process input queue
182
205
  self.input_queue do |queue|
183
- worker = Proc::new do
184
- @dispatcher.available? do
185
- queue.reserve do |job|
186
- self.process_job(job)
187
- job.delete()
188
- worker.call()
189
- end
190
- end
206
+ queue.pop(true) do |job|
207
+ self.process_job(job)
191
208
  end
192
-
193
- worker.call()
194
209
  end
195
210
  end
196
-
211
+
197
212
  ##
198
213
  # Returns input queue.
199
214
  # @param [Proc] block block to which will be input queue given
200
215
  #
201
216
 
202
217
  def input_queue(&block)
203
- if not @input_queue
204
- @input_queue = EMJack::Connection::new(:host => @locator.host, :port => @locator.port)
205
- @input_queue.watch(self.input_name.to_s) do
206
- @input_queue.ignore("default") do
207
- block.call(@input_queue)
218
+ if @input_queue.nil?
219
+ @input_queue = @locator.input_queue
220
+ @input_queue.subscribe(self.input_name.to_s) do
221
+ @input_queue.unsubscribe("default") do
222
+ yield @input_queue
208
223
  end
209
224
  end
210
225
  else
211
- block.call(@input_queue)
226
+ @input_queue.subscribe(self.input_name.to_s) do
227
+ yield @input_queue
228
+ end
212
229
  end
213
230
  end
214
-
231
+
215
232
  ##
216
233
  # Returns output queue.
217
- # @return [EMJack::Connection] output queue Beanstalk connection
234
+ # @param [Proc] block block to which will be output queue given
218
235
  #
219
236
 
220
- def output_queue
237
+ def output_queue(&block)
221
238
  if @output_queue.nil?
222
- @output_queue = EMJack::Connection::new(:host => @locator.host, :port => @locator.port)
239
+ @output_queue = @locator.output_queue
240
+ else
241
+ @output_queue
223
242
  end
224
-
225
- return @output_queue
226
243
  end
227
244
 
228
245
  ##
@@ -236,7 +253,7 @@ module QRPC
236
253
  client_index = client.to_sym
237
254
 
238
255
  if not @output_name_cache.include? client_index
239
- output_name = QRPC::QUEUE_PREFIX.dup << "-" << client.to_s << "-" << QRPC::QUEUE_POSTFIX_OUTPUT
256
+ output_name = QRPC::QUEUE_PREFIX + "-" + client.to_s + "-" + QRPC::QUEUE_POSTFIX_OUTPUT
240
257
  output_name = output_name.to_sym
241
258
  @output_name_cache[client_index] = output_name
242
259
  else
@@ -255,7 +272,7 @@ module QRPC
255
272
 
256
273
  def input_name
257
274
  if @input_name.nil?
258
- @input_name = (QRPC::QUEUE_PREFIX.dup << "-" << @locator.queue << "-" << QRPC::QUEUE_POSTFIX_INPUT).to_sym
275
+ @input_name = (QRPC::QUEUE_PREFIX + "-" + @locator.queue_name + "-" + QRPC::QUEUE_POSTFIX_INPUT).to_sym
259
276
  end
260
277
 
261
278
  return @input_name
@@ -270,16 +287,14 @@ module QRPC
270
287
  #
271
288
 
272
289
  def process_job(job)
273
- our_job = QRPC::Server::Job::new(@api, job)
274
- our_job.callback do |result|
275
- call = Proc::new { self.output_queue.put(result, :priority => our_job.priority) }
276
- output_name = self.output_name(our_job.client)
277
-
278
- if @output_used != output_name
279
- @output_used = output_name
280
- self.output_queue.use(output_name.to_s, &call)
281
- else
282
- call.call
290
+ our_job = QRPC::Server::Job::new(@api, @synchronicity, job, @protocol)
291
+ if not our_job.request.notification?
292
+ our_job.callback do |result|
293
+ output_name = self.output_name(our_job.client)
294
+ output_queue = self.output_queue
295
+ output_queue.use(output_name.to_s) do
296
+ output_queue.push(result, our_job.priority)
297
+ end
283
298
  end
284
299
  end
285
300
 
@@ -1,12 +1,15 @@
1
1
  # encoding: utf-8
2
- require "depq"
3
-
4
2
 
5
3
  ##
6
4
  # General QRPC module.
7
5
  #
8
6
 
9
7
  module QRPC
8
+
9
+ ##
10
+ # Queue RPC server.
11
+ #
12
+
10
13
  class Server
11
14
 
12
15
  ##
@@ -15,120 +18,15 @@ module QRPC
15
18
 
16
19
  class Dispatcher
17
20
 
18
- ##
19
- # Holds running EM fibers count.
20
- #
21
-
22
- @count
23
-
24
- ##
25
- # Holds unprocessed jobs queue.
26
- #
27
-
28
- @queue
29
-
30
- ##
31
- # Holds max jobs count.
32
- #
33
-
34
- @max_jobs
35
-
36
- ##
37
- # Holds "full state" locking mutex.
38
- #
39
-
40
- @mutex
41
-
42
- ##
43
- # Constructor.
44
- #
45
-
46
- def initialize(max_jobs = 0)
47
- @count = 0
48
- @queue = Depq::new
49
- @mutex = Mutex::new
50
- @max_jobs = max_jobs
51
-
52
- if @max_jobs.nil?
53
- @max_jobs = 0
54
- end
55
- end
56
-
57
21
  ##
58
22
  # Puts job to dispatcher.
59
23
  # @param [QRPC::Server::Job] job job for dispatching
60
24
  #
61
25
 
62
26
  def put(job)
63
- begin
64
- @queue.put(job, job.priority)
65
- rescue ::Exception => e
66
- return
67
- end
68
-
69
- if self.available?
70
- self.process_next!
71
- @count += 1
72
- self.regulate!
73
- end
74
- end
75
-
76
- ##
77
- # Sets up next job for processing.
78
- #
79
-
80
- def process_next!
81
- job = @queue.pop
82
- job.callback do
83
- if self.available? and not @queue.empty?
84
- self.process_next!
85
- else
86
- @count -= 1
87
- self.regulate!
88
- end
89
- end
90
-
91
27
  job.process!
92
28
  end
93
29
 
94
- ##
95
- # Indicates free space is available in dispatcher.
96
- #
97
- # If block is given, locks to time space in dispatcher is
98
- # available so works as synchronization primitive by this
99
- # way.
100
- #
101
- # @overload available?
102
- # @return [Boolean] +true+ if it is, +false+ in otherwise
103
- # @overload available?(&block)
104
- # @param [Proc] block synchronized block
105
- #
106
-
107
- def available?(&block)
108
- if block.nil?
109
- return ((@count < @max_jobs) or (@max_jobs == 0))
110
- else
111
- @mutex.synchronize(&block)
112
- end
113
- end
114
-
115
-
116
- protected
117
-
118
- ##
119
- # Regulates by locking the dispatcher it if it's full.
120
- #
121
-
122
- def regulate!
123
- if self.available?
124
- if @mutex.locked?
125
- @mutex.unlock
126
- end
127
- else
128
- @mutex.try_lock
129
- end
130
- end
131
-
132
30
  end
133
31
  end
134
32
  end