diff --git a/lua/cfc_http_restrictions/shared/url.lua b/lua/cfc_http_restrictions/shared/url.lua index 22598f2..1c19c38 100644 --- a/lua/cfc_http_restrictions/shared/url.lua +++ b/lua/cfc_http_restrictions/shared/url.lua @@ -59,16 +59,16 @@ function CFCHTTP.ReplaceURLs( text, f ) return html end -local parsedAddressCache = {} +local parsedAddressCache = CFCHTTP.LimitedCache.New( 1000, 60 * 60 ) ---@param url string ---@return string|nil function CFCHTTP.GetAddress( url ) if not url then return end - local cached = parsedAddressCache[url] + local cached = parsedAddressCache:Get( url ) if cached then return cached end local data = CFCHTTP.ParseURL( url ) - parsedAddressCache[url] = data.address + parsedAddressCache:Set( url, data.address ) return data.address end diff --git a/lua/includes/modules/cfchttp/limitedcache.lua b/lua/includes/modules/cfchttp/limitedcache.lua new file mode 100644 index 0000000..fc65259 --- /dev/null +++ b/lua/includes/modules/cfchttp/limitedcache.lua @@ -0,0 +1,79 @@ +---@alias LimitedCacheValue {key: string, value: any, created: number} + +---@class LimitedCache +---@field private data table +---@field private queue table +---@field private limit number +---@field private ttlSeconds number +---@field private first number +---@field private last number +local cacheIndex = {} + +---@param key string +---@param value any +function cacheIndex:Set( key, value ) + self:pruneQueue() + + local v = { + key = key, + value = value, + created = os.time(), + } + + self.data[key] = v + self:pushRight( v ) +end + +---@param key string +---@return any +function cacheIndex:Get( key ) + local v = self.data[key] + if v then + return v.value + end +end + +function cacheIndex:pushRight( value ) + local last = self.last + 1 + self.last = last + self.queue[last] = value +end + +function cacheIndex:pruneQueue() + local amountOverLimit = self.last - self.first - self.limit + + for i = self.first, self.last do + local v = self.queue[i] + if os.time() - v.created <= self.ttlSeconds and amountOverLimit <= 0 then + break + end + self.queue[i] = nil + self.data[v.key] = nil + self.first = self.first + 1 + amountOverLimit = amountOverLimit - 1 + end +end + +---@param limit number +---@param ttlSeconds number +local function New( limit, ttlSeconds ) + limit = limit or 1000 + ttlSeconds = ttlSeconds or (60 * 60) + return setmetatable( { + data = {}, + queue = {}, + + limit = limit, + ttlSeconds = ttlSeconds, + + first = 0, + last = -1, + }, { + __index = cacheIndex, + } ) +end + +CFCHTTP = CFCHTTP or {} +CFCHTTP.LimitedCache = { + New = New, +}