Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created June 4, 2012 16:39
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tenderlove/2869461 to your computer and use it in GitHub Desktop.
Save tenderlove/2869461 to your computer and use it in GitHub Desktop.
An adapter for Rack that makes it look like node
##
# Make Rack look like node.
#
# http://youtu.be/Zp91yUH-zAw
#
# Run like this:
#
# $ unicorn -I. app.ru
require 'node_adapter'
use Rack::Chunked
run createServer { |req, res|
res.writeHead(200, {'Content-Type' => 'text/plain'})
10.times do
res.chunk "hi mom!\n"
sleep 0.5
end
res.end "Hello World\n"
}
require 'thread'
class Adapter
class Latch # :nodoc:
def initialize
@mutex = Mutex.new
@cond = ConditionVariable.new
@released = false
end
def release
@mutex.synchronize {
@released = true
@cond.broadcast
}
end
def await
@mutex.synchronize {
@cond.wait @mutex unless @released
}
end
end
class Buffer < Struct.new(:q)
def each
while part = q.pop
yield part
end
end
end
class << self; attr_accessor :block; end
def self.call env
new(block).call env
end
def initialize block
@block = block
@code = 200
@header = {}
@body_written = Latch.new
@q = ::Queue.new
end
def call env
Thread.new { @block.call(env, self) }
# Wait for the child thread to write to the body,
# effectively "closing" the response.
@body_written.await
[@code, @header, Buffer.new(@q)]
end
def writeHead code, header
@code = code
@header = header
end
def chunk string
@body_written.release
@q.push string
end
def end string
@body_written.release
@q.push string
@q.push nil
end
end
def createServer &block
Adapter.block = block
Adapter
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment