local get_phase = ngx.get_phase local timer_at = ngx.timer.at local kong = kong local PK = { id = "", } local TTL = { ttl = 0, } local DATA = { session_id = "", data = "", expires = 0, } local STALE_DATA = { expires = 0, } local storage = {} storage.__index = storage local function load_session_from_db(key) return kong.db.sessions:select_by_session_id(key) end local function load_session_from_cache(key) local cache_key = kong.db.sessions:cache_key(key) return kong.cache:get(cache_key, nil, load_session_from_db, key) end local function insert_session_metadata(metadata, session) if not metadata then return end local audiences = metadata.audiences local subjects = metadata.subjects local count = #audiences for i = 1, count do local _, err = kong.db.session_metadatas:insert({ sid = session.session_id, audience = audiences[i], subject = subjects[i], session = session, }) if err then kong.db.sessions:delete(session.id) return false, err end end return true end local function insert_session(key, value, ttl, current_time, old_key, stale_ttl, metadata, remember) DATA.session_id = key DATA.data = value DATA.expires = current_time + ttl TTL.ttl = ttl local insert_ok, insert_err = kong.db.sessions:insert(DATA, TTL) if not insert_err then local ok, err = insert_session_metadata(metadata, insert_ok) if not ok and err then return nil, err end end if not old_key then return insert_ok, insert_err end local old_row, err = load_session_from_cache(old_key) if err then kong.log.notice(err) elseif old_row then PK.id = old_row.id if remember then local ok, err = kong.db.sessions:delete(PK) if not ok then if err then kong.log.notice(err) else kong.log.notice("unable to delete session data") end end else STALE_DATA.expires = current_time + stale_ttl TTL.ttl = stale_ttl local ok, err = kong.db.sessions:update(PK, STALE_DATA, TTL) if not ok then if err then kong.log.notice(err) else kong.log.notice("unable update session ttl") end end end end return insert_ok, insert_err end local function insert_session_timer(premature, ...) if premature then return end local ok, err = insert_session(...) if not ok then if err then kong.log.notice(err) else kong.log.warn("unable to insert session") end end end function storage:set(name, key, value, ttl, current_time, old_key, stale_ttl, metadata, remember) if get_phase() == "header_filter" then timer_at(0, insert_session_timer, key, value, ttl, current_time, old_key, stale_ttl, metadata, remember) return true end return insert_session(key, value, ttl, current_time, old_key, stale_ttl, metadata, remember) end function storage:get(name, key, current_time) if get_phase() == "header_filter" then return end local row, err = load_session_from_cache(key) if not row then return nil, err end return row.data end function storage:delete(name, key, current_time, metadata) local row, err = load_session_from_cache(key) if not row then return nil, err end PK.id = row.id return kong.db.sessions:delete(PK) end return storage