goliath 0.9.4 → 1.0.0.beta.1
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 +3 -0
- data/Guardfile +8 -0
- data/HISTORY.md +10 -0
- data/LICENSE +1 -1
- data/README.md +28 -29
- data/Rakefile +10 -2
- data/examples/activerecord/config/srv.rb +2 -1
- data/examples/activerecord/srv.rb +14 -5
- data/examples/api_proxy.rb +3 -7
- data/examples/around.rb +38 -0
- data/examples/async_aroundware_demo.rb +2 -2
- data/examples/async_upload.rb +1 -1
- data/examples/auth_and_rate_limit.rb +1 -1
- data/examples/clone.rb +26 -0
- data/examples/config/websocket.rb +1 -0
- data/examples/custom_logs.rb +21 -0
- data/examples/custom_server.rb +6 -44
- data/examples/early_abort.rb +6 -3
- data/examples/echo.rb +1 -1
- data/examples/fiber_pool.rb +35 -0
- data/examples/grape/config/apiserver.rb +8 -0
- data/examples/grape/server.rb +67 -0
- data/examples/gziped.rb +1 -1
- data/examples/params.rb +36 -0
- data/examples/rasterize/rasterize.rb +1 -2
- data/examples/router.rb +15 -0
- data/examples/template.rb +14 -7
- data/examples/test.rb +31 -0
- data/examples/upload.rb +17 -0
- data/examples/views/joke.markdown +4 -4
- data/examples/websocket.rb +39 -0
- data/examples/ws/favicon.ico +0 -0
- data/examples/ws/index.erb +50 -0
- data/goliath.gemspec +24 -6
- data/lib/goliath/api.rb +15 -82
- data/lib/goliath/application.rb +3 -17
- data/lib/goliath/connection.rb +16 -9
- data/lib/goliath/constants.rb +2 -0
- data/lib/goliath/env.rb +2 -3
- data/lib/goliath/goliath.rb +24 -34
- data/lib/goliath/plugins/latency.rb +7 -3
- data/lib/goliath/rack/builder.rb +1 -37
- data/lib/goliath/rack/favicon.rb +31 -0
- data/lib/goliath/rack/formatters/json.rb +1 -1
- data/lib/goliath/rack/heartbeat.rb +1 -0
- data/lib/goliath/rack/jsonp.rb +1 -0
- data/lib/goliath/rack/params.rb +2 -17
- data/lib/goliath/rack/render.rb +0 -1
- data/lib/goliath/rack/templates.rb +18 -7
- data/lib/goliath/rack/types/base.rb +24 -0
- data/lib/goliath/rack/types/boolean.rb +18 -0
- data/lib/goliath/rack/types/core.rb +19 -0
- data/lib/goliath/rack/types/symbol.rb +16 -0
- data/lib/goliath/rack/types.rb +10 -0
- data/lib/goliath/rack/validation/coerce.rb +48 -0
- data/lib/goliath/rack/validation/param.rb +113 -0
- data/lib/goliath/rack/validation/request_method.rb +1 -1
- data/lib/goliath/rack/validation/required.rb +47 -0
- data/lib/goliath/rack/validation/required_param.rb +42 -17
- data/lib/goliath/rack/validation.rb +3 -0
- data/lib/goliath/rack.rb +2 -2
- data/lib/goliath/request.rb +41 -9
- data/lib/goliath/response.rb +0 -2
- data/lib/goliath/runner.rb +55 -4
- data/lib/goliath/server.rb +7 -3
- data/lib/goliath/test_helper.rb +70 -16
- data/lib/goliath/test_helper_ws.rb +42 -0
- data/lib/goliath/version.rb +1 -1
- data/lib/goliath/websocket.rb +80 -0
- data/pkg/goliath-0.9.4.gem +0 -0
- data/pkg/goliath-1.0.0.beta.1.gem +0 -0
- data/spec/integration/async_request_processing.rb +1 -1
- data/spec/integration/early_abort_spec.rb +3 -10
- data/spec/integration/echo_spec.rb +8 -8
- data/spec/integration/jsonp_spec.rb +31 -0
- data/spec/integration/keepalive_spec.rb +2 -2
- data/spec/integration/template_spec.rb +10 -5
- data/spec/integration/test_helper_spec.rb +33 -0
- data/spec/integration/valid_spec.rb +35 -5
- data/spec/integration/websocket_spec.rb +44 -0
- data/spec/unit/api_spec.rb +2 -19
- data/spec/unit/connection_spec.rb +3 -0
- data/spec/unit/rack/formatters/json_spec.rb +3 -3
- data/spec/unit/rack/heartbeat_spec.rb +13 -0
- data/spec/unit/rack/params_spec.rb +2 -8
- data/spec/unit/rack/validation/param_spec.rb +443 -0
- data/spec/unit/rack/validation/request_method_spec.rb +5 -0
- data/spec/unit/rack/validation/required_param_spec.rb +71 -1
- data/spec/unit/runner_spec.rb +21 -7
- data/test/echo_test.rb +25 -0
- data/test/test_helper.rb +5 -0
- metadata +316 -78
- data/examples/env_use_statements.rb +0 -20
- data/examples/favicon.rb +0 -40
- data/examples/rack_routes.rb +0 -125
- data/examples/rasterize/thumb/f7ad4cb03e5bfd0e2c43db8e598fb3cd.png +0 -0
- data/examples/valid.rb +0 -17
- data/lib/goliath/deprecated/async_aroundware.rb +0 -133
- data/lib/goliath/deprecated/mongo_receiver.rb +0 -84
- data/lib/goliath/deprecated/response_receiver.rb +0 -97
- data/spec/integration/rack_routes_spec.rb +0 -169
- data/spec/unit/rack/builder_spec.rb +0 -40
@@ -1,20 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$:<< '../lib' << 'lib'
|
3
|
-
|
4
|
-
require 'goliath'
|
5
|
-
require 'yajl'
|
6
|
-
|
7
|
-
# API must be started with -e [production, development, ...]
|
8
|
-
# or set your ENV['RACK_ENV'] to specify the environemtn
|
9
|
-
|
10
|
-
class EnvUseStatements < Goliath::API
|
11
|
-
if Goliath.dev?
|
12
|
-
use Goliath::Rack::Render, 'json'
|
13
|
-
elsif Goliath.prod?
|
14
|
-
use Goliath::Rack::Render, 'xml'
|
15
|
-
end
|
16
|
-
|
17
|
-
def response(env)
|
18
|
-
[200, {}, {'Test' => 'Response'}]
|
19
|
-
end
|
20
|
-
end
|
data/examples/favicon.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'time'
|
3
|
-
|
4
|
-
#
|
5
|
-
# Reads a favicon.ico statically at load time, renders it on any request for
|
6
|
-
# '/favicon.ico', and sends every other request on downstream.
|
7
|
-
#
|
8
|
-
# If you will be serving even one more file than this one, you should instead
|
9
|
-
# use Rack::Static:
|
10
|
-
#
|
11
|
-
# use(Rack::Static, # render static files from ./public
|
12
|
-
# :root => Goliath::Application.app_path("public"),
|
13
|
-
# :urls => ["/favicon.ico", '/stylesheets', '/javascripts', '/images'])
|
14
|
-
#
|
15
|
-
class Favicon
|
16
|
-
def initialize(app, filename)
|
17
|
-
@@favicon = File.read(filename)
|
18
|
-
@@last_mod = File.mtime(filename).utc.rfc822
|
19
|
-
@@expires = Time.at(Time.now + 604800).utc.rfc822 # 1 week from now
|
20
|
-
@app = app
|
21
|
-
end
|
22
|
-
|
23
|
-
def call(env, *args)
|
24
|
-
if env['REQUEST_PATH'] == '/favicon.ico'
|
25
|
-
return [200, {"Last-Modified"=> @@last_mod.to_s, "Expires" => @@expires, "Content-Type"=>"image/vnd.microsoft.icon"}, @@favicon]
|
26
|
-
else
|
27
|
-
return @app.call(env)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
if File.expand_path($0) == File.expand_path(__FILE__)
|
33
|
-
$:<< '../lib' << 'lib'
|
34
|
-
require 'goliath'
|
35
|
-
puts "starting hello world!"
|
36
|
-
class HelloWorld < Goliath::API
|
37
|
-
HelloWorld.use(Favicon, File.expand_path(File.dirname(__FILE__)+"/public/favicon.ico"))
|
38
|
-
end
|
39
|
-
require(File.dirname(__FILE__)+'/hello_world.rb')
|
40
|
-
end
|
data/examples/rack_routes.rb
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
$:<< '../lib' << 'lib'
|
4
|
-
|
5
|
-
require 'goliath'
|
6
|
-
|
7
|
-
# Example demonstrating how to have an API acting as a router.
|
8
|
-
# RackRoutes defines multiple uris and how to map them accordingly.
|
9
|
-
# Some of these routes are redirected to other Goliath API.
|
10
|
-
#
|
11
|
-
# The reason why only the last API is being used by the Goliath Server
|
12
|
-
# is because its name matches the filename.
|
13
|
-
# All the APIs are available but by default the server will use the one
|
14
|
-
# matching the file name.
|
15
|
-
|
16
|
-
# Our custom Goliath API
|
17
|
-
class HelloWorld < Goliath::API
|
18
|
-
def response(env)
|
19
|
-
[200, {}, "hello world!"]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class PostHelloWorld < Goliath::API
|
24
|
-
def response(env)
|
25
|
-
[200, {}, "hello post world!"]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class HeaderCollector < Goliath::API
|
30
|
-
def on_headers(env, header)
|
31
|
-
@headers ||= {}
|
32
|
-
@headers.merge!(header)
|
33
|
-
end
|
34
|
-
|
35
|
-
def response(env)
|
36
|
-
[200, {}, "headers: #{@headers.inspect}"]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class HelloNumber < Goliath::API
|
41
|
-
use Goliath::Rack::Params
|
42
|
-
def response(env)
|
43
|
-
[200, {}, "number #{params[:number]}!"]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class BigNumber < Goliath::API
|
48
|
-
use Goliath::Rack::Params
|
49
|
-
def response(env)
|
50
|
-
[200, {}, "big number #{params[:number]}!"]
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class Bonjour < Goliath::API
|
55
|
-
def response(env)
|
56
|
-
[200, {}, "bonjour!"]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class Hola < Goliath::API
|
61
|
-
use Goliath::Rack::Params
|
62
|
-
use Goliath::Rack::Validation::RequiredParam, {:key => "foo"}
|
63
|
-
|
64
|
-
def response(env)
|
65
|
-
[200, {}, "hola!"]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class Aloha < Goliath::API
|
70
|
-
use Goliath::Rack::Validation::RequestMethod, %w(GET)
|
71
|
-
|
72
|
-
def response(env)
|
73
|
-
[200, {}, "Aloha"]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class RackRoutes < Goliath::API
|
78
|
-
map '/version' do
|
79
|
-
run Proc.new { |env| [200, {"Content-Type" => "text/html"}, ["Version 0.1"]] }
|
80
|
-
end
|
81
|
-
|
82
|
-
post "/hello_world" do
|
83
|
-
run PostHelloWorld.new
|
84
|
-
end
|
85
|
-
|
86
|
-
get "/hello_world" do
|
87
|
-
run HelloWorld.new
|
88
|
-
end
|
89
|
-
|
90
|
-
head "/hello_world" do
|
91
|
-
run HelloWorld.new
|
92
|
-
end
|
93
|
-
|
94
|
-
map "/headers", HeaderCollector do
|
95
|
-
use Goliath::Rack::Validation::RequestMethod, %w(GET)
|
96
|
-
end
|
97
|
-
|
98
|
-
map "/bonjour" do
|
99
|
-
run Bonjour.new
|
100
|
-
end
|
101
|
-
|
102
|
-
map "/hola" do
|
103
|
-
use Goliath::Rack::Validation::RequestMethod, %w(GET)
|
104
|
-
run Hola.new
|
105
|
-
end
|
106
|
-
|
107
|
-
map "/aloha", Aloha
|
108
|
-
|
109
|
-
map "/:number", :number => /\d+/ do
|
110
|
-
if params[:number].to_i > 100
|
111
|
-
run BigNumber.new
|
112
|
-
else
|
113
|
-
run HelloNumber.new
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
not_found('/') do
|
118
|
-
run Proc.new { |env| [404, {"Content-Type" => "text/html"}, ["Try /version /hello_world, /bonjour, or /hola"]] }
|
119
|
-
end
|
120
|
-
|
121
|
-
# You must use either maps or response, but never both!
|
122
|
-
def response(env)
|
123
|
-
raise RuntimeException.new("#response is ignored when using maps, so this exception won't raise. See spec/integration/rack_routes_spec.")
|
124
|
-
end
|
125
|
-
end
|
Binary file
|
data/examples/valid.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$:<< '../lib' << 'lib'
|
3
|
-
|
4
|
-
require 'goliath'
|
5
|
-
|
6
|
-
class Valid < Goliath::API
|
7
|
-
use Goliath::Rack::Params
|
8
|
-
use Goliath::Rack::Validation::RequiredParam, {:key => 'test'}
|
9
|
-
|
10
|
-
# If you are using Golaith version <=0.9.1 you need to use Goliath::Rack::ValidationError
|
11
|
-
# to prevent the request from remaining open after an error occurs
|
12
|
-
#use Goliath::Rack::ValidationError
|
13
|
-
|
14
|
-
def response(env)
|
15
|
-
[200, {}, 'OK']
|
16
|
-
end
|
17
|
-
end
|
@@ -1,133 +0,0 @@
|
|
1
|
-
module Goliath
|
2
|
-
module Rack
|
3
|
-
#
|
4
|
-
# Note: This class is deprecated. Instead, use BarrierAroundwareFactory
|
5
|
-
# (orchestrates multiple concurrent requests) or SimpleAroundwareFactory
|
6
|
-
# (like AsyncMiddleware, but with a simpler interface).
|
7
|
-
#
|
8
|
-
# The differences:
|
9
|
-
# * ResponseReceiver/MultiReceiver was a stupid name. The thing that has
|
10
|
-
# pre_ and post_process is the Aroundware, the thing that manufactures
|
11
|
-
# it is an AroundwareFactory.
|
12
|
-
# * An aroundware's pre_process may return a direct response, which is
|
13
|
-
# immediately sent back upstream (no further downstream processing
|
14
|
-
# happens). In the typical case, you will want to add
|
15
|
-
# return Goliath::Connection::AsyncResponse
|
16
|
-
# to your pre_process method.
|
17
|
-
# * ResponseReceiver used to masquerade as callback and middleware. Yuck.
|
18
|
-
# The downstream response is now set via #accept_response, not #call.
|
19
|
-
#
|
20
|
-
# * change
|
21
|
-
# use Goliath::Rack::AsyncAroundware, MyObsoleteReceiver
|
22
|
-
# to
|
23
|
-
# use Goliath::Rack::BarrierAroundwareFactory, MyHappyBarrier
|
24
|
-
# * `BarrierAroundware` provides the combined functionality of
|
25
|
-
# `MultiReceiver` and `ResponseReceiver`, which will go away. It's now a
|
26
|
-
# mixin (module) so you're not forced to inherit from it.
|
27
|
-
# * There is no more `responses` method: either use instance accessors or
|
28
|
-
# look in the `successes`/`failures` hashes for yourresults.
|
29
|
-
# * Both enqueued responses and the downstream response are sent to
|
30
|
-
# `accept_response`; there is no more `call` method.
|
31
|
-
# * `MongoReceiver` will go away, because there's no need for it. See
|
32
|
-
# `examples/auth_and_rate_limit.rb` for examples
|
33
|
-
#
|
34
|
-
class AsyncAroundware
|
35
|
-
include Goliath::Rack::Validator
|
36
|
-
|
37
|
-
#
|
38
|
-
# Called by the framework to create the middleware.
|
39
|
-
#
|
40
|
-
# Any extra args passed to the use statement are sent to each
|
41
|
-
# aroundware_klass as it is created.
|
42
|
-
#
|
43
|
-
# @example
|
44
|
-
# class Awesomizer2011 < Goliath::Rack::MultiReceiver
|
45
|
-
# def initialize(env, aq)
|
46
|
-
# @awesomeness_quotient = aq
|
47
|
-
# super(env)
|
48
|
-
# end
|
49
|
-
# # ... define pre_process and post_process ...
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# class AwesomeApiWithShortening < Goliath::API
|
53
|
-
# use Goliath::Rack::AsyncAroundware, Awesomizer2011, 3
|
54
|
-
# # ... stuff ...
|
55
|
-
# end
|
56
|
-
#
|
57
|
-
# @param app [#call] the downstream app
|
58
|
-
# @param aroundware_klass a class that quacks like a
|
59
|
-
# Goliath::Rack::ResponseReceiver and an EM::Deferrable
|
60
|
-
# @param *args [Array] extra args to pass to the aroundware
|
61
|
-
# @return [Goliath::Rack::AsyncAroundware]
|
62
|
-
def initialize app, aroundware_klass, *args
|
63
|
-
@app = app
|
64
|
-
@aroundware_klass = aroundware_klass
|
65
|
-
@aroundware_args = args
|
66
|
-
end
|
67
|
-
|
68
|
-
# Coordinates aroundware to process a request.
|
69
|
-
#
|
70
|
-
# We hook the aroundware in the middle of the async_callback chain:
|
71
|
-
# * send the downstream response to the aroundware, whether received directly
|
72
|
-
# from @app.call or via async callback
|
73
|
-
# * have the upstream callback chain be invoked when the aroundware completes
|
74
|
-
#
|
75
|
-
# @param env [Goliath::Env] The goliath environment
|
76
|
-
# @return [Array] The [status_code, headers, body] tuple
|
77
|
-
def call(env)
|
78
|
-
aroundware = new_aroundware(env)
|
79
|
-
|
80
|
-
aroundware_resp = aroundware.pre_process
|
81
|
-
|
82
|
-
hook_into_callback_chain(env, aroundware)
|
83
|
-
|
84
|
-
downstream_resp = @app.call(env)
|
85
|
-
|
86
|
-
# if downstream resp is final, pass it to the aroundware; it will invoke
|
87
|
-
# the callback chain at its leisure. Our response is *always* async.
|
88
|
-
if final_response?(downstream_resp)
|
89
|
-
aroundware.call(downstream_resp)
|
90
|
-
end
|
91
|
-
return Goliath::Connection::AsyncResponse
|
92
|
-
end
|
93
|
-
|
94
|
-
# Put aroundware in the middle of the async_callback chain:
|
95
|
-
# * save the old callback chain;
|
96
|
-
# * have the downstream callback send results to the aroundware (possibly
|
97
|
-
# completing it)
|
98
|
-
# * set the old callback chain to fire when the aroundware completes
|
99
|
-
def hook_into_callback_chain(env, aroundware)
|
100
|
-
async_callback = env['async.callback']
|
101
|
-
|
102
|
-
# The response from the downstream app is accepted by the aroundware...
|
103
|
-
downstream_callback = Proc.new do |resp|
|
104
|
-
safely(env){ aroundware.call(resp) }
|
105
|
-
end
|
106
|
-
|
107
|
-
# .. but the upstream chain is only invoked when the aroundware completes
|
108
|
-
invoke_upstream_chain = Proc.new do
|
109
|
-
new_resp = safely(env){ aroundware.post_process }
|
110
|
-
async_callback.call(new_resp)
|
111
|
-
end
|
112
|
-
|
113
|
-
env['async.callback'] = downstream_callback
|
114
|
-
aroundware.callback(&invoke_upstream_chain)
|
115
|
-
aroundware.errback(&invoke_upstream_chain)
|
116
|
-
end
|
117
|
-
|
118
|
-
def final_response?(resp)
|
119
|
-
resp != Goliath::Connection::AsyncResponse
|
120
|
-
end
|
121
|
-
|
122
|
-
# Generate a aroundware to process the request, using request env & any args
|
123
|
-
# passed to this AsyncAroundware at creation
|
124
|
-
#
|
125
|
-
# @param env [Goliath::Env] The goliath environment
|
126
|
-
# @return [Goliath::Rack::ResponseReceiver] The response_receiver to process this request
|
127
|
-
def new_aroundware(env)
|
128
|
-
@aroundware_klass.new(env, *@aroundware_args)
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'goliath/deprecated/response_receiver'
|
2
|
-
require 'em-synchrony/em-mongo'
|
3
|
-
|
4
|
-
module Goliath
|
5
|
-
module Synchrony
|
6
|
-
#
|
7
|
-
# Note: This class is deprecated. Please instead use BarrierAroundware
|
8
|
-
# (orchestrates multiple concurrent requests) or SimpleAroundware (like
|
9
|
-
# AsyncMiddleware, but with a simpler interface).
|
10
|
-
#
|
11
|
-
# There are more notes on the lib/goliath/deprecated/async_aroundware docs.
|
12
|
-
#
|
13
|
-
# ___________________________________________________________________________
|
14
|
-
#
|
15
|
-
# Currently, you must provide in the env a method 'mongo' that returns a mongo
|
16
|
-
# collection or collection proxy (probably by setting it up in the config).
|
17
|
-
#
|
18
|
-
# This will almost certainly change to something less crappy.
|
19
|
-
#
|
20
|
-
class MongoReceiver
|
21
|
-
include Goliath::Synchrony::ResponseReceiver
|
22
|
-
include EM::Deferrable
|
23
|
-
include Goliath::Rack::Validator
|
24
|
-
|
25
|
-
def initialize(env, db_name)
|
26
|
-
@env = env
|
27
|
-
@pending_queries = 0
|
28
|
-
@db = env.config[db_name]
|
29
|
-
end
|
30
|
-
|
31
|
-
def db
|
32
|
-
@db
|
33
|
-
end
|
34
|
-
|
35
|
-
def finished?
|
36
|
-
response_received? && (@pending_queries == 0)
|
37
|
-
end
|
38
|
-
|
39
|
-
def enqueue(handle, req_id)
|
40
|
-
# ... requests aren't deferrables so they're tracked in @pending_queries
|
41
|
-
end
|
42
|
-
|
43
|
-
if defined?(EM::Mongo::Cursor)
|
44
|
-
def find(collection, selector={}, opts={}, &block)
|
45
|
-
@pending_queries += 1
|
46
|
-
db.collection(collection).afind(selector, opts).to_a.callback do |result|
|
47
|
-
yield result
|
48
|
-
@pending_queries -= 1
|
49
|
-
self.succeed if finished?
|
50
|
-
end
|
51
|
-
end
|
52
|
-
else
|
53
|
-
def find(collection, selector={}, opts={}, &block)
|
54
|
-
@pending_queries += 1
|
55
|
-
db.collection(collection).afind(selector, opts) do |result|
|
56
|
-
yield result
|
57
|
-
@pending_queries -= 1
|
58
|
-
self.succeed if finished?
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def first(collection, selector={}, opts={}, &block)
|
64
|
-
opts[:limit] = 1
|
65
|
-
self.find(collection, selector, opts) do |result|
|
66
|
-
yield result.first
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def insert(collection, *args)
|
71
|
-
db.collection(collection).insert(*args)
|
72
|
-
end
|
73
|
-
def update(collection, *args)
|
74
|
-
db.collection(collection).update(*args)
|
75
|
-
end
|
76
|
-
def save(collection, *args)
|
77
|
-
db.collection(collection).save(*args)
|
78
|
-
end
|
79
|
-
def remove(collection, *args)
|
80
|
-
db.collection(collection).remove(*args)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
module Goliath
|
2
|
-
module Synchrony
|
3
|
-
|
4
|
-
#
|
5
|
-
# Note: This class is deprecated. Please instead use BarrierAroundware
|
6
|
-
# (orchestrates multiple concurrent requests) or SimpleAroundware (like
|
7
|
-
# AsyncMiddleware, but with a simpler interface).
|
8
|
-
#
|
9
|
-
# There are more notes on the lib/goliath/deprecated/async_aroundware docs.
|
10
|
-
#
|
11
|
-
module ResponseReceiver
|
12
|
-
# The request environment, set in the initializer
|
13
|
-
attr_reader :env
|
14
|
-
# The response, set by the ResponseReceiver's downstream
|
15
|
-
attr_accessor :status, :headers, :body
|
16
|
-
|
17
|
-
# Override this method in your middleware to perform any preprocessing
|
18
|
-
# (launching a deferred request, perhaps).
|
19
|
-
#
|
20
|
-
# @return [Array] array contains [status, headers, body]
|
21
|
-
def pre_process
|
22
|
-
Goliath::Connection::AsyncResponse
|
23
|
-
end
|
24
|
-
|
25
|
-
# Override this method in your middleware to perform any postprocessing.
|
26
|
-
# This will only be invoked when all deferred requests (including the
|
27
|
-
# response) have completed.
|
28
|
-
#
|
29
|
-
# @return [Array] array contains [status, headers, body]
|
30
|
-
def post_process
|
31
|
-
[status, headers, body]
|
32
|
-
end
|
33
|
-
|
34
|
-
# Virtual setter for the downstream middleware/endpoint response
|
35
|
-
def downstream_resp=(status_headers_body)
|
36
|
-
@status, @headers, @body = status_headers_body
|
37
|
-
end
|
38
|
-
|
39
|
-
# Invoked by the async_callback chain. Stores the [status, headers, body]
|
40
|
-
# for post_process'ing
|
41
|
-
def call resp
|
42
|
-
return resp if resp.first == Goliath::Connection::AsyncResponse.first
|
43
|
-
self.downstream_resp = resp
|
44
|
-
check_progress(nil)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Have we received a response?
|
48
|
-
def response_received?
|
49
|
-
!! @status
|
50
|
-
end
|
51
|
-
|
52
|
-
protected
|
53
|
-
|
54
|
-
def check_progress(fiber)
|
55
|
-
if finished?
|
56
|
-
succeed
|
57
|
-
# continue processing
|
58
|
-
fiber.resume(self) if fiber && fiber.alive? && fiber != Fiber.current
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
#
|
64
|
-
# Note: This class is deprecated. Please instead use BarrierAroundware
|
65
|
-
# (orchestrates multiple concurrent requests) or SimpleAroundware (like
|
66
|
-
# AsyncMiddleware, but with a simpler interface).
|
67
|
-
#
|
68
|
-
# There are more notes on the lib/goliath/deprecated/async_aroundware docs.
|
69
|
-
#
|
70
|
-
class MultiReceiver < EM::Synchrony::Multi
|
71
|
-
include ResponseReceiver
|
72
|
-
|
73
|
-
# Create a new MultiReceiver
|
74
|
-
# @param env [Goliath::Env] the current environment
|
75
|
-
def initialize env
|
76
|
-
@env = env
|
77
|
-
super()
|
78
|
-
end
|
79
|
-
|
80
|
-
alias_method :enqueue, :add
|
81
|
-
|
82
|
-
def successes
|
83
|
-
responses[:callback]
|
84
|
-
end
|
85
|
-
|
86
|
-
def failures
|
87
|
-
responses[:errback]
|
88
|
-
end
|
89
|
-
|
90
|
-
# Finished if we received a response and the multi request is finished
|
91
|
-
def finished?
|
92
|
-
super && response_received?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
@@ -1,169 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'spec_helper'
|
3
|
-
require File.join(File.dirname(__FILE__), '../../', 'examples/rack_routes')
|
4
|
-
|
5
|
-
describe RackRoutes do
|
6
|
-
let(:err) { Proc.new { fail "API request failed" } }
|
7
|
-
|
8
|
-
context "when using maps" do
|
9
|
-
|
10
|
-
it "ignores #response" do
|
11
|
-
expect {
|
12
|
-
with_api(RackRoutes) do
|
13
|
-
get_request({:path => '/'}, err) {}
|
14
|
-
end
|
15
|
-
}.to_not raise_error
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'fallback not found to missing' do
|
19
|
-
with_api(RackRoutes) do
|
20
|
-
get_request({:path => '/donkey'}, err) do |cb|
|
21
|
-
cb.response_header.status.should == 404
|
22
|
-
cb.response.should == 'Try /version /hello_world, /bonjour, or /hola'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
with_api(RackRoutes) do
|
26
|
-
get_request({:path => '/'}, err) do |cb|
|
27
|
-
cb.response_header.status.should == 404
|
28
|
-
cb.response.should == 'Try /version /hello_world, /bonjour, or /hola'
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'fallback not found to /' do
|
34
|
-
with_api(RackRoutes) do
|
35
|
-
get_request({:path => '/donkey'}, err) do |cb|
|
36
|
-
cb.response_header.status.should == 404
|
37
|
-
cb.response.should == 'Try /version /hello_world, /bonjour, or /hola'
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'routes to the correct API' do
|
43
|
-
with_api(RackRoutes) do
|
44
|
-
get_request({:path => '/bonjour'}, err) do |c|
|
45
|
-
c.response_header.status.should == 200
|
46
|
-
c.response.should == 'bonjour!'
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'routes to the correct API using regex filters' do
|
52
|
-
with_api(RackRoutes) do
|
53
|
-
get_request({:path => '/98'}, err) do |c|
|
54
|
-
c.response_header.status.should == 200
|
55
|
-
c.response.should == 'number 98!'
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'routes to the correct API referencing params in the body of the buidler' do
|
61
|
-
with_api(RackRoutes) do
|
62
|
-
get_request({:path => '/123123'}, err) do |c|
|
63
|
-
c.response_header.status.should == 200
|
64
|
-
c.response.should == 'big number 123123!'
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context 'sinatra style route definition' do
|
70
|
-
it 'should honor the request method' do
|
71
|
-
with_api(RackRoutes) do
|
72
|
-
post_request({:path => '/hello_world'}, err) do |c|
|
73
|
-
c.response_header.status.should == 200
|
74
|
-
c.response.should == 'hello post world!'
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'should reject other request methods' do
|
80
|
-
with_api(RackRoutes) do
|
81
|
-
put_request({:path => '/hello_world'}, err) do |c|
|
82
|
-
c.response_header.status.should == 405
|
83
|
-
c.response_header['ALLOW'].split(/, /).should == %w(GET HEAD POST)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context 'routes defined with get' do
|
90
|
-
it 'should allow get' do
|
91
|
-
with_api(RackRoutes) do
|
92
|
-
get_request({:path => '/hello_world'}, err) do |c|
|
93
|
-
c.response_header.status.should == 200
|
94
|
-
c.response.should == 'hello world!'
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
context 'routes defined with head' do
|
101
|
-
it 'should allow head' do
|
102
|
-
with_api(RackRoutes) do
|
103
|
-
head_request({:path => '/hello_world'}, err) do |c|
|
104
|
-
c.response_header.status.should == 200
|
105
|
-
c.response.should == 'hello world!'
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
context "defined in blocks" do
|
112
|
-
it 'uses middleware defined in the block' do
|
113
|
-
with_api(RackRoutes) do
|
114
|
-
post_request({:path => '/hola'}, err) do |c|
|
115
|
-
# the /hola route only supports GET requests
|
116
|
-
c.response_header.status.should == 405
|
117
|
-
c.response.should == '[:error, "Invalid request method"]'
|
118
|
-
c.response_header['ALLOW'].should == 'GET'
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
it "doesn't use middleware defined in the API" do
|
124
|
-
with_api(RackRoutes) do
|
125
|
-
get_request({:path => '/hola'}, err) do |cb|
|
126
|
-
# it doesn't raise required param error
|
127
|
-
cb.response_header.status.should == 200
|
128
|
-
cb.response.should == "hola!"
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
context "defined in classes" do
|
135
|
-
it 'uses API middleware' do
|
136
|
-
with_api(RackRoutes) do
|
137
|
-
post_request({:path => '/aloha'}, err) do |c|
|
138
|
-
# the /hola route only supports GET requests
|
139
|
-
c.response_header.status.should == 405
|
140
|
-
c.response.should == '[:error, "Invalid request method"]'
|
141
|
-
c.response_header['ALLOW'].should == 'GET'
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
context "with event handlers" do
|
148
|
-
it "collects header events" do
|
149
|
-
with_api(RackRoutes) do
|
150
|
-
get_request({:path => '/headers'}, err) do |c|
|
151
|
-
c.response_header.status.should == 200
|
152
|
-
c.response.should == 'headers: {"Connection"=>"close", "Host"=>"localhost:9900", "User-Agent"=>"EventMachine HttpClient"}'
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
it "rejects POST request" do
|
158
|
-
with_api(RackRoutes) do
|
159
|
-
post_request({:path => '/headers'}, err) do |c|
|
160
|
-
# the /headers route only supports GET requests
|
161
|
-
c.response_header.status.should == 405
|
162
|
-
c.response.should == '[:error, "Invalid request method"]'
|
163
|
-
c.response_header['ALLOW'].should == 'GET'
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|