1
|
5 |
|
import { createHash } from 'node:crypto'; |
2
|
|
|
import { Cache } from '@/ExpressBeansTypes'; |
3
|
5 |
|
import { logger, registeredMethods } from '@/core'; |
4
|
|
|
|
5
|
|
|
type BeanFunction = (...args: any) => any |
6
|
|
|
type CacheEntry = { |
7
|
|
|
data: ReturnType<BeanFunction>, |
8
|
|
|
expiration: number, |
9
|
|
|
} |
10
|
|
|
|
11
|
8 |
|
const createKey = (obj: any) => createHash('sha224') |
12
|
|
|
.update(JSON.stringify(obj)) |
13
|
|
|
.digest('hex'); |
14
|
|
|
|
15
|
5 |
|
const getCachedData = (cache: Map<string, CacheEntry>, key: string) => { |
16
|
8 |
|
const cached = cache.get(key); |
17
|
8 |
|
if (!cached) { |
18
|
4 |
|
throw new Error(`Key ${key} not found in cache`); |
19
|
|
|
} |
20
|
4 |
|
if (cached.expiration < Date.now()) { |
21
|
1 |
|
cache.delete(key); |
22
|
1 |
|
throw new Error(`Key ${key} expired in cache`); |
23
|
|
|
} |
24
|
3 |
|
return cached; |
25
|
|
|
}; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Caches the result of a method |
29
|
|
|
* @param options {Cache} |
30
|
|
|
* @decorator |
31
|
|
|
*/ |
32
|
5 |
|
export function Cached<This>( |
33
|
|
|
options: Cache = { duration: 60_000, type: 'memory' }, |
34
|
|
|
) { |
35
|
3 |
|
return ( |
36
|
|
|
method: BeanFunction, |
37
|
|
|
context: ClassMethodDecoratorContext<This, BeanFunction>, |
38
|
|
|
) => { |
39
|
3 |
|
logger.debug(`Initializing cache for method ${String(context.name)}`); |
40
|
3 |
|
const cache = new Map<string, CacheEntry>(); |
41
|
3 |
|
return (...args: any) => { |
42
|
8 |
|
const key = createKey(args); |
43
|
|
|
let result; |
44
|
8 |
|
try { |
45
|
8 |
|
result = getCachedData(cache, key); |
46
|
3 |
|
logger.debug(`Returning cached data for ${key}`); |
47
|
|
|
} catch (error) { |
48
|
5 |
|
logger.debug(error); |
49
|
5 |
|
const computed = method.bind(registeredMethods.get(method))(...args); |
50
|
5 |
|
cache.set(key, { |
51
|
|
|
data: computed, |
52
|
|
|
expiration: Date.now() + options.duration, |
53
|
|
|
}); |
54
|
5 |
|
return computed; |
55
|
|
|
} |
56
|
3 |
|
logger.debug(result); |
57
|
3 |
|
return result.data; |
58
|
|
|
}; |
59
|
|
|
}; |
60
|
|
|
} |
61
|
|
|
|