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.
- data/CHANGES.txt +9 -6
- data/Gemfile +10 -4
- data/Gemfile.lock +34 -12
- data/LICENSE.txt +1 -1
- data/README.md +92 -25
- data/Rakefile +2 -1
- data/TODO.md +1 -3
- data/VERSION +1 -1
- data/lib/qrpc/client.rb +13 -5
- data/lib/qrpc/client/dispatcher.rb +66 -50
- data/lib/qrpc/client/exception.rb +8 -37
- data/lib/qrpc/client/job.rb +49 -16
- data/lib/qrpc/general.rb +61 -1
- data/lib/qrpc/generator/object-id.rb +43 -0
- data/lib/qrpc/generator/uuid.rb +43 -0
- data/lib/qrpc/locator.rb +11 -85
- data/lib/qrpc/locator/em-jack.rb +160 -0
- data/lib/qrpc/locator/evented-queue.rb +101 -0
- data/lib/qrpc/protocol/abstract.rb +119 -0
- data/lib/qrpc/protocol/abstract/error.rb +54 -0
- data/lib/qrpc/protocol/abstract/object.rb +81 -0
- data/lib/qrpc/protocol/abstract/request.rb +126 -0
- data/lib/qrpc/protocol/abstract/response.rb +103 -0
- data/lib/qrpc/protocol/json-rpc.rb +32 -0
- data/lib/qrpc/protocol/json-rpc/error.rb +71 -0
- data/lib/qrpc/protocol/json-rpc/native/exception-data.rb +247 -0
- data/lib/qrpc/protocol/json-rpc/native/qrpc-object.rb +137 -0
- data/lib/qrpc/protocol/json-rpc/request.rb +140 -0
- data/lib/qrpc/protocol/json-rpc/response.rb +146 -0
- data/lib/qrpc/protocol/object.rb +32 -0
- data/lib/qrpc/protocol/object/error.rb +46 -0
- data/lib/qrpc/protocol/object/request.rb +111 -0
- data/lib/qrpc/protocol/object/response.rb +93 -0
- data/lib/qrpc/server.rb +63 -48
- data/lib/qrpc/server/dispatcher.rb +5 -107
- data/lib/qrpc/server/job.rb +69 -19
- data/qrpc.gemspec +55 -19
- data/test-both.rb +85 -0
- data/test-client.rb +36 -8
- data/test-server.rb +17 -12
- metadata +181 -31
- data/lib/qrpc/protocol/exception-data.rb +0 -227
- data/lib/qrpc/protocol/qrpc-object.rb +0 -103
- 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
|
-
|
3
|
-
|
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 "
|
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.
|
136
|
-
@input_queue.
|
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
|
175
|
-
|
197
|
+
@dispatcher = QRPC::Server::Dispatcher::new
|
198
|
+
|
176
199
|
# Cache cleaning dispatcher
|
177
|
-
EM
|
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
|
-
|
184
|
-
|
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
|
204
|
-
@input_queue =
|
205
|
-
@input_queue.
|
206
|
-
@input_queue.
|
207
|
-
|
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
|
-
|
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
|
-
# @
|
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 =
|
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
|
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
|
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.
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
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
|