local http_rq = require 'http.request' local json = require 'json' local lmdb = require 'lmdb' local M = {} local db local function get_db() if db then return db end db = assert(lmdb.open("data/cache.mdb", {nosubdir = true, mapsize = 2^20})) return db end function M.lookup(domain) if not domain:match "^[%w_%-%.]+$" then return nil, "invalid service name!" end domain = domain:gsub('%.+', ".") local db = get_db() local txn = db:txn_begin() if txn then local cache = txn:open() if cache[domain] then local sv = json.decode(cache[domain]) if os.time() <= sv.expires then txn:commit() return sv end end txn:commit() end local meta_uri = "https://"..domain.."/.well-known/citrons/auth" local rq = http_rq.new_from_uri(meta_uri) local headers, stream = rq:go(8) if not headers then return nil, stream end if headers:get ":status" ~= "200" then return nil, "HTTP error: "..headers:get ":status" end local data, err = stream:get_body_chars(4096, 4) if not data then return nil, err end local ok, result = pcall(json.decode, data) if not ok then return nil, "could not decode JSON" end local txn = db:txn_begin(true) if txn then local cache = txn:open() result.expires = os.time() + (result.ttl or 300) cache[domain] = json.encode(result) pcall(txn.commit, txn) end return result end return M