@trifrost/core
Version:
Blazingly fast, runtime-agnostic server framework for modern edge and node environments
77 lines (76 loc) • 2.05 kB
JavaScript
import { split } from '@valkyriestudios/utils/array';
import { TriFrostCache } from '../modules/Cache/_Cache';
import { TriFrostRateLimit } from '../modules/RateLimit/_RateLimit';
import { Store } from './_Storage';
/**
* MARK: Adapter
*/
export class RedisStoreAdapter {
#redis;
constructor(redis) {
this.#redis = redis;
}
async get(key) {
const val = await this.#redis.get(key);
if (!val)
return null;
return JSON.parse(val);
}
async set(key, value, ttl) {
await this.#redis.set(key, JSON.stringify(value), 'EX', ttl);
}
async del(key) {
await this.#redis.del(key);
}
async delPrefixed(prefix) {
let cursor = '0';
const acc = new Set();
do {
const [next, keys] = await this.#redis.scan(cursor, 'MATCH', prefix + '*', 'COUNT', 250);
cursor = next;
for (let i = 0; i < keys.length; i++)
acc.add(keys[i]);
} while (cursor && cursor !== '0');
if (!acc.size)
return;
for (const batch of split([...acc], 100)) {
await this.#redis.del(...batch);
}
}
async stop() {
/* Nothing to do here */
}
}
/**
* MARK: Store
*/
export class RedisStore extends Store {
constructor(redis) {
super('RedisStore', new RedisStoreAdapter(redis));
}
}
/**
* MARK: Cache
*/
export class RedisCache extends TriFrostCache {
constructor(cfg) {
if (!cfg?.store)
throw new Error('RedisCache: Expected a store initializer');
super({
store: new Store('RedisCache', new RedisStoreAdapter(cfg.store)),
});
}
}
/**
* MARK: RateLimit
*/
export class RedisRateLimit extends TriFrostRateLimit {
constructor(cfg) {
if (!cfg?.store)
throw new Error('RedisRateLimit: Expected a store initializer');
super({
...cfg,
store: new Store('RedisRateLimit', new RedisStoreAdapter(cfg.store)),
});
}
}