refactor:重构Zulip模块按业务功能模块化架构

- 将技术实现服务从business层迁移到core层
- 创建src/core/zulip/核心服务模块,包含API客户端、连接池等技术服务
- 保留src/business/zulip/业务逻辑,专注游戏相关的业务规则
- 通过依赖注入实现业务层与核心层的解耦
- 更新模块导入关系,确保架构分层清晰

重构后的架构符合单一职责原则,提高了代码的可维护性和可测试性
This commit is contained in:
moyin
2025-12-31 15:44:36 +08:00
parent 5140bd1a54
commit 2d10131838
36 changed files with 2773 additions and 125 deletions

View File

@@ -0,0 +1,515 @@
/**
* Zulip集成系统接口定义
*
* 功能描述:
* - 定义Zulip集成系统中使用的所有接口和类型
* - 提供类型安全和代码提示支持
* - 统一数据结构定义
*
* @author angjustinl
* @version 1.0.0
* @since 2025-12-25
*/
/**
* 游戏协议消息接口
*/
export namespace GameProtocol {
/**
* 登录消息接口
*/
export interface LoginMessage {
type: 'login';
token: string;
}
/**
* 聊天消息接口
*/
export interface ChatMessage {
t: 'chat';
content: string;
scope: string; // "local" 或 topic名称
}
/**
* 位置更新消息接口
*/
export interface PositionMessage {
t: 'position';
x: number;
y: number;
mapId: string;
}
/**
* 聊天渲染消息接口 - 发送给客户端
*/
export interface ChatRenderMessage {
t: 'chat_render';
from: string;
txt: string;
bubble: boolean;
}
/**
* 登录成功消息接口
*/
export interface LoginSuccessMessage {
t: 'login_success';
sessionId: string;
currentMap: string;
}
/**
* 错误消息接口
*/
export interface ErrorMessage {
t: 'error';
message: string;
code?: string;
}
}
/**
* Zulip API接口
*/
export namespace ZulipAPI {
/**
* Zulip消息接口
*/
export interface Message {
id: number;
sender_email: string;
sender_full_name: string;
content: string;
stream_id: number;
subject: string;
timestamp: number;
}
/**
* Zulip事件接口
*/
export interface Event {
type: string;
message?: Message;
queue_id: string;
}
/**
* Zulip Stream接口
*/
export interface Stream {
stream_id: number;
name: string;
description: string;
}
/**
* 发送消息请求接口
*/
export interface SendMessageRequest {
type: 'stream';
to: string;
subject: string;
content: string;
}
/**
* 事件队列注册请求接口
*/
export interface RegisterQueueRequest {
event_types: string[];
narrow?: Array<[string, string]>;
}
/**
* 事件队列响应接口
*/
export interface RegisterQueueResponse {
queue_id: string;
last_event_id: number;
}
}
/**
* 系统内部接口
*/
export namespace Internal {
/**
* 位置信息接口
*/
export interface Position {
x: number;
y: number;
}
/**
* 游戏会话接口
*
* 功能描述:
* - 维护WebSocket连接ID与Zulip队列ID的映射关系
* - 跟踪玩家位置和地图信息
* - 支持会话状态的序列化和反序列化
*
* Redis存储结构
* - Key: zulip:session:{socketId}
* - Value: JSON序列化的GameSession对象
* - TTL: 3600秒1小时
*
* @since 2025-12-25
*/
export interface GameSession {
socketId: string; // WebSocket连接ID
userId: string; // 用户ID
username: string; // 用户名
zulipQueueId: string; // Zulip事件队列ID (关键绑定)
currentMap: string; // 当前地图ID
position: Position; // 当前位置
lastActivity: Date; // 最后活动时间
createdAt: Date; // 会话创建时间
}
/**
* 游戏会话序列化格式用于Redis存储
*/
export interface GameSessionSerialized {
socketId: string;
userId: string;
username: string;
zulipQueueId: string;
currentMap: string;
position: Position;
lastActivity: string; // ISO 8601格式的日期字符串
createdAt: string; // ISO 8601格式的日期字符串
}
/**
* 创建会话请求接口
*/
export interface CreateSessionRequest {
socketId: string;
userId: string;
username?: string;
zulipQueueId: string;
initialMap?: string;
initialPosition?: Position;
}
/**
* 会话统计信息接口
*/
export interface SessionStats {
totalSessions: number;
mapDistribution: Record<string, number>;
oldestSession?: Date;
newestSession?: Date;
}
/**
* Zulip客户端接口
*/
export interface ZulipClient {
userId: string;
apiKey: string;
queueId?: string;
client?: any;
createdAt: Date;
lastActivity: Date;
}
/**
* 地图配置接口
*
* 功能描述:
* - 定义游戏地图到Zulip Stream的映射关系
* - 包含地图内的交互对象配置
*
* 验证规则:
* - mapId: 必填,非空字符串,唯一标识
* - mapName: 必填,非空字符串,用于显示
* - zulipStream: 必填非空字符串对应Zulip Stream名称
* - interactionObjects: 可选,交互对象数组
*
* @since 2025-12-25
*/
export interface MapConfig {
mapId: string; // 地图ID (例如: "whale_port")
mapName: string; // 地图名称 (例如: "新手村")
zulipStream: string; // 对应的Zulip Stream (例如: "Whale Port")
description?: string; // 地图描述(可选)
interactionObjects: InteractionObject[]; // 交互对象配置
}
/**
* 交互对象接口
*
* 功能描述:
* - 定义地图内交互对象到Zulip Topic的映射关系
* - 包含对象位置信息用于空间过滤
*
* 验证规则:
* - objectId: 必填,非空字符串,唯一标识
* - objectName: 必填,非空字符串,用于显示
* - zulipTopic: 必填非空字符串对应Zulip Topic名称
* - position: 必填包含有效的x和y坐标
*
* @since 2025-12-25
*/
export interface InteractionObject {
objectId: string; // 对象ID (例如: "notice_board")
objectName: string; // 对象名称 (例如: "公告板")
zulipTopic: string; // 对应的Zulip Topic (例如: "Notice Board")
position: { // 对象位置
x: number;
y: number;
};
}
/**
* 地图配置文件结构接口
*
* 功能描述:
* - 定义配置文件的根结构
* - 用于配置文件的加载和验证
*
* @since 2025-12-25
*/
export interface MapConfigFile {
maps: MapConfig[]; // 地图配置数组
version?: string; // 配置版本(可选)
lastModified?: string; // 最后修改时间(可选)
}
/**
* 配置验证结果接口
*
* 功能描述:
* - 定义配置验证的结果结构
* - 包含验证状态和错误信息
*
* @since 2025-12-25
*/
export interface ConfigValidationResult {
valid: boolean; // 是否有效
errors: string[]; // 错误信息列表
warnings?: string[]; // 警告信息列表(可选)
}
/**
* 配置统计信息接口
*
* 功能描述:
* - 定义配置统计信息的结构
* - 用于监控和调试
*
* @since 2025-12-25
*/
export interface ConfigStats {
mapCount: number; // 地图数量
totalObjects: number; // 交互对象总数
configLoadTime: Date; // 配置加载时间
isValid: boolean; // 配置是否有效
}
/**
* 上下文信息接口
*/
export interface ContextInfo {
stream: string;
topic?: string;
}
/**
* 消息过滤结果接口
*/
export interface ContentFilterResult {
allowed: boolean;
filtered?: string;
reason?: string;
}
/**
* 错误处理结果接口
*/
export interface ErrorHandlingResult {
success: boolean;
shouldRetry: boolean;
retryAfter?: number;
degradedMode?: boolean;
message: string;
}
}
/**
* 服务请求接口
*/
export namespace ServiceRequests {
/**
* 玩家登录请求
*/
export interface PlayerLoginRequest {
token: string;
socketId: string;
}
/**
* 聊天消息请求
*/
export interface ChatMessageRequest {
socketId: string;
content: string;
scope: string;
}
/**
* 位置更新请求
*/
export interface PositionUpdateRequest {
socketId: string;
x: number;
y: number;
mapId: string;
}
}
/**
* 服务响应接口
*/
export namespace ServiceResponses {
/**
* 基础响应接口
*/
export interface BaseResponse {
success: boolean;
error?: string;
}
/**
* 登录响应
*/
export interface LoginResponse extends BaseResponse {
sessionId?: string;
}
/**
* 聊天消息响应
*/
export interface ChatMessageResponse extends BaseResponse {
messageId?: string;
}
}
/**
* 配置接口
*/
export namespace Config {
/**
* Zulip配置接口
*/
export interface ZulipConfig {
zulipServerUrl: string;
zulipBotEmail: string;
zulipBotApiKey: string;
websocketPort: number;
websocketNamespace: string;
messageRateLimit: number;
messageMaxLength: number;
sessionTimeout: number;
cleanupInterval: number;
enableContentFilter: boolean;
allowedStreams: string[];
}
/**
* 重试配置接口
*/
export interface RetryConfig {
maxRetries: number;
baseDelay: number;
maxDelay: number;
backoffMultiplier: number;
}
}
/**
* 枚举定义
*/
export namespace Enums {
/**
* 服务状态枚举
*/
export enum ServiceStatus {
NORMAL = 'normal',
DEGRADED = 'degraded',
UNAVAILABLE = 'unavailable',
}
/**
* 错误类型枚举
*/
export enum ErrorType {
ZULIP_API_ERROR = 'zulip_api_error',
CONNECTION_ERROR = 'connection_error',
TIMEOUT_ERROR = 'timeout_error',
AUTHENTICATION_ERROR = 'authentication_error',
RATE_LIMIT_ERROR = 'rate_limit_error',
UNKNOWN_ERROR = 'unknown_error',
}
/**
* 违规类型枚举
*/
export enum ViolationType {
CONTENT = 'content',
RATE = 'rate',
PERMISSION = 'permission',
}
/**
* 消息范围枚举
*/
export enum MessageScope {
LOCAL = 'local',
GLOBAL = 'global',
TOPIC = 'topic',
}
}
/**
* 常量定义
*/
export namespace Constants {
/**
* Redis键前缀
*/
export const REDIS_PREFIXES = {
SESSION: 'zulip:session:',
MAP_PLAYERS: 'zulip:map_players:',
RATE_LIMIT: 'zulip:rate_limit:',
VIOLATION: 'zulip:violation:',
} as const;
/**
* 默认配置值
*/
export const DEFAULTS = {
SESSION_TIMEOUT: 3600, // 1小时
RATE_LIMIT: 10, // 每分钟10条消息
RATE_LIMIT_WINDOW: 60, // 60秒窗口
MESSAGE_MAX_LENGTH: 1000,
RETRY_MAX_ATTEMPTS: 3,
RETRY_BASE_DELAY: 1000,
WEBSOCKET_NAMESPACE: '/game',
} as const;
/**
* 默认地图配置
*/
export const DEFAULT_MAPS = {
NOVICE_VILLAGE: 'novice_village',
TAVERN: 'tavern',
MARKET: 'market',
} as const;
}