qrpc 0.4.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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