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.

Files changed (102) hide show
  1. data/.gitignore +3 -0
  2. data/Guardfile +8 -0
  3. data/HISTORY.md +10 -0
  4. data/LICENSE +1 -1
  5. data/README.md +28 -29
  6. data/Rakefile +10 -2
  7. data/examples/activerecord/config/srv.rb +2 -1
  8. data/examples/activerecord/srv.rb +14 -5
  9. data/examples/api_proxy.rb +3 -7
  10. data/examples/around.rb +38 -0
  11. data/examples/async_aroundware_demo.rb +2 -2
  12. data/examples/async_upload.rb +1 -1
  13. data/examples/auth_and_rate_limit.rb +1 -1
  14. data/examples/clone.rb +26 -0
  15. data/examples/config/websocket.rb +1 -0
  16. data/examples/custom_logs.rb +21 -0
  17. data/examples/custom_server.rb +6 -44
  18. data/examples/early_abort.rb +6 -3
  19. data/examples/echo.rb +1 -1
  20. data/examples/fiber_pool.rb +35 -0
  21. data/examples/grape/config/apiserver.rb +8 -0
  22. data/examples/grape/server.rb +67 -0
  23. data/examples/gziped.rb +1 -1
  24. data/examples/params.rb +36 -0
  25. data/examples/rasterize/rasterize.rb +1 -2
  26. data/examples/router.rb +15 -0
  27. data/examples/template.rb +14 -7
  28. data/examples/test.rb +31 -0
  29. data/examples/upload.rb +17 -0
  30. data/examples/views/joke.markdown +4 -4
  31. data/examples/websocket.rb +39 -0
  32. data/examples/ws/favicon.ico +0 -0
  33. data/examples/ws/index.erb +50 -0
  34. data/goliath.gemspec +24 -6
  35. data/lib/goliath/api.rb +15 -82
  36. data/lib/goliath/application.rb +3 -17
  37. data/lib/goliath/connection.rb +16 -9
  38. data/lib/goliath/constants.rb +2 -0
  39. data/lib/goliath/env.rb +2 -3
  40. data/lib/goliath/goliath.rb +24 -34
  41. data/lib/goliath/plugins/latency.rb +7 -3
  42. data/lib/goliath/rack/builder.rb +1 -37
  43. data/lib/goliath/rack/favicon.rb +31 -0
  44. data/lib/goliath/rack/formatters/json.rb +1 -1
  45. data/lib/goliath/rack/heartbeat.rb +1 -0
  46. data/lib/goliath/rack/jsonp.rb +1 -0
  47. data/lib/goliath/rack/params.rb +2 -17
  48. data/lib/goliath/rack/render.rb +0 -1
  49. data/lib/goliath/rack/templates.rb +18 -7
  50. data/lib/goliath/rack/types/base.rb +24 -0
  51. data/lib/goliath/rack/types/boolean.rb +18 -0
  52. data/lib/goliath/rack/types/core.rb +19 -0
  53. data/lib/goliath/rack/types/symbol.rb +16 -0
  54. data/lib/goliath/rack/types.rb +10 -0
  55. data/lib/goliath/rack/validation/coerce.rb +48 -0
  56. data/lib/goliath/rack/validation/param.rb +113 -0
  57. data/lib/goliath/rack/validation/request_method.rb +1 -1
  58. data/lib/goliath/rack/validation/required.rb +47 -0
  59. data/lib/goliath/rack/validation/required_param.rb +42 -17
  60. data/lib/goliath/rack/validation.rb +3 -0
  61. data/lib/goliath/rack.rb +2 -2
  62. data/lib/goliath/request.rb +41 -9
  63. data/lib/goliath/response.rb +0 -2
  64. data/lib/goliath/runner.rb +55 -4
  65. data/lib/goliath/server.rb +7 -3
  66. data/lib/goliath/test_helper.rb +70 -16
  67. data/lib/goliath/test_helper_ws.rb +42 -0
  68. data/lib/goliath/version.rb +1 -1
  69. data/lib/goliath/websocket.rb +80 -0
  70. data/pkg/goliath-0.9.4.gem +0 -0
  71. data/pkg/goliath-1.0.0.beta.1.gem +0 -0
  72. data/spec/integration/async_request_processing.rb +1 -1
  73. data/spec/integration/early_abort_spec.rb +3 -10
  74. data/spec/integration/echo_spec.rb +8 -8
  75. data/spec/integration/jsonp_spec.rb +31 -0
  76. data/spec/integration/keepalive_spec.rb +2 -2
  77. data/spec/integration/template_spec.rb +10 -5
  78. data/spec/integration/test_helper_spec.rb +33 -0
  79. data/spec/integration/valid_spec.rb +35 -5
  80. data/spec/integration/websocket_spec.rb +44 -0
  81. data/spec/unit/api_spec.rb +2 -19
  82. data/spec/unit/connection_spec.rb +3 -0
  83. data/spec/unit/rack/formatters/json_spec.rb +3 -3
  84. data/spec/unit/rack/heartbeat_spec.rb +13 -0
  85. data/spec/unit/rack/params_spec.rb +2 -8
  86. data/spec/unit/rack/validation/param_spec.rb +443 -0
  87. data/spec/unit/rack/validation/request_method_spec.rb +5 -0
  88. data/spec/unit/rack/validation/required_param_spec.rb +71 -1
  89. data/spec/unit/runner_spec.rb +21 -7
  90. data/test/echo_test.rb +25 -0
  91. data/test/test_helper.rb +5 -0
  92. metadata +316 -78
  93. data/examples/env_use_statements.rb +0 -20
  94. data/examples/favicon.rb +0 -40
  95. data/examples/rack_routes.rb +0 -125
  96. data/examples/rasterize/thumb/f7ad4cb03e5bfd0e2c43db8e598fb3cd.png +0 -0
  97. data/examples/valid.rb +0 -17
  98. data/lib/goliath/deprecated/async_aroundware.rb +0 -133
  99. data/lib/goliath/deprecated/mongo_receiver.rb +0 -84
  100. data/lib/goliath/deprecated/response_receiver.rb +0 -97
  101. data/spec/integration/rack_routes_spec.rb +0 -169
  102. 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
 
@@ -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
- # use bluecloth as default markdown renderer
15
- require 'bluecloth'
16
- Tilt.register 'markdown', Tilt::BlueClothTemplate
17
- require 'yajl/json_gem'
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
- :root => Goliath::Application.app_path("public"),
28
- :urls => ["/favicon.ico", '/stylesheets', '/javascripts', '/images'])
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
- when '/' then [200, {}, haml(:root)]
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
@@ -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
- "Hey Pirate, What's With The Steering Wheel?"
8
+ Hey Pirate, What's With The Steering Wheel?
9
9
 
10
10
 
11
- Pirate says
11
+ Pirate says
12
12
 
13
- "Arr, I dunno matey -- but it's drivin' me nuts!"
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' />&nbsp;
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.add_dependency 'eventmachine', '>= 1.0.0.beta.3'
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 'http_parser.rb'
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
- ignores = File.readlines(".gitignore").grep(/\S+/).map {|s| s.chomp }
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([::Rack::ContentLength, nil, nil])
40
+ @middlewares.unshift([::AsyncRack::ContentLength, nil, nil])
42
41
 
43
- if Goliath.dev? && !@middlewares.detect {|mw| mw.first == ::Rack::Reloader}
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
- # Returns the router maps configured for the API
97
- #
98
- # @return [Array] array contains [path, klass, block]
99
- def maps
100
- @maps ||= []
101
- end
102
-
103
- def maps?
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
- env[ASYNC_CALLBACK].call(validation_error(500, e.message))
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
@@ -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 do |con|
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)
@@ -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
- @api.set_event_handler!(env) if @api
37
-
38
- env[ASYNC_HEADERS] = env.event_handler.method(:on_headers) if env.event_handler.respond_to? :on_headers
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
 
@@ -47,7 +47,9 @@ module Goliath
47
47
  PATH_INFO = 'PATH_INFO'
48
48
  FRAGMENT = 'FRAGMENT'
49
49
  CONNECTION = 'CONNECTION'
50
+ UPGRADE_DATA = 'UPGRADE_DATA'
50
51
 
51
52
  GOLIATH_ENV = 'goliath.env'
53
+ GOLIATH_SIGNATURE = 'goliath.signature'
52
54
  end
53
55
  end
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.
@@ -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 or fail "environment has not been set"
34
+ @env
18
35
  end
19
36
 
20
37
  # Sets the current goliath environment
21
38
  #
22
- # @param [String|Symbol] env the environment symbol of [dev | development | prod | production | test]
39
+ # @param [String|Symbol] env the environment symbol
23
40
  def env=(e)
24
- es = case(e.to_sym)
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 the staging environment
48
+ # Determines if we are in a particular environment
59
49
  #
60
- # @return [Boolean] true if current environment is staging.
61
- def staging?
62
- env == :staging
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(1) do
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