Skip to content

Commit

Permalink
better sessions; route modules and urlfor; other small changes
Browse files Browse the repository at this point in the history
  • Loading branch information
benglard committed Oct 18, 2015
1 parent fa78d2d commit 6eed118
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 194 deletions.
51 changes: 37 additions & 14 deletions README.md
Expand Up @@ -251,20 +251,21 @@ end)
Waffle has both in-memory and redis sessions using [redis-async](https://github.com/ocallaco/redis-async).

```lua
local app = require('waffle')
app.session('redis')
local app = require('../waffle').CmdLine()

app.get('/', function(req, res)
app.session:get('n', function(n)
if n == nil then n = 0 end
n = tonumber(n)
if app.session.type == 'memory' then
local n = app.session.n or 0
res.send('#' .. n)
if n > 19 then
app.session:delete('n')
else
app.session.n = n + 1
end
end)
if n > 19 then app.session.n = nil
else app.session.n = n + 1 end
else
app.session:get('n', function(n)
res.send('#' .. n)
if n > 19 then app.session:delete('n')
else app.session.n = n + 1 end
end, 0)
end
end)

app.listen()
Expand All @@ -277,6 +278,30 @@ app.get('/', function(req, res)
end)
```

## urlfor and Modules

```lua
-- Add a name parameter, e.g. 'test'
app.get('/test', function(req, res) res.send('Hello World!') end, 'test')

-- Retreive url corresponding to route named 'test'
local url = app.urlfor('test')
```

Modules let you group routes together by url and name (really by function)

```lua
app.module('/', 'home') -- Home Routes
.get('', function(req, res) res.send 'Home' end, 'index')
.get('test', function(req, res) res.send 'Test' end, 'test')

app.module('/auth', 'auth') -- Authentication Routes
.get('', function(req, res) res.redirect(app.urlfor('auth.login'))
end, 'index')
.get('/login', function(req, res) res.send 'Login' end, 'login')
.get('/signup', function(req, res) res.send 'Signup' end, 'signup')
```

## Command Line Options

Allows you to write every currently possible waffle application property as a command line option, and have it handled seamlessly.
Expand Down Expand Up @@ -364,6 +389,4 @@ app.listen()
## TODO
* Named URL route parameters
* Automatic caching of static files
* Testing
* Documentation
* more?
* Secure cookies & cookie based sessions
14 changes: 12 additions & 2 deletions examples/demo.lua
Expand Up @@ -9,7 +9,7 @@ app.get('/', function(req, res)
<body>Hello</body>
</html>
]]
end)
end, 'index')

app.post('/', function(req, res)
res.send('Posting...')
Expand All @@ -25,7 +25,7 @@ end)

app.get('/test', function(req, res)
res.send('Hello World!')
end)
end, 'test')

app.get('/html', function(req, res)
res.sendFile('./examples/index.html')
Expand All @@ -43,6 +43,12 @@ app.get('/lua', function(req, res)
res.sendFile('./examples/demo.lua')
end)

app.get('/user/(%a+)/(%d+)', function(req, res)
local name = req.params[1]
local idx = req.params[2]
res.send(string.format('Hello, %s, %d', name, idx))
end, 'user.name.index')

app.get('/user/(%d+)', function(req, res)
local userId = tonumber(req.params[1])
local users = {
Expand Down Expand Up @@ -93,4 +99,8 @@ app.error(500, function(description, req, res)
end
end)

print(app.urlfor('index'))
print(app.urlfor('test'))
print(app.urlfor('user.name.index', { ['(%a+)'] = 'Lua', ['(%d+)'] = 1 }))

app.listen()
23 changes: 23 additions & 0 deletions examples/modules.lua
@@ -0,0 +1,23 @@
local app = require('../waffle')
local urlfor = app.urlfor

-- Home Routes

app.module('/', 'home')
.get('', function(req, res) res.send 'Home' end, 'index')
.get('test', function(req, res) res.send 'Test' end, 'test')

-- Authentication Routes

app.module('/auth', 'auth')
.get('', function(req, res) res.redirect(urlfor 'auth.login')
end, 'index')
.get('/login', function(req, res) res.send 'Login' end, 'login')
.get('/signup', function(req, res) res.send 'Signup' end, 'signup')

app.error(404, function(des, req, res)
res.redirect(app.urlfor 'home.index')
end)

print(app.viewFuncs)
app.listen()
41 changes: 12 additions & 29 deletions examples/session.lua
@@ -1,35 +1,18 @@
local app = require('../waffle') --.CmdLine()
local async = require 'async'

-- Test

--[[app.session('cache')
app.session['test'] = true
print(app.session.test)
app.session.data = nil
app.session('redis')
async.setTimeout(100, function()
app.session['test'] = true
app.session:get('test', function(data)
print(data)
end)
end)]]

app.session('redis')
local app = require('../waffle').CmdLine()

app.get('/', function(req, res)
app.session:get('n', function(n)
if n == nil then n = 0 end
n = tonumber(n)
if app.session.type == 'memory' then
local n = app.session.n or 0
res.send('#' .. n)
if n > 19 then
app.session:delete('n')
else
app.session.n = n + 1
end
end)
if n > 19 then app.session.n = nil
else app.session.n = n + 1 end
else
app.session:get('n', function(n)
res.send('#' .. n)
if n > 19 then app.session:delete('n')
else app.session.n = n + 1 end
end, 0)
end
end)

app.listen()
79 changes: 59 additions & 20 deletions waffle/app.lua
Expand Up @@ -9,6 +9,10 @@ local Cache = require 'waffle.cache'
local Session = require 'waffle.session'
local WebSocket = require 'waffle.websocket'

local _httpverbs = {
'head', 'get', 'post', 'delete', 'patch', 'put', 'options'
}

local app = {}
app.viewFuncs = {}
app.errorFuncs = {}
Expand Down Expand Up @@ -36,7 +40,9 @@ app.set = function(field, value)
end
end

local _handle = function(request, handler)
local _handle = function(request, handler, client)
request.socket = client

local url = request.url.path
local method = request.method
local delim = ''
Expand All @@ -59,6 +65,7 @@ local _handle = function(request, handler)
request.params = cache.match
request.url.args = cache.args
wrequest(request)
app.session:start(request, response)
cache.cb(request, response)
end
return nil
Expand All @@ -82,6 +89,7 @@ local _handle = function(request, handler)
end
end
wrequest(request)
app.session:start(request, response)

if funcs[method] then
local ok, err = pcall(funcs[method], request, response)
Expand Down Expand Up @@ -121,39 +129,53 @@ app.listen = function(options)
async.go()
end

app.serve = function(url, method, cb)
app.serve = function(url, method, cb, name)
utils.stringassert(url)
utils.stringassert(method)
assert(cb ~= nil)

if app.viewFuncs[url] == nil then
app.viewFuncs[url] = {}
end
app.viewFuncs[url][method] = cb
app.viewFuncs[url][method] = setmetatable(
{ name = name },
{ __call = function(_, ...) return cb(...) end }
)
end

app.get = function(url, cb) app.serve(url, 'GET', cb)
for _, verb in pairs(_httpverbs) do
app[verb] = function(url, cb, name)
app.serve(url, verb:upper(), cb, name)
end
end

app.post = function(url, cb) app.serve(url, 'POST', cb)
end
app.urlfor = function(search, replacements)
for pattern, funcs in pairs(app.viewFuncs) do
for verb, handlers in pairs(funcs) do
local name = handlers.name
if name ~= nil and name == search then
if replacements == nil then
return pattern
else
local gsub = string.gsub
local find = '[%%%]%^%-$().[*+?]'
local replace = '%%%1'

app.put = function(url, cb) app.serve(url, 'PUT', cb)
end
for key, value in pairs(replacements) do
local search = gsub(key, find, replace)
pattern = gsub(pattern, search, value)
end

app.delete = function(url, cb) app.serve(url, 'DELETE', cb)
return pattern
end
end
end
end
end

app.ws = {
defined = false,
clients = WebSocket.clients
}
app.ws = { clients = WebSocket.clients }

app.ws.serve = function(url, cb)
if not app.ws.defined then
async.http.listen = WebSocket.listen
app.ws.defined = true
end
app.get(url, function(req, res)
local ws = WebSocket(req, res)
local ok, err = pcall(cb, ws) -- implement ws methods
Expand Down Expand Up @@ -214,11 +236,10 @@ app.CmdLine = function(args)
cmd:option('--replhost', '127.0.0.1', 'Host IP on which to recieve REPL requests')
cmd:option('--replport', '8081', 'Host Port on which to recieve REPL requests')
cmd:option('--print', false, 'Print the method and url of every request if true')
cmd:option('--session', 'cache', 'Type of session: cache | redis')
cmd:option('--sessionsize', 1000, 'Size of session (only valid for cached sessions)')
cmd:option('--session', 'memory', 'Type of session: memory | redis')
cmd:option('--redishost', '127.0.0.1', 'Redis host (only valid for redis sessions)')
cmd:option('--redisport', '6379', 'Redis port (only valid for redis sessions)')
cmd:option('--redisprefix', 'waffle-', 'Redis key prefix (only valid for redis sessions)')
cmd:option('--redisprefix', 'waffle', 'Redis key prefix (only valid for redis sessions)')
cmd:option('--cachesize', 20, 'Size of URL cache')
cmd:option('--autocache', false, 'Automatically cache response body, headers, and status code if true')
cmd:text()
Expand All @@ -227,6 +248,24 @@ app.CmdLine = function(args)
return app(opt)
end

app.module = function(urlprefix, modname)
utils.stringassert(urlprefix)
utils.stringassert(modname)

local mod = {}
local format = string.format

for _, verb in pairs(_httpverbs) do
mod[verb] = function(url, cb, name)
local fullurl = format('%s%s', urlprefix, url)
local fullname = format('%s.%s', modname, name)
app[verb](fullurl, cb, fullname)
return mod
end
end
return mod
end

setmetatable(app, {
__call = function(self, options)
options = options or {}
Expand Down
17 changes: 17 additions & 0 deletions waffle/encodings.lua
Expand Up @@ -24,4 +24,21 @@ encodings.urldecode = function(url)
return rv
end

encodings.uuid4 = function()
local rv = {}
local rand = math.random
local format = string.format

local map = { '8', '9', 'a', 'b' }
local y = map[rand(1, 4)]

rv[1] = format('%08x', rand(0, 4294967295)) -- 2**32 - 1
rv[2] = format('%04x', rand(0, 65535)) -- 2**16 - 1
rv[3] = format('4%03x', rand(0, 4095)) -- 2**12 - 1
rv[4] = format('%s%03x', y, rand(0, 4095)) -- 2**12 - 1
rv[5] = format('%012x', rand(0, 281474976710656)) -- 2**48 - 1

return table.concat(rv, '-')
end

return encodings

0 comments on commit 6eed118

Please sign in to comment.