forked from datawhale/whale-town-end
feat(zulip): 添加全面的 Zulip 集成系统
* **新增 Zulip 模块**:包含完整的集成服务,涵盖客户端池(client pool)、会话管理及事件处理。 * **新增 WebSocket 网关**:用于处理 Zulip 的实时事件监听与双向通信。 * **新增安全服务**:支持 API 密钥加密存储及凭据的安全管理。 * **新增配置管理服务**:支持配置热加载(hot-reload),实现动态配置更新。 * **新增错误处理与监控服务**:提升系统的可靠性与可观测性。 * **新增消息过滤服务**:用于内容校验及速率限制(流控)。 * **新增流初始化与会话清理服务**:优化资源管理与回收。 * **完善测试覆盖**:包含单元测试及端到端(e2e)集成测试。 * **完善详细文档**:包括 API 参考手册、配置指南及集成概述。 * **新增地图配置系统**:实现游戏地点与 Zulip Stream(频道)及 Topic(话题)的逻辑映射。 * **新增环境变量配置**:涵盖 Zulip 服务器地址、身份验证及监控相关设置。 * **更新 App 模块**:注册并启用新的 Zulip 集成模块。 * **更新 Redis 接口**:以支持增强型的会话管理功能。 * **实现 WebSocket 协议支持**:确保与 Zulip 之间的实时双向通信。
This commit is contained in:
515
src/business/zulip/interfaces/zulip.interfaces.ts
Normal file
515
src/business/zulip/interfaces/zulip.interfaces.ts
Normal file
@@ -0,0 +1,515 @@
|
||||
/**
|
||||
* Zulip集成系统接口定义
|
||||
*
|
||||
* 功能描述:
|
||||
* - 定义Zulip集成系统中使用的所有接口和类型
|
||||
* - 提供类型安全和代码提示支持
|
||||
* - 统一数据结构定义
|
||||
*
|
||||
* @author 开发团队
|
||||
* @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;
|
||||
}
|
||||
Reference in New Issue
Block a user