Revision: 4530 http://trac.macosforge.org/projects/ruby/changeset/4530 Author: joshua.ballanco@apple.com Date: 2010-09-20 15:45:39 -0700 (Mon, 20 Sep 2010) Log Message: ----------- Update samples. Modified Paths: -------------- ControlTower/trunk/sample/file_upload.ru ControlTower/trunk/sample/simple_hello.ru ControlTower/trunk/sample/sinatra_hello.ru ControlTower/trunk/sample/x_sendfile.ru Added Paths: ----------- ControlTower/trunk/sample/README.rdoc ControlTower/trunk/sample/example_file.txt ControlTower/trunk/sample/photo_search.ru Removed Paths: ------------- ControlTower/trunk/sample/body_content.txt ControlTower/trunk/sample/example_content.txt Added: ControlTower/trunk/sample/README.rdoc =================================================================== --- ControlTower/trunk/sample/README.rdoc (rev 0) +++ ControlTower/trunk/sample/README.rdoc 2010-09-20 22:45:39 UTC (rev 4530) @@ -0,0 +1,64 @@ +== ControlTower Sample Files + +The samples in this directory should help you explore ControlTower's features. +To use these samples, first build and install the Control Tower gem. Then, start +the Rack-up config for each example like so: + +> control_tower -R <sample.ru> + +and test it with a curl or wget like so: + +> curl http://0.0.0.0:3000/ + +To try a POST request, use curl (or similar tool) to send a post with some file +content like so: + +> curl -F "file=@README.rdoc" http://0.0.0.0:3000/ + +Each of the samples demonstrates a different feature of ControlTower. + + +=== simple_hello.ru + +This is just a basic 'hello, world' style app. It demonstrates the basic concept +of Rack. Specifically, the object that you pass as an argument to 'run' in the +Rack-up config must have a #call method. That call method takes one argument, +the environment (which is returned with the request in this sample), and it must +return an array of 3 items: the response code, a hash of response headers, and +the response body. + + +=== sinatra_hello.ru + +This sample demonstrates how you can use a Rack-based web app framework with +ControlTower. In this case, the "MyApp" class inherits from Sinatra::Base, and +is compliant with the Rack app contract. Don't forget to install Sinatra before +you give this one a try! + + +=== file_upload.ru + +POST bodies are delivered as either StringIO or Tempfiles, and if the Post is a +multipart-form MIME type, the Rack utilities will parse the various parts. This +sample demonstrates these features by returning the parts of a multipart-form +POST body, including reading the contents of any file uploaded. + + +=== x_sendfile.ru + +MacRuby includes the ability to use the sendfile(2) API with IO objects. Since +ControlTower directly handles interaction with the system-level sockets for +incoming connections, we can utilize this to send files to a client very +efficiently (sendfile avoids excess kernel-userland context switches). This +sample demonstrates how to use the X-Sendfile header in your response to take +advantage of this feature. + + +=== photo_search.ru + +This is a slightly more complicated example. This sample takes the first letter +from the query string (the bit that comes after a "?" in the URL) and searches +Picasa for photos with that first letter as the first letter of their +descriptions using the Picasa API. Try benchmarking this sample when running +with the "-c" switch, and you'll see why being GCD based is an advantage when +working with apps that call out to APIs which might have non-trivial latency. Deleted: ControlTower/trunk/sample/body_content.txt =================================================================== --- ControlTower/trunk/sample/body_content.txt 2010-09-20 22:45:36 UTC (rev 4529) +++ ControlTower/trunk/sample/body_content.txt 2010-09-20 22:45:39 UTC (rev 4530) @@ -1 +0,0 @@ -You should get this as a response... Deleted: ControlTower/trunk/sample/example_content.txt =================================================================== --- ControlTower/trunk/sample/example_content.txt 2010-09-20 22:45:36 UTC (rev 4529) +++ ControlTower/trunk/sample/example_content.txt 2010-09-20 22:45:39 UTC (rev 4530) @@ -1,3 +0,0 @@ -This is a file with some content to demonstrate ControlTower's X-Sendfile functionality. - -See the README for more info. Copied: ControlTower/trunk/sample/example_file.txt (from rev 4529, ControlTower/trunk/sample/example_content.txt) =================================================================== --- ControlTower/trunk/sample/example_file.txt (rev 0) +++ ControlTower/trunk/sample/example_file.txt 2010-09-20 22:45:39 UTC (rev 4530) @@ -0,0 +1,3 @@ +This is a file with some content to demonstrate ControlTower's X-Sendfile functionality. + +See the README for more info. Modified: ControlTower/trunk/sample/file_upload.ru =================================================================== --- ControlTower/trunk/sample/file_upload.ru 2010-09-20 22:45:36 UTC (rev 4529) +++ ControlTower/trunk/sample/file_upload.ru 2010-09-20 22:45:39 UTC (rev 4530) @@ -1,3 +1,6 @@ +# This sample will read a file passed as part of a multipart-post body in a +# section named 'file' + require 'rack' class Uploader Added: ControlTower/trunk/sample/photo_search.ru =================================================================== --- ControlTower/trunk/sample/photo_search.ru (rev 0) +++ ControlTower/trunk/sample/photo_search.ru 2010-09-20 22:45:39 UTC (rev 4530) @@ -0,0 +1,48 @@ +framework 'Foundation' +require 'rack' + +class PhotoSearch + RESPONSE_TEMPLATE =<<-RESPONSE + <!DOCTYPE HTML> + <html> + <head><title>%s is for...</title></head> + <body style='background-color:#CCFFFF; margin:5%%; padding:5%%'> + <h1><b>%s</b> is for:</h1> + <p>%s<img src='%s' style='text-align:center;max-width:600px;max-height:400px;'></p> + </body> + </html> + RESPONSE + + PICASA_URL_TEMPLATE = "http://picasaweb.google.com/data/feed/api/all?q=%s&max-results=%i" + + def build_response(letter, photo) + summary = photo.nodesForXPath("./summary", error:nil).first.stringValue + src = photo.nodesForXPath("./media:group/media:content/@url", error:nil).first.stringValue + RESPONSE_TEMPLATE % [letter, letter, summary, src] + end + + def get_photo(letter, max_results=10) + return "Must provide a letter" unless letter + return "No results found in the first 200 results" if max_results > 200 + url = NSURL.URLWithString(PICASA_URL_TEMPLATE % [Rack::Utils.escape(letter), max_results]) + xmlDoc = NSXMLDocument.alloc.initWithContentsOfURL(url, options:NSXMLDocumentTidyXML, error:nil) + + entries = xmlDoc.nodesForXPath("//entry", error:nil) + entries.each do |entry| + summary = entry.nodesForXPath("./summary", error:nil)[0].stringValue + if summary[0] == letter + return build_response(letter, entry) + end + end + get_photo(letter, max_results+=10) + end + + def call(env) + letter_to_search = Rack::Utils.unescape(env['QUERY_STRING']).chars.first + [200, { 'Content-Type' => 'text/html; charset=UTF-8' }, get_photo(letter_to_search)] + end + + +end + +run PhotoSearch.new Modified: ControlTower/trunk/sample/simple_hello.ru =================================================================== --- ControlTower/trunk/sample/simple_hello.ru 2010-09-20 22:45:36 UTC (rev 4529) +++ ControlTower/trunk/sample/simple_hello.ru 2010-09-20 22:45:39 UTC (rev 4530) @@ -1,3 +1,5 @@ +# This is just a basic "hello, world" stlye rack-up to get you going + class Hello def call(env) [200, { 'Content-Type' => 'text/plain' }, "Hello, world! Your environment is #{env}"] Modified: ControlTower/trunk/sample/sinatra_hello.ru =================================================================== --- ControlTower/trunk/sample/sinatra_hello.ru 2010-09-20 22:45:36 UTC (rev 4529) +++ ControlTower/trunk/sample/sinatra_hello.ru 2010-09-20 22:45:39 UTC (rev 4530) @@ -1,3 +1,7 @@ +# This is a basic Sinatra sample. +# +# NOTE: You must have the Sinatra gem installed before running + require 'rubygems' require 'sinatra/base' Modified: ControlTower/trunk/sample/x_sendfile.ru =================================================================== --- ControlTower/trunk/sample/x_sendfile.ru 2010-09-20 22:45:36 UTC (rev 4529) +++ ControlTower/trunk/sample/x_sendfile.ru 2010-09-20 22:45:39 UTC (rev 4530) @@ -1,9 +1,13 @@ -# NOTE: Your cwd needs to be the sample/ directory when you start ControlTower +# This is a quick demonstration of ControlTower's X-Sendfile functionality +# +# NOTE: Set the EXAMPLE_FILE environment variable to the path of the file you +# want to send. See the README for more info. + class FileSender def call(env) - headers = { 'Content-Type' => 'text/plain', - 'X-Sendfile' => ::File.expand_path('../body_content.txt', __FILE__) } - [200, headers, "You shouldn't get this body..."] + headers = { 'Content-Type' => 'text/plain' } + headers['X-Sendfile'] = ::File.expand_path(ENV['EXAMPLE_FILE']) if ENV['EXAMPLE_FILE'] + [200, headers, "You shouldn't get this body... see the README for more info\n"] end end