Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
156 lines
4.1 KiB
JavaScript
156 lines
4.1 KiB
JavaScript
import Redis from 'ioredis';
|
|
import { logger } from '../utils/logger.js';
|
|
|
|
export class RedisClient {
|
|
constructor() {
|
|
this.client = null;
|
|
}
|
|
|
|
static getInstance() {
|
|
if (!RedisClient.instance) {
|
|
RedisClient.instance = new RedisClient();
|
|
}
|
|
return RedisClient.instance;
|
|
}
|
|
|
|
async connect() {
|
|
const config = {
|
|
host: process.env.REDIS_HOST || 'localhost',
|
|
port: process.env.REDIS_PORT || 6379,
|
|
password: process.env.REDIS_PASSWORD || undefined,
|
|
db: parseInt(process.env.REDIS_DB) || 2, // Different DB for safety guard
|
|
retryStrategy: (times) => {
|
|
const delay = Math.min(times * 50, 2000);
|
|
return delay;
|
|
},
|
|
enableOfflineQueue: false
|
|
};
|
|
|
|
try {
|
|
this.client = new Redis(config);
|
|
|
|
this.client.on('connect', () => {
|
|
logger.info('Redis connection established');
|
|
});
|
|
|
|
this.client.on('error', (err) => {
|
|
logger.error('Redis error:', err);
|
|
});
|
|
|
|
this.client.on('close', () => {
|
|
logger.warn('Redis connection closed');
|
|
});
|
|
|
|
// Wait for connection
|
|
await this.client.ping();
|
|
|
|
return this.client;
|
|
} catch (error) {
|
|
logger.error('Failed to connect to Redis:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async checkHealth() {
|
|
try {
|
|
const result = await this.client.ping();
|
|
return result === 'PONG';
|
|
} catch (error) {
|
|
logger.error('Redis health check failed:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async disconnect() {
|
|
if (this.client) {
|
|
await this.client.quit();
|
|
logger.info('Redis connection closed');
|
|
}
|
|
}
|
|
|
|
// Cache methods with JSON serialization
|
|
async setWithExpiry(key, value, ttl) {
|
|
return await this.client.setex(key, ttl, JSON.stringify(value));
|
|
}
|
|
|
|
async get(key) {
|
|
const value = await this.client.get(key);
|
|
return value ? JSON.parse(value) : null;
|
|
}
|
|
|
|
async del(key) {
|
|
return await this.client.del(key);
|
|
}
|
|
|
|
async exists(key) {
|
|
return await this.client.exists(key);
|
|
}
|
|
|
|
// Hash operations
|
|
async hset(key, field, value) {
|
|
return await this.client.hset(key, field, JSON.stringify(value));
|
|
}
|
|
|
|
async hget(key, field) {
|
|
const value = await this.client.hget(key, field);
|
|
return value ? JSON.parse(value) : null;
|
|
}
|
|
|
|
async hdel(key, field) {
|
|
return await this.client.hdel(key, field);
|
|
}
|
|
|
|
async hgetall(key) {
|
|
const data = await this.client.hgetall(key);
|
|
const result = {};
|
|
for (const [field, value] of Object.entries(data)) {
|
|
result[field] = JSON.parse(value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// List operations
|
|
async lpush(key, value) {
|
|
return await this.client.lpush(key, JSON.stringify(value));
|
|
}
|
|
|
|
async rpush(key, value) {
|
|
return await this.client.rpush(key, JSON.stringify(value));
|
|
}
|
|
|
|
async lrange(key, start, stop) {
|
|
const items = await this.client.lrange(key, start, stop);
|
|
return items.map(item => JSON.parse(item));
|
|
}
|
|
|
|
async ltrim(key, start, stop) {
|
|
return await this.client.ltrim(key, start, stop);
|
|
}
|
|
|
|
// Set operations
|
|
async sadd(key, member) {
|
|
return await this.client.sadd(key, JSON.stringify(member));
|
|
}
|
|
|
|
async srem(key, member) {
|
|
return await this.client.srem(key, JSON.stringify(member));
|
|
}
|
|
|
|
async smembers(key) {
|
|
const members = await this.client.smembers(key);
|
|
return members.map(member => JSON.parse(member));
|
|
}
|
|
|
|
async sismember(key, member) {
|
|
return await this.client.sismember(key, JSON.stringify(member));
|
|
}
|
|
|
|
// Expiry operations
|
|
async expire(key, seconds) {
|
|
return await this.client.expire(key, seconds);
|
|
}
|
|
|
|
async ttl(key) {
|
|
return await this.client.ttl(key);
|
|
}
|
|
} |