From 58318bed8f22357da6f932a9486a9aae129cb620 Mon Sep 17 00:00:00 2001 From: _why Date: Fri, 19 May 2006 20:51:55 +0000 Subject: [PATCH] * README, lib/camping/*.rb: all docs are up-to-date. * lib/camping/webrick.rb: added X-Sendfile support. * bin/camping: really be sure this guy has the right sqlite3. --- README | 6 ++-- Rakefile | 2 +- bin/camping | 15 ++++++++ lib/camping/fastcgi.rb | 78 ++++++++++++++++++++++++++++++++++++++---- lib/camping/session.rb | 2 +- lib/camping/webrick.rb | 54 ++++++++++++++++++++++++++--- 6 files changed, 142 insertions(+), 15 deletions(-) diff --git a/README b/README index c6e78f8..e6ddab5 100644 --- a/README +++ b/README @@ -102,7 +102,7 @@ Camping comes with an tool for launching apps from the commandline: * Run: camping blog.rb * Visit http://localhost:3301/blog/ to use the app. -== Debugging Camping Apps +== How the Camping Tool Works If your application isn't working with the camping tool, keep in mind that the tool expects the following conventions to be used: @@ -111,7 +111,7 @@ that the tool expects the following conventions to be used: http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for instructions.) 2. If your script is called test.rb, Camping expects your application to be stored in a module called Test. Case is not imporant, though. The - module can be called TeSt or any other permuation. + module can be called TeSt or any other permutation. 3. Your script's postamble (anything enclosed in if __FILE__ == $0) will be ignored by the tool, since the tool will create an SQLite3 database at ~/.camping.db. Or, on Windows, $USER/Application Data/Camping.db. @@ -120,7 +120,7 @@ that the tool expects the following conventions to be used: == The Rules of Thumb -Once you've started writing your own Camping app, I'd highly recommend becoming familiar +Once you've started writing your own Camping app, I'd highly recommend that you become familiar with the Camping Rules of Thumb which are listed on the wiki: http://code.whytheluckystiff.net/camping/wiki/CampingRulesOfThumb diff --git a/Rakefile b/Rakefile index fab6e05..cc9289b 100644 --- a/Rakefile +++ b/Rakefile @@ -32,7 +32,7 @@ Rake::RDocTask.new do |rdoc| rdoc.template = "extras/flipbook_rdoc.rb" rdoc.main = "README" rdoc.title = "Camping, the Documentation" - rdoc.rdoc_files.add ['README', 'CHANGELOG', 'COPYING', 'lib/camping.rb'] + rdoc.rdoc_files.add ['README', 'CHANGELOG', 'COPYING', 'lib/camping.rb', 'lib/camping/*.rb'] end task :after_doc do diff --git a/bin/camping b/bin/camping index a358328..f3cb3c3 100755 --- a/bin/camping +++ b/bin/camping @@ -12,6 +12,7 @@ require 'optparse' require 'stringio' require 'rubygems' require 'camping' +require 'camping/session' host = '0.0.0.0' port = 3301 @@ -68,6 +69,20 @@ if ARGV.length < 1 end Camping::Models::Base.establish_connection :adapter => 'sqlite3', :database => db +begin + Camping::Models::Session.create_schema +rescue MissingSourceFile + puts "** #$0 stopped: SQLite3 not found, please install." + puts "** See http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for instructions." + exit +end + +begin + require 'sqlite3_api' +rescue LoadError + puts "!! Your SQLite3 adapter isn't a compiled extension." + abort "!! Please check out http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for tips." +end class CampingReloader attr_accessor :klass, :mtime, :mount diff --git a/lib/camping/fastcgi.rb b/lib/camping/fastcgi.rb index 0d8e043..685a7a7 100644 --- a/lib/camping/fastcgi.rb +++ b/lib/camping/fastcgi.rb @@ -1,21 +1,72 @@ +# == About camping/fastcgi.rb +# +# Camping works very well with FastCGI, since your application is only loaded +# once -- when FastCGI starts. In addition, this class lets you mount several +# Camping apps under a single FastCGI process, to help save memory costs. +# +# So where do you use the Camping::FastCGI class? Use it in your application's +# postamble and then you can point your web server directly at your application. +# See Camping::FastCGI docs for more. require 'fcgi' module Camping +# Camping::FastCGI is a small class for hooking one or more Camping apps up to +# FastCGI. Generally, you'll use this class in your application's postamble. +# +# == The Smallest Example +# +# if __FILE__ == $0 +# require 'camping/fastcgi' +# Camping::FastCGI.start(YourApp) +# end +# +# This example is stripped down to the basics. The postamble has no database +# connection. It just loads this class and calls Camping::FastCGI.start. +# +# Now, in Lighttpd or Apache, you can point to your app's file, which will +# be executed, only to discover that your app now speaks the FastCGI protocol. +# +# Here's a sample lighttpd.conf (tested with Lighttpd 1.4.11) to serve as example: +# +# server.port = 3044 +# server.bind = "127.0.0.1" +# server.modules = ( "mod_fastcgi" ) +# server.document-root = "/var/www/camping/blog/" +# server.errorlog = "/var/www/camping/blog/error.log" +# +# #### fastcgi module +# fastcgi.server = ( "/" => ( +# "localhost" => ( +# "socket" => "/tmp/camping-blog.socket", +# "bin-path" => "/var/www/camping/blog/blog.rb", +# "check-local" => "disable", +# "max-procs" => 1 ) ) ) +# +# The file /var/www/camping/blog/blog.rb is the Camping app with +# the postamble. +# +# == Mounting Many Apps +# +# require 'camping/fastcgi' +# fast = Camping::FastCGI.new +# fast.mount("/blog", Blog) +# fast.mount("/tepee", Tepee) +# fast.mount("/", Index) +# fast.start +# class FastCGI + # Creates a Camping::FastCGI class with empty mounts. def initialize @mounts = {} end + # Mounts a Camping application. The +dir+ being the name of the directory + # to serve as the application's root. The +app+ is a Camping class. def mount(dir, app) dir.gsub!(/\/{2,}/, '/') dir.gsub!(/\/+$/, '') @mounts[dir] = app end - def match(path, mount) - m = path.match(/^#{Regexp::quote mount}(\/|$)/) - if m: m.end(0) - else -1 - end - end + # Starts the FastCGI main loop. def start FCGI.each do |req| # req.out << app.run(req.in, req.env) @@ -27,10 +78,25 @@ def start req.finish end end + + # A simple single-app starter mechanism + # + # Camping::FastCGI.start(Blog) + # def self.start(app) cf = Camping::FastCGI.new cf.mount("/", app) cf.start end + + private + + def match(path, mount) + m = path.match(/^#{Regexp::quote mount}(\/|$)/) + if m: m.end(0) + else -1 + end + end + end end diff --git a/lib/camping/session.rb b/lib/camping/session.rb index 9b40dc5..c719bbc 100644 --- a/lib/camping/session.rb +++ b/lib/camping/session.rb @@ -86,7 +86,7 @@ module Camping # # 1. require 'camping/session' # 2. Mixin the module: module YourApp; include Camping::Session end -# 3. In your application's create method, add a call to Camping::Models::Schema.create_schema +# 3. In your application's create method, add a call to Camping::Models::Session.create_schema # 4. Throughout your application, use the @state var like a hash to store your application's data. # # If you are unfamiliar with the create method, see diff --git a/lib/camping/webrick.rb b/lib/camping/webrick.rb index 40fff61..d429ffe 100644 --- a/lib/camping/webrick.rb +++ b/lib/camping/webrick.rb @@ -1,20 +1,66 @@ +# == About camping/webrick.rb +# +# For many who have Ruby installed, Camping and WEBrick is a great option. +# It's definitely the easiest configuration, however some performance is sacrificed. +# For better speed, check out Mongrel at http://mongrel.rubyforge.org/, which comes +# with Camping hooks and is supported by the Camping Tool. require 'camping' require 'webrick/httpservlet/abstract.rb' -class WEBrick::CampingHandler < WEBrick::HTTPServlet::AbstractServlet +# WEBrick::CampingHandler is a very simple handle for hosting Camping apps in +# a WEBrick server. It's used much like any other WEBrick handler. +# +# == Mounting a Camping App +# +# Assuming Camping.goes(:Blog), the Blog application can be mounted alongside +# other WEBrick mounts. +# +# s = WEBrick::HTTPServer.new(:BindAddress => host, :Port => port) +# s.mount "/blog", WEBrick::CampingHandler, Blog +# s.mount_proc("/") { ... } +# +# == How Does it Compare? +# +# Compared to other handlers, WEBrick is well-equipped in terms of features. +# +# * The X-Sendfile header is supported, along with etags and +# modification time headers for the file served. Since this handler +# is a subclass of WEBrick::HTTPServlet::DefaultFileHandler, all of its +# logic is used. +# * IO is streaming up and down. When you upload a file, it is streamed to +# the server's filesystem. When you download a file, it is streamed to +# your browser. +# +# While WEBrick is a bit slower than Mongrel and FastCGI options, it's +# a decent choice, for sure! +module WEBrick # :nodoc: +class CampingHandler < WEBrick::HTTPServlet::DefaultFileHandler + # Creates a CampingHandler, which answers for the application within +klass+. def initialize(server, klass) super(server, klass) @klass = klass end + # Handler for WEBrick requests (also aliased as do_POST). def do_GET(req, resp) controller = @klass.run((req.body and StringIO.new(req.body)), req.meta_vars) resp.status = controller.status + @local_path = nil controller.headers.each do |k, v| - [*v].each do |vi| - resp[k] = vi + if k =~ /^X-SENDFILE$/i + @local_path = v + else + [*v].each do |vi| + resp[k] = vi + end end end - resp.body = controller.body + + if @local_path + super(req, res) + else + resp.body = controller.body + end end alias_method :do_POST, :do_GET end +end