Skip to content

Instantly share code, notes, and snippets.

@mascarenhas
Created April 14, 2011 01:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mascarenhas/918768 to your computer and use it in GitHub Desktop.
Save mascarenhas/918768 to your computer and use it in GitHub Desktop.
Proof of concept for FastCGI handler with helper threads
#!/usr/bin/env lua
-- Example application for the FastCGI handler with helper threads
local fastcgi = require "thfcgi"
local hello = {}
local heartbeat = [[
local zmq = require "zmq"
local socket = require "socket"
local luabins = require "luabins"
local ctx = zmq.init_ctx(...)
local s = ctx:socket(zmq.REQ)
s:connect("inproc://wsapi")
local i = 1
while true do
socket.sleep(1)
s:send(luabins.save("beat", i))
i = i + 1
if s:recv() ~= "ack" then
break
end
end
s:close()
]]
hello.helpers = { heartbeat }
function hello.run(wsapi_env)
local headers = { ["Content-type"] = "text/html" }
local function hello_text()
coroutine.yield("<html><body>")
coroutine.yield("<p>Hello Wsapi!</p>")
coroutine.yield("<p>PATH_INFO: " .. wsapi_env.PATH_INFO .. "</p>")
coroutine.yield("<p>SCRIPT_NAME: " .. wsapi_env.SCRIPT_NAME .. "</p>")
coroutine.yield("</body></html>")
end
return 200, headers, coroutine.wrap(hello_text)
end
function hello:beat(i)
local log = io.open("/tmp/hello.tmp", "a+")
log:write("Heartbeat " .. i .. "\n")
log:close()
end
fastcgi.run(hello)
-------------------------------------------------------------
--- Proof of concept for FastCGI handler with helper threads
-------------------------------------------------------------
local llthreads = require "llthreads"
local lfcgi = require "lfcgi"
local os = require "os"
local io = require "io"
local common = require "wsapi.common"
local zmq = require "zmq"
local luabins = require "luabins"
local ipairs = ipairs
local print = print
local type = type
local select = select
local pcall = pcall
local unpack = unpack
local _M = {}
io.stdout = lfcgi.stdout
io.stderr = lfcgi.stderr
io.stdin = lfcgi.stdin
local accept = [=[
local lfcgi = require "lfcgi"
local zmq = require "zmq"
local luabins = require "luabins"
local ctx = zmq.init_ctx(...)
local s = ctx:socket(zmq.REQ)
s:connect("inproc://wsapi")
while lfcgi.accept() >= 0 do
s:send(luabins.save("accept"))
if s:recv() ~= "ack" then
break
end
end
s:close()
]=]
-- Runs an WSAPI application for each FastCGI request that comes
-- from the FastCGI pipeline
function _M.run(app)
if type(app) == "function" then
app = { helpers = {}, run = app }
end
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REP)
s:bind("inproc://wsapi")
local threads = {}
threads.accept = llthreads.new(accept, ctx:lightuserdata())
threads.accept:start()
for i, code in ipairs(app.helpers) do
threads[i] = llthreads.new(code, ctx:lightuserdata())
threads[i]:start()
end
while true do
local msg = { luabins.load(s:recv()) }
if not msg[1] then
error(msg[2])
end
local method = msg[2]
if method == "accept" then
local headers
local function getenv(n)
if n == "headers" then
if headers then return headers end
local env_vars = lfcgi.environ()
headers = {}
for _, s in ipairs(env_vars) do
local name, val = s:match("^([^=]+)=(.*)$")
headers[name] = val
end
return headers
else
return lfcgi.getenv(n) or os.getenv(n)
end
end
common.run(app, { input = lfcgi.stdin,
output = lfcgi.stdout,
error = lfcgi.stderr,
env = getenv })
s:send("ack")
else
local ok, err = pcall(app[method], app, select(3, unpack(msg)))
if ok then
s:send("ack")
else
s:send(err)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment