goliath 0.9.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of goliath might be problematic. Click here for more details.
- data/.gitignore +1 -0
- data/HISTORY +50 -0
- data/README.md +2 -0
- data/examples/activerecord/srv.rb +1 -3
- data/examples/async_aroundware_demo.rb +81 -0
- data/examples/async_upload.rb +1 -2
- data/examples/auth_and_rate_limit.rb +143 -0
- data/examples/chunked_streaming.rb +37 -0
- data/examples/conf_test.rb +1 -3
- data/examples/config/auth_and_rate_limit.rb +30 -0
- data/examples/config/template.rb +8 -0
- data/examples/content_stream.rb +1 -3
- data/examples/echo.rb +8 -6
- data/examples/env_use_statements.rb +17 -0
- data/examples/gziped.rb +1 -3
- data/examples/public/stylesheets/style.css +296 -0
- data/examples/rack_routes.rb +65 -3
- data/examples/rasterize/rasterize.js +15 -0
- data/examples/rasterize/rasterize.rb +36 -0
- data/examples/rasterize/rasterize_and_shorten.rb +37 -0
- data/examples/stream.rb +2 -2
- data/examples/template.rb +48 -0
- data/examples/test_rig.rb +125 -0
- data/examples/valid.rb +4 -2
- data/examples/views/debug.haml +4 -0
- data/examples/views/joke.markdown +13 -0
- data/examples/views/layout.erb +12 -0
- data/examples/views/layout.haml +39 -0
- data/examples/views/root.haml +28 -0
- data/goliath.gemspec +10 -3
- data/lib/goliath.rb +0 -36
- data/lib/goliath/api.rb +137 -26
- data/lib/goliath/application.rb +71 -21
- data/lib/goliath/connection.rb +4 -2
- data/lib/goliath/constants.rb +1 -0
- data/lib/goliath/env.rb +40 -1
- data/lib/goliath/goliath.rb +30 -15
- data/lib/goliath/headers.rb +2 -2
- data/lib/goliath/plugins/latency.rb +8 -2
- data/lib/goliath/rack.rb +18 -0
- data/lib/goliath/rack/async_aroundware.rb +56 -0
- data/lib/goliath/rack/async_middleware.rb +93 -0
- data/lib/goliath/rack/builder.rb +42 -0
- data/lib/goliath/rack/default_response_format.rb +3 -15
- data/lib/goliath/rack/formatters.rb +11 -0
- data/lib/goliath/rack/formatters/html.rb +2 -18
- data/lib/goliath/rack/formatters/json.rb +2 -17
- data/lib/goliath/rack/formatters/plist.rb +32 -0
- data/lib/goliath/rack/formatters/xml.rb +23 -31
- data/lib/goliath/rack/formatters/yaml.rb +27 -0
- data/lib/goliath/rack/jsonp.rb +1 -13
- data/lib/goliath/rack/params.rb +55 -27
- data/lib/goliath/rack/render.rb +13 -22
- data/lib/goliath/rack/templates.rb +357 -0
- data/lib/goliath/rack/tracer.rb +11 -12
- data/lib/goliath/rack/validation.rb +12 -0
- data/lib/goliath/rack/validation/default_params.rb +0 -2
- data/lib/goliath/rack/validation/numeric_range.rb +11 -2
- data/lib/goliath/rack/validation/request_method.rb +3 -2
- data/lib/goliath/rack/validation/required_param.rb +13 -11
- data/lib/goliath/rack/validation/required_value.rb +11 -15
- data/lib/goliath/rack/validator.rb +51 -0
- data/lib/goliath/request.rb +34 -20
- data/lib/goliath/response.rb +3 -2
- data/lib/goliath/runner.rb +5 -11
- data/lib/goliath/server.rb +2 -1
- data/lib/goliath/synchrony/mongo_receiver.rb +64 -0
- data/lib/goliath/synchrony/response_receiver.rb +64 -0
- data/lib/goliath/test_helper.rb +39 -21
- data/lib/goliath/validation.rb +2 -0
- data/lib/goliath/{rack/validation_error.rb → validation/error.rb} +0 -16
- data/lib/goliath/validation/standard_http_errors.rb +31 -0
- data/lib/goliath/version.rb +1 -1
- data/spec/integration/http_log_spec.rb +16 -16
- data/spec/integration/rack_routes_spec.rb +144 -0
- data/spec/integration/reloader_spec.rb +4 -4
- data/spec/integration/template_spec.rb +54 -0
- data/spec/integration/trace_spec.rb +23 -0
- data/spec/integration/valid_spec.rb +21 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/unit/api_spec.rb +30 -0
- data/spec/unit/rack/builder_spec.rb +40 -0
- data/spec/unit/rack/formatters/plist_spec.rb +51 -0
- data/spec/unit/rack/formatters/yaml_spec.rb +53 -0
- data/spec/unit/rack/params_spec.rb +22 -0
- data/spec/unit/rack/render_spec.rb +10 -5
- data/spec/unit/rack/validation/numeric_range_spec.rb +8 -1
- data/spec/unit/rack/validation/request_method_spec.rb +8 -8
- data/spec/unit/rack/validation/required_param_spec.rb +19 -15
- data/spec/unit/rack/validation/required_value_spec.rb +10 -13
- data/spec/unit/server_spec.rb +4 -4
- data/spec/unit/validation/standard_http_errors_spec.rb +21 -0
- metadata +177 -35
- data/spec/unit/rack/validation_error_spec.rb +0 -40
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'goliath/rack/
|
1
|
+
require 'goliath/rack/validator'
|
2
2
|
|
3
3
|
module Goliath
|
4
4
|
module Rack
|
@@ -9,6 +9,7 @@ module Goliath
|
|
9
9
|
# use Goliath::Rack::Validation::RequestMethod, %w(GET POST)
|
10
10
|
#
|
11
11
|
class RequestMethod
|
12
|
+
include Goliath::Rack::Validator
|
12
13
|
attr_reader :methods
|
13
14
|
|
14
15
|
ERROR = 'Invalid request method'
|
@@ -24,7 +25,7 @@ module Goliath
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def call(env)
|
27
|
-
|
28
|
+
return validation_error(405, ERROR, "Allow" => methods.map{|m| m.to_s.upcase}.join(', ')) unless methods.include?(env['REQUEST_METHOD'])
|
28
29
|
@app.call(env)
|
29
30
|
end
|
30
31
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'goliath/rack/
|
1
|
+
require 'goliath/rack/validator'
|
2
2
|
|
3
3
|
module Goliath
|
4
4
|
module Rack
|
@@ -9,7 +9,8 @@ module Goliath
|
|
9
9
|
# use Goliath::Rack::Validation::RequiredParam, {:key => 'mode', :type => 'Mode'}
|
10
10
|
#
|
11
11
|
class RequiredParam
|
12
|
-
|
12
|
+
include Goliath::Rack::Validator
|
13
|
+
attr_reader :type, :key, :message
|
13
14
|
|
14
15
|
# Creates the Goliath::Rack::Validation::RequiredParam validator
|
15
16
|
#
|
@@ -17,38 +18,39 @@ module Goliath
|
|
17
18
|
# @param opts [Hash] The validator options
|
18
19
|
# @option opts [String] :key The key to look for in params (default: id)
|
19
20
|
# @option opts [String] :type The type string to put in the error message. (default: :key)
|
21
|
+
# @option opts [String] :message The message string to display after the type string. (default: 'identifier missing')
|
20
22
|
# @return [Goliath::Rack::Validation::RequiredParam] The validator
|
21
23
|
def initialize(app, opts = {})
|
22
24
|
@app = app
|
23
25
|
@key = opts[:key] || 'id'
|
24
26
|
@type = opts[:type] || @key.capitalize
|
27
|
+
@message = opts[:message] || 'identifier missing'
|
25
28
|
end
|
26
29
|
|
27
30
|
def call(env)
|
28
|
-
key_valid
|
31
|
+
return validation_error(400, "#{@type} #{@message}") unless key_valid?(env['params'])
|
29
32
|
@app.call(env)
|
30
33
|
end
|
31
34
|
|
32
|
-
def key_valid
|
33
|
-
error = false
|
35
|
+
def key_valid?(params)
|
34
36
|
if !params.has_key?(key) || params[key].nil? ||
|
35
37
|
(params[key].is_a?(String) && params[key] =~ /^\s*$/)
|
36
|
-
|
38
|
+
return false
|
37
39
|
end
|
38
40
|
|
39
41
|
if params[key].is_a?(Array)
|
40
42
|
unless params[key].compact.empty?
|
41
43
|
params[key].each do |k|
|
42
|
-
return unless k.is_a?(String)
|
43
|
-
return unless k =~ /^\s*$/
|
44
|
+
return true unless k.is_a?(String)
|
45
|
+
return true unless k =~ /^\s*$/
|
44
46
|
end
|
45
47
|
end
|
46
|
-
|
48
|
+
return false
|
47
49
|
end
|
48
50
|
|
49
|
-
|
51
|
+
true
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
54
|
-
end
|
56
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'goliath/rack/
|
1
|
+
require 'goliath/rack/validator'
|
2
2
|
|
3
3
|
module Goliath
|
4
4
|
module Rack
|
@@ -10,6 +10,8 @@ module Goliath
|
|
10
10
|
# use Goliath::Rack::Validation::RequiredValue, {:key => 'baz', :values => 'awesome'}
|
11
11
|
#
|
12
12
|
class RequiredValue
|
13
|
+
include Goliath::Rack::Validator
|
14
|
+
|
13
15
|
attr_reader :key, :values
|
14
16
|
|
15
17
|
# Creates the Goliath::Rack::Validation::RequiredValue validator.
|
@@ -26,31 +28,25 @@ module Goliath
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def call(env)
|
29
|
-
value_valid
|
31
|
+
return validation_error(400, "Provided #{@key} is invalid") unless value_valid?(env['params'])
|
30
32
|
@app.call(env)
|
31
33
|
end
|
32
34
|
|
33
|
-
def value_valid
|
34
|
-
error = false
|
35
|
+
def value_valid?(params)
|
35
36
|
if !params.has_key?(key) || params[key].nil? ||
|
36
37
|
(params[key].is_a?(String) && params[key] =~ /^\s*$/)
|
37
|
-
|
38
|
+
return false
|
38
39
|
end
|
39
40
|
|
40
41
|
if params[key].is_a?(Array)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
unless values.include?(k)
|
45
|
-
error = true
|
46
|
-
break
|
47
|
-
end
|
48
|
-
end
|
42
|
+
return false if params[key].empty?
|
43
|
+
params[key].each { |k| return false unless values.include?(k) }
|
44
|
+
|
49
45
|
elsif !values.include?(params[key])
|
50
|
-
|
46
|
+
return false
|
51
47
|
end
|
52
48
|
|
53
|
-
|
49
|
+
true
|
54
50
|
end
|
55
51
|
end
|
56
52
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Goliath
|
2
|
+
module Rack
|
3
|
+
module Validator
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# @param status_code [Integer] HTTP status code for this error.
|
7
|
+
# @param msg [String] message to inject into the response body.
|
8
|
+
# @param headers [Hash] Response headers to preserve in an error response;
|
9
|
+
# (the Content-Length header, if any, is removed)
|
10
|
+
def validation_error(status_code, msg, headers={})
|
11
|
+
headers.delete('Content-Length')
|
12
|
+
[status_code, headers, {:error => msg}]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Execute a block of code safely.
|
16
|
+
#
|
17
|
+
# If the block raises any exception that derives from
|
18
|
+
# Goliath::Validation::Error (see specifically those in
|
19
|
+
# goliath/validation/standard_http_errors.rb), it will be turned into the
|
20
|
+
# corresponding 4xx response with a corresponding message.
|
21
|
+
#
|
22
|
+
# If the block raises any other kind of error, we log it and return a
|
23
|
+
# less-communicative 500 response.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# # will convert the ForbiddenError exception into a 403 response
|
27
|
+
# # and an uncaught error in do_something_risky! into a 500 response
|
28
|
+
# safely(env, headers) do
|
29
|
+
# raise ForbiddenError unless account_info['valid'] == true
|
30
|
+
# do_something_risky!
|
31
|
+
# [status, headers, body]
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
#
|
35
|
+
# @param env [Goliath::Env] The current request env
|
36
|
+
# @param headers [Hash] Response headers to preserve in an error response
|
37
|
+
#
|
38
|
+
def safely(env, headers={})
|
39
|
+
begin
|
40
|
+
yield
|
41
|
+
rescue Goliath::Validation::Error => e
|
42
|
+
validation_error(e.status_code, e.message, headers)
|
43
|
+
rescue Exception => e
|
44
|
+
env.logger.error(e.message)
|
45
|
+
env.logger.error(e.backtrace.join("\n"))
|
46
|
+
validation_error(500, e.message, headers)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/goliath/request.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
require 'goliath/constants'
|
3
|
+
require 'goliath/response'
|
4
|
+
require 'goliath/validation'
|
3
5
|
require 'async_rack'
|
4
6
|
require 'stringio'
|
5
7
|
|
@@ -26,8 +28,11 @@ module Goliath
|
|
26
28
|
|
27
29
|
@env[STREAM_SEND] = proc { |data| callback { @conn.send_data(data) } }
|
28
30
|
@env[STREAM_CLOSE] = proc { callback { @conn.terminate_request(false) } }
|
29
|
-
@env[STREAM_START] = proc do
|
31
|
+
@env[STREAM_START] = proc do |status, headers|
|
30
32
|
callback do
|
33
|
+
@response.status = status
|
34
|
+
@response.headers = headers
|
35
|
+
|
31
36
|
@conn.send_data(@response.head)
|
32
37
|
@conn.send_data(@response.headers_output)
|
33
38
|
end
|
@@ -125,14 +130,15 @@ module Goliath
|
|
125
130
|
#
|
126
131
|
# @return [Nil]
|
127
132
|
def process
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
Fiber.new {
|
134
|
+
begin
|
135
|
+
@state = :finished
|
136
|
+
@env['rack.input'].rewind if @env['rack.input']
|
137
|
+
post_process(@app.call(@env))
|
138
|
+
rescue Exception => e
|
139
|
+
server_exception(e)
|
140
|
+
end
|
141
|
+
}.resume
|
136
142
|
end
|
137
143
|
|
138
144
|
# Invoked by the app / middleware once the request
|
@@ -164,10 +170,10 @@ module Goliath
|
|
164
170
|
@response.status, @response.headers, @response.body = status, headers, body
|
165
171
|
@response.each { |chunk| @conn.send_data(chunk) }
|
166
172
|
@env[RACK_LOGGER].info("Status: #{@response.status}, " +
|
167
|
-
|
168
|
-
|
173
|
+
"Content-Length: #{@response.headers['Content-Length']}, " +
|
174
|
+
"Response Time: #{"%.2f" % ((Time.now.to_f - @env[:start_time]) * 1000)}ms")
|
169
175
|
|
170
|
-
|
176
|
+
@conn.terminate_request(keep_alive)
|
171
177
|
rescue Exception => e
|
172
178
|
server_exception(e)
|
173
179
|
end
|
@@ -185,24 +191,32 @@ module Goliath
|
|
185
191
|
# @param e [Exception] The exception to log
|
186
192
|
# @return [Nil]
|
187
193
|
def server_exception(e)
|
188
|
-
|
189
|
-
|
194
|
+
if e.is_a?(Goliath::Validation::Error)
|
195
|
+
status, headers, body = [e.status_code, {}, ('{"error":"%s"}'%e.message)] #
|
196
|
+
else
|
197
|
+
@env[RACK_LOGGER].error("#{e.message}\n#{e.backtrace.join("\n")}")
|
198
|
+
status, headers, body = [500, {}, 'An error happened']
|
199
|
+
end
|
200
|
+
headers['Content-Length'] = body.bytesize.to_s
|
201
|
+
@env[:terminate_connection] = true
|
202
|
+
post_process([status, headers, body])
|
190
203
|
end
|
191
204
|
|
192
205
|
# Used to determine if the connection should be kept open
|
193
206
|
#
|
194
207
|
# @return [Boolean] True to keep the connection open, false otherwise
|
195
208
|
def keep_alive
|
209
|
+
return false if @env[:terminate_connection]
|
196
210
|
case @env[HTTP_VERSION]
|
197
211
|
# HTTP 1.1: all requests are persistent requests, client
|
198
212
|
# must send a Connection:close header to indicate otherwise
|
199
|
-
|
200
|
-
|
213
|
+
when '1.1' then
|
214
|
+
(@env[HTTP_PREFIX + CONNECTION].downcase != 'close') rescue true
|
201
215
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
216
|
+
# HTTP 1.0: all requests are non keep-alive, client must
|
217
|
+
# send a Connection: Keep-Alive to indicate otherwise
|
218
|
+
when '1.0' then
|
219
|
+
(@env[HTTP_PREFIX + CONNECTION].downcase == 'keep-alive') rescue false
|
206
220
|
end
|
207
221
|
end
|
208
222
|
end
|
data/lib/goliath/response.rb
CHANGED
@@ -18,11 +18,12 @@ module Goliath
|
|
18
18
|
# The body to send
|
19
19
|
attr_accessor :body
|
20
20
|
|
21
|
-
SERVER = 'Server'
|
22
|
-
DATE = 'Date'
|
21
|
+
SERVER = 'Server'
|
22
|
+
DATE = 'Date'
|
23
23
|
|
24
24
|
# Used to signal that a response is a streaming response
|
25
25
|
STREAMING = :goliath_stream_response
|
26
|
+
CHUNKED_STREAM_HEADERS = { 'Transfer-Encoding' => 'chunked' }
|
26
27
|
|
27
28
|
def initialize
|
28
29
|
@headers = Goliath::Headers.new
|
data/lib/goliath/runner.rb
CHANGED
@@ -4,7 +4,7 @@ require 'optparse'
|
|
4
4
|
require 'log4r'
|
5
5
|
|
6
6
|
module Goliath
|
7
|
-
# The Goliath::Runner is responsible for parsing any provided options,
|
7
|
+
# The Goliath::Runner is responsible for parsing any provided options, setting up the
|
8
8
|
# rack application, creating a logger, and then executing the Goliath::Server with the loaded information.
|
9
9
|
class Runner
|
10
10
|
# The address of the server @example 127.0.0.1
|
@@ -63,6 +63,7 @@ module Goliath
|
|
63
63
|
def initialize(argv, api)
|
64
64
|
api.options_parser(options_parser, options) if api
|
65
65
|
options_parser.parse!(argv)
|
66
|
+
Goliath.env = options.delete(:env)
|
66
67
|
|
67
68
|
@api = api
|
68
69
|
@address = options.delete(:address)
|
@@ -88,7 +89,8 @@ module Goliath
|
|
88
89
|
|
89
90
|
:daemonize => false,
|
90
91
|
:verbose => false,
|
91
|
-
:log_stdout => false
|
92
|
+
:log_stdout => false,
|
93
|
+
:env => :development,
|
92
94
|
}
|
93
95
|
|
94
96
|
@options_parser ||= OptionParser.new do |opts|
|
@@ -97,7 +99,7 @@ module Goliath
|
|
97
99
|
opts.separator ""
|
98
100
|
opts.separator "Server options:"
|
99
101
|
|
100
|
-
opts.on('-e', '--environment NAME', "Set the execution environment (prod, dev or test) (default: #{
|
102
|
+
opts.on('-e', '--environment NAME', "Set the execution environment (prod, dev or test) (default: #{@options[:env]})") { |val| @options[:env] = val }
|
101
103
|
|
102
104
|
opts.on('-a', '--address HOST', "Bind to HOST address (default: #{@options[:address]})") { |addr| @options[:address] = addr }
|
103
105
|
opts.on('-p', '--port PORT', "Use PORT (default: #{@options[:port]})") { |port| @options[:port] = port.to_i }
|
@@ -115,14 +117,6 @@ module Goliath
|
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
118
|
-
# Given a block, this will use Rack::Builder to create the application
|
119
|
-
#
|
120
|
-
# @param blk [Block] The application block to load
|
121
|
-
# @return [Object] The Rack application
|
122
|
-
def load_app(&blk)
|
123
|
-
@app = ::Rack::Builder.app(&blk)
|
124
|
-
end
|
125
|
-
|
126
120
|
# Stores the list of plugins to be used by the server
|
127
121
|
#
|
128
122
|
# @param plugins [Array] The list of plugins to use
|
data/lib/goliath/server.rb
CHANGED
@@ -68,7 +68,7 @@ module Goliath
|
|
68
68
|
# start listening for requests
|
69
69
|
#
|
70
70
|
# @return Does not return until the server has halted.
|
71
|
-
def start
|
71
|
+
def start(&blk)
|
72
72
|
EM.synchrony do
|
73
73
|
trap("INT") { EM.stop }
|
74
74
|
trap("TERM") { EM.stop }
|
@@ -90,6 +90,7 @@ module Goliath
|
|
90
90
|
conn.options = options
|
91
91
|
end
|
92
92
|
|
93
|
+
blk.call(self) if blk
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'goliath/synchrony/response_receiver'
|
2
|
+
|
3
|
+
module Goliath
|
4
|
+
module Synchrony
|
5
|
+
#
|
6
|
+
# Currently, you must provide in the env a method 'mongo' that returns a mongo
|
7
|
+
# collection or collection proxy (probably by setting it up in the config).
|
8
|
+
#
|
9
|
+
# This will almost certainly change to something less crappy.
|
10
|
+
#
|
11
|
+
class MongoReceiver
|
12
|
+
include Goliath::Synchrony::ResponseReceiver
|
13
|
+
include EM::Deferrable
|
14
|
+
include Goliath::Rack::Validator
|
15
|
+
|
16
|
+
def initialize(env, db_name)
|
17
|
+
@env = env
|
18
|
+
@pending_queries = 0
|
19
|
+
@db = env.config[db_name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def db
|
23
|
+
@db
|
24
|
+
end
|
25
|
+
|
26
|
+
def finished?
|
27
|
+
response_received? && (@pending_queries == 0)
|
28
|
+
end
|
29
|
+
|
30
|
+
def enqueue(handle, req_id)
|
31
|
+
# ... requests aren't deferrables so they're tracked in @pending_queries
|
32
|
+
end
|
33
|
+
|
34
|
+
def find(collection, selector={}, opts={}, &block)
|
35
|
+
@pending_queries += 1
|
36
|
+
db.collection(collection).find(selector, opts) do |result|
|
37
|
+
yield result
|
38
|
+
@pending_queries -= 1
|
39
|
+
self.succeed if finished?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def first(collection, selector={}, opts={}, &block)
|
44
|
+
opts[:limit] = 1
|
45
|
+
find(collection, selector, opts) do |result|
|
46
|
+
yield result.first
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def insert(collection, *args)
|
51
|
+
db.collection(collection).insert(*args)
|
52
|
+
end
|
53
|
+
def update(collection, *args)
|
54
|
+
db.collection(collection).update(*args)
|
55
|
+
end
|
56
|
+
def save(collection, *args)
|
57
|
+
db.collection(collection).save(*args)
|
58
|
+
end
|
59
|
+
def remove(collection, *args)
|
60
|
+
db.collection(collection).remove(*args)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Goliath
|
2
|
+
module Synchrony
|
3
|
+
|
4
|
+
#
|
5
|
+
# FIXME: generalize this to work with any deferrable
|
6
|
+
module ResponseReceiver
|
7
|
+
attr_accessor :env, :status, :headers, :body
|
8
|
+
|
9
|
+
# Override this method in your middleware to perform any preprocessing
|
10
|
+
# (launching a deferred request, perhaps)
|
11
|
+
def pre_process
|
12
|
+
end
|
13
|
+
|
14
|
+
# Override this method in your middleware to perform any postprocessing. This
|
15
|
+
# will only be invoked when the deferrable and the response have been
|
16
|
+
# received.
|
17
|
+
#
|
18
|
+
# @return [Array] array contains [status, headers, body]
|
19
|
+
def post_process
|
20
|
+
[status, headers, body]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Invoked by the async_callback chain. Stores the [status, headers, body]
|
24
|
+
# for post_process'ing
|
25
|
+
def call shb
|
26
|
+
return shb if shb.first == Goliath::Connection::AsyncResponse.first
|
27
|
+
@status, @headers, @body = shb
|
28
|
+
succeed if finished?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Have we received a response?
|
32
|
+
def response_received?
|
33
|
+
!! @status
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class MultiReceiver < EM::Synchrony::Multi
|
38
|
+
include ResponseReceiver
|
39
|
+
|
40
|
+
# Create a new MultiReceiver
|
41
|
+
# @param env [Goliath::Env] the current environment
|
42
|
+
def initialize env
|
43
|
+
@env = env
|
44
|
+
super()
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :enqueue, :add
|
48
|
+
|
49
|
+
def successes
|
50
|
+
responses[:callback]
|
51
|
+
end
|
52
|
+
|
53
|
+
def failures
|
54
|
+
responses[:errback]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Finished if we received a response and the multi request is finished
|
58
|
+
def finished?
|
59
|
+
super && response_received?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|