Permalink
Please
sign in to comment.
Browse files
feat(apps/user-access): aggressively cache user access
* cache user access by login * invalidate user access based on received webhook events Related to #80
- Loading branch information
Showing
with
262 additions
and 33 deletions.
@@ -0,0 +1,117 @@ | ||
/** | ||
* A cache that allows tree-like keys | ||
*/ | ||
class TreeCache { | ||
|
||
constructor(ttl = -1) { | ||
this._cache = {}; | ||
this._accessed = {}; | ||
|
||
this._ttl = ttl; | ||
} | ||
|
||
async get(key, defaultValue) { | ||
|
||
this._access(key); | ||
|
||
if (key in this._cache) { | ||
return this._cache[key]; | ||
} | ||
|
||
if (typeof defaultValue === 'function') { | ||
defaultValue = await defaultValue(key); | ||
} | ||
|
||
this.set(key, defaultValue); | ||
|
||
return defaultValue; | ||
} | ||
|
||
set(key, value) { | ||
this._cache[key] = value; | ||
} | ||
|
||
_access(key) { | ||
this._accessed[key] = Date.now(); | ||
} | ||
|
||
invalidate(key) { | ||
|
||
const matches = this.match(key); | ||
|
||
for (const match of matches) { | ||
this.remove(match.key); | ||
} | ||
} | ||
|
||
match(key) { | ||
|
||
let test; | ||
|
||
if (key.includes('*')) { | ||
const pattern = new RegExp('^' + key.split('*').map(regexEscape).join('([^:]+)') + '$'); | ||
|
||
test = (str) => pattern.exec(str); | ||
} else { | ||
test = (str) => str === key; | ||
} | ||
|
||
const matches = []; | ||
|
||
for (const cacheKey of Object.keys(this._cache)) { | ||
|
||
const match = test(cacheKey); | ||
|
||
if (!match) { | ||
continue; | ||
} | ||
|
||
if (match === true) { | ||
matches.push({ | ||
key: cacheKey, | ||
value: this._cache[cacheKey], | ||
match: [] | ||
}); | ||
} else { | ||
|
||
const [ _, ...matchedPatterns ] = match; | ||
|
||
matches.push({ | ||
key: cacheKey, | ||
value: this._cache[cacheKey], | ||
match: matchedPatterns | ||
}); | ||
} | ||
} | ||
|
||
return matches; | ||
} | ||
|
||
remove(key) { | ||
delete this._cache[key]; | ||
delete this._accessed[key]; | ||
} | ||
|
||
evict(now = Date.now()) { | ||
|
||
const evictBefore = now - this._ttl; | ||
|
||
for (const [ key, accessed ] of Object.entries(this._accessed)) { | ||
|
||
if (accessed < evictBefore) { | ||
this.remove(key); | ||
} | ||
} | ||
|
||
} | ||
|
||
} | ||
|
||
module.exports = TreeCache; | ||
|
||
|
||
// helpers /////////////// | ||
|
||
function regexEscape(s) { | ||
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} |
0 comments on commit
de5403d