# 核心模块
**本文引用的文件**
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts)
- [src/command/index.ts](file://src/command/index.ts)
- [src/scheduler/index.ts](file://src/scheduler/index.ts)
- [src/index.ts](file://src/index.ts)
- [src/command/handlers/start.ts](file://src/command/handlers/start.ts)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts)
- [package.json](file://package.json)
- [wrangler.jsonc](file://wrangler.jsonc)
- [tsconfig.json](file://tsconfig.json)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向 Cosmoe Bot 的核心模块,系统性梳理以下方面:
- API 客户端模块(cosmoe.ts)的封装设计、认证机制与错误处理策略
- 命令处理器系统(命令路由、对话状态管理、KV 存储)
- 用户认证系统(登录流程、会话与凭证存储)
- 活动管理系统(数据获取、展示与交互)
- 预约管理系统(业务流程、时间槽管理、优惠券联动)
- 模块间依赖关系与协作模式
- 接口定义、配置项、使用示例与最佳实践
## 项目结构
该项目采用按功能域划分的目录组织方式,核心代码位于 src 目录下:
- client:对外 API 客户端封装
- command:Telegram Bot 命令与对话处理
- scheduler:定时任务(新活动推送)
- 入口与部署:src/index.ts、wrangler.jsonc、package.json
```mermaid
graph TB
A["src/index.ts
入口与 Webhook/定时触发"] --> B["src/command/index.ts
命令注册与对话插件"]
B --> C["src/command/handlers/*.ts
命令处理器"]
A --> D["src/scheduler/index.ts
定时任务"]
C --> E["src/client/cosmoe.ts
API 客户端"]
D --> E
E --> F["外部 API: https://cos.cx/api/v1
事件/预约/用户相关接口"]
B --> G["KV: COSMOE_CREDENTIALS/COSMOE_STORAGE
凭证与会话/状态存储"]
D --> G
```
图表来源
- [src/index.ts](file://src/index.ts#L1-L47)
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
章节来源
- [src/index.ts](file://src/index.ts#L1-L47)
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
## 核心组件
- API 客户端(CosmoeClient)
- 职责:封装对 Cosmoe 后端 API 的调用,统一响应格式、认证参数传递与错误处理
- 关键能力:登录、事件查询、活动详情、个人资料、预约历史、预约、改价/备注/取消/转赠等
- 认证:支持手动设置 user_id/token 或通过 getToken 获取并缓存
- 命令与对话系统
- 职责:注册命令、建立对话(会话)、KV 存储对话状态、路由到具体处理器
- 组件:命令注册器、登录对话、各命令处理器(活动列表、详情、预约、历史、取消、登出)
- 定时任务
- 职责:周期性检查新活动并推送通知给已登录用户
- 配置与运行环境
- 依赖:Grammy、@grammyjs/conversations、@grammyjs/storage-cloudflare
- 部署:Wrangler(Cloudflare Workers),KV 命名空间绑定
章节来源
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L88)
- [package.json](file://package.json#L18-L22)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)
## 架构总览
整体交互链路如下:
- 用户在 Telegram 中发送命令或回调,由入口函数接收并交由命令系统处理
- 命令系统根据路由进入相应处理器,必要时读取 KV 中的用户凭证
- 处理器通过 CosmoeClient 调用后端 API,返回结果并构造消息回复
- 定时任务周期性拉取活动列表,筛选新活动并向已登录用户推送
```mermaid
sequenceDiagram
participant U as "用户"
participant W as "入口(src/index.ts)"
participant CMD as "命令系统(src/command/index.ts)"
participant H as "处理器(如 login/events/bookEvent)"
participant KV as "KV(COSMOE_CREDENTIALS/STORAGE)"
participant API as "CosmoeClient"
participant S as "后端API(cos.cx)"
U->>W : "发送命令/回调"
W->>CMD : "分发至对应命令"
CMD->>H : "执行处理器逻辑"
H->>KV : "读取/写入用户凭证/会话"
H->>API : "构建请求并调用"
API->>S : "HTTP 请求"
S-->>API : "JSON 响应(code/msg/data)"
API-->>H : "返回解析后的结果"
H-->>U : "发送 Telegram 消息/内联键盘"
```
图表来源
- [src/index.ts](file://src/index.ts#L13-L46)
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L27)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
## 详细组件分析
### API 客户端模块(CosmoeClient)
- 设计理念
- 单一职责:封装 API 调用,统一响应结构与认证参数拼装
- 明确的错误边界:非 200 响应抛出错误或返回带错误信息的结果
- 凭证缓存:支持手动设置或登录后自动缓存,避免重复登录
- 数据模型与复杂度
- 主要数据结构:事件(Event)、活动详情(EventDetail)、时间槽(TimeSlot)、用户信息(UserInfo)、统计(Statistics)、优惠券(Coupon)、预约(Booking)、通用响应(ApiResponse)
- 复杂度:多数方法为 O(1) 请求开销;排序时间槽为 O(n log n),其中 n 为时间槽数量
- 关键方法与流程
- getToken:表单提交用户名/密码,成功后缓存 user_id 与 token
- setCredentials/getCredentials/isAuthenticated:凭证管理
- getEvents/getEventDetail:活动列表与详情获取
- getProfile/getUserProfile/getMyBookings:用户资料与预约历史
- bookEvent/changePassword/getAvailableCoupons/updatePaymentOrder/updateBookingNote/cancelBooking/selfReschedule/selfTransfer:预约相关操作
- 错误处理
- 认证要求:需要登录的方法在未认证时抛出错误
- 参数校验:修改密码长度校验、优惠券获取降级处理
- 异常捕获:上层处理器统一打印日志并提示用户
```mermaid
classDiagram
class CosmoeClient {
-baseUrl : string
-userId : number
-token : string
+getToken(username, password) Promise~ApiResponse~
+setCredentials(userId, token) void
+getCredentials() {userId, token}|null
+isAuthenticated() boolean
+getEvents() Promise~ApiResponse~Event[]~~
+getEventDetail(eventId) Promise~ApiResponse~EventDetail~~
+getProfile() Promise~ApiResponse~ProfileData~~
+getUserProfile() Promise~ApiResponse~UserProfile~~
+getMyBookings() Promise~ApiResponse~Booking[]~~
+bookEvent(req) Promise~ApiResponse~
+changePassword(old, new) Promise~ApiResponse~
+getAvailableCoupons(eventId) Promise~ApiResponse~Coupon[]~~
+updatePaymentOrder(id, orderId) Promise~ApiResponse~
+updateBookingNote(id, note) Promise~ApiResponse~
+cancelBooking(id) Promise~ApiResponse~
+selfReschedule(id, slot) Promise~ApiResponse~
+selfTransfer(id, user) Promise~ApiResponse~
+register(key, username, email, pwd, identity) Promise~ApiResponse~
}
```
图表来源
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
章节来源
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L9-L112)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
### 命令处理器系统(路由与对话状态)
- 路由机制
- 命令:/start、/login、/events、/history、/logout
- 文本匹配:/event_{id}、/book_{event_id}_{slot_index}、/cancel_{booking_id}
- 回调查询:内联键盘确认取消、优惠券选择
- 对话状态管理
- 使用 @grammyjs/conversations 插件,结合 KV 存储对话状态
- 登录对话:交互式输入用户名/密码,成功后写入 KV
- 会话存储适配
- 自定义 KV 适配器,负责 JSON 序列化/反序列化与异常处理
```mermaid
flowchart TD
Start(["收到命令/回调"]) --> Route{"命令类型?"}
Route --> |/login| LoginConv["进入登录对话"]
Route --> |/events| Events["获取活动列表并展示"]
Route --> |/event_*| Details["解析活动ID并获取详情"]
Route --> |/book_*_*| Book["解析活动ID/槽位并处理预约"]
Route --> |/history| History["读取凭证并获取预约历史"]
Route --> |/cancel_*| Cancel["解析预约ID并发起取消确认"]
Route --> |/logout| Logout["删除KV中的凭证"]
LoginConv --> Done(["结束"])
Events --> Done
Details --> Done
Book --> Done
History --> Done
Cancel --> Done
Logout --> Done
```
图表来源
- [src/command/index.ts](file://src/command/index.ts#L59-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L61)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L107)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L132)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L10-L34)
章节来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
### 用户认证系统(登录流程与会话管理)
- 登录流程
- 进入登录对话,提示输入用户名/密码
- 调用 CosmoeClient.getToken 获取 user_id 与 token
- 将凭证以 {user_id, token, timestamp} 形式写入 KV,键为 Telegram 用户 ID
- 会话管理
- 读取:每次需要认证的操作前从 KV 读取凭证并注入到 CosmoeClient
- 清除:/logout 删除 KV 中的凭证
- 安全与健壮性
- 输入校验:用户名/密码非空判断
- 异常处理:网络错误/解析错误统一捕获并提示用户
```mermaid
sequenceDiagram
participant U as "用户"
participant Conv as "登录对话"
participant KV as "KV(COSMOE_CREDENTIALS)"
participant API as "CosmoeClient"
participant S as "后端API"
U->>Conv : "/login"
Conv->>U : "提示输入用户名"
U-->>Conv : "用户名"
Conv->>U : "提示输入密码"
U-->>Conv : "密码"
Conv->>API : "getToken(用户名, 密码)"
API->>S : "POST /CreatToken.php"
S-->>API : "{code,data : {user_id,token}}"
API-->>Conv : "返回结果"
alt 成功
Conv->>KV : "put(Telegram用户ID, 凭证JSON)"
Conv-->>U : "登录成功"
else 失败
Conv-->>U : "登录失败"
end
```
图表来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L124-L140)
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L75)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L10-L34)
### 活动管理系统(数据获取与展示)
- 功能点
- /events:获取最新活动列表,限制展示数量,生成 Markdown 列表
- /event_{id}:获取活动详情,渲染时间槽与预约入口;根据是否为活动当日或之前决定是否显示“预约”链接
- 展示逻辑
- 时间处理:转换为北京时间进行比较,确保展示一致性
- 排序:按时间段字符串排序,保证输出稳定
- 错误处理
- API 失败时统一提示;无活动时友好提示
```mermaid
flowchart TD
A["/events"] --> B["CosmoeClient.getEvents()"]
B --> C{"code==200 且有数据?"}
C --> |否| D["提示无活动"]
C --> |是| E["取前N条并生成Markdown列表"]
E --> F["发送消息"]
G["/event_{id}"] --> H["解析ID并getEventDetail()"]
H --> I{"code==200"}
I --> |否| J["提示错误"]
I --> |是| K["计算是否活动当日或之前"]
K --> L["按range排序时间槽"]
L --> M{"剩余容量>0 且活动有效?"}
M --> |是| N["为每个槽位添加 /book_... 链接"]
M --> |否| O["仅显示不可预约"]
N --> P["发送Markdown详情"]
O --> P
```
图表来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L61)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L199)
章节来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L61)
### 预约管理系统(业务流程与时间槽管理)
- 业务流程
- 解析 /book_{event_id}_{slot_index}
- 读取 KV 凭证并设置到 CosmoeClient
- 获取活动详情,排序时间槽,校验索引与剩余容量
- 查询可用优惠券,若多于一个则弹出内联键盘供选择;否则自动使用唯一优惠券或不使用
- 调用 bookEvent 提交预约,返回成功/失败消息
- 时间槽管理
- 排序规则:按时间段字符串排序,确保索引稳定
- 可用性判断:剩余容量>0 且活动尚未过期
- 优惠券联动
- 支持多优惠券选择与“不使用”选项
- 自动回退:获取失败时降级为无优惠券继续流程
- 取消流程
- /cancel_{booking_id}:弹出确认内联键盘
- 确认后调用 cancelBooking 并反馈结果
```mermaid
sequenceDiagram
participant U as "用户"
participant CMD as "命令系统"
participant H as "bookEvent处理器"
participant KV as "KV"
participant API as "CosmoeClient"
participant S as "后端API"
U->>CMD : "/book_{event}_{slot}"
CMD->>H : "解析event_id/slot_index"
H->>KV : "读取凭证"
H->>API : "setCredentials + getEventDetail"
API->>S : "GET /api.php?action=get_event_detail"
S-->>API : "EventDetail"
API-->>H : "返回详情"
H->>H : "排序时间槽并校验索引/剩余"
H->>API : "getAvailableCoupons"
API->>S : "GET /api.php?action=get_available_coupons"
S-->>API : "Coupons"
API-->>H : "返回优惠券列表"
alt 多个优惠券
H-->>U : "内联键盘选择优惠券"
else 一个或无
H->>API : "bookEvent(含可选coupon_code)"
API->>S : "POST /api.php?action=book_event"
S-->>API : "结果"
API-->>H : "返回结果"
H-->>U : "发送成功/失败消息"
end
```
图表来源
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L191-L270)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L132)
章节来源
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L132)
### 历史与概览命令
- /start:欢迎与命令菜单提示
- /history:读取凭证,获取预约历史,按时间倒序并截取最新若干条,标注可取消项
章节来源
- [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L4-L6)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L107)
## 依赖分析
- 内部依赖
- src/index.ts 依赖命令系统与定时任务
- 命令系统依赖各处理器与 KV 存储
- 处理器依赖 CosmoeClient
- 定时任务依赖 CosmoeClient 与 KV
- 外部依赖
- GrammY 生态:bot、conversations、storage-cloudflare
- Cloudflare Workers:KV、定时触发器
- 配置依赖
- Wrangler:KV 绑定、定时计划、变量
- TypeScript:严格类型检查
```mermaid
graph LR
IDX["src/index.ts"] --> CMD["src/command/index.ts"]
IDX --> SCH["src/scheduler/index.ts"]
CMD --> H1["handlers/start.ts"]
CMD --> H2["handlers/login.ts"]
CMD --> H3["handlers/events.ts"]
CMD --> H4["handlers/eventDetails.ts"]
CMD --> H5["handlers/bookEvent.ts"]
CMD --> H6["handlers/history.ts"]
CMD --> H7["handlers/cancel.ts"]
CMD --> H8["handlers/logout.ts"]
CMD --> CLI["src/client/cosmoe.ts"]
SCH --> CLI
CMD --> KV["KV: COSMOE_CREDENTIALS/STORAGE"]
SCH --> KV
```
图表来源
- [src/index.ts](file://src/index.ts#L1-L47)
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
章节来源
- [package.json](file://package.json#L18-L22)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)
- [tsconfig.json](file://tsconfig.json#L1-L46)
## 性能考虑
- 网络请求
- 批量 API 调用建议合并或复用客户端实例,减少握手开销
- 对外请求增加超时与重试策略(建议在生产环境增强)
- KV 访问
- 读写 KV 为异步 IO,尽量减少不必要的读写次数
- 对话状态与凭证均使用 KV,注意键命名规范与序列化开销
- 消息体积
- 历史与活动列表消息可能较长,建议分页或截断,避免超过 Telegram API 限制
- 定时任务
- 当前每分钟触发一次,建议评估活动更新频率与推送阈值,避免冗余通知
## 故障排查指南
- 认证相关
- 未登录即进行需认证操作:提示“请先登录”
- KV 中无凭证:/logout 后需重新 /login
- 凭证失效:建议重新登录或检查后端返回
- API 返回异常
- code 非 200:检查用户名/密码、网络连通性与后端状态
- 个别接口降级:如优惠券获取失败不影响主流程
- 消息与键盘
- 内联键盘点击无响应:确认回调查询正则匹配与回调处理
- Markdown 渲染问题:检查特殊字符转义与长度限制
- 定时任务
- 未推送新活动:检查 latestEventId 是否正确更新、KV 可读写、用户是否已登录
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L67-L74)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L67-L74)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L84)
## 结论
本项目以清晰的功能域划分与模块化设计实现了完整的 Telegram Bot 服务:
- API 客户端提供一致的调用体验与错误处理
- 命令系统与对话插件结合 KV 实现稳定的会话与状态管理
- 活动与预约流程完整覆盖前端展示、交互与后端业务
- 定时任务完善了运营自动化能力
建议后续在生产环境中补充超时/重试、日志分级与可观测性指标,进一步提升稳定性与可维护性。
## 附录
- 配置项说明
- BOT_INFO:Bot 基本信息(JSON 字符串)
- BOT_TOKEN:Telegram Bot Token
- KV 命名空间:COSMOE_CREDENTIALS(凭证)、COSMOE_STORAGE(会话/状态)
- 触发器:*/1 * * * *(每分钟)
- 最佳实践
- 在处理器中优先检查认证状态与输入参数
- 对 KV 读写进行 try/catch 并记录错误日志
- 对长消息进行分片或截断,避免 Telegram API 限制
- 对外请求增加超时控制与幂等设计
章节来源
- [wrangler.jsonc](file://wrangler.jsonc#L18-L30)
- [src/command/index.ts](file://src/command/index.ts#L20-L52)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L94-L97)