Test library version
This commit is contained in:
133
src/lib/server/redis.ts
Normal file
133
src/lib/server/redis.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { Redis } from 'ioredis';
|
||||
import { env } from '$env/dynamic/private';
|
||||
|
||||
export type RedisValue = string | number | boolean | object | null;
|
||||
|
||||
interface RedisConfig {
|
||||
host: string;
|
||||
port: number;
|
||||
password?: string;
|
||||
db?: number;
|
||||
}
|
||||
|
||||
class Cache {
|
||||
private redis: Redis;
|
||||
private _isReady: boolean;
|
||||
private readonly _readyPromise: Promise<boolean>;
|
||||
|
||||
constructor(config?: Partial<RedisConfig>) {
|
||||
const redisConfig: RedisConfig = {
|
||||
host: env.REDIS_HOST || '127.0.0.1',
|
||||
port: env.REDIS_PORT ? parseInt(env.REDIS_PORT) : 6379,
|
||||
password: env.REDIS_PASSWORD,
|
||||
db: env.REDIS_DB ? parseInt(env.REDIS_DB) : 0,
|
||||
...config
|
||||
};
|
||||
|
||||
this.redis = new Redis(redisConfig);
|
||||
this._isReady = false;
|
||||
this._readyPromise = new Promise<boolean>((resolve, reject) => {
|
||||
this.redis.on('ready', () => {
|
||||
this._isReady = true;
|
||||
resolve(true);
|
||||
});
|
||||
this.redis.on('error', (err: Error) => {
|
||||
if (!this._isReady) reject(err);
|
||||
console.error('Redis error:', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async ready(): Promise<boolean> {
|
||||
if (this._isReady) return true;
|
||||
return this._readyPromise;
|
||||
}
|
||||
|
||||
async put(key: string, value: RedisValue, ttl?: number): Promise<boolean> {
|
||||
await this.ready();
|
||||
try {
|
||||
const serialized = JSON.stringify(value);
|
||||
if (ttl) {
|
||||
await this.redis.set(key, serialized, 'EX', ttl);
|
||||
} else {
|
||||
await this.redis.set(key, serialized);
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Cache put error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async get<T extends RedisValue = RedisValue>(
|
||||
key: string,
|
||||
defaultValue: T | null = null
|
||||
): Promise<T | null> {
|
||||
await this.ready();
|
||||
try {
|
||||
const value = await this.redis.get(key);
|
||||
return value ? (JSON.parse(value) as T) : defaultValue;
|
||||
} catch (error) {
|
||||
console.error('Cache get error:', error);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
async has(key: string): Promise<boolean> {
|
||||
await this.ready();
|
||||
try {
|
||||
return (await this.redis.exists(key)) === 1;
|
||||
} catch (error) {
|
||||
console.error('Cache has error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async forget(key: string): Promise<boolean> {
|
||||
await this.ready();
|
||||
try {
|
||||
return (await this.redis.del(key)) > 0;
|
||||
} catch (error) {
|
||||
console.error('Cache forget error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async flush(): Promise<boolean> {
|
||||
await this.ready();
|
||||
try {
|
||||
await this.redis.flushdb();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Cache flush error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async forever(key: string, value: RedisValue): Promise<boolean> {
|
||||
return this.put(key, value);
|
||||
}
|
||||
|
||||
async remember<T extends RedisValue>(
|
||||
key: string,
|
||||
ttl: number,
|
||||
callback: () => Promise<T> | T
|
||||
): Promise<T> {
|
||||
const cached = await this.get<T>(key);
|
||||
if (cached !== null) return cached;
|
||||
|
||||
const value = await callback();
|
||||
await this.put(key, value, ttl);
|
||||
return value;
|
||||
}
|
||||
|
||||
async rememberForever<T extends RedisValue>(
|
||||
key: string,
|
||||
callback: () => Promise<T> | T
|
||||
): Promise<T> {
|
||||
return this.remember(key, 0, callback);
|
||||
}
|
||||
}
|
||||
|
||||
const cache = new Cache();
|
||||
export default cache;
|
||||
Reference in New Issue
Block a user