waves-stable 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- data/app/Rakefile +72 -0
- data/app/bin/waves-console +4 -0
- data/app/bin/waves-server +4 -0
- data/app/configurations/development.rb.erb +31 -0
- data/app/configurations/mapping.rb.erb +14 -0
- data/app/configurations/production.rb.erb +31 -0
- data/app/controllers/.gitignore +0 -0
- data/app/doc/.gitignore +0 -0
- data/app/helpers/.gitignore +0 -0
- data/app/lib/application.rb.erb +5 -0
- data/app/lib/tasks/.gitignore +0 -0
- data/app/log/.gitignore +0 -0
- data/app/models/.gitignore +0 -0
- data/app/public/css/.gitignore +0 -0
- data/app/public/flash/.gitignore +0 -0
- data/app/public/images/.gitignore +0 -0
- data/app/public/javascript/.gitignore +0 -0
- data/app/schema/migrations/.gitignore +0 -0
- data/app/startup.rb +5 -0
- data/app/templates/errors/not_found_404.mab +2 -0
- data/app/templates/errors/server_error_500.mab +2 -0
- data/app/templates/layouts/default.mab +14 -0
- data/app/tmp/sessions/.gitignore +0 -0
- data/app/views/.gitignore +0 -0
- data/bin/waves +84 -0
- data/bin/waves-console +4 -0
- data/bin/waves-server +4 -0
- data/doc/HISTORY +44 -0
- data/doc/LICENSE +22 -0
- data/lib/commands/waves-console.rb +21 -0
- data/lib/commands/waves-server.rb +55 -0
- data/lib/controllers/base.rb +11 -0
- data/lib/controllers/mixin.rb +165 -0
- data/lib/dispatchers/base.rb +67 -0
- data/lib/dispatchers/default.rb +81 -0
- data/lib/foundations/default.rb +27 -0
- data/lib/foundations/simple.rb +30 -0
- data/lib/helpers/asset_helper.rb +67 -0
- data/lib/helpers/common.rb +66 -0
- data/lib/helpers/default.rb +13 -0
- data/lib/helpers/form.rb +40 -0
- data/lib/helpers/formatting.rb +30 -0
- data/lib/helpers/model.rb +33 -0
- data/lib/helpers/number_helper.rb +25 -0
- data/lib/helpers/tag_helper.rb +58 -0
- data/lib/helpers/url_helper.rb +77 -0
- data/lib/helpers/view.rb +24 -0
- data/lib/layers/default_errors.rb +26 -0
- data/lib/layers/inflect/english.rb +24 -0
- data/lib/layers/inflect/english/rules.rb +88 -0
- data/lib/layers/inflect/english/string.rb +24 -0
- data/lib/layers/mvc.rb +54 -0
- data/lib/layers/orm/active_record.rb +92 -0
- data/lib/layers/orm/active_record/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/active_record/tasks/generate.rb +28 -0
- data/lib/layers/orm/active_record/tasks/schema.rb +22 -0
- data/lib/layers/orm/data_mapper.rb +38 -0
- data/lib/layers/orm/filebase.rb +22 -0
- data/lib/layers/orm/migration.rb +79 -0
- data/lib/layers/orm/sequel.rb +86 -0
- data/lib/layers/orm/sequel/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/sequel/tasks/generate.rb +28 -0
- data/lib/layers/orm/sequel/tasks/schema.rb +16 -0
- data/lib/layers/simple.rb +32 -0
- data/lib/layers/simple_errors.rb +23 -0
- data/lib/mapping/mapping.rb +289 -0
- data/lib/mapping/pretty_urls.rb +96 -0
- data/lib/renderers/erubis.rb +63 -0
- data/lib/renderers/haml.rb +45 -0
- data/lib/renderers/markaby.rb +33 -0
- data/lib/renderers/mixin.rb +50 -0
- data/lib/runtime/application.rb +69 -0
- data/lib/runtime/blackboard.rb +57 -0
- data/lib/runtime/configuration.rb +185 -0
- data/lib/runtime/console.rb +20 -0
- data/lib/runtime/debugger.rb +9 -0
- data/lib/runtime/logger.rb +59 -0
- data/lib/runtime/mime_types.rb +22 -0
- data/lib/runtime/request.rb +78 -0
- data/lib/runtime/response.rb +40 -0
- data/lib/runtime/response_mixin.rb +38 -0
- data/lib/runtime/response_proxy.rb +30 -0
- data/lib/runtime/server.rb +107 -0
- data/lib/runtime/session.rb +66 -0
- data/lib/tasks/cluster.rb +26 -0
- data/lib/tasks/gem.rb +31 -0
- data/lib/tasks/generate.rb +80 -0
- data/lib/utilities/hash.rb +31 -0
- data/lib/utilities/inflect.rb +110 -0
- data/lib/utilities/integer.rb +24 -0
- data/lib/utilities/module.rb +21 -0
- data/lib/utilities/object.rb +25 -0
- data/lib/utilities/proc.rb +16 -0
- data/lib/utilities/string.rb +49 -0
- data/lib/utilities/symbol.rb +10 -0
- data/lib/utilities/tempfile.rb +9 -0
- data/lib/views/base.rb +9 -0
- data/lib/views/mixin.rb +110 -0
- data/lib/waves.rb +84 -0
- data/samples/blog/Rakefile +14 -0
- data/samples/blog/bin/waves-console +3 -0
- data/samples/blog/bin/waves-server +3 -0
- data/samples/blog/configurations/development.rb +31 -0
- data/samples/blog/configurations/mapping.rb +23 -0
- data/samples/blog/configurations/production.rb +30 -0
- data/samples/blog/doc/EMTPY +0 -0
- data/samples/blog/lib/application.rb +5 -0
- data/samples/blog/models/comment.rb +14 -0
- data/samples/blog/models/entry.rb +14 -0
- data/samples/blog/public/css/site.css +2 -0
- data/samples/blog/public/javascript/site.js +13 -0
- data/samples/blog/schema/migrations/001_initial_schema.rb +17 -0
- data/samples/blog/schema/migrations/002_add_comments.rb +18 -0
- data/samples/blog/schema/migrations/templates/empty.rb.erb +9 -0
- data/samples/blog/startup.rb +6 -0
- data/samples/blog/templates/comment/add.mab +10 -0
- data/samples/blog/templates/comment/list.mab +6 -0
- data/samples/blog/templates/entry/editor.mab +13 -0
- data/samples/blog/templates/entry/list.mab +11 -0
- data/samples/blog/templates/entry/show.mab +9 -0
- data/samples/blog/templates/entry/summary.mab +5 -0
- data/samples/blog/templates/errors/not_found_404.mab +2 -0
- data/samples/blog/templates/errors/server_error_500.mab +2 -0
- data/samples/blog/templates/layouts/default.mab +17 -0
- data/verify/app_generation/helpers.rb +24 -0
- data/verify/app_generation/startup.rb +39 -0
- data/verify/blackboard/blackboard_verify.rb +92 -0
- data/verify/blackboard/helpers.rb +5 -0
- data/verify/configurations/attributes.rb +37 -0
- data/verify/configurations/helpers.rb +1 -0
- data/verify/configurations/rack_integration.rb +29 -0
- data/verify/controllers/base.rb +37 -0
- data/verify/controllers/helpers.rb +13 -0
- data/verify/controllers/interface.rb +51 -0
- data/verify/core/helpers.rb +3 -0
- data/verify/core/utilities.rb +177 -0
- data/verify/foundations/default.rb +86 -0
- data/verify/foundations/default_application/Rakefile +14 -0
- data/verify/foundations/default_application/bin/waves-console +3 -0
- data/verify/foundations/default_application/bin/waves-server +3 -0
- data/verify/foundations/default_application/configurations/development.rb +26 -0
- data/verify/foundations/default_application/configurations/mapping.rb +14 -0
- data/verify/foundations/default_application/configurations/production.rb +30 -0
- data/verify/foundations/default_application/controllers/default.rb +15 -0
- data/verify/foundations/default_application/controllers/loaded.rb +15 -0
- data/verify/foundations/default_application/defaultapplication.db +0 -0
- data/verify/foundations/default_application/helpers/loaded.rb +10 -0
- data/verify/foundations/default_application/lib/application.rb +5 -0
- data/verify/foundations/default_application/models/default.rb +13 -0
- data/verify/foundations/default_application/models/loaded.rb +13 -0
- data/verify/foundations/default_application/schema/migrations/templates/empty.rb.erb +9 -0
- data/verify/foundations/default_application/startup.rb +7 -0
- data/verify/foundations/default_application/templates/errors/not_found_404.mab +2 -0
- data/verify/foundations/default_application/templates/errors/server_error_500.mab +2 -0
- data/verify/foundations/default_application/templates/layouts/default.mab +14 -0
- data/verify/foundations/default_application/views/default.rb +7 -0
- data/verify/foundations/default_application/views/loaded.rb +15 -0
- data/verify/foundations/helpers.rb +1 -0
- data/verify/foundations/simple.rb +25 -0
- data/verify/helpers.rb +76 -0
- data/verify/layers/data_mapper/association_verify.rb +87 -0
- data/verify/layers/default_errors.rb +29 -0
- data/verify/layers/helpers.rb +1 -0
- data/verify/layers/migration.rb +33 -0
- data/verify/layers/sequel/model.rb +41 -0
- data/verify/mapping/always.rb +19 -0
- data/verify/mapping/filters.rb +65 -0
- data/verify/mapping/handle.rb +24 -0
- data/verify/mapping/helpers.rb +7 -0
- data/verify/mapping/matches.rb +27 -0
- data/verify/mapping/named.rb +29 -0
- data/verify/mapping/options.rb +17 -0
- data/verify/mapping/path.rb +40 -0
- data/verify/mapping/response_proxy.rb +50 -0
- data/verify/mapping/threaded.rb +25 -0
- data/verify/requests/helpers.rb +16 -0
- data/verify/requests/request.rb +73 -0
- data/verify/requests/response.rb +59 -0
- data/verify/requests/session.rb +54 -0
- data/verify/views/helpers.rb +1 -0
- data/verify/views/rendering.rb +34 -0
- data/verify/views/templates/foo.erb +0 -0
- data/verify/views/templates/moo.erb +0 -0
- data/verify/views/templates/moo.mab +0 -0
- metadata +439 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
class Console < Application
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_reader :console
|
8
|
+
|
9
|
+
def load( options={} )
|
10
|
+
@console ||= Waves::Console.new( options )
|
11
|
+
end
|
12
|
+
|
13
|
+
# allow Waves::Console to act as The Console Instance
|
14
|
+
def method_missing(*args); @console.send(*args); end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Kernel
|
2
|
+
unless respond_to?(:debugger)
|
3
|
+
# Starts a debugging session if ruby-debug has been loaded (call waves-server --debugger to do load it).
|
4
|
+
def debugger
|
5
|
+
puts "debugger called"
|
6
|
+
Waves::Logger.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Waves
|
3
|
+
|
4
|
+
# Waves::Logger is based on Ruby's built-in Logger. It uses the same filtering approach
|
5
|
+
# (debug, info, warn, error, fatal), although the interface is slightly different.
|
6
|
+
# You won't typically instantiate this class directly; instead, you will specify the
|
7
|
+
# logging configuration you want in your configuration files. See Waves::Configurations
|
8
|
+
# for more information on this.
|
9
|
+
#
|
10
|
+
# To use the logger for output, you can usually just call +log+, since the Waves::ResponseHelper
|
11
|
+
# mixin defines it (meaning it is available in the mapping file, controllers, views, and
|
12
|
+
# templates). Or, you can access Waves::Logger directly. Either way, the logger provides five
|
13
|
+
# methods for output corresponding to the log levels.
|
14
|
+
#
|
15
|
+
# *Examples*
|
16
|
+
# # log the value of foo
|
17
|
+
# log.info "Value of foo: #{foo}"
|
18
|
+
#
|
19
|
+
# # fatal error!
|
20
|
+
# Waves::Logger.fatal "She can't hold up any longer, cap'n!"
|
21
|
+
#
|
22
|
+
module Logger
|
23
|
+
|
24
|
+
class << self
|
25
|
+
|
26
|
+
# Returns the object being used for output by the logger.
|
27
|
+
def output
|
28
|
+
@output ||= ( config[:output] ? File.expand_path( config[:output] ) : $stderr )
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the active configuration for the logger.
|
32
|
+
def config
|
33
|
+
@config ||= Waves::Server.config.log
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the logging level used to filter logging events.
|
37
|
+
def level ; @level ||= ::Logger.const_get( config[:level].to_s.upcase || 'INFO' ) ; end
|
38
|
+
|
39
|
+
# Starts the logger, using the active configuration to initialize it.
|
40
|
+
def start
|
41
|
+
@log = config[:rotation] ?
|
42
|
+
::Logger.new( output, config[:rotation].intern ) :
|
43
|
+
::Logger.new( output )
|
44
|
+
@log.level = level
|
45
|
+
@log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Forwards logging methods to the logger.
|
50
|
+
def method_missing(name,*args,&block)
|
51
|
+
@log.send name,*args, &block if @log
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
# Waves::MimeTypes defines an interface for adding MIME types used in mapping requests
|
4
|
+
# to content types. Mongrel's MIME_TYPES hash is used as the baseline MIME map.
|
5
|
+
|
6
|
+
module MimeTypes
|
7
|
+
|
8
|
+
def self.[]( path )
|
9
|
+
mapping[ File.extname( path ) ]
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO: This does not seem to be working.
|
13
|
+
def self.<<( mapping )
|
14
|
+
mapping.merge!( mapping )
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.mapping
|
18
|
+
@mapping ||= Mongrel::DirHandler::MIME_TYPES
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Waves
|
2
|
+
# Waves::Request represents an HTTP request and provides convenient methods for accessing request attributes. See Rack::Request for documentation of any method not defined here.
|
3
|
+
class Request
|
4
|
+
|
5
|
+
class ParseError < Exception ; end
|
6
|
+
|
7
|
+
attr_reader :response, :session, :blackboard
|
8
|
+
|
9
|
+
# Create a new request. Takes a env parameter representing the request passed in from Rack.
|
10
|
+
# You shouldn't need to call this directly.
|
11
|
+
def initialize( env )
|
12
|
+
@request = Rack::Request.new( env )
|
13
|
+
@response = Waves::Response.new( self )
|
14
|
+
@session = Waves::Session.new( self )
|
15
|
+
@blackboard = Waves::Blackboard.new( self )
|
16
|
+
end
|
17
|
+
|
18
|
+
def rack_request; @request; end
|
19
|
+
|
20
|
+
# Accessor not explicitly defined by Waves::Request are delegated to Rack::Request.
|
21
|
+
# Check the Rack documentation for more information.
|
22
|
+
def method_missing(name,*args)
|
23
|
+
@request.send(name,*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
# The request path (PATH_INFO). Ex: +/entry/2008-01-17+
|
27
|
+
def path
|
28
|
+
@request.path_info
|
29
|
+
end
|
30
|
+
|
31
|
+
# The request domain. Ex: +www.fubar.com+
|
32
|
+
def domain
|
33
|
+
@request.host
|
34
|
+
end
|
35
|
+
|
36
|
+
# The request content type.
|
37
|
+
def content_type
|
38
|
+
@request.env['CONTENT_TYPE']
|
39
|
+
end
|
40
|
+
|
41
|
+
# Supported request methods
|
42
|
+
METHODS = %w{get post put delete head options trace}
|
43
|
+
|
44
|
+
# Override the Rack methods for querying the request method.
|
45
|
+
METHODS.each do |method|
|
46
|
+
class_eval "def #{method}?; method == :#{method} end"
|
47
|
+
end
|
48
|
+
|
49
|
+
# The request method. Because browsers can't send PUT or DELETE
|
50
|
+
# requests this can be simulated by sending a POST with a hidden
|
51
|
+
# field named '_method' and a value with 'PUT' or 'DELETE'. Also
|
52
|
+
# accepted is when a query parameter named '_method' is provided.
|
53
|
+
def method
|
54
|
+
@method ||= begin
|
55
|
+
request_method = @request.request_method.downcase
|
56
|
+
if request_method == 'post'
|
57
|
+
_method = @request['_method']
|
58
|
+
_method.downcase! if _method
|
59
|
+
METHODS.include?(_method) ? _method.intern : :post
|
60
|
+
else
|
61
|
+
request_method.intern
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Raise a not found exception.
|
67
|
+
def not_found
|
68
|
+
raise Waves::Dispatchers::NotFoundError.new( @request.url + ' not found.' )
|
69
|
+
end
|
70
|
+
|
71
|
+
# Issue a redirect for the given path.
|
72
|
+
def redirect( path, status = '302' )
|
73
|
+
raise Waves::Dispatchers::Redirect.new( path, status )
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Waves
|
2
|
+
# Waves::Response represents an HTTP response and has methods for constructing a response.
|
3
|
+
# These include setters for +content_type+, +content_length+, +location+, and +expires+
|
4
|
+
# headers. You may also set the headers directly using the [] operator. See Rack::Response for documentation of any method not defined here.
|
5
|
+
class Response
|
6
|
+
|
7
|
+
attr_reader :request
|
8
|
+
|
9
|
+
# Create a new response. Takes the request object. You shouldn't need to call this directly.
|
10
|
+
def initialize( request )
|
11
|
+
@request = request
|
12
|
+
@response = Rack::Response.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def rack_response; @response; end
|
16
|
+
|
17
|
+
%w( Content-Type Content-Length Location Expires ).each do |header|
|
18
|
+
define_method( header.downcase.gsub('-','_')+ '=' ) do | val |
|
19
|
+
@response[header] = val
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the sessions associated with the request, allowing you to set values within it.
|
24
|
+
# The session will be created if necessary and saved when the response is complete.
|
25
|
+
def session ; request.session ; end
|
26
|
+
|
27
|
+
# Finish the response. This will send the response back to the client, so you shouldn't
|
28
|
+
# attempt to further modify the response once this method is called. You don't usually
|
29
|
+
# need to call it yourself, since it is called by the dispatcher once request processing
|
30
|
+
# is finished.
|
31
|
+
def finish ; request.session.save ; @response.finish ; end
|
32
|
+
|
33
|
+
# Methods not explicitly defined by Waves::Response are delegated to Rack::Response.
|
34
|
+
# Check the Rack documentation for more informations
|
35
|
+
def method_missing(name,*args)
|
36
|
+
@response.send(name,*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
# Defines a set of methods that simplify accessing common request and response methods.
|
4
|
+
# These include methods not necessarily associated with the Waves::Request and Waves::Response
|
5
|
+
# objects, but which may still be useful for constructing a response.
|
6
|
+
#
|
7
|
+
# This mixin assumes that a @request@ accessor already exists.
|
8
|
+
module ResponseMixin
|
9
|
+
# Access the response.
|
10
|
+
def response; request.response; end
|
11
|
+
# Access the request parameters.
|
12
|
+
def params; request.params; end
|
13
|
+
# Access the request session.
|
14
|
+
def session; request.session; end
|
15
|
+
# Access the request path.
|
16
|
+
def path; request.path; end
|
17
|
+
# Access the request url.
|
18
|
+
def url; request.url; end
|
19
|
+
# Access the request domain.
|
20
|
+
def domain; request.domain; end
|
21
|
+
# Issue a redirect for the given location.
|
22
|
+
def redirect(location, status = '302'); request.redirect(location, status); end
|
23
|
+
# Access the primary application's models
|
24
|
+
def models; Waves.application.models; end
|
25
|
+
# Access the primary application's views
|
26
|
+
def views; Waves.application.views; end
|
27
|
+
# Access the primary application's controllers
|
28
|
+
def controllers; Waves.application.controllers; end
|
29
|
+
# Raise a "not found" exception.
|
30
|
+
def not_found; request.not_found; end
|
31
|
+
# Access the Waves::Logger.
|
32
|
+
def log; Waves::Logger; end
|
33
|
+
# Access the Blackboard
|
34
|
+
def blackboard; request.blackboard; end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
# Mapping actions are evaluated in the context of a ResponseProxy.
|
4
|
+
class ResponseProxy
|
5
|
+
|
6
|
+
attr_reader :request
|
7
|
+
|
8
|
+
include ResponseMixin
|
9
|
+
|
10
|
+
def initialize(request)
|
11
|
+
@request = request
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource( resource, &block )
|
15
|
+
@resource = resource; yield.call
|
16
|
+
end
|
17
|
+
|
18
|
+
def controller( &block )
|
19
|
+
lambda { Waves.application.controllers[ @resource ].process( @request, &block ) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def view( &block )
|
23
|
+
lambda { |val| Waves.application.views[ @resource ].process( @request, val, &block ) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def redirect(path, status = '302'); @request.redirect(path, status); end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Waves
|
2
|
+
# You can run the Waves::Server via the +waves-server+ command or via <tt>rake cluster:start</tt>. Run <tt>waves-server --help</tt> for options on the <tt>waves-server</tt> command. The <tt>cluster:start</tt> task uses the +mode+ environment variable to determine the active configuration. You can define +port+ to run on a single port, or +ports+ (taking an array) to run on multiple ports.
|
3
|
+
#
|
4
|
+
# *Example*
|
5
|
+
#
|
6
|
+
# Assume that +ports+ is set in the development configuration like this:
|
7
|
+
#
|
8
|
+
# ports [ 2020, 2021, 2022 ]
|
9
|
+
#
|
10
|
+
# Then you could start up instances on all three ports using:
|
11
|
+
#
|
12
|
+
# rake cluster:start mode=development
|
13
|
+
#
|
14
|
+
# This is the equivalent of running:
|
15
|
+
#
|
16
|
+
# waves-server -c development -p 2020 -d
|
17
|
+
# waves-server -c development -p 2021 -d
|
18
|
+
# waves-server -c development -p 2022 -d
|
19
|
+
#
|
20
|
+
# The +cluster:stop+ task stops all of the instances.
|
21
|
+
#
|
22
|
+
class Server < Application
|
23
|
+
|
24
|
+
# Access the server thread.
|
25
|
+
attr_reader :thread
|
26
|
+
|
27
|
+
# Access the host we're binding to (set via the configuration).
|
28
|
+
def host ; options[:host] || config.host ; end
|
29
|
+
|
30
|
+
# Access the port we're listening on (set via the configuration).
|
31
|
+
def port ; options[:port] || config.port ; end
|
32
|
+
|
33
|
+
# Run the server as a daemon. Corresponds to the -d switch on +waves-server+.
|
34
|
+
def daemonize
|
35
|
+
pwd = Dir.pwd
|
36
|
+
Daemonize.daemonize( Waves::Logger.output )
|
37
|
+
Dir.chdir(pwd)
|
38
|
+
File.write( :log / "#{port}.pid", $$ )
|
39
|
+
end
|
40
|
+
|
41
|
+
def trap(signal)
|
42
|
+
Kernel::trap(signal) { yield }
|
43
|
+
Thread.new { loop {sleep 1} } if RUBY_PLATFORM =~ /mswin32/
|
44
|
+
end
|
45
|
+
|
46
|
+
# Start and / or access the Waves::Logger instance.
|
47
|
+
def log
|
48
|
+
@log ||= Waves::Logger.start
|
49
|
+
end
|
50
|
+
|
51
|
+
# Start the server.
|
52
|
+
def start
|
53
|
+
daemonize if options[:daemon]
|
54
|
+
start_debugger if options[:debugger]
|
55
|
+
log.info "** Waves Server starting on #{host}:#{port}"
|
56
|
+
handler, options = config.handler
|
57
|
+
handler.run( config.application.to_app, options ) do |server|
|
58
|
+
@server = server
|
59
|
+
self.trap('INT') { puts; stop } if @server.respond_to? :stop
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Stop the server.
|
64
|
+
def stop
|
65
|
+
log.info "** Waves Server Stopping ..."
|
66
|
+
if options[:daemon]
|
67
|
+
pid_file = :log / $$ + '.pid'; FileUtils.rm( pid_file ) if File.exist?( pid_file )
|
68
|
+
end
|
69
|
+
@server.stop
|
70
|
+
log.info "** Waves Server Stopped"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Provides access to the server mutex for thread-safe operation.
|
74
|
+
def synchronize( &block ) ; ( @mutex ||= Mutex.new ).synchronize( &block ) ; end
|
75
|
+
|
76
|
+
class << self
|
77
|
+
private :new, :dup, :clone
|
78
|
+
# Start or restart the server.
|
79
|
+
def run( options={} )
|
80
|
+
@server.stop if @server; @server = new( options ); @server.start
|
81
|
+
end
|
82
|
+
|
83
|
+
# Allows us to access the Waves::Server instance.
|
84
|
+
def method_missing(*args)
|
85
|
+
@server.send(*args)
|
86
|
+
end
|
87
|
+
|
88
|
+
#-- Probably wouldn't need this if I added a block parameter to method_missing.
|
89
|
+
def synchronize(&block) ; @server.synchronize(&block) ; end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def start_debugger
|
95
|
+
begin
|
96
|
+
require 'ruby-debug'
|
97
|
+
Debugger.start
|
98
|
+
Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
|
99
|
+
log.info "Debugger enabled"
|
100
|
+
rescue Exception
|
101
|
+
log.info "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
|
102
|
+
exit
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
# Encapsulates the session associated with a given request. A session has an expiration
|
4
|
+
# and path, which must be provided in a Waves::Configuration. Sensible defaults are defined
|
5
|
+
# in Waves::Configurations::Default
|
6
|
+
class Session
|
7
|
+
|
8
|
+
# Concoct a (probably) unique session id
|
9
|
+
def self.generate_session_id
|
10
|
+
# from Camping ...
|
11
|
+
chars = [*'A'..'Z'] + [*'0'..'9'] + [*'a'..'z']
|
12
|
+
(0..48).inject(''){|s,x| s+=chars[ rand(chars.length) ] }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create a new session object using the given request. This is not necessarily the
|
16
|
+
# same as constructing a new session. The session_id cookie for the request domain
|
17
|
+
# is used to store a session id. The actual session data will be stored in a directory
|
18
|
+
# specified by the application's configuration file.
|
19
|
+
def initialize( request )
|
20
|
+
@request = request
|
21
|
+
@data ||= ( File.exist?( session_path ) ? load_session : {} )
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return the session data as a hash
|
25
|
+
def to_hash
|
26
|
+
@data.to_hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.base_path
|
30
|
+
Waves::Application.instance.config.session[:path]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Save the session data. You shouldn't typically have to call this directly, since it
|
34
|
+
# is called by Waves::Response#finish.
|
35
|
+
def save
|
36
|
+
if @data && @data.length > 0
|
37
|
+
File.write( session_path, @data.to_yaml )
|
38
|
+
@request.response.set_cookie( 'session_id',
|
39
|
+
:value => session_id, :path => '/',
|
40
|
+
:expires => Time.now + Waves::Server.config.session[:duration] )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Access a given data element of the session using the given key.
|
45
|
+
def [](key) ; @data[key] ; end
|
46
|
+
# Set the given data element of the session using the given key and value.
|
47
|
+
def []=(key,val) ; @data[key] = val ; end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def session_id
|
52
|
+
@session_id ||= ( @request.cookies['session_id'] || Waves::Session.generate_session_id )
|
53
|
+
end
|
54
|
+
|
55
|
+
def session_path
|
56
|
+
Waves::Session.base_path / session_id
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_session
|
60
|
+
YAML.load( File.read( session_path ) )
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|