aboutsummaryrefslogtreecommitdiffstats
path: root/server/resty/session/storage/redis.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server/resty/session/storage/redis.lua')
-rw-r--r--server/resty/session/storage/redis.lua478
1 files changed, 0 insertions, 478 deletions
diff --git a/server/resty/session/storage/redis.lua b/server/resty/session/storage/redis.lua
deleted file mode 100644
index 3de0472..0000000
--- a/server/resty/session/storage/redis.lua
+++ /dev/null
@@ -1,478 +0,0 @@
-local setmetatable = setmetatable
-local tonumber = tonumber
-local type = type
-local reverse = string.reverse
-local gmatch = string.gmatch
-local find = string.find
-local byte = string.byte
-local sub = string.sub
-local concat = table.concat
-local sleep = ngx.sleep
-local null = ngx.null
-local var = ngx.var
-
-local LB = byte("[")
-local RB = byte("]")
-
-local function parse_cluster_nodes(nodes)
- if not nodes or nodes == "" then
- return nil
- end
-
- if type(nodes) == "table" then
- return nodes
- end
-
- local addrs
- local i
- for node in gmatch(nodes, "%S+") do
- local ip = node
- local port = 6379
- local pos = find(reverse(ip), ":", 2, true)
- if pos then
- local p = tonumber(sub(ip, -pos + 1), 10)
- if p >= 1 and p <= 65535 then
- local addr = sub(ip, 1, -pos - 1)
- if find(addr, ":", 1, true) then
- if byte(addr, -1) == RB then
- ip = addr
- port = p
- end
-
- else
- ip = addr
- port = p
- end
- end
- end
-
- if byte(ip, 1, 1) == LB then
- ip = sub(ip, 2)
- end
-
- if byte(ip, -1) == RB then
- ip = sub(ip, 1, -2)
- end
-
- if not addrs then
- i = 1
- addrs = {{
- ip = ip,
- port = port,
- }}
- else
- i = i + 1
- addrs[i] = {
- ip = ip,
- port = port,
- }
- end
- end
-
- if not i then
- return
- end
-
- return addrs
-end
-
-local redis_single = require "resty.redis"
-local redis_cluster
-do
- local pcall = pcall
- local require = require
- local ok
- ok, redis_cluster = pcall(require, "resty.rediscluster")
- if not ok then
- ok, redis_cluster = pcall(require, "rediscluster")
- if not ok then
- redis_cluster = nil
- end
- end
-end
-
-local UNLOCK = [[
-if redis.call("GET", KEYS[1]) == ARGV[1] then
- return redis.call("DEL", KEYS[1])
-else
- return 0
-end
-]]
-
-local function enabled(value)
- if value == nil then return nil end
- return value == true or (value == "1" or value == "true" or value == "on")
-end
-
-local function ifnil(value, default)
- if value == nil then
- return default
- end
-
- return enabled(value)
-end
-
-local defaults = {
- prefix = var.session_redis_prefix or "sessions",
- socket = var.session_redis_socket,
- host = var.session_redis_host or "127.0.0.1",
- username = var.session_redis_username,
- password = var.session_redis_password or var.session_redis_auth,
- server_name = var.session_redis_server_name,
- ssl = enabled(var.session_redis_ssl) or false,
- ssl_verify = enabled(var.session_redis_ssl_verify) or false,
- uselocking = enabled(var.session_redis_uselocking or true),
- port = tonumber(var.session_redis_port, 10) or 6379,
- database = tonumber(var.session_redis_database, 10) or 0,
- connect_timeout = tonumber(var.session_redis_connect_timeout, 10),
- read_timeout = tonumber(var.session_redis_read_timeout, 10),
- send_timeout = tonumber(var.session_redis_send_timeout, 10),
- spinlockwait = tonumber(var.session_redis_spinlockwait, 10) or 150,
- maxlockwait = tonumber(var.session_redis_maxlockwait, 10) or 30,
- pool = {
- name = var.session_redis_pool_name,
- timeout = tonumber(var.session_redis_pool_timeout, 10),
- size = tonumber(var.session_redis_pool_size, 10),
- backlog = tonumber(var.session_redis_pool_backlog, 10),
- },
-}
-
-
-if redis_cluster then
- defaults.cluster = {
- name = var.session_redis_cluster_name,
- dict = var.session_redis_cluster_dict,
- maxredirections = tonumber(var.session_redis_cluster_maxredirections, 10),
- nodes = parse_cluster_nodes(var.session_redis_cluster_nodes),
- }
-end
-
-local storage = {}
-
-storage.__index = storage
-
-function storage.new(session)
- local config = session.redis or defaults
- local pool = config.pool or defaults.pool
- local cluster = config.cluster or defaults.cluster
- local locking = ifnil(config.uselocking, defaults.uselocking)
-
- local self = {
- prefix = config.prefix or defaults.prefix,
- uselocking = locking,
- spinlockwait = tonumber(config.spinlockwait, 10) or defaults.spinlockwait,
- maxlockwait = tonumber(config.maxlockwait, 10) or defaults.maxlockwait,
- }
-
- local username = config.username or defaults.username
- if username == "" then
- username = nil
- end
- local password = config.password or config.auth or defaults.password
- if password == "" then
- password = nil
- end
-
- local connect_timeout = tonumber(config.connect_timeout, 10) or defaults.connect_timeout
-
- local cluster_nodes
- if redis_cluster then
- cluster_nodes = parse_cluster_nodes(cluster.nodes or defaults.cluster.nodes)
- end
-
- local connect_opts = {
- pool = pool.name or defaults.pool.name,
- pool_size = tonumber(pool.size, 10) or defaults.pool.size,
- backlog = tonumber(pool.backlog, 10) or defaults.pool.backlog,
- server_name = config.server_name or defaults.server_name,
- ssl = ifnil(config.ssl, defaults.ssl),
- ssl_verify = ifnil(config.ssl_verify, defaults.ssl_verify),
- }
-
- if cluster_nodes then
- self.redis = redis_cluster:new({
- name = cluster.name or defaults.cluster.name,
- dict_name = cluster.dict or defaults.cluster.dict,
- username = var.session_redis_username,
- password = var.session_redis_password or defaults.password,
- connection_timout = connect_timeout, -- typo in library
- connection_timeout = connect_timeout,
- keepalive_timeout = tonumber(pool.timeout, 10) or defaults.pool.timeout,
- keepalive_cons = tonumber(pool.size, 10) or defaults.pool.size,
- max_redirection = tonumber(cluster.maxredirections, 10) or defaults.cluster.maxredirections,
- serv_list = cluster_nodes,
- connect_opts = connect_opts,
- })
- self.cluster = true
-
- else
- local redis = redis_single:new()
-
- if redis.set_timeouts then
- local send_timeout = tonumber(config.send_timeout, 10) or defaults.send_timeout
- local read_timeout = tonumber(config.read_timeout, 10) or defaults.read_timeout
-
- if connect_timeout then
- if send_timeout and read_timeout then
- redis:set_timeouts(connect_timeout, send_timeout, read_timeout)
- else
- redis:set_timeout(connect_timeout)
- end
- end
-
- elseif redis.set_timeout and connect_timeout then
- redis:set_timeout(connect_timeout)
- end
-
- self.redis = redis
- self.username = username
- self.password = password
- self.database = tonumber(config.database, 10) or defaults.database
- self.pool_timeout = tonumber(pool.timeout, 10) or defaults.pool.timeout
- self.connect_opts = connect_opts
-
- local socket = config.socket or defaults.socket
- if socket and socket ~= "" then
- self.socket = socket
- else
- self.host = config.host or defaults.host
- self.port = config.port or defaults.port
- end
- end
-
- return setmetatable(self, storage)
-end
-
-function storage:connect()
- if self.cluster then
- return true -- cluster handles this on its own
- end
-
- local ok, err
- if self.socket then
- ok, err = self.redis:connect(self.socket, self.connect_opts)
- else
- ok, err = self.redis:connect(self.host, self.port, self.connect_opts)
- end
-
- if not ok then
- return nil, err
- end
-
- if self.password and self.redis:get_reused_times() == 0 then
- -- usernames are supported only on Redis 6+, so use new AUTH form only when absolutely necessary
- if self.username then
- ok, err = self.redis:auth(self.username, self.password)
- else
- ok, err = self.redis:auth(self.password)
- end
- if not ok then
- self.redis:close()
- return nil, err
- end
- end
-
- if self.database ~= 0 then
- ok, err = self.redis:select(self.database)
- if not ok then
- self.redis:close()
- end
- end
-
- return ok, err
-end
-
-function storage:set_keepalive()
- if self.cluster then
- return true -- cluster handles this on its own
- end
-
- return self.redis:set_keepalive(self.pool_timeout)
-end
-
-function storage:key(id)
- return concat({ self.prefix, id }, ":" )
-end
-
-function storage:lock(key)
- if not self.uselocking or self.locked then
- return true
- end
-
- if not self.token then
- self.token = var.request_id
- end
-
- local lock_key = concat({ key, "lock" }, "." )
- local lock_ttl = self.maxlockwait + 1
- local attempts = (1000 / self.spinlockwait) * self.maxlockwait
- local waittime = self.spinlockwait / 1000
-
- for _ = 1, attempts do
- local ok = self.redis:set(lock_key, self.token, "EX", lock_ttl, "NX")
- if ok ~= null then
- self.locked = true
- return true
- end
-
- sleep(waittime)
- end
-
- return false, "unable to acquire a session lock"
-end
-
-function storage:unlock(key)
- if not self.uselocking or not self.locked then
- return
- end
-
- local lock_key = concat({ key, "lock" }, "." )
-
- self.redis:eval(UNLOCK, 1, lock_key, self.token)
- self.locked = nil
-end
-
-function storage:get(key)
- local data, err = self.redis:get(key)
- if not data then
- return nil, err
- end
-
- if data == null then
- return nil
- end
-
- return data
-end
-
-function storage:set(key, data, lifetime)
- return self.redis:setex(key, lifetime, data)
-end
-
-function storage:expire(key, lifetime)
- return self.redis:expire(key, lifetime)
-end
-
-function storage:delete(key)
- return self.redis:del(key)
-end
-
-function storage:open(id, keep_lock)
- local ok, err = self:connect()
- if not ok then
- return nil, err
- end
-
- local key = self:key(id)
-
- ok, err = self:lock(key)
- if not ok then
- self:set_keepalive()
- return nil, err
- end
-
- local data
- data, err = self:get(key)
-
- if err or not data or not keep_lock then
- self:unlock(key)
- end
- self:set_keepalive()
-
- return data, err
-end
-
-function storage:start(id)
- if not self.uselocking or not self.locked then
- return true
- end
-
- local ok, err = self:connect()
- if not ok then
- return nil, err
- end
-
- ok, err = self:lock(self:key(id))
-
- self:set_keepalive()
-
- return ok, err
-end
-
-function storage:save(id, ttl, data, close)
- local ok, err = self:connect()
- if not ok then
- return nil, err
- end
-
- local key = self:key(id)
-
- ok, err = self:set(key, data, ttl)
-
- if close then
- self:unlock(key)
- end
-
- self:set_keepalive()
-
- if not ok then
- return nil, err
- end
-
- return true
-end
-
-function storage:close(id)
- if not self.uselocking or not self.locked then
- return true
- end
-
- local ok, err = self:connect()
- if not ok then
- return nil, err
- end
-
- local key = self:key(id)
-
- self:unlock(key)
- self:set_keepalive()
-
- return true
-end
-
-function storage:destroy(id)
- local ok, err = self:connect()
- if not ok then
- return nil, err
- end
-
- local key = self:key(id)
-
- ok, err = self:delete(key)
-
- self:unlock(key)
- self:set_keepalive()
-
- return ok, err
-end
-
-function storage:ttl(id, ttl, close)
- local ok, err = self:connect()
- if not ok then
- return nil, err
- end
-
- local key = self:key(id)
-
- ok, err = self:expire(key, ttl)
-
- if close then
- self:unlock(key)
- end
-
- self:set_keepalive()
-
- return ok, err
-end
-
-return storage