/
QueryCache.ts
90 lines (77 loc) 路 2.63 KB
/
QueryCache.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { Player } from '../Player';
import { SearchResult } from '../Structures/SearchResult';
import { Track } from '../Structures/Track';
import { User } from 'discord.js';
import { SearchQueryType } from '../types/types';
export interface QueryCacheOptions {
checkInterval?: number;
}
// 5h
const DEFAULT_EXPIRY_TIMEOUT = 18_000_000;
export class QueryCache {
#defaultCache = new Map<string, DiscordPlayerQueryResultCache<Track>>();
public timer: NodeJS.Timer;
public constructor(
public player: Player,
public options: QueryCacheOptions = {
checkInterval: DEFAULT_EXPIRY_TIMEOUT
}
) {
this.timer = setInterval(this.cleanup.bind(this), this.checkInterval).unref();
}
public get checkInterval() {
return this.options.checkInterval ?? DEFAULT_EXPIRY_TIMEOUT;
}
public async cleanup() {
for (const [id, value] of this.#defaultCache) {
if (value.hasExpired()) {
this.#defaultCache.delete(id);
}
}
}
public async clear() {
this.#defaultCache.clear();
}
public async getData() {
return [...this.#defaultCache.values()];
}
public async addData(data: SearchResult) {
data.tracks.forEach((d) => {
if (this.#defaultCache.has(d.url)) return;
this.#defaultCache.set(d.url, new DiscordPlayerQueryResultCache(d));
});
}
public async resolve(context: QueryCacheResolverContext) {
const result = this.#defaultCache.get(context.query);
if (!result)
return new SearchResult(this.player, {
query: context.query,
requestedBy: context.requestedBy,
queryType: context.queryType
});
return new SearchResult(this.player, {
query: context.query,
tracks: [result.data],
playlist: null,
queryType: context.queryType,
requestedBy: context.requestedBy
});
}
}
export class DiscordPlayerQueryResultCache<T = unknown> {
public expireAfter = DEFAULT_EXPIRY_TIMEOUT;
public constructor(public data: T, expireAfter: number = DEFAULT_EXPIRY_TIMEOUT) {
if (typeof expireAfter === 'number') {
this.expireAfter = Date.now() + expireAfter;
}
}
public hasExpired() {
if (typeof this.expireAfter !== 'number' || isNaN(this.expireAfter) || this.expireAfter < 1) return false;
return Date.now() <= this.expireAfter;
}
}
export interface QueryCacheResolverContext {
query: string;
requestedBy?: User;
queryType?: SearchQueryType | `ext:${string}`;
}