* **新增 Zulip 模块**:包含完整的集成服务,涵盖客户端池(client pool)、会话管理及事件处理。 * **新增 WebSocket 网关**:用于处理 Zulip 的实时事件监听与双向通信。 * **新增安全服务**:支持 API 密钥加密存储及凭据的安全管理。 * **新增配置管理服务**:支持配置热加载(hot-reload),实现动态配置更新。 * **新增错误处理与监控服务**:提升系统的可靠性与可观测性。 * **新增消息过滤服务**:用于内容校验及速率限制(流控)。 * **新增流初始化与会话清理服务**:优化资源管理与回收。 * **完善测试覆盖**:包含单元测试及端到端(e2e)集成测试。 * **完善详细文档**:包括 API 参考手册、配置指南及集成概述。 * **新增地图配置系统**:实现游戏地点与 Zulip Stream(频道)及 Topic(话题)的逻辑映射。 * **新增环境变量配置**:涵盖 Zulip 服务器地址、身份验证及监控相关设置。 * **更新 App 模块**:注册并启用新的 Zulip 集成模块。 * **更新 Redis 接口**:以支持增强型的会话管理功能。 * **实现 WebSocket 协议支持**:确保与 Zulip 之间的实时双向通信。
177 lines
4.8 KiB
TypeScript
177 lines
4.8 KiB
TypeScript
import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import Redis from 'ioredis';
|
|
import { IRedisService } from './redis.interface';
|
|
|
|
/**
|
|
* 真实Redis服务
|
|
* 连接到真实的Redis服务器
|
|
*/
|
|
@Injectable()
|
|
export class RealRedisService implements IRedisService, OnModuleDestroy {
|
|
private readonly logger = new Logger(RealRedisService.name);
|
|
private redis: Redis;
|
|
|
|
constructor(private configService: ConfigService) {
|
|
this.initializeRedis();
|
|
}
|
|
|
|
/**
|
|
* 初始化Redis连接
|
|
*/
|
|
private initializeRedis(): void {
|
|
const redisConfig = {
|
|
host: this.configService.get<string>('REDIS_HOST', 'localhost'),
|
|
port: this.configService.get<number>('REDIS_PORT', 6379),
|
|
password: this.configService.get<string>('REDIS_PASSWORD') || undefined,
|
|
db: this.configService.get<number>('REDIS_DB', 0),
|
|
retryDelayOnFailover: 100,
|
|
maxRetriesPerRequest: 3,
|
|
lazyConnect: true,
|
|
};
|
|
|
|
this.redis = new Redis(redisConfig);
|
|
|
|
this.redis.on('connect', () => {
|
|
this.logger.log('Redis连接成功');
|
|
});
|
|
|
|
this.redis.on('error', (error) => {
|
|
this.logger.error('Redis连接错误', error);
|
|
});
|
|
|
|
this.redis.on('close', () => {
|
|
this.logger.warn('Redis连接关闭');
|
|
});
|
|
}
|
|
|
|
async set(key: string, value: string, ttl?: number): Promise<void> {
|
|
try {
|
|
if (ttl && ttl > 0) {
|
|
await this.redis.setex(key, ttl, value);
|
|
} else {
|
|
await this.redis.set(key, value);
|
|
}
|
|
this.logger.debug(`设置Redis键: ${key}, TTL: ${ttl || '永不过期'}`);
|
|
} catch (error) {
|
|
this.logger.error(`设置Redis键失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async get(key: string): Promise<string | null> {
|
|
try {
|
|
return await this.redis.get(key);
|
|
} catch (error) {
|
|
this.logger.error(`获取Redis键失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async del(key: string): Promise<boolean> {
|
|
try {
|
|
const result = await this.redis.del(key);
|
|
this.logger.debug(`删除Redis键: ${key}, 结果: ${result > 0}`);
|
|
return result > 0;
|
|
} catch (error) {
|
|
this.logger.error(`删除Redis键失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async exists(key: string): Promise<boolean> {
|
|
try {
|
|
const result = await this.redis.exists(key);
|
|
return result > 0;
|
|
} catch (error) {
|
|
this.logger.error(`检查Redis键存在性失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async expire(key: string, ttl: number): Promise<void> {
|
|
try {
|
|
await this.redis.expire(key, ttl);
|
|
this.logger.debug(`设置Redis键过期时间: ${key}, TTL: ${ttl}秒`);
|
|
} catch (error) {
|
|
this.logger.error(`设置Redis键过期时间失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async ttl(key: string): Promise<number> {
|
|
try {
|
|
return await this.redis.ttl(key);
|
|
} catch (error) {
|
|
this.logger.error(`获取Redis键TTL失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async flushall(): Promise<void> {
|
|
try {
|
|
await this.redis.flushall();
|
|
this.logger.log('清空所有Redis数据');
|
|
} catch (error) {
|
|
this.logger.error('清空Redis数据失败', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async setex(key: string, ttl: number, value: string): Promise<void> {
|
|
try {
|
|
await this.redis.setex(key, ttl, value);
|
|
this.logger.debug(`设置Redis键(setex): ${key}, TTL: ${ttl}秒`);
|
|
} catch (error) {
|
|
this.logger.error(`设置Redis键失败(setex): ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async incr(key: string): Promise<number> {
|
|
try {
|
|
const result = await this.redis.incr(key);
|
|
this.logger.debug(`自增Redis键: ${key}, 新值: ${result}`);
|
|
return result;
|
|
} catch (error) {
|
|
this.logger.error(`自增Redis键失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async sadd(key: string, member: string): Promise<void> {
|
|
try {
|
|
await this.redis.sadd(key, member);
|
|
this.logger.debug(`添加集合成员: ${key} -> ${member}`);
|
|
} catch (error) {
|
|
this.logger.error(`添加集合成员失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async srem(key: string, member: string): Promise<void> {
|
|
try {
|
|
await this.redis.srem(key, member);
|
|
this.logger.debug(`移除集合成员: ${key} -> ${member}`);
|
|
} catch (error) {
|
|
this.logger.error(`移除集合成员失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async smembers(key: string): Promise<string[]> {
|
|
try {
|
|
return await this.redis.smembers(key);
|
|
} catch (error) {
|
|
this.logger.error(`获取集合成员失败: ${key}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
onModuleDestroy(): void {
|
|
if (this.redis) {
|
|
this.redis.disconnect();
|
|
this.logger.log('Redis连接已断开');
|
|
}
|
|
}
|
|
} |