# 核心模块 **本文引用的文件** - [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)