import { RedisClientType, createClient } from 'redis'; import { StorageInterface } from "./StorageInterface"; let client: RedisClientType; /** * Implementace úložiště využívající Redis server. */ export default class RedisStorage implements StorageInterface { constructor() { const HOST = process.env.REDIS_HOST ?? 'localhost'; const PORT = process.env.REDIS_PORT ?? 6379; client = createClient({ url: `redis://${HOST}:${PORT}` }) as RedisClientType; } async initialize() { await client.connect(); } async hasData(key: string) { const data = await client.json.get(key); return (!!data); } async getData(key: string) { const data = await client.json.get(key, { path: '.' }); return data as Type; } async setData(key: string, data: Type) { await client.json.set(key, '.', data as any); } async updateData(key: string, mutator: (current: Type | undefined) => Type): Promise { return (client as any).executeIsolated(async (c: any) => { for (let attempt = 0; attempt < 10; attempt++) { await c.watch(key); const current = await c.json.get(key, { path: '.' }) as Type | undefined; const next = mutator(current); const multi = c.multi(); multi.json.set(key, '.', next); const result = await multi.exec(); if (result !== null) return next; } throw new Error(`updateData: optimistic lock failed after 10 retries for key: ${key}`); }); } async healthCheck(): Promise { try { const pong = await client.ping(); return pong === 'PONG'; } catch { return false; } } } /** Vrátí hlavní Redis klient — používá se pro lease připomínkovače a shutdown. */ export function getRedisClient(): RedisClientType | undefined { return client; } /** Zavře připojení k Redisu. Volá se při graceful shutdown. */ export async function shutdownRedisStorage(): Promise { await client?.quit(); }