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