初始化提交
This commit is contained in:
		
							
								
								
									
										110
									
								
								doc/nginx/lua/MySQLOps.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								doc/nginx/lua/MySQLOps.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
---
 | 
			
		||||
--- Created by mark.
 | 
			
		||||
--- Desc: 演示对OpenResty中使用Lua对MySQL操作
 | 
			
		||||
--- Note:本Lua脚本借鉴了网络,未经测试,仅供参考,也不提供任何技术支持
 | 
			
		||||
---
 | 
			
		||||
local function close_db(db)
 | 
			
		||||
    if not db then
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    db:close()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local mysql = require("resty.mysql")
 | 
			
		||||
 | 
			
		||||
local db, err = mysql:new()
 | 
			
		||||
if not db then
 | 
			
		||||
    ngx.say("new mysql error : ", err)
 | 
			
		||||
    return
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
db:set_timeout(1000)
 | 
			
		||||
 | 
			
		||||
local props = {
 | 
			
		||||
    host = "127.0.0.1",
 | 
			
		||||
    port = 3306,
 | 
			
		||||
    database = "mysql",
 | 
			
		||||
    user = "root",
 | 
			
		||||
    password = "123"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local res, err, errno, sqlstate = db:connect(props)
 | 
			
		||||
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
---------------------------------------
 | 
			
		||||
-- 执行SQL语句范例
 | 
			
		||||
 | 
			
		||||
local create_table_sql = "create table test(id int primary key auto_increment, ch varchar(100))"
 | 
			
		||||
res, err, errno, sqlstate = db:query(create_table_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("create table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local drop_table_sql = "drop table if exists test"
 | 
			
		||||
res, err, errno, sqlstate = db:query(drop_table_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("drop table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local insert_sql = "insert into test (ch) values('hello')"
 | 
			
		||||
res, err, errno, sqlstate = db:query(insert_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("insert error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
res, err, errno, sqlstate = db:query(insert_sql)
 | 
			
		||||
ngx.say("insert rows : ", res.affected_rows, " , id : ", res.insert_id, "<br/>")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local update_sql = "update test set ch = 'hello2' where id =" .. res.insert_id
 | 
			
		||||
res, err, errno, sqlstate = db:query(update_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("update error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
ngx.say("update rows : ", res.affected_rows, "<br/>")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local select_sql = "select id, ch from test"
 | 
			
		||||
res, err, errno, sqlstate = db:query(select_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
for i, row in ipairs(res) do
 | 
			
		||||
    for name, value in pairs(row) do
 | 
			
		||||
        ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
ngx.say("<br/>")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local ch_param = ngx.req.get_uri_args()["ch"] or ''
 | 
			
		||||
local query_sql = "select id, ch from test where ch = " .. ngx.quote_sql_str(ch_param)
 | 
			
		||||
res, err, errno, sqlstate = db:query(query_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
for i, row in ipairs(res) do
 | 
			
		||||
    for name, value in pairs(row) do
 | 
			
		||||
        ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local delete_sql = "delete from test"
 | 
			
		||||
res, err, errno, sqlstate = db:query(delete_sql)
 | 
			
		||||
if not res then
 | 
			
		||||
    ngx.say("delete error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
 | 
			
		||||
    return close_db(db)
 | 
			
		||||
end
 | 
			
		||||
ngx.say("delete rows : ", res.affected_rows, "<br/>")
 | 
			
		||||
 | 
			
		||||
close_db(db)
 | 
			
		||||
							
								
								
									
										320
									
								
								doc/nginx/lua/RedisExtOps.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								doc/nginx/lua/RedisExtOps.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,320 @@
 | 
			
		||||
---
 | 
			
		||||
--- Desc: 对OpenResty中使用Lua对Redis操作的封装库,支持订阅、管道等功能
 | 
			
		||||
--- Note:本Lua脚本借鉴了网络,未经测试,仅供参考,也不提供任何技术支持
 | 
			
		||||
---
 | 
			
		||||
local redis_c = require "resty.redis"
 | 
			
		||||
 | 
			
		||||
local ok, new_tab = pcall(require, "table.new")
 | 
			
		||||
if not ok or type(new_tab) ~= "function" then
 | 
			
		||||
    new_tab = function (narr, nrec) return {} end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local _M = new_tab(0, 155)
 | 
			
		||||
_M._VERSION = '0.01'
 | 
			
		||||
 | 
			
		||||
local commands = {
 | 
			
		||||
    "append",            "auth",              "bgrewriteaof",
 | 
			
		||||
    "bgsave",            "bitcount",          "bitop",
 | 
			
		||||
    "blpop",             "brpop",
 | 
			
		||||
    "brpoplpush",        "client",            "config",
 | 
			
		||||
    "dbsize",
 | 
			
		||||
    "debug",             "decr",              "decrby",
 | 
			
		||||
    "del",               "discard",           "dump",
 | 
			
		||||
    "echo",
 | 
			
		||||
    "eval",              "exec",              "exists",
 | 
			
		||||
    "expire",            "expireat",          "flushall",
 | 
			
		||||
    "flushdb",           "get",               "getbit",
 | 
			
		||||
    "getrange",          "getset",            "hdel",
 | 
			
		||||
    "hexists",           "hget",              "hgetall",
 | 
			
		||||
    "hincrby",           "hincrbyfloat",      "hkeys",
 | 
			
		||||
    "hlen",
 | 
			
		||||
    "hmget",              "hmset",      "hscan",
 | 
			
		||||
    "hset",
 | 
			
		||||
    "hsetnx",            "hvals",             "incr",
 | 
			
		||||
    "incrby",            "incrbyfloat",       "info",
 | 
			
		||||
    "keys",
 | 
			
		||||
    "lastsave",          "lindex",            "linsert",
 | 
			
		||||
    "llen",              "lpop",              "lpush",
 | 
			
		||||
    "lpushx",            "lrange",            "lrem",
 | 
			
		||||
    "lset",              "ltrim",             "mget",
 | 
			
		||||
    "migrate",
 | 
			
		||||
    "monitor",           "move",              "mset",
 | 
			
		||||
    "msetnx",            "multi",             "object",
 | 
			
		||||
    "persist",           "pexpire",           "pexpireat",
 | 
			
		||||
    "ping",              "psetex",            "psubscribe",
 | 
			
		||||
    "pttl",
 | 
			
		||||
    "publish",      --[[ "punsubscribe", ]]   "pubsub",
 | 
			
		||||
    "quit",
 | 
			
		||||
    "randomkey",         "rename",            "renamenx",
 | 
			
		||||
    "restore",
 | 
			
		||||
    "rpop",              "rpoplpush",         "rpush",
 | 
			
		||||
    "rpushx",            "sadd",              "save",
 | 
			
		||||
    "scan",              "scard",             "script",
 | 
			
		||||
    "sdiff",             "sdiffstore",
 | 
			
		||||
    "select",            "set",               "setbit",
 | 
			
		||||
    "setex",             "setnx",             "setrange",
 | 
			
		||||
    "shutdown",          "sinter",            "sinterstore",
 | 
			
		||||
    "sismember",         "slaveof",           "slowlog",
 | 
			
		||||
    "smembers",          "smove",             "sort",
 | 
			
		||||
    "spop",              "srandmember",       "srem",
 | 
			
		||||
    "sscan",
 | 
			
		||||
    "strlen",       --[[ "subscribe",  ]]     "sunion",
 | 
			
		||||
    "sunionstore",       "sync",              "time",
 | 
			
		||||
    "ttl",
 | 
			
		||||
    "type",         --[[ "unsubscribe", ]]    "unwatch",
 | 
			
		||||
    "watch",             "zadd",              "zcard",
 | 
			
		||||
    "zcount",            "zincrby",           "zinterstore",
 | 
			
		||||
    "zrange",            "zrangebyscore",     "zrank",
 | 
			
		||||
    "zrem",              "zremrangebyrank",   "zremrangebyscore",
 | 
			
		||||
    "zrevrange",         "zrevrangebyscore",  "zrevrank",
 | 
			
		||||
    "zscan",
 | 
			
		||||
    "zscore",            "zunionstore",       "evalsha"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local mt = { __index = _M }
 | 
			
		||||
 | 
			
		||||
local function is_redis_null( res )
 | 
			
		||||
    if type(res) == "table" then
 | 
			
		||||
        for k,v in pairs(res) do
 | 
			
		||||
            if v ~= ngx.null then
 | 
			
		||||
                return false
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        return true
 | 
			
		||||
    elseif res == ngx.null then
 | 
			
		||||
        return true
 | 
			
		||||
    elseif res == nil then
 | 
			
		||||
        return true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function _M.close_redis(self, redis)
 | 
			
		||||
    if not redis then
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    --释放连接(连接池实现)
 | 
			
		||||
    local pool_max_idle_time = self.pool_max_idle_time --最大空闲时间 毫秒
 | 
			
		||||
    local pool_size = self.pool_size --连接池大小
 | 
			
		||||
 | 
			
		||||
    local ok, err = redis:set_keepalive(pool_max_idle_time, pool_size)
 | 
			
		||||
    if not ok then
 | 
			
		||||
        ngx.say("set keepalive error : ", err)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- change connect address as you need
 | 
			
		||||
function _M.connect_mod( self, redis )
 | 
			
		||||
    redis:set_timeout(self.timeout)
 | 
			
		||||
 | 
			
		||||
    local ok, err = redis:connect(self.ip, self.port)
 | 
			
		||||
    if not ok then
 | 
			
		||||
        ngx.say("connect to redis error : ", err)
 | 
			
		||||
        return self:close_redis(redis)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if self.password then ----密码认证
 | 
			
		||||
    local count, err = redis:get_reused_times()
 | 
			
		||||
        if 0 == count then ----新建连接,需要认证密码
 | 
			
		||||
        ok, err = redis:auth(self.password)
 | 
			
		||||
            if not ok then
 | 
			
		||||
                ngx.say("failed to auth: ", err)
 | 
			
		||||
                return
 | 
			
		||||
            end
 | 
			
		||||
        elseif err then  ----从连接池中获取连接,无需再次认证密码
 | 
			
		||||
        ngx.say("failed to get reused times: ", err)
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return ok,err;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function _M.init_pipeline( self )
 | 
			
		||||
    self._reqs = {}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function _M.commit_pipeline( self )
 | 
			
		||||
    local reqs = self._reqs
 | 
			
		||||
 | 
			
		||||
    if nil == reqs or 0 == #reqs then
 | 
			
		||||
        return {}, "no pipeline"
 | 
			
		||||
    else
 | 
			
		||||
        self._reqs = nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local redis, err = redis_c:new()
 | 
			
		||||
    if not redis then
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local ok, err = self:connect_mod(redis)
 | 
			
		||||
    if not ok then
 | 
			
		||||
        return {}, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    redis:init_pipeline()
 | 
			
		||||
    for _, vals in ipairs(reqs) do
 | 
			
		||||
        local fun = redis[vals[1]]
 | 
			
		||||
        table.remove(vals , 1)
 | 
			
		||||
 | 
			
		||||
        fun(redis, unpack(vals))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local results, err = redis:commit_pipeline()
 | 
			
		||||
    if not results or err then
 | 
			
		||||
        return {}, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if is_redis_null(results) then
 | 
			
		||||
        results = {}
 | 
			
		||||
        ngx.log(ngx.WARN, "is null")
 | 
			
		||||
    end
 | 
			
		||||
    -- table.remove (results , 1)
 | 
			
		||||
 | 
			
		||||
    --self.set_keepalive_mod(redis)
 | 
			
		||||
    self:close_redis(redis)
 | 
			
		||||
 | 
			
		||||
    for i,value in ipairs(results) do
 | 
			
		||||
        if is_redis_null(value) then
 | 
			
		||||
            results[i] = nil
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return results, err
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function do_command(self, cmd, ... )
 | 
			
		||||
    if self._reqs then
 | 
			
		||||
        table.insert(self._reqs, {cmd, ...})
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local redis, err = redis_c:new()
 | 
			
		||||
    if not redis then
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local ok, err = self:connect_mod(redis)
 | 
			
		||||
    if not ok or err then
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    redis:select(self.db_index)
 | 
			
		||||
 | 
			
		||||
    local fun = redis[cmd]
 | 
			
		||||
    local result, err = fun(redis, ...)
 | 
			
		||||
    if not result or err then
 | 
			
		||||
        -- ngx.log(ngx.ERR, "pipeline result:", result, " err:", err)
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if is_redis_null(result) then
 | 
			
		||||
        result = nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    --self.set_keepalive_mod(redis)
 | 
			
		||||
    self:close_redis(redis)
 | 
			
		||||
 | 
			
		||||
    return result, err
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
for i = 1, #commands do
 | 
			
		||||
    local cmd = commands[i]
 | 
			
		||||
    _M[cmd] =
 | 
			
		||||
    function (self, ...)
 | 
			
		||||
        return do_command(self, cmd, ...)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function _M.new(self, opts)
 | 
			
		||||
    opts = opts or {}
 | 
			
		||||
    local timeout = (opts.timeout and opts.timeout * 1000) or 1000
 | 
			
		||||
    local db_index= opts.db_index or 0
 | 
			
		||||
    local ip = opts.ip or '127.0.0.1'
 | 
			
		||||
    local port = opts.port or 6379
 | 
			
		||||
    local password = opts.password
 | 
			
		||||
    local pool_max_idle_time = opts.pool_max_idle_time or 60000
 | 
			
		||||
    local pool_size = opts.pool_size or 100
 | 
			
		||||
 | 
			
		||||
    return setmetatable({
 | 
			
		||||
        timeout = timeout,
 | 
			
		||||
        db_index = db_index,
 | 
			
		||||
        ip = ip,
 | 
			
		||||
        port = port,
 | 
			
		||||
        password = password,
 | 
			
		||||
        pool_max_idle_time = pool_max_idle_time,
 | 
			
		||||
        pool_size = pool_size,
 | 
			
		||||
        _reqs = nil }, mt)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function _M.subscribe( self, channel )
 | 
			
		||||
    local redis, err = redis_c:new()
 | 
			
		||||
    if not redis then
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local ok, err = self:connect_mod(redis)
 | 
			
		||||
    if not ok or err then
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local res, err = redis:subscribe(channel)
 | 
			
		||||
    if not res then
 | 
			
		||||
        return nil, err
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local function do_read_func ( do_read )
 | 
			
		||||
        if do_read == nil or do_read == true then
 | 
			
		||||
            res, err = redis:read_reply()
 | 
			
		||||
            if not res then
 | 
			
		||||
                return nil, err
 | 
			
		||||
            end
 | 
			
		||||
            return res
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        redis:unsubscribe(channel)
 | 
			
		||||
        self.set_keepalive_mod(redis)
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return do_read_func
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return _M
 | 
			
		||||
 | 
			
		||||
---------------------------------------
 | 
			
		||||
-- 调用案例
 | 
			
		||||
 | 
			
		||||
local redis = require "RedisExtOps"
 | 
			
		||||
local opts = {
 | 
			
		||||
    ip = "10.11.0.215",
 | 
			
		||||
    port = "6379",
 | 
			
		||||
    password = "redis123",
 | 
			
		||||
    db_index = 1
 | 
			
		||||
}
 | 
			
		||||
local red = redis:new(opts)
 | 
			
		||||
local ok, err = red:set("dog", "an animal")
 | 
			
		||||
if not ok then
 | 
			
		||||
    ngx.say("failed to set dog: ", err)
 | 
			
		||||
    return
 | 
			
		||||
end
 | 
			
		||||
ngx.say("set result: ", ok)
 | 
			
		||||
 | 
			
		||||
---------------------------------------
 | 
			
		||||
-- 管道
 | 
			
		||||
red:init_pipeline()
 | 
			
		||||
red:set("cat", "Marry")
 | 
			
		||||
red:set("horse", "Bob")
 | 
			
		||||
red:get("cat")
 | 
			
		||||
red:get("horse")
 | 
			
		||||
local results, err = red:commit_pipeline()
 | 
			
		||||
if not results then
 | 
			
		||||
    ngx.say("failed to commit the pipelined requests: ", err)
 | 
			
		||||
    return
 | 
			
		||||
end
 | 
			
		||||
for i, res in ipairs(results) do
 | 
			
		||||
    ngx.say(res,"<br/>");
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										14
									
								
								doc/nginx/lua/product.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								doc/nginx/lua/product.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
-- 导入lua-resty-template函数库
 | 
			
		||||
local template = require('resty.template')
 | 
			
		||||
local flashPromotionId = ngx.var.arg_flashPromotionId
 | 
			
		||||
ngx.log(ngx.ERR, "秒杀活动ID: ", flashPromotionId)
 | 
			
		||||
local promotionProductId = ngx.var.arg_promotionProductId
 | 
			
		||||
ngx.log(ngx.ERR, "秒杀产品ID: ", promotionProductId)
 | 
			
		||||
local templateName = "seckill_"..flashPromotionId.."_"..promotionProductId..".html"
 | 
			
		||||
local context = {
 | 
			
		||||
    memberId = ngx.var.arg_memberId,
 | 
			
		||||
    productId = promotionProductId,
 | 
			
		||||
    flashPromotionId = flashPromotionId
 | 
			
		||||
}
 | 
			
		||||
ngx.log(ngx.ERR, "渲染页面输出,获得当前用户ID: ", context.memberId)
 | 
			
		||||
template.render(templateName, context)
 | 
			
		||||
							
								
								
									
										58
									
								
								doc/nginx/lua/redisOps.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								doc/nginx/lua/redisOps.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
-- 导入redis的Lua模块
 | 
			
		||||
local redis = require('resty.redis')
 | 
			
		||||
-- 初始化redis
 | 
			
		||||
local red = redis:new()
 | 
			
		||||
red:set_timeouts(1000, 1000, 1000)
 | 
			
		||||
 | 
			
		||||
-- 关闭redis连接的工具方法,其实是放入连接池
 | 
			
		||||
local function close_redis(red)
 | 
			
		||||
    local pool_max_idle_time = 10000 -- 连接的空闲时间,单位是毫秒
 | 
			
		||||
    local pool_size = 100 --连接池大小
 | 
			
		||||
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
 | 
			
		||||
    if not ok then
 | 
			
		||||
        ngx.log(ngx.ERR, "放入redis连接池失败: ", err)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- 查询redis的方法 ip和port是redis地址,key是查询的key
 | 
			
		||||
local function read_redis(ip, port, key)
 | 
			
		||||
    -- 获取一个连接
 | 
			
		||||
    local ok, err = red:connect(ip, port)
 | 
			
		||||
    if not ok then
 | 
			
		||||
        ngx.log(ngx.ERR, "连接redis失败 : ", err)
 | 
			
		||||
        return nil
 | 
			
		||||
    end
 | 
			
		||||
    -- 查询redis
 | 
			
		||||
    local resp, err = red:get(key)
 | 
			
		||||
    -- 查询失败处理
 | 
			
		||||
    if not resp then
 | 
			
		||||
        ngx.log(ngx.ERR, "查询Redis失败: ", err, ", key = " , key)
 | 
			
		||||
    end
 | 
			
		||||
    --得到的数据为空处理
 | 
			
		||||
    if resp == ngx.null then
 | 
			
		||||
        resp = nil
 | 
			
		||||
        ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key)
 | 
			
		||||
    end
 | 
			
		||||
    close_redis(red)
 | 
			
		||||
    return resp
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- 封装函数,发送http请求,并解析响应
 | 
			
		||||
local function read_http(path, params)
 | 
			
		||||
    local resp = ngx.location.capture(path,{
 | 
			
		||||
        method = ngx.HTTP_GET,
 | 
			
		||||
        args = params,
 | 
			
		||||
    })
 | 
			
		||||
    if not resp then
 | 
			
		||||
        -- 记录错误信息,返回404
 | 
			
		||||
        ngx.log(ngx.ERR, "http查询失败, path: ", path , ", args: ", args)
 | 
			
		||||
        ngx.exit(404)
 | 
			
		||||
    end
 | 
			
		||||
    return resp.body
 | 
			
		||||
end
 | 
			
		||||
-- 将方法导出
 | 
			
		||||
local _M = {
 | 
			
		||||
    read_http = read_http,
 | 
			
		||||
    read_redis = read_redis
 | 
			
		||||
}
 | 
			
		||||
return _M
 | 
			
		||||
							
								
								
									
										42
									
								
								doc/nginx/lua/stock.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								doc/nginx/lua/stock.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
-- 导入redisOps函数库
 | 
			
		||||
local redisOps = require('redisOps')
 | 
			
		||||
local read_redis = redisOps.read_redis
 | 
			
		||||
-- 导入cjson库
 | 
			
		||||
local cjson = require('cjson')
 | 
			
		||||
-- 导入共享词典,本地缓存
 | 
			
		||||
-- 本地缓存的主要目的为库存检查,当商品的库存<=0时,提前终止秒杀
 | 
			
		||||
-- 这里从业务上来说,同样需要解决退单等引发的库存增加允许重新秒杀的情况,
 | 
			
		||||
-- 解决思路:同样可以订阅对应的Redis的channel,本次不做具体实现,Lua订阅Redis的Channel的参考代码写在RedisExtOps.lua中
 | 
			
		||||
local item_cache = ngx.shared.stock_cache
 | 
			
		||||
 | 
			
		||||
-- 封装查询函数
 | 
			
		||||
function read_data(key, expire)
 | 
			
		||||
    -- 查询本地缓存
 | 
			
		||||
    local val = item_cache:get(key)
 | 
			
		||||
    if not val then
 | 
			
		||||
        ngx.log(ngx.ERR, "本地缓存查询失败,尝试查询Redis, key: ", key)
 | 
			
		||||
        -- 查询redis
 | 
			
		||||
        val = read_redis("127.0.0.1", 6379, key)
 | 
			
		||||
        -- 判断查询结果
 | 
			
		||||
        if not val then
 | 
			
		||||
            ngx.log(ngx.ERR, "redis查询失败,key: ", key)
 | 
			
		||||
            -- redis查询失败,给一个缺省值
 | 
			
		||||
            val = 0
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    -- 查询成功,把数据写入本地缓存,expire秒后过期
 | 
			
		||||
    if tonumber(val) <= 0 then
 | 
			
		||||
        item_cache:set(key, val, expire)
 | 
			
		||||
    end
 | 
			
		||||
    -- 返回数据
 | 
			
		||||
    return val
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- 获取请求参数中的productId,也可以使用ngx.req.get_uri_args["productId"],req.get_uri_args在productId有多个时,会返回一个table
 | 
			
		||||
local product_id = ngx.var.arg_productId
 | 
			
		||||
 | 
			
		||||
-- 查询库存信息
 | 
			
		||||
local stock = read_data("miaosha:stock:cache:"..product_id, 3600)
 | 
			
		||||
 | 
			
		||||
-- 返回结果
 | 
			
		||||
ngx.say(cjson.encode(stock))
 | 
			
		||||
							
								
								
									
										94
									
								
								doc/nginx/nginx.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								doc/nginx/nginx.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
worker_processes  7;        #nginx worker 数量
 | 
			
		||||
error_log logs/error.log;   #指定错误日志文件路径
 | 
			
		||||
events {
 | 
			
		||||
    worker_connections 1024;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
http {
 | 
			
		||||
 | 
			
		||||
    include       mime.types;
 | 
			
		||||
    # 这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,
 | 
			
		||||
    # 建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。
 | 
			
		||||
    open_file_cache max=100 inactive=30s;
 | 
			
		||||
 | 
			
		||||
    # open_file_cache 指令中的inactive 参数时间内文件的最少使用次数,
 | 
			
		||||
    # 如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个
 | 
			
		||||
    # 文件在inactive 时间内一次没被使用,它将被移除。
 | 
			
		||||
    open_file_cache_min_uses 1;
 | 
			
		||||
 | 
			
		||||
    # 这个是指多长时间检查一次缓存的有效信息
 | 
			
		||||
    open_file_cache_valid 60s;
 | 
			
		||||
 | 
			
		||||
    #开启高效文件传输模式
 | 
			
		||||
    sendfile on;
 | 
			
		||||
    #提高I/O性能
 | 
			
		||||
    tcp_nodelay on;
 | 
			
		||||
 | 
			
		||||
    access_log  logs/access.log;
 | 
			
		||||
 | 
			
		||||
    #lua 模块
 | 
			
		||||
    lua_package_path "/usr/local/openresty/lua/?.lua;/usr/local/openresty/lualib/?.lua;;";
 | 
			
		||||
    #c模块
 | 
			
		||||
    lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
 | 
			
		||||
    lua_code_cache on;
 | 
			
		||||
 | 
			
		||||
    # 共享字典,也就是本地缓存,名称叫做:stock_cache,大小1m
 | 
			
		||||
    lua_shared_dict stock_cache 1m;
 | 
			
		||||
 | 
			
		||||
    #秒杀确认页相关负载均衡
 | 
			
		||||
    upstream confirm {
 | 
			
		||||
         server 192.168.65.155:8855;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #秒杀订单相关负载均衡
 | 
			
		||||
    upstream order {
 | 
			
		||||
         server 192.168.65.133:8844;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    server {
 | 
			
		||||
        #监听端口
 | 
			
		||||
        listen 80;
 | 
			
		||||
 | 
			
		||||
        charset utf-8;
 | 
			
		||||
 | 
			
		||||
        set $template_root /usr/local/openresty/tpl;
 | 
			
		||||
 | 
			
		||||
        location /test {
 | 
			
		||||
            default_type text/html;
 | 
			
		||||
            content_by_lua_block {
 | 
			
		||||
                ngx.say("泰勒斯说万物充满了神明,是让我们把神明拉下神座,从此诸神迎来了他们的黄昏")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #产品静态模板化网页访问
 | 
			
		||||
        location /product {
 | 
			
		||||
            default_type text/html;
 | 
			
		||||
            content_by_lua_file lua/product.lua;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #静态资源访问
 | 
			
		||||
        location /static {
 | 
			
		||||
            root /usr/local/openresty;
 | 
			
		||||
            index index.html index.htm;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #秒杀确认页反向代理
 | 
			
		||||
        location /skcart {
 | 
			
		||||
            proxy_pass http://confirm;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #秒杀订单反向代理
 | 
			
		||||
        location /seckillOrder {
 | 
			
		||||
            proxy_pass http://order;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #秒杀产品当前库存
 | 
			
		||||
        location /cache/stock {
 | 
			
		||||
            # 默认的响应类型
 | 
			
		||||
            default_type application/json;
 | 
			
		||||
            # 响应结果由lua/stock.lua文件来处理
 | 
			
		||||
            content_by_lua_file lua/stock.lua;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										688
									
								
								doc/nginx/template/template.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										688
									
								
								doc/nginx/template/template.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,688 @@
 | 
			
		||||
local setmetatable = setmetatable
 | 
			
		||||
local loadstring = loadstring
 | 
			
		||||
local tostring = tostring
 | 
			
		||||
local setfenv = setfenv
 | 
			
		||||
local require = require
 | 
			
		||||
local concat = table.concat
 | 
			
		||||
local assert = assert
 | 
			
		||||
local write = io.write
 | 
			
		||||
local pcall = pcall
 | 
			
		||||
local phase
 | 
			
		||||
local open = io.open
 | 
			
		||||
local load = load
 | 
			
		||||
local type = type
 | 
			
		||||
local dump = string.dump
 | 
			
		||||
local find = string.find
 | 
			
		||||
local gsub = string.gsub
 | 
			
		||||
local byte = string.byte
 | 
			
		||||
local null
 | 
			
		||||
local sub = string.sub
 | 
			
		||||
local ngx = ngx
 | 
			
		||||
local jit = jit
 | 
			
		||||
local var
 | 
			
		||||
 | 
			
		||||
local _VERSION = _VERSION
 | 
			
		||||
local _ENV = _ENV -- luacheck: globals _ENV
 | 
			
		||||
local _G = _G
 | 
			
		||||
 | 
			
		||||
local HTML_ENTITIES = {
 | 
			
		||||
    ["&"] = "&",
 | 
			
		||||
    ["<"] = "<",
 | 
			
		||||
    [">"] = ">",
 | 
			
		||||
    ['"'] = """,
 | 
			
		||||
    ["'"] = "'",
 | 
			
		||||
    ["/"] = "/"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local CODE_ENTITIES = {
 | 
			
		||||
    ["{"] = "{",
 | 
			
		||||
    ["}"] = "}",
 | 
			
		||||
    ["&"] = "&",
 | 
			
		||||
    ["<"] = "<",
 | 
			
		||||
    [">"] = ">",
 | 
			
		||||
    ['"'] = """,
 | 
			
		||||
    ["'"] = "'",
 | 
			
		||||
    ["/"] = "/"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local VAR_PHASES
 | 
			
		||||
 | 
			
		||||
local ESC    = byte("\27")
 | 
			
		||||
local NUL    = byte("\0")
 | 
			
		||||
local HT     = byte("\t")
 | 
			
		||||
local VT     = byte("\v")
 | 
			
		||||
local LF     = byte("\n")
 | 
			
		||||
local SOL    = byte("/")
 | 
			
		||||
local BSOL   = byte("\\")
 | 
			
		||||
local SP     = byte(" ")
 | 
			
		||||
local AST    = byte("*")
 | 
			
		||||
local NUM    = byte("#")
 | 
			
		||||
local LPAR   = byte("(")
 | 
			
		||||
local LSQB   = byte("[")
 | 
			
		||||
local LCUB   = byte("{")
 | 
			
		||||
local MINUS  = byte("-")
 | 
			
		||||
local PERCNT = byte("%")
 | 
			
		||||
 | 
			
		||||
local EMPTY  = ""
 | 
			
		||||
 | 
			
		||||
local VIEW_ENV
 | 
			
		||||
if _VERSION == "Lua 5.1" then
 | 
			
		||||
    VIEW_ENV = { __index = function(t, k)
 | 
			
		||||
        return t.context[k] or t.template[k] or _G[k]
 | 
			
		||||
    end }
 | 
			
		||||
else
 | 
			
		||||
    VIEW_ENV = { __index = function(t, k)
 | 
			
		||||
        return t.context[k] or t.template[k] or _ENV[k]
 | 
			
		||||
    end }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local newtab
 | 
			
		||||
do
 | 
			
		||||
    local ok
 | 
			
		||||
    ok, newtab = pcall(require, "table.new")
 | 
			
		||||
    if not ok then newtab = function() return {} end end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function enabled(val)
 | 
			
		||||
    if val == nil then return true end
 | 
			
		||||
    return val == true or (val == "1" or val == "true" or val == "on")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function trim(s)
 | 
			
		||||
    return gsub(gsub(s, "^%s+", EMPTY), "%s+$", EMPTY)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function rpos(view, s)
 | 
			
		||||
    while s > 0 do
 | 
			
		||||
        local c = byte(view, s, s)
 | 
			
		||||
        if c == SP or c == HT or c == VT or c == NUL then
 | 
			
		||||
            s = s - 1
 | 
			
		||||
        else
 | 
			
		||||
            break
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return s
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function escaped(view, s)
 | 
			
		||||
    if s > 1 and byte(view, s - 1, s - 1) == BSOL then
 | 
			
		||||
        if s > 2 and byte(view, s - 2, s - 2) == BSOL then
 | 
			
		||||
            return false, 1
 | 
			
		||||
        else
 | 
			
		||||
            return true, 1
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return false, 0
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function read_file(path)
 | 
			
		||||
    local file, err = open(path, "rb")
 | 
			
		||||
    if not file then return nil, err end
 | 
			
		||||
    local content
 | 
			
		||||
    content, err = file:read "*a"
 | 
			
		||||
    file:close()
 | 
			
		||||
    return content, err
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local print_view
 | 
			
		||||
local load_view
 | 
			
		||||
if ngx then
 | 
			
		||||
    print_view = ngx.print or write
 | 
			
		||||
 | 
			
		||||
    var = ngx.var
 | 
			
		||||
    null = ngx.null
 | 
			
		||||
    phase = ngx.get_phase
 | 
			
		||||
 | 
			
		||||
    VAR_PHASES = {
 | 
			
		||||
        set           = true,
 | 
			
		||||
        rewrite       = true,
 | 
			
		||||
        access        = true,
 | 
			
		||||
        content       = true,
 | 
			
		||||
        header_filter = true,
 | 
			
		||||
        body_filter   = true,
 | 
			
		||||
        log           = true,
 | 
			
		||||
        preread       = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    local capture = ngx.location.capture
 | 
			
		||||
    local prefix = ngx.config.prefix()
 | 
			
		||||
    load_view = function(template)
 | 
			
		||||
        return function(view, plain)
 | 
			
		||||
            if plain == true then return view end
 | 
			
		||||
            local vars = VAR_PHASES[phase()]
 | 
			
		||||
            local path = view
 | 
			
		||||
            local root = template.location
 | 
			
		||||
            if (not root or root == EMPTY) and vars then
 | 
			
		||||
                root = var.template_location
 | 
			
		||||
            end
 | 
			
		||||
            if root and root ~= EMPTY then
 | 
			
		||||
                if byte(root, -1) == SOL then root = sub(root, 1, -2) end
 | 
			
		||||
                if byte(path,  1) == SOL then path = sub(path, 2) end
 | 
			
		||||
                path = root .. "/" .. path
 | 
			
		||||
                local res = capture(path)
 | 
			
		||||
                if res.status == 200 then return res.body end
 | 
			
		||||
            end
 | 
			
		||||
            path = view
 | 
			
		||||
            root = template.root
 | 
			
		||||
            if (not root or root == EMPTY) and vars then
 | 
			
		||||
                root = var.template_root
 | 
			
		||||
                if not root or root == EMPTY then root = var.document_root or prefix end
 | 
			
		||||
            end
 | 
			
		||||
            if root and root ~= EMPTY then
 | 
			
		||||
                if byte(root, -1) == SOL then root = sub(root, 1, -2) end
 | 
			
		||||
                if byte(path,  1) == SOL then path = sub(path, 2) end
 | 
			
		||||
                path = root .. "/" .. path
 | 
			
		||||
            end
 | 
			
		||||
            return plain == false and assert(read_file(path)) or read_file(path) or view
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
else
 | 
			
		||||
    print_view = write
 | 
			
		||||
    load_view = function(template)
 | 
			
		||||
        return function(view, plain)
 | 
			
		||||
            if plain == true then return view end
 | 
			
		||||
            local path, root = view, template.root
 | 
			
		||||
            if root and root ~= EMPTY then
 | 
			
		||||
                if byte(root, -1) == SOL then root = sub(root, 1, -2) end
 | 
			
		||||
                if byte(view,  1) == SOL then path = sub(view, 2) end
 | 
			
		||||
                path = root .. "/" .. path
 | 
			
		||||
            end
 | 
			
		||||
            return plain == false and assert(read_file(path)) or read_file(path) or view
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function load_file(func)
 | 
			
		||||
    return function(view) return func(view, false) end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function load_string(func)
 | 
			
		||||
    return function(view) return func(view, true) end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local loader
 | 
			
		||||
if jit or _VERSION ~= "Lua 5.1" then
 | 
			
		||||
    loader = function(template)
 | 
			
		||||
        return function(view)
 | 
			
		||||
            return assert(load(view, nil, nil, setmetatable({ template = template }, VIEW_ENV)))
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
else
 | 
			
		||||
    loader = function(template)
 | 
			
		||||
        return function(view)
 | 
			
		||||
            local func = assert(loadstring(view))
 | 
			
		||||
            setfenv(func, setmetatable({ template = template }, VIEW_ENV))
 | 
			
		||||
            return func
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function visit(visitors, content, tag, name)
 | 
			
		||||
    if not visitors then
 | 
			
		||||
        return content
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    for i = 1, visitors.n do
 | 
			
		||||
        content = visitors[i](content, tag, name)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return content
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function new(template, safe)
 | 
			
		||||
    template = template or newtab(0, 26)
 | 
			
		||||
 | 
			
		||||
    template._VERSION    = "2.0"
 | 
			
		||||
    template.cache       = {}
 | 
			
		||||
    template.load        = load_view(template)
 | 
			
		||||
    template.load_file   = load_file(template.load)
 | 
			
		||||
    template.load_string = load_string(template.load)
 | 
			
		||||
    template.print       = print_view
 | 
			
		||||
 | 
			
		||||
    local load_chunk = loader(template)
 | 
			
		||||
 | 
			
		||||
    local caching
 | 
			
		||||
    if VAR_PHASES and VAR_PHASES[phase()] then
 | 
			
		||||
        caching = enabled(var.template_cache)
 | 
			
		||||
    else
 | 
			
		||||
        caching = true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local visitors
 | 
			
		||||
    function template.visit(func)
 | 
			
		||||
        if not visitors then
 | 
			
		||||
            visitors = { func, n = 1 }
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
        visitors.n = visitors.n + 1
 | 
			
		||||
        visitors[visitors.n] = func
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.caching(enable)
 | 
			
		||||
        if enable ~= nil then caching = enable == true end
 | 
			
		||||
        return caching
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.output(s)
 | 
			
		||||
        if s == nil or s == null then return EMPTY end
 | 
			
		||||
        if type(s) == "function" then return template.output(s()) end
 | 
			
		||||
        return tostring(s)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.escape(s, c)
 | 
			
		||||
        if type(s) == "string" then
 | 
			
		||||
            if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end
 | 
			
		||||
            return gsub(s, "[\">/<'&]", HTML_ENTITIES)
 | 
			
		||||
        end
 | 
			
		||||
        return template.output(s)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.new(view, layout)
 | 
			
		||||
        local vt = type(view)
 | 
			
		||||
 | 
			
		||||
        if vt == "boolean" then return new(nil,  view) end
 | 
			
		||||
        if vt == "table"   then return new(view, safe) end
 | 
			
		||||
        if vt == "nil"     then return new(nil,  safe) end
 | 
			
		||||
 | 
			
		||||
        local render
 | 
			
		||||
        local process
 | 
			
		||||
        if layout then
 | 
			
		||||
            if type(layout) == "table" then
 | 
			
		||||
                render = function(self, context)
 | 
			
		||||
                    context = context or self
 | 
			
		||||
                    context.blocks = context.blocks or {}
 | 
			
		||||
                    context.view = function(ctx) return template.process(view, ctx or context) end
 | 
			
		||||
                    layout.blocks = context.blocks or {}
 | 
			
		||||
                    layout.view = context.view or EMPTY
 | 
			
		||||
                    layout:render()
 | 
			
		||||
                end
 | 
			
		||||
                process = function(self, context)
 | 
			
		||||
                    context = context or self
 | 
			
		||||
                    context.blocks = context.blocks or {}
 | 
			
		||||
                    context.view = function(ctx) return template.process(view, ctx or context) end
 | 
			
		||||
                    layout.blocks = context.blocks or {}
 | 
			
		||||
                    layout.view = context.view
 | 
			
		||||
                    return tostring(layout)
 | 
			
		||||
                end
 | 
			
		||||
            else
 | 
			
		||||
                render = function(self, context)
 | 
			
		||||
                    context = context or self
 | 
			
		||||
                    context.blocks = context.blocks or {}
 | 
			
		||||
                    context.view = function(ctx) return template.process(view, ctx or context) end
 | 
			
		||||
                    template.render(layout, context)
 | 
			
		||||
                end
 | 
			
		||||
                process = function(self, context)
 | 
			
		||||
                    context = context or self
 | 
			
		||||
                    context.blocks = context.blocks or {}
 | 
			
		||||
                    context.view = function(ctx) return template.process(view, ctx or context) end
 | 
			
		||||
                    return template.process(layout, context)
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            render = function(self, context)
 | 
			
		||||
                return template.render(view, context or self)
 | 
			
		||||
            end
 | 
			
		||||
            process = function(self, context)
 | 
			
		||||
                return template.process(view, context or self)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if safe then
 | 
			
		||||
            return setmetatable({
 | 
			
		||||
                render = function(...)
 | 
			
		||||
                    local ok, err = pcall(render, ...)
 | 
			
		||||
                    if not ok then
 | 
			
		||||
                        return nil, err
 | 
			
		||||
                    end
 | 
			
		||||
                end,
 | 
			
		||||
                process = function(...)
 | 
			
		||||
                    local ok, output = pcall(process, ...)
 | 
			
		||||
                    if not ok then
 | 
			
		||||
                        return nil, output
 | 
			
		||||
                    end
 | 
			
		||||
                    return output
 | 
			
		||||
                end,
 | 
			
		||||
             }, {
 | 
			
		||||
                __tostring = function(...)
 | 
			
		||||
                    local ok, output = pcall(process, ...)
 | 
			
		||||
                    if not ok then
 | 
			
		||||
                        return ""
 | 
			
		||||
                    end
 | 
			
		||||
                    return output
 | 
			
		||||
            end })
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        return setmetatable({
 | 
			
		||||
            render = render,
 | 
			
		||||
            process = process
 | 
			
		||||
        }, {
 | 
			
		||||
            __tostring = process
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.precompile(view, path, strip, plain)
 | 
			
		||||
        local chunk = dump(template.compile(view, nil, plain), strip ~= false)
 | 
			
		||||
        if path then
 | 
			
		||||
            local file = open(path, "wb")
 | 
			
		||||
            file:write(chunk)
 | 
			
		||||
            file:close()
 | 
			
		||||
        end
 | 
			
		||||
        return chunk
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.precompile_string(view, path, strip)
 | 
			
		||||
        return template.precompile(view, path, strip, true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.precompile_file(view, path, strip)
 | 
			
		||||
        return template.precompile(view, path, strip, false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.compile(view, cache_key, plain)
 | 
			
		||||
        assert(view, "view was not provided for template.compile(view, cache_key, plain)")
 | 
			
		||||
        if cache_key == "no-cache" then
 | 
			
		||||
            return load_chunk(template.parse(view, plain)), false
 | 
			
		||||
        end
 | 
			
		||||
        cache_key = cache_key or view
 | 
			
		||||
        local cache = template.cache
 | 
			
		||||
        if cache[cache_key] then return cache[cache_key], true end
 | 
			
		||||
        local func = load_chunk(template.parse(view, plain))
 | 
			
		||||
        if caching then cache[cache_key] = func end
 | 
			
		||||
        return func, false
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.compile_file(view, cache_key)
 | 
			
		||||
        return template.compile(view, cache_key, false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.compile_string(view, cache_key)
 | 
			
		||||
        return template.compile(view, cache_key, true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.parse(view, plain)
 | 
			
		||||
        assert(view, "view was not provided for template.parse(view, plain)")
 | 
			
		||||
        if plain ~= true then
 | 
			
		||||
            view = template.load(view, plain)
 | 
			
		||||
            if byte(view, 1, 1) == ESC then return view end
 | 
			
		||||
        end
 | 
			
		||||
        local j = 2
 | 
			
		||||
        local c = {[[
 | 
			
		||||
context=... or {}
 | 
			
		||||
local ___,blocks,layout={},blocks or {}
 | 
			
		||||
local function include(v, c) return template.process(v, c or context) end
 | 
			
		||||
local function echo(...) for i=1,select("#", ...) do ___[#___+1] = tostring(select(i, ...)) end end
 | 
			
		||||
]] }
 | 
			
		||||
        local i, s = 1, find(view, "{", 1, true)
 | 
			
		||||
        while s do
 | 
			
		||||
            local t, p = byte(view, s + 1, s + 1), s + 2
 | 
			
		||||
            if t == LCUB then
 | 
			
		||||
                local e = find(view, "}}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local z, w = escaped(view, s)
 | 
			
		||||
                    if i < s - w then
 | 
			
		||||
                        c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                        c[j+2] = "]=]\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                    end
 | 
			
		||||
                    if z then
 | 
			
		||||
                        i = s
 | 
			
		||||
                    else
 | 
			
		||||
                        c[j] = "___[#___+1]=template.escape("
 | 
			
		||||
                        c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "{")
 | 
			
		||||
                        c[j+2] = ")\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                        s, i = e + 1, e + 2
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            elseif t == AST then
 | 
			
		||||
                local e = find(view, "*}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local z, w = escaped(view, s)
 | 
			
		||||
                    if i < s - w then
 | 
			
		||||
                        c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                        c[j+2] = "]=]\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                    end
 | 
			
		||||
                    if z then
 | 
			
		||||
                        i = s
 | 
			
		||||
                    else
 | 
			
		||||
                        c[j] = "___[#___+1]=template.output("
 | 
			
		||||
                        c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "*")
 | 
			
		||||
                        c[j+2] = ")\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                        s, i = e + 1, e + 2
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            elseif t == PERCNT then
 | 
			
		||||
                local e = find(view, "%}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local z, w = escaped(view, s)
 | 
			
		||||
                    if z then
 | 
			
		||||
                        if i < s - w then
 | 
			
		||||
                            c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                            c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                            c[j+2] = "]=]\n"
 | 
			
		||||
                            j=j+3
 | 
			
		||||
                        end
 | 
			
		||||
                        i = s
 | 
			
		||||
                    else
 | 
			
		||||
                        local n = e + 2
 | 
			
		||||
                        if byte(view, n, n) == LF then
 | 
			
		||||
                            n = n + 1
 | 
			
		||||
                        end
 | 
			
		||||
                        local r = rpos(view, s - 1)
 | 
			
		||||
                        if i <= r then
 | 
			
		||||
                            c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                            c[j+1] = visit(visitors, sub(view, i, r))
 | 
			
		||||
                            c[j+2] = "]=]\n"
 | 
			
		||||
                            j=j+3
 | 
			
		||||
                        end
 | 
			
		||||
                        c[j] = visit(visitors, trim(sub(view, p, e - 1)), "%")
 | 
			
		||||
                        c[j+1] = "\n"
 | 
			
		||||
                        j=j+2
 | 
			
		||||
                        s, i = n - 1, n
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            elseif t == LPAR then
 | 
			
		||||
                local e = find(view, ")}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local z, w = escaped(view, s)
 | 
			
		||||
                    if i < s - w then
 | 
			
		||||
                        c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                        c[j+2] = "]=]\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                    end
 | 
			
		||||
                    if z then
 | 
			
		||||
                        i = s
 | 
			
		||||
                    else
 | 
			
		||||
                        local f = visit(visitors, sub(view, p, e - 1), "(")
 | 
			
		||||
                        local x = find(f, ",", 2, true)
 | 
			
		||||
                        if x then
 | 
			
		||||
                            c[j] = "___[#___+1]=include([=["
 | 
			
		||||
                            c[j+1] = trim(sub(f, 1, x - 1))
 | 
			
		||||
                            c[j+2] = "]=],"
 | 
			
		||||
                            c[j+3] = trim(sub(f, x + 1))
 | 
			
		||||
                            c[j+4] = ")\n"
 | 
			
		||||
                            j=j+5
 | 
			
		||||
                        else
 | 
			
		||||
                            c[j] = "___[#___+1]=include([=["
 | 
			
		||||
                            c[j+1] = trim(f)
 | 
			
		||||
                            c[j+2] = "]=])\n"
 | 
			
		||||
                            j=j+3
 | 
			
		||||
                        end
 | 
			
		||||
                        s, i = e + 1, e + 2
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            elseif t == LSQB then
 | 
			
		||||
                local e = find(view, "]}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local z, w = escaped(view, s)
 | 
			
		||||
                    if i < s - w then
 | 
			
		||||
                        c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                        c[j+2] = "]=]\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                    end
 | 
			
		||||
                    if z then
 | 
			
		||||
                        i = s
 | 
			
		||||
                    else
 | 
			
		||||
                        c[j] = "___[#___+1]=include("
 | 
			
		||||
                        c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "[")
 | 
			
		||||
                        c[j+2] = ")\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                        s, i = e + 1, e + 2
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            elseif t == MINUS then
 | 
			
		||||
                local e = find(view, "-}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local x, y = find(view, sub(view, s, e + 1), e + 2, true)
 | 
			
		||||
                    if x then
 | 
			
		||||
                        local z, w = escaped(view, s)
 | 
			
		||||
                        if z then
 | 
			
		||||
                            if i < s - w then
 | 
			
		||||
                                c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                                c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                                c[j+2] = "]=]\n"
 | 
			
		||||
                                j=j+3
 | 
			
		||||
                            end
 | 
			
		||||
                            i = s
 | 
			
		||||
                        else
 | 
			
		||||
                            y = y + 1
 | 
			
		||||
                            x = x - 1
 | 
			
		||||
                            if byte(view, y, y) == LF then
 | 
			
		||||
                                y = y + 1
 | 
			
		||||
                            end
 | 
			
		||||
                            local b = trim(sub(view, p, e - 1))
 | 
			
		||||
                            if b == "verbatim" or b == "raw" then
 | 
			
		||||
                                if i < s - w then
 | 
			
		||||
                                    c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                                    c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                                    c[j+2] = "]=]\n"
 | 
			
		||||
                                    j=j+3
 | 
			
		||||
                                end
 | 
			
		||||
                                c[j] = "___[#___+1]=[=["
 | 
			
		||||
                                c[j+1] = visit(visitors, sub(view, e + 2, x))
 | 
			
		||||
                                c[j+2] = "]=]\n"
 | 
			
		||||
                                j=j+3
 | 
			
		||||
                            else
 | 
			
		||||
                                if byte(view, x, x) == LF then
 | 
			
		||||
                                    x = x - 1
 | 
			
		||||
                                end
 | 
			
		||||
                                local r = rpos(view, s - 1)
 | 
			
		||||
                                if i <= r then
 | 
			
		||||
                                    c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                                    c[j+1] = visit(visitors, sub(view, i, r))
 | 
			
		||||
                                    c[j+2] = "]=]\n"
 | 
			
		||||
                                    j=j+3
 | 
			
		||||
                                end
 | 
			
		||||
                                c[j] = 'blocks["'
 | 
			
		||||
                                c[j+1] = b
 | 
			
		||||
                                c[j+2] = '"]=include[=['
 | 
			
		||||
                                c[j+3] = visit(visitors, sub(view, e + 2, x), "-", b)
 | 
			
		||||
                                c[j+4] = "]=]\n"
 | 
			
		||||
                                j=j+5
 | 
			
		||||
                            end
 | 
			
		||||
                            s, i = y - 1, y
 | 
			
		||||
                        end
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            elseif t == NUM then
 | 
			
		||||
                local e = find(view, "#}", p, true)
 | 
			
		||||
                if e then
 | 
			
		||||
                    local z, w = escaped(view, s)
 | 
			
		||||
                    if i < s - w then
 | 
			
		||||
                        c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
 | 
			
		||||
                        c[j+2] = "]=]\n"
 | 
			
		||||
                        j=j+3
 | 
			
		||||
                    end
 | 
			
		||||
                    if z then
 | 
			
		||||
                        i = s
 | 
			
		||||
                    else
 | 
			
		||||
                        e = e + 2
 | 
			
		||||
                        if byte(view, e, e) == LF then
 | 
			
		||||
                            e = e + 1
 | 
			
		||||
                        end
 | 
			
		||||
                        s, i = e - 1, e
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
            s = find(view, "{", s + 1, true)
 | 
			
		||||
        end
 | 
			
		||||
        s = sub(view, i)
 | 
			
		||||
        if s and s ~= EMPTY then
 | 
			
		||||
            c[j] = "___[#___+1]=[=[\n"
 | 
			
		||||
            c[j+1] = visit(visitors, s)
 | 
			
		||||
            c[j+2] = "]=]\n"
 | 
			
		||||
            j=j+3
 | 
			
		||||
        end
 | 
			
		||||
        c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" -- luacheck: ignore
 | 
			
		||||
        return concat(c)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.parse_file(view)
 | 
			
		||||
        return template.parse(view, false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.parse_string(view)
 | 
			
		||||
        return template.parse(view, true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.process(view, context, cache_key, plain)
 | 
			
		||||
        assert(view, "view was not provided for template.process(view, context, cache_key, plain)")
 | 
			
		||||
        return template.compile(view, cache_key, plain)(context)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.process_file(view, context, cache_key)
 | 
			
		||||
        assert(view, "view was not provided for template.process_file(view, context, cache_key)")
 | 
			
		||||
        return template.compile(view, cache_key, false)(context)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.process_string(view, context, cache_key)
 | 
			
		||||
        assert(view, "view was not provided for template.process_string(view, context, cache_key)")
 | 
			
		||||
        return template.compile(view, cache_key, true)(context)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.render(view, context, cache_key, plain)
 | 
			
		||||
        assert(view, "view was not provided for template.render(view, context, cache_key, plain)")
 | 
			
		||||
        template.print(template.process(view, context, cache_key, plain))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.render_file(view, context, cache_key)
 | 
			
		||||
        assert(view, "view was not provided for template.render_file(view, context, cache_key)")
 | 
			
		||||
        template.render(view, context, cache_key, false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function template.render_string(view, context, cache_key)
 | 
			
		||||
        assert(view, "view was not provided for template.render_string(view, context, cache_key)")
 | 
			
		||||
        template.render(view, context, cache_key, true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if safe then
 | 
			
		||||
        return setmetatable({}, {
 | 
			
		||||
            __index = function(_, k)
 | 
			
		||||
                if type(template[k]) == "function" then
 | 
			
		||||
                    return function(...)
 | 
			
		||||
                        local ok, a, b = pcall(template[k], ...)
 | 
			
		||||
                        if not ok then
 | 
			
		||||
                            return nil, a
 | 
			
		||||
                        end
 | 
			
		||||
                        return a, b
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                return template[k]
 | 
			
		||||
            end,
 | 
			
		||||
            __new_index = function(_, k, v)
 | 
			
		||||
                template[k] = v
 | 
			
		||||
            end,
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return template
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return new()
 | 
			
		||||
							
								
								
									
										52
									
								
								doc/nginx/template/template/html.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								doc/nginx/template/template/html.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
local template = require "resty.template"
 | 
			
		||||
local setmetatable = setmetatable
 | 
			
		||||
local escape = template.escape
 | 
			
		||||
local concat = table.concat
 | 
			
		||||
local pairs = pairs
 | 
			
		||||
local type = type
 | 
			
		||||
 | 
			
		||||
local function tag(name, content, attr)
 | 
			
		||||
    local r, a = {}, {}
 | 
			
		||||
    content = content or attr
 | 
			
		||||
    r[#r + 1] = "<"
 | 
			
		||||
    r[#r + 1] = name
 | 
			
		||||
    if attr then
 | 
			
		||||
        for k, v in pairs(attr) do
 | 
			
		||||
            if type(k) == "number" then
 | 
			
		||||
                a[#a + 1] = escape(v)
 | 
			
		||||
            else
 | 
			
		||||
                a[#a + 1] = k .. '="' .. escape(v) .. '"'
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        if #a > 0 then
 | 
			
		||||
            r[#r + 1] = " "
 | 
			
		||||
            r[#r + 1] = concat(a, " ")
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    if type(content) == "string" then
 | 
			
		||||
        r[#r + 1] = ">"
 | 
			
		||||
        r[#r + 1] = escape(content)
 | 
			
		||||
        r[#r + 1] = "</"
 | 
			
		||||
        r[#r + 1] = name
 | 
			
		||||
        r[#r + 1] = ">"
 | 
			
		||||
    else
 | 
			
		||||
        r[#r + 1] = " />"
 | 
			
		||||
    end
 | 
			
		||||
    return concat(r)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local html = { __index = function(_, name)
 | 
			
		||||
    return function(attr)
 | 
			
		||||
        if type(attr) == "table" then
 | 
			
		||||
            return function(content)
 | 
			
		||||
                return tag(name, content, attr)
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            return tag(name, attr)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end }
 | 
			
		||||
 | 
			
		||||
template.html = setmetatable(html, html)
 | 
			
		||||
 | 
			
		||||
return template.html
 | 
			
		||||
							
								
								
									
										153
									
								
								doc/nginx/template/template/microbenchmark.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								doc/nginx/template/template/microbenchmark.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
local template = require "resty.template"
 | 
			
		||||
 | 
			
		||||
local ok, new_tab = pcall(require, "table.new")
 | 
			
		||||
if not ok then
 | 
			
		||||
    new_tab = function() return {} end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function run(iterations)
 | 
			
		||||
 | 
			
		||||
    local gc, total, print, parse, compile, clock, format = collectgarbage, 0, ngx and ngx.say or print, template.parse,
 | 
			
		||||
                                                            template.compile, os.clock, string.format
 | 
			
		||||
 | 
			
		||||
    iterations = iterations or 1000
 | 
			
		||||
 | 
			
		||||
    local view = [[
 | 
			
		||||
    <ul>
 | 
			
		||||
    {% for _, v in ipairs(context) do %}
 | 
			
		||||
        <li>{{v}}</li>
 | 
			
		||||
    {% end %}
 | 
			
		||||
    </ul>]]
 | 
			
		||||
 | 
			
		||||
    print(format("Running %d iterations in each test", iterations))
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    local x = clock()
 | 
			
		||||
    for _ = 1, iterations do
 | 
			
		||||
        parse(view, true)
 | 
			
		||||
    end
 | 
			
		||||
    local z = clock() - x
 | 
			
		||||
    print(format("    Parsing Time: %.6f", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for _ = 1, iterations do
 | 
			
		||||
        compile(view, nil, true)
 | 
			
		||||
        template.cache = {}
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("Compilation Time: %.6f (template)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    compile(view, nil, true)
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for _ = 1, iterations do
 | 
			
		||||
        compile(view, 1, true)
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("Compilation Time: %.6f (template, cached)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    local context = { "Emma", "James", "Nicholas", "Mary" }
 | 
			
		||||
 | 
			
		||||
    template.cache = {}
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for _ = 1, iterations do
 | 
			
		||||
        compile(view, 1, true)(context)
 | 
			
		||||
        template.cache = {}
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("  Execution Time: %.6f (same template)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    template.cache = {}
 | 
			
		||||
    compile(view, 1, true)
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for _ = 1, iterations do
 | 
			
		||||
        compile(view, 1, true)(context)
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("  Execution Time: %.6f (same template, cached)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    template.cache = {}
 | 
			
		||||
 | 
			
		||||
    local views = new_tab(iterations, 0)
 | 
			
		||||
    for i = 1, iterations do
 | 
			
		||||
        views[i] = "<h1>Iteration " .. i .. "</h1>\n" .. view
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for i = 1, iterations do
 | 
			
		||||
        compile(views[i], i, true)(context)
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("  Execution Time: %.6f (different template)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for i = 1, iterations do
 | 
			
		||||
        compile(views[i], i, true)(context)
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("  Execution Time: %.6f (different template, cached)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    local contexts = new_tab(iterations, 0)
 | 
			
		||||
 | 
			
		||||
    for i = 1, iterations do
 | 
			
		||||
        contexts[i] = { "Emma", "James", "Nicholas", "Mary" }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    template.cache = {}
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for i = 1, iterations do
 | 
			
		||||
        compile(views[i], i, true)(contexts[i])
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("  Execution Time: %.6f (different template, different context)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
 | 
			
		||||
    gc()
 | 
			
		||||
    gc()
 | 
			
		||||
 | 
			
		||||
    x = clock()
 | 
			
		||||
    for i = 1, iterations do
 | 
			
		||||
        compile(views[i], i, true)(contexts[i])
 | 
			
		||||
    end
 | 
			
		||||
    z = clock() - x
 | 
			
		||||
    print(format("  Execution Time: %.6f (different template, different context, cached)", z))
 | 
			
		||||
    total = total + z
 | 
			
		||||
    print(format("      Total Time: %.6f", total))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return {
 | 
			
		||||
    run = run
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								doc/nginx/template/template/safe.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								doc/nginx/template/template/safe.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
return require "resty.template".new(true)
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user