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
@@ -2,7 +2,6 @@
|
|
2
2
|
$: << File.dirname(__FILE__)+'/../../lib'
|
3
3
|
require 'goliath'
|
4
4
|
require 'postrank-uri'
|
5
|
-
require File.dirname(__FILE__)+'/../favicon'
|
6
5
|
|
7
6
|
# Install phantomjs: http://code.google.com/p/phantomjs/wiki/QuickStart
|
8
7
|
# $> ruby rasterize.rb -sv
|
@@ -10,7 +9,7 @@ require File.dirname(__FILE__)+'/../favicon'
|
|
10
9
|
|
11
10
|
class Rasterize < Goliath::API
|
12
11
|
use Goliath::Rack::Params
|
13
|
-
use Favicon, File.expand_path(File.dirname(__FILE__)+"/../public/favicon.ico")
|
12
|
+
use Goliath::Rack::Favicon, File.expand_path(File.dirname(__FILE__)+"/../public/favicon.ico")
|
14
13
|
use Goliath::Rack::Validation::RequestMethod, %w(GET)
|
15
14
|
use Goliath::Rack::Validation::RequiredParam, {:key => 'url'}
|
16
15
|
|
data/examples/router.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:<< '../lib' << 'lib'
|
3
|
+
|
4
|
+
require 'goliath'
|
5
|
+
require 'test'
|
6
|
+
|
7
|
+
|
8
|
+
class Router < Goliath::API
|
9
|
+
get '/v1/app/:appid/binary/:key', RawFileApp
|
10
|
+
put '/v1/app/:appid/binary/:key', RawFileApp
|
11
|
+
|
12
|
+
not_found do
|
13
|
+
run Proc.new { |env| [404, {"Content-Type" => "text/html"}, "not found"] }
|
14
|
+
end
|
15
|
+
end
|
data/examples/template.rb
CHANGED
@@ -11,10 +11,15 @@ $:<< '../lib' << 'lib'
|
|
11
11
|
# your template's extension must match the engine (foo.markdown, not foo.md)
|
12
12
|
|
13
13
|
require 'tilt'
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
require '
|
14
|
+
|
15
|
+
if RUBY_PLATFORM != 'java'
|
16
|
+
require 'yajl/json_gem'
|
17
|
+
require 'bluecloth' # use bluecloth as default markdown renderer
|
18
|
+
Tilt.register 'markdown', Tilt::BlueClothTemplate
|
19
|
+
else
|
20
|
+
require 'maruku'
|
21
|
+
Tilt.register 'markdown', Tilt::MarukuTemplate
|
22
|
+
end
|
18
23
|
|
19
24
|
require 'goliath'
|
20
25
|
require 'goliath/rack/templates'
|
@@ -24,8 +29,8 @@ class Template < Goliath::API
|
|
24
29
|
include Goliath::Rack::Templates # render templated files from ./views
|
25
30
|
|
26
31
|
use(Rack::Static, # render static files from ./public
|
27
|
-
|
28
|
-
|
32
|
+
:root => Goliath::Application.app_path("public"),
|
33
|
+
:urls => ["/favicon.ico", '/stylesheets', '/javascripts', '/images'])
|
29
34
|
|
30
35
|
plugin Goliath::Plugin::Latency # ask eventmachine reactor to track its latency
|
31
36
|
|
@@ -35,7 +40,9 @@ class Template < Goliath::API
|
|
35
40
|
|
36
41
|
def response(env)
|
37
42
|
case env['PATH_INFO']
|
38
|
-
|
43
|
+
# TODO(dj2): change /root -> / when rack > 1.4.0 is released
|
44
|
+
when '/root' then [200, {}, haml(:root)]
|
45
|
+
when '/haml_str' then [200, {}, haml("%h1 Header")]
|
39
46
|
when '/debug' then [200, {}, haml(:debug)]
|
40
47
|
when '/oops' then [200, {}, haml(:no_such_template)] # will 500
|
41
48
|
when '/joke' then
|
data/examples/test.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:<< '../lib' << 'lib'
|
3
|
+
|
4
|
+
require 'goliath'
|
5
|
+
|
6
|
+
class RawFileApp < Goliath::API
|
7
|
+
use Goliath::Rack::Params # parse & merge query and body parameters
|
8
|
+
use Goliath::Rack::DefaultMimeType # cleanup accepted media types
|
9
|
+
use Goliath::Rack::Formatters::JSON # JSON output formatter
|
10
|
+
use Goliath::Rack::Render # auto-negotiate response format
|
11
|
+
|
12
|
+
def response(env)
|
13
|
+
p params
|
14
|
+
p params['key2']
|
15
|
+
p params[:key2]
|
16
|
+
obj = {
|
17
|
+
somekey: 'val',
|
18
|
+
otherkey: 42
|
19
|
+
}
|
20
|
+
[200, { 'Content-Type' => 'application/json' }, obj]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Router < Goliath::API
|
25
|
+
get '/v1/app/:appid/binary/:key', RawFileApp
|
26
|
+
put '/v1/app/:appid/binary/:key', RawFileApp
|
27
|
+
|
28
|
+
not_found do
|
29
|
+
run Proc.new { |env| [404, {"Content-Type" => "text/html"}, "not found"] }
|
30
|
+
end
|
31
|
+
end
|
data/examples/upload.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:<< '../lib' << 'lib'
|
3
|
+
|
4
|
+
require 'goliath'
|
5
|
+
|
6
|
+
class Upload < Goliath::API
|
7
|
+
|
8
|
+
def on_headers(env, h)
|
9
|
+
if h['Expect'] == '100-continue'
|
10
|
+
env.stream_send "HTTP/1.1 100 Continue\r\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def response(env)
|
15
|
+
[200, {}, "oh hai"]
|
16
|
+
end
|
17
|
+
end
|
@@ -3,11 +3,11 @@
|
|
3
3
|
Pirate walks into a bar with a steering wheel half-in, half-out of his pants.
|
4
4
|
|
5
5
|
|
6
|
-
Bartender says
|
6
|
+
Bartender says
|
7
7
|
|
8
|
-
|
8
|
+
Hey Pirate, What's With The Steering Wheel?
|
9
9
|
|
10
10
|
|
11
|
-
Pirate says
|
11
|
+
Pirate says
|
12
12
|
|
13
|
-
|
13
|
+
Arr, I dunno matey -- but it is driving me nuts!
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:<< '../lib' << 'lib'
|
3
|
+
|
4
|
+
require 'goliath'
|
5
|
+
require 'goliath/websocket'
|
6
|
+
require 'goliath/rack/templates'
|
7
|
+
|
8
|
+
class Websocket < Goliath::WebSocket
|
9
|
+
include Goliath::Rack::Templates
|
10
|
+
|
11
|
+
use Goliath::Rack::Favicon, File.expand_path(File.dirname(__FILE__) + '/ws/favicon.ico')
|
12
|
+
|
13
|
+
def on_open(env)
|
14
|
+
env.logger.info("WS OPEN")
|
15
|
+
env['subscription'] = env.channel.subscribe { |m| env.stream_send(m) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_message(env, msg)
|
19
|
+
env.logger.info("WS MESSAGE: #{msg}")
|
20
|
+
env.channel << msg
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_close(env)
|
24
|
+
env.logger.info("WS CLOSED")
|
25
|
+
env.channel.unsubscribe(env['subscription'])
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_error(env, error)
|
29
|
+
env.logger.error error
|
30
|
+
end
|
31
|
+
|
32
|
+
def response(env)
|
33
|
+
if env['REQUEST_PATH'] == '/ws'
|
34
|
+
super(env)
|
35
|
+
else
|
36
|
+
[200, {}, erb(:index, :views => Goliath::Application.root_path('ws'))]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
Binary file
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>WebSocket ...</title>
|
5
|
+
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'></script>
|
6
|
+
<script>
|
7
|
+
function debug(str)
|
8
|
+
{
|
9
|
+
$("#debug").append("<p>" + str + "</p>");
|
10
|
+
};
|
11
|
+
|
12
|
+
$(document).ready(function()
|
13
|
+
{
|
14
|
+
if (!("WebSocket" in window))
|
15
|
+
{
|
16
|
+
alert("Sorry, WebSockets unavailable.");
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
var ws = new WebSocket("ws://localhost:9000/ws");
|
21
|
+
ws.onmessage = function(evt) { $("#msg").append("<p>" + evt.data + "</p>"); };
|
22
|
+
ws.onclose = function() { debug("socket closed"); };
|
23
|
+
ws.onopen = function() { debug("connected..."); };
|
24
|
+
|
25
|
+
$('#submit').click(function()
|
26
|
+
{
|
27
|
+
var nick = $('#nick').val();
|
28
|
+
var msg = $('#message').val();
|
29
|
+
|
30
|
+
ws.send(nick + ": " + msg);
|
31
|
+
return false;
|
32
|
+
});
|
33
|
+
|
34
|
+
});
|
35
|
+
</script>
|
36
|
+
</head>
|
37
|
+
<body>
|
38
|
+
<form>
|
39
|
+
<label>Nick</label>
|
40
|
+
<input type='text' autofocus='true' id='nick' name='nick' value='anon' size='20' /><br />
|
41
|
+
|
42
|
+
<label>Message</label>
|
43
|
+
<input type='text' autofocus='true' id='message' name='message' value='' size='80' />
|
44
|
+
<input type='submit' id='submit' />
|
45
|
+
</form>
|
46
|
+
|
47
|
+
<div id="debug"></div>
|
48
|
+
<div id="msg"></div>
|
49
|
+
</body>
|
50
|
+
</html>
|
data/goliath.gemspec
CHANGED
@@ -12,9 +12,12 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = 'Async framework for writing API servers'
|
13
13
|
s.description = s.summary
|
14
14
|
|
15
|
-
s.
|
15
|
+
s.required_ruby_version = '>=1.9.2'
|
16
|
+
|
17
|
+
s.add_dependency 'eventmachine', '>= 1.0.0.beta.4'
|
16
18
|
s.add_dependency 'em-synchrony', '>= 1.0.0'
|
17
|
-
s.add_dependency '
|
19
|
+
s.add_dependency 'em-websocket'
|
20
|
+
s.add_dependency 'http_parser.rb', '0.5.3'
|
18
21
|
s.add_dependency 'log4r'
|
19
22
|
|
20
23
|
s.add_dependency 'rack', '>=1.2.2'
|
@@ -22,24 +25,39 @@ Gem::Specification.new do |s|
|
|
22
25
|
s.add_dependency 'rack-respond_to'
|
23
26
|
s.add_dependency 'async-rack'
|
24
27
|
s.add_dependency 'multi_json'
|
25
|
-
s.add_dependency 'http_router', '~> 0.9.0'
|
26
28
|
|
27
29
|
s.add_development_dependency 'rake', '>=0.8.7'
|
28
30
|
s.add_development_dependency 'rspec', '>2.0'
|
29
31
|
s.add_development_dependency 'nokogiri'
|
30
32
|
s.add_development_dependency 'em-http-request', '>=1.0.0'
|
31
33
|
s.add_development_dependency 'em-mongo', '~> 0.4.0'
|
32
|
-
s.add_development_dependency 'yajl-ruby'
|
33
34
|
s.add_development_dependency 'rack-rewrite'
|
34
35
|
s.add_development_dependency 'multipart_body'
|
35
36
|
s.add_development_dependency 'amqp', '>=0.7.1'
|
37
|
+
s.add_development_dependency 'em-websocket-client'
|
36
38
|
|
37
39
|
s.add_development_dependency 'tilt', '>=1.2.2'
|
38
40
|
s.add_development_dependency 'haml', '>=3.0.25'
|
39
41
|
s.add_development_dependency 'yard'
|
40
|
-
s.add_development_dependency 'bluecloth'
|
41
42
|
|
42
|
-
|
43
|
+
s.add_development_dependency 'guard'
|
44
|
+
s.add_development_dependency 'guard-rspec'
|
45
|
+
|
46
|
+
if RUBY_PLATFORM != 'java'
|
47
|
+
s.add_development_dependency 'yajl-ruby'
|
48
|
+
s.add_development_dependency 'bluecloth'
|
49
|
+
s.add_development_dependency 'bson_ext'
|
50
|
+
else
|
51
|
+
s.add_development_dependency 'json-jruby'
|
52
|
+
s.add_development_dependency 'maruku'
|
53
|
+
end
|
54
|
+
|
55
|
+
if RUBY_PLATFORM.include?('darwin')
|
56
|
+
s.add_development_dependency 'growl', '~> 1.0.3'
|
57
|
+
s.add_development_dependency 'rb-fsevent'
|
58
|
+
end
|
59
|
+
|
60
|
+
ignores = File.readlines(".gitignore").grep(/\S+/).map {|i| i.chomp }
|
43
61
|
dotfiles = [".gemtest", ".gitignore", ".rspec", ".yardopts"]
|
44
62
|
|
45
63
|
s.files = Dir["**/*"].reject {|f| File.directory?(f) || ignores.any? {|i| File.fnmatch(i, f) } } + dotfiles
|
data/lib/goliath/api.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'http_router'
|
2
1
|
require 'goliath/goliath'
|
3
2
|
require 'goliath/response'
|
4
3
|
require 'goliath/request'
|
@@ -38,9 +37,9 @@ module Goliath
|
|
38
37
|
|
39
38
|
unless @loaded_default_middlewares
|
40
39
|
@middlewares.unshift([::Goliath::Rack::DefaultResponseFormat, nil, nil])
|
41
|
-
@middlewares.unshift([::
|
40
|
+
@middlewares.unshift([::AsyncRack::ContentLength, nil, nil])
|
42
41
|
|
43
|
-
if Goliath.
|
42
|
+
if Goliath.env?(:development) && !@middlewares.detect {|mw| mw.first == ::Rack::Reloader}
|
44
43
|
@middlewares.unshift([::Rack::Reloader, 0, nil])
|
45
44
|
end
|
46
45
|
|
@@ -73,6 +72,7 @@ module Goliath
|
|
73
72
|
end
|
74
73
|
|
75
74
|
@middlewares << [name, args, block]
|
75
|
+
@middlewares = @middlewares.uniq
|
76
76
|
end
|
77
77
|
|
78
78
|
# Returns the plugins configured for this API
|
@@ -92,70 +92,16 @@ module Goliath
|
|
92
92
|
def plugin(name, *args)
|
93
93
|
plugins.push([name, args])
|
94
94
|
end
|
95
|
+
end
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
!maps.empty?
|
105
|
-
end
|
106
|
-
|
107
|
-
# Specify a router map to be used by the API
|
108
|
-
#
|
109
|
-
# @example
|
110
|
-
# map '/version' do
|
111
|
-
# run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Version 0.1"]] }
|
112
|
-
# end
|
113
|
-
#
|
114
|
-
# @example
|
115
|
-
# map '/user/:id', :id => /\d+/ do
|
116
|
-
# # params[:id] will be a number
|
117
|
-
# run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Loading user #{params[:id]}"]] }
|
118
|
-
# end
|
119
|
-
#
|
120
|
-
# @param name [String] The URL path to map.
|
121
|
-
# Optional parts are supported via <tt>(.:format)</tt>, variables as <tt>:var</tt> and globs via <tt>*remaining_path</tt>.
|
122
|
-
# Variables can be validated by supplying a Regexp.
|
123
|
-
# @param klass [Class] The class to retrieve the middlewares from
|
124
|
-
# @param block The code to execute
|
125
|
-
def map(name, *args, &block)
|
126
|
-
opts = args.last.is_a?(Hash) ? args.pop : {}
|
127
|
-
klass = args.first
|
128
|
-
maps.push([name, klass, opts, block])
|
129
|
-
end
|
130
|
-
|
131
|
-
[:get, :post, :head, :put, :delete].each do |http_method|
|
132
|
-
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
133
|
-
def #{http_method}(name, *args, &block)
|
134
|
-
opts = args.last.is_a?(Hash) ? args.pop : {}
|
135
|
-
klass = args.first
|
136
|
-
opts[:conditions] ||= {}
|
137
|
-
opts[:conditions][:request_method] = [#{http_method.to_s.upcase.inspect}]
|
138
|
-
map(name, klass, opts, &block)
|
139
|
-
end
|
140
|
-
EOT
|
141
|
-
end
|
142
|
-
|
143
|
-
def router
|
144
|
-
unless @router
|
145
|
-
@router = HttpRouter.new
|
146
|
-
@router.default(proc{ |env|
|
147
|
-
@router.routes.last.dest.call(env)
|
148
|
-
})
|
149
|
-
end
|
150
|
-
@router
|
151
|
-
end
|
152
|
-
|
153
|
-
# Use to define the 404 routing logic. As well, define any number of other paths to also run the not_found block.
|
154
|
-
def not_found(*other_paths, &block)
|
155
|
-
app = ::Rack::Builder.new(&block).to_app
|
156
|
-
router.default(app)
|
157
|
-
other_paths.each {|path| router.add(path).to(app) }
|
158
|
-
end
|
97
|
+
##
|
98
|
+
# The default constructor does nothing with the options
|
99
|
+
# passed, redefine your own to use them.
|
100
|
+
#
|
101
|
+
# @param [Hash] opts options passed to a map call if any
|
102
|
+
#
|
103
|
+
def initialize(opts = {})
|
104
|
+
@opts = opts
|
159
105
|
end
|
160
106
|
|
161
107
|
# Default stub method to add options into the option parser.
|
@@ -232,7 +178,9 @@ module Goliath
|
|
232
178
|
env.logger.error(e.message)
|
233
179
|
env.logger.error(e.backtrace.join("\n"))
|
234
180
|
env[RACK_EXCEPTION] = e
|
235
|
-
|
181
|
+
|
182
|
+
message = Goliath.env?(:production) ? 'An error happened' : e.message
|
183
|
+
env[ASYNC_CALLBACK].call(validation_error(500, message))
|
236
184
|
end
|
237
185
|
|
238
186
|
Goliath::Connection::AsyncResponse
|
@@ -278,20 +226,5 @@ module Goliath
|
|
278
226
|
def chunked_streaming_response(status_code = 200, headers = {})
|
279
227
|
streaming_response(status_code, headers.merge(Goliath::Response::CHUNKED_STREAM_HEADERS))
|
280
228
|
end
|
281
|
-
|
282
|
-
# Helper method to initialize the approriate API handler
|
283
|
-
#
|
284
|
-
# Called by the parser once headers are available to detect
|
285
|
-
# which API class should be handling the incoming request
|
286
|
-
def set_event_handler!(env)
|
287
|
-
if self.class.maps?
|
288
|
-
response = self.class.router.recognize(env)
|
289
|
-
if response = self.class.router.recognize(env) and response.respond_to?(:path) and response.path.route.api_class
|
290
|
-
env.event_handler = response.path.route.api_class.new
|
291
|
-
end
|
292
|
-
end
|
293
|
-
env.event_handler ||= self
|
294
|
-
end
|
295
|
-
|
296
229
|
end
|
297
230
|
end
|
data/lib/goliath/application.rb
CHANGED
@@ -2,19 +2,6 @@ require 'goliath/goliath'
|
|
2
2
|
require 'goliath/runner'
|
3
3
|
require 'goliath/rack'
|
4
4
|
|
5
|
-
# Pre-load the goliath environment so it's available as we try to parse the class.
|
6
|
-
# This means we can use Goliath.dev? or Goliath.prod? in the use statements.
|
7
|
-
#
|
8
|
-
# Note, as implmented, you have to have -e as it's own flag, you can't do -sve dev
|
9
|
-
# as it won't pickup the e flag.
|
10
|
-
env = ENV['RACK_ENV']
|
11
|
-
env ||= begin
|
12
|
-
if ((i = ARGV.index('-e')) || (i = ARGV.index('--environment')))
|
13
|
-
ARGV[i + 1]
|
14
|
-
end
|
15
|
-
end
|
16
|
-
Goliath.env = env if env
|
17
|
-
|
18
5
|
module Goliath
|
19
6
|
# The main execution class for Goliath. This will execute in the at_exit
|
20
7
|
# handler to run the server.
|
@@ -91,7 +78,7 @@ module Goliath
|
|
91
78
|
# @param args [Array] Any arguments to append to the path
|
92
79
|
# @return [String] path for the given arguments
|
93
80
|
def self.root_path(*args)
|
94
|
-
return app_path(args) if Goliath.test
|
81
|
+
return app_path(args) if Goliath.env?(:test)
|
95
82
|
|
96
83
|
@root_path ||= File.expand_path("./")
|
97
84
|
File.join(@root_path, *args)
|
@@ -108,12 +95,11 @@ module Goliath
|
|
108
95
|
|
109
96
|
begin
|
110
97
|
klass = Kernel
|
111
|
-
@app_class.split('::').each
|
112
|
-
klass = klass.const_get(con)
|
113
|
-
end
|
98
|
+
@app_class.split('::').each { |con| klass = klass.const_get(con) }
|
114
99
|
rescue NameError
|
115
100
|
raise NameError, "Class #{@app_class} not found."
|
116
101
|
end
|
102
|
+
|
117
103
|
api = klass.new
|
118
104
|
|
119
105
|
runner = Goliath::Runner.new(ARGV, api)
|
data/lib/goliath/connection.rb
CHANGED
@@ -22,7 +22,6 @@ module Goliath
|
|
22
22
|
|
23
23
|
@parser = Http::Parser.new
|
24
24
|
@parser.on_headers_complete = proc do |h|
|
25
|
-
|
26
25
|
env = Thread.current[GOLIATH_ENV] = Goliath::Env.new
|
27
26
|
env[SERVER_PORT] = port.to_s
|
28
27
|
env[RACK_LOGGER] = logger
|
@@ -33,11 +32,9 @@ module Goliath
|
|
33
32
|
|
34
33
|
r = Goliath::Request.new(@app, self, env)
|
35
34
|
r.parse_header(h, @parser) do
|
36
|
-
|
37
|
-
|
38
|
-
env[
|
39
|
-
env[ASYNC_BODY] = env.event_handler.method(:on_body) if env.event_handler.respond_to? :on_body
|
40
|
-
env[ASYNC_CLOSE] = env.event_handler.method(:on_close) if env.event_handler.respond_to? :on_close
|
35
|
+
env[ASYNC_HEADERS] = api.method(:on_headers) if api.respond_to?(:on_headers)
|
36
|
+
env[ASYNC_BODY] = api.method(:on_body) if api.respond_to?(:on_body)
|
37
|
+
env[ASYNC_CLOSE] = api.method(:on_close) if api.respond_to?(:on_close)
|
41
38
|
end
|
42
39
|
|
43
40
|
@requests.push(r)
|
@@ -57,21 +54,31 @@ module Goliath
|
|
57
54
|
@pending.push(req)
|
58
55
|
end
|
59
56
|
|
60
|
-
req.process
|
57
|
+
req.process if !@parser.upgrade? && !req.env[:terminate_connection]
|
61
58
|
end
|
62
59
|
end
|
63
60
|
|
64
61
|
def receive_data(data)
|
65
62
|
begin
|
66
63
|
@parser << data
|
64
|
+
|
65
|
+
if @parser.upgrade?
|
66
|
+
if !@current.env[UPGRADE_DATA]
|
67
|
+
@current.env[UPGRADE_DATA] = @parser.upgrade_data
|
68
|
+
@current.process
|
69
|
+
else
|
70
|
+
@current.parse(data)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
67
74
|
rescue HTTP::Parser::Error => e
|
68
75
|
terminate_request(false)
|
69
76
|
end
|
70
77
|
end
|
71
78
|
|
72
79
|
def unbind
|
73
|
-
@requests.map {|r| r.close }
|
74
|
-
@pending.map {|r| r.close }
|
80
|
+
@requests.map { |r| r.close }
|
81
|
+
@pending.map { |r| r.close }
|
75
82
|
@current.close if @current
|
76
83
|
end
|
77
84
|
|
data/lib/goliath/constants.rb
CHANGED
data/lib/goliath/env.rb
CHANGED
@@ -6,7 +6,6 @@ module Goliath
|
|
6
6
|
# Goliath::Env also provides access to the logger, configuration information
|
7
7
|
# and anything else set into the config data during initialization.
|
8
8
|
class Env < Hash
|
9
|
-
attr_accessor :event_handler
|
10
9
|
include Constants
|
11
10
|
|
12
11
|
# Create a new Goliath::Env object
|
@@ -64,8 +63,8 @@ module Goliath
|
|
64
63
|
|
65
64
|
# If the API is a streaming API this will be executed by the API to signal that
|
66
65
|
# the stream is complete. This will close the connection with the client.
|
67
|
-
def stream_close
|
68
|
-
self[STREAM_CLOSE].call
|
66
|
+
def stream_close(*args)
|
67
|
+
self[STREAM_CLOSE].call(args)
|
69
68
|
end
|
70
69
|
|
71
70
|
# Sends a chunk in a Chunked transfer encoding stream.
|
data/lib/goliath/goliath.rb
CHANGED
@@ -10,55 +10,45 @@ module Goliath
|
|
10
10
|
|
11
11
|
ENVIRONMENTS = [:development, :production, :test, :staging]
|
12
12
|
|
13
|
+
# for example:
|
14
|
+
#
|
15
|
+
# def development?
|
16
|
+
# env? :development
|
17
|
+
# end
|
18
|
+
class << self
|
19
|
+
ENVIRONMENTS.each do |e|
|
20
|
+
define_method "#{e}?" do
|
21
|
+
warn "[DEPRECATION] `Goliath.#{e}?` is deprecated. Please use `Goliath.env?(#{e})` instead."
|
22
|
+
env? e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
alias :prod? :production?
|
27
|
+
alias :dev? :development?
|
28
|
+
end
|
29
|
+
|
13
30
|
# Retrieves the current goliath environment
|
14
31
|
#
|
15
32
|
# @return [String] the current environment
|
16
33
|
def env
|
17
|
-
@env
|
34
|
+
@env
|
18
35
|
end
|
19
36
|
|
20
37
|
# Sets the current goliath environment
|
21
38
|
#
|
22
|
-
# @param [String|Symbol] env the environment symbol
|
39
|
+
# @param [String|Symbol] env the environment symbol
|
23
40
|
def env=(e)
|
24
|
-
|
41
|
+
@env = case(e.to_sym)
|
25
42
|
when :dev then :development
|
26
43
|
when :prod then :production
|
27
44
|
else e.to_sym
|
28
45
|
end
|
29
|
-
|
30
|
-
if ENVIRONMENTS.include?(es)
|
31
|
-
@env = es
|
32
|
-
else
|
33
|
-
fail "did not recognize environment: #{e}, expected one of: #{ENVIRONMENTS.join(', ')}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Determines if we are in the production environment
|
38
|
-
#
|
39
|
-
# @return [Boolean] true if current environment is production, false otherwise
|
40
|
-
def prod?
|
41
|
-
env == :production
|
42
|
-
end
|
43
|
-
|
44
|
-
# Determines if we are in the development environment
|
45
|
-
#
|
46
|
-
# @return [Boolean] true if current environment is development, false otherwise
|
47
|
-
def dev?
|
48
|
-
env == :development
|
49
|
-
end
|
50
|
-
|
51
|
-
# Determines if we are in the test environment
|
52
|
-
#
|
53
|
-
# @return [Boolean] true if current environment is test, false otherwise
|
54
|
-
def test?
|
55
|
-
env == :test
|
56
46
|
end
|
57
47
|
|
58
|
-
# Determines if we are in
|
48
|
+
# Determines if we are in a particular environment
|
59
49
|
#
|
60
|
-
# @return [Boolean] true if current environment
|
61
|
-
def
|
62
|
-
env ==
|
50
|
+
# @return [Boolean] true if current environment matches, false otherwise
|
51
|
+
def env?(e)
|
52
|
+
env == e.to_sym
|
63
53
|
end
|
64
54
|
end
|
@@ -6,6 +6,10 @@ module Goliath
|
|
6
6
|
# plugin Goliath::Plugin::Latency
|
7
7
|
#
|
8
8
|
class Latency
|
9
|
+
|
10
|
+
# Number of seconds to wait before logging latency
|
11
|
+
LATENCY_TIMING = 1
|
12
|
+
|
9
13
|
# Called by the framework to initialize the plugin
|
10
14
|
#
|
11
15
|
# @param port [Integer] Unused
|
@@ -28,9 +32,9 @@ module Goliath
|
|
28
32
|
|
29
33
|
# Called automatically to start the plugin
|
30
34
|
def run
|
31
|
-
EM.add_periodic_timer(
|
32
|
-
@@recent_latency = (Time.now.to_f - @last)
|
33
|
-
@logger.info "LATENCY: #{@@recent_latency}"
|
35
|
+
EM.add_periodic_timer(LATENCY_TIMING) do
|
36
|
+
@@recent_latency = ((Time.now.to_f - @last) - LATENCY_TIMING)
|
37
|
+
@logger.info "LATENCY: #{(@@recent_latency * 1000)} ms"
|
34
38
|
@last = Time.now.to_f
|
35
39
|
end
|
36
40
|
end
|