Created
March 16, 2009 15:26
-
-
Save raggi/79926 to your computer and use it in GitHub Desktop.
Example implementation for Sinatra::Async, to be used with async thin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# async_sinatra_example.ru | |
require 'sinatra' | |
# Normally Sinatra::Base expects that the completion of a request is | |
# determined by the block exiting, and returning a value for the body. | |
# | |
# In an async environment, we want to tell the webserver that we're not going | |
# to provide a response now, but some time in the future. | |
# | |
# The a* methods provide a method for doing this, by informing the server of | |
# our asynchronous intent, and then scheduling our action code (your block) | |
# as the next thing to be invoked by the server. | |
# | |
# This code can then do a number of things, including waiting (asynchronously) | |
# for external servers, services, and whatnot to complete. When ready to send | |
# the real response, simply setup your environment as you normally would for | |
# sinatra (using #content_type, #headers, etc). Finally, you complete your | |
# response body by calling the #body method. This will push your body into the | |
# response object, and call out to the server to actually send that data. | |
module Sinatra::Async | |
module ClassMethods | |
def aget(path, opts={}, &block) | |
conditions = @conditions.dup | |
aroute('GET', path, opts, &block) | |
@conditions = conditions | |
aroute('HEAD', path, opts, &block) | |
end | |
def aput(path, opts={}, &bk); aroute 'PUT', path, opts, &bk; end | |
def apost(path, opts={}, &bk); aroute 'POST', path, opts, &bk; end | |
def adelete(path, opts={}, &bk); aroute 'DELETE', path, opts, &bk; end | |
def ahead(path, opts={}, &bk); aroute 'HEAD', path, opts, &bk; end | |
private | |
def aroute(*args, &block) | |
self.send :route, *args do |*bargs| | |
mc = class << self; self; end | |
mc.send :define_method, :__async_callback, &block | |
EM.next_tick { send(:__async_callback, *bargs) } | |
throw :async | |
end | |
end | |
end | |
def self.included(klass) | |
klass.extend ClassMethods | |
end | |
def body(*args, &blk) | |
super | |
request.env['async.callback'][[response.status, response.headers, response.body]] | |
end | |
end | |
class AsyncTest < Sinatra::Base | |
include Sinatra::Async | |
aget '/' do | |
body "hello async" | |
end | |
aget '/delay/:n' do |n| | |
EM.add_timer(n.to_i) { body { "delayed for #{n} seconds" } } | |
end | |
end | |
run AsyncTest.new |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment