# Zulip 业务模块

Zulip业务模块是游戏服务器与Zulip聊天系统集成的核心业务层，负责处理Zulip账号关联管理和事件处理的业务逻辑，实现游戏内聊天消息与Zulip平台的双向同步。

## 对外提供的接口

### ZulipAccountsBusinessService

#### create(createDto: CreateZulipAccountDto): Promise<ZulipAccountResponseDto>
创建游戏用户与Zulip账号的关联关系，支持数据验证和唯一性检查。

#### findByGameUserId(gameUserId: string, includeGameUser?: boolean): Promise<ZulipAccountResponseDto | null>
根据游戏用户ID查找对应的Zulip账号关联信息，支持缓存优化。

#### getStatusStatistics(): Promise<ZulipAccountStatsResponseDto>
获取所有Zulip账号关联的状态统计信息，包括活跃、非活跃、暂停、错误状态的数量。

### ZulipEventProcessorService

#### startEventProcessing(): Promise<void>
启动Zulip事件处理循环，监听所有活跃的事件队列。

#### stopEventProcessing(): Promise<void>
停止事件处理循环，清理所有事件队列资源。

#### registerEventQueue(queueId: string, userId: string, lastEventId?: number): Promise<void>
注册新的Zulip事件队列到处理列表中。

#### unregisterEventQueue(queueId: string): Promise<void>
从处理列表中注销指定的事件队列。

#### setMessageDistributor(distributor: MessageDistributor): void
设置消息分发器，用于向游戏客户端发送消息。

#### processMessageEvent(event: ZulipEvent, senderUserId: string): Promise<void>
处理Zulip消息事件，转换格式后分发给相关的游戏客户端。

#### convertMessageFormat(zulipMessage: ZulipMessage, streamName?: string): Promise<GameMessage>
将Zulip消息转换为游戏协议格式（chat_render）。

#### determineTargetPlayers(message: ZulipMessage, streamName: string, senderUserId: string): Promise<string[]>
根据消息的Stream确定应该接收消息的玩家（空间过滤）。

#### distributeMessage(gameMessage: GameMessage, targetPlayers: string[]): Promise<void>
通过WebSocket将消息发送给目标客户端。

#### broadcastToMap(mapId: string, gameMessage: GameMessage): Promise<void>
向指定地图区域内的所有在线玩家广播消息。

#### getProcessingStats(): EventProcessingStats
获取事件处理的统计信息，包括活跃队列数、处理事件数等。

## 使用的项目内部依赖

### ISessionQueryService (来自 core/session_core)
会话查询接口，用于获取地图中的在线玩家和会话信息，实现空间过滤功能。

### IZulipConfigService (来自 core/zulip_core)
Zulip配置服务接口，用于获取Stream与地图的映射关系。

### IZulipClientPoolService (来自 core/zulip_core)
Zulip客户端池服务接口，用于获取用户的Zulip客户端实例。

### ZulipAccountsRepository (来自 core/db/zulip_accounts)
Zulip账号数据仓库，提供账号关联的CRUD操作。

### AppLoggerService (来自 core/utils/logger)
日志服务，用于记录业务操作和系统事件。

### Cache (来自 @nestjs/cache-manager)
缓存管理器，用于缓存账号查询结果和统计数据，提升查询性能。

### CreateZulipAccountDto, ZulipAccountResponseDto (来自 core/db/zulip_accounts)
数据传输对象，定义账号创建和响应的数据结构。

## 核心特性

### 事件队列轮询机制
- 支持多用户并发事件队列管理
- 2秒轮询间隔，非阻塞模式获取事件
- 自动处理队列错误和重连机制
- 支持队列的动态注册和注销

### 消息格式转换
- Zulip消息到游戏协议（chat_render）的自动转换
- Markdown格式移除，保留纯文本内容
- HTML标签清理和实体解码
- 消息长度限制（200字符）和截断处理

### 空间过滤机制
- 根据Zulip Stream确定对应的游戏地图
- 从SessionManager获取地图内的在线玩家
- 自动排除消息发送者，避免收到自己的消息
- 支持区域广播功能

### 缓存优化
- 账号查询结果缓存（5分钟TTL）
- 统计数据缓存（1分钟TTL）
- 自动缓存失效和更新机制
- 缓存键前缀隔离

### 性能监控
- 操作耗时记录和日志输出
- 事件处理统计（处理事件数、消息数）
- 队列状态监控（活跃队列数、总队列数）
- 最后事件时间追踪

## 潜在风险

### 事件队列连接风险
- Zulip服务器不可用时事件队列无法获取
- 队列ID过期导致BAD_EVENT_QUEUE_ID错误
- 网络不稳定时轮询失败
- 缓解措施：自动禁用错误队列、支持队列重新激活、错误日志记录

### 消息分发延迟风险
- 大量并发消息可能导致分发延迟
- WebSocket连接断开时消息丢失
- 目标玩家列表过大时性能下降
- 缓解措施：异步分发、连接状态检查、分批发送

### 缓存一致性风险
- 缓存数据与数据库不一致
- 缓存清理失败导致脏数据
- 高并发下缓存穿透
- 缓解措施：写操作后主动清理缓存、缓存失败降级查询、合理设置TTL

### 内存泄漏风险
- 事件队列未正确注销导致内存累积
- 长时间运行后统计数据累积
- 缓解措施：模块销毁时清理资源、提供统计重置接口

## 架构定位

- **层级**: Business层（业务层）
- **职责**: 业务逻辑处理、服务协调
- **依赖**: Core层的ZulipCoreModule、ZulipAccountsModule等

## 文件结构

```
src/business/zulip/
├── services/
│   ├── zulip_accounts_business.service.ts    # Zulip账号业务服务
│   ├── zulip_accounts_business.service.spec.ts
│   ├── zulip_event_processor.service.ts      # Zulip事件处理服务
│   └── zulip_event_processor.service.spec.ts
├── zulip.module.ts                           # 业务模块定义
├── zulip.module.spec.ts                      # 模块测试
└── README.md                                 # 本文档
```

## 依赖关系

```
ZulipModule (Business层)
  ├─ imports: ZulipCoreModule (Core层)
  ├─ imports: ZulipAccountsModule (Core层)
  ├─ imports: RedisModule (Core层)
  ├─ imports: LoggerModule (Core层)
  ├─ imports: LoginCoreModule (Core层)
  ├─ imports: AuthModule (Business层)
  ├─ imports: ChatModule (Business层)
  ├─ providers: [ZulipEventProcessorService, ZulipAccountsBusinessService]
  └─ exports: [ZulipEventProcessorService, ZulipAccountsBusinessService, DynamicConfigManagerService]
```

## 架构规范

### Business层职责
- 业务逻辑实现
- 服务协调和编排
- 业务规则验证
- 调用Core层服务

### Business层禁止
- 包含HTTP协议处理（Controller应在Gateway层）
- 直接访问数据库（应通过Core层Repository）
- 包含技术实现细节

## 迁移说明

### 2026-01-14 架构优化

**Controller迁移到Gateway层**

所有Controller已从本模块迁移到 `src/gateway/zulip/`：
- `DynamicConfigController` -> `src/gateway/zulip/dynamic_config.controller.ts`
- `WebSocketDocsController` -> `src/gateway/zulip/websocket_docs.controller.ts`
- `WebSocketOpenApiController` -> `src/gateway/zulip/websocket_openapi.controller.ts`
- `WebSocketTestController` -> `src/gateway/zulip/websocket_test.controller.ts`
- `ZulipAccountsController` -> `src/gateway/zulip/zulip_accounts.controller.ts`

**原因**：符合四层架构规范，Controller属于Gateway层（HTTP协议处理），不应在Business层。

## 相关文档

- [Gateway层Zulip模块](../../gateway/zulip/README.md)
- [架构文档](../../../docs/ARCHITECTURE.md)
- [开发指南](../../../docs/development/backend_development_guide.md)

## 最近更新

- 2026-01-14: 功能文档完善 - 补充对外接口、内部依赖、核心特性、潜在风险章节 (moyin)
- 2026-01-14: 架构优化 - Controller迁移到Gateway层 (moyin)
- 2026-01-14: 聊天功能迁移到business/chat模块 (moyin)

## 维护者

- angjustinl
- moyin
