# 命令系统 **本文引用的文件** - [src/index.ts](file://src/index.ts) - [src/command/index.ts](file://src/command/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) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts) - [src/scheduler/index.ts](file://src/scheduler/index.ts) - [package.json](file://package.json) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件系统性梳理该 Telegram 机器人的命令系统,覆盖命令路由机制(command() 与 hears())、正则表达式匹配、交互式对话(conversations)与回调查询处理、以及命令处理器的实现模式与错误处理策略。重点解释 /start、/login、/events、/history、/logout 等命令的处理流程,并给出命令注册最佳实践与性能优化建议。 ## 项目结构 - 入口与运行时:Cloudflare Worker 环境下的入口文件负责初始化 Bot、设置命令菜单、挂载命令路由与调度任务。 - 命令注册中心:集中定义所有命令与消息监听规则,统一管理对话与回调。 - 命令处理器:按功能拆分到 handlers 目录,职责单一,便于测试与维护。 - 客户端封装:对第三方 API 的统一封装,提供认证、事件列表、预约、历史等能力。 - 调度模块:定时任务用于新活动通知推送。 ```mermaid graph TB A["入口: src/index.ts"] --> B["命令注册: src/command/index.ts"] B --> C["命令处理器: handlers/*"] C --> D["客户端: src/client/cosmoe.ts"] A --> E["调度: src/scheduler/index.ts"] A --> F["依赖: package.json"] ``` 图表来源 - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L1-L110) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88) - [package.json](file://package.json#L1-L24) 章节来源 - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L1-L110) - [package.json](file://package.json#L1-L24) ## 核心组件 - Bot 初始化与 Webhook:入口文件创建 Bot 实例,设置命令菜单并通过 Cloudflare 的 webhook 回调处理请求;同时注册定时任务。 - 命令注册与路由: - 使用 bot.command() 注册标准命令(如 /start、/login、/events、/history、/logout)。 - 使用 bot.hears() 注册基于正则的消息监听(如 /event_{id}、/book_{event_id}_{slot_id}、/cancel_{booking_id})。 - 使用 bot.callbackQuery() 注册回调查询处理(如确认取消、优惠券选择)。 - 对话系统:通过 @grammyjs/conversations 插件启用交互式对话,结合 KV 存储持久化会话状态。 - 客户端封装:统一的 CosmoeClient 提供认证、事件、预约、历史、取消等 API 封装,支持错误码与数据结构校验。 章节来源 - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L20-L110) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503) ## 架构总览 整体采用“入口初始化 + 命令注册中心 + 处理器 + 客户端 + 调度”的分层架构。命令注册中心集中管理路由与对话,处理器专注于业务逻辑,客户端抽象外部 API,调度模块负责定时任务。 ```mermaid graph TB subgraph "运行时" W["Worker 入口
src/index.ts"] S["调度任务
src/scheduler/index.ts"] end subgraph "命令系统" R["命令注册中心
src/command/index.ts"] H1["start 处理器
handlers/start.ts"] H2["login 处理器
handlers/login.ts"] H3["events 处理器
handlers/events.ts"] H4["eventDetails 处理器
handlers/eventDetails.ts"] H5["bookEvent 处理器
handlers/bookEvent.ts"] H6["history 处理器
handlers/history.ts"] H7["cancel 处理器
handlers/cancel.ts"] H8["logout 处理器
handlers/logout.ts"] end subgraph "外部服务" C["Cosmoe API 客户端
src/client/cosmoe.ts"] end W --> R R --> H1 R --> H2 R --> H3 R --> H4 R --> H5 R --> H6 R --> H7 R --> H8 H2 --> C H3 --> C H4 --> C H5 --> C H6 --> C H7 --> C H8 --> C W --> S ``` 图表来源 - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L1-L110) - [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L1-L6) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75) - [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27) - [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132) - [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88) ## 详细组件分析 ### 命令路由机制:command() 与 hears() - 标准命令路由 - /start:直接回复欢迎与可用命令列表。 - /login:进入交互式登录对话。 - /events:拉取最新活动列表,生成带链接的消息。 - /history:根据用户凭证拉取预约历史并格式化展示。 - /logout:删除用户凭证。 - 正则消息监听 - /event_{id}:解析活动 ID,获取详情并列出时间段与预约链接。 - /book_{event_id}_{slot_index}:解析活动与时间段索引,检查配额与优惠券,发起预约。 - /cancel_{booking_id}:解析预约 ID,生成确认键盘。 - 回调查询处理 - confirm_cancel_{id}:执行取消操作。 - select_coupon_{event_id}_{slot_index}_{coupon_code}:处理优惠券选择并继续预约流程。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L59-L109) - [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27) - [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132) ### 正则表达式匹配与参数解析 - /event_{id}:使用 /^\/event_(.+)$/ 匹配并提取活动 ID,随后调用事件详情接口。 - /book_{event_id}_{slot_index}:使用 /^\/book_(\d+)_(\d+)$/ 捕获两个数字参数,分别对应活动 ID 与时间段索引。 - /cancel_{booking_id}:使用 /^\/cancel_(\d+)$/ 捕获预约 ID。 - 回调动作解析:使用字符串分割解析 select_coupon_{event_id}_{slot_index}_{coupon_code} 与 confirm_cancel_{id}。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L72-L97) - [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L10-L11) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L17-L20) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L17-L19) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L166-L175) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L89-L91) ### 交互式对话与回调处理 - 登录对话:通过 createConversation 创建交互式对话,逐步收集用户名与密码,调用 CosmoeClient 获取 token 并存入 KV。 - 优惠券选择:当活动存在多个可用优惠券时,生成内联键盘供用户选择;回调解析后继续预约流程。 - 取消确认:发送内联键盘,用户点击确认或取消,分别执行取消或提示已取消。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L54-L57) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L74) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L76-L117) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L60-L78) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L87-L131) ### 命令处理函数标准化模板 - 输入输出约定 - 输入:Context 或带 Context 的组合(如带 Conversation 的上下文)。 - 输出:Promise,统一通过 ctx.reply()/editMessageText()/answerCallbackQuery() 进行响应。 - 错误处理策略 - try/catch 包裹关键逻辑,捕获异常后向用户反馈通用错误信息。 - 对外部 API 调用进行结果码校验,区分成功与失败分支。 - 对 KV 读写进行异常捕获与日志记录。 - 参数解析与校验 - 使用正则捕获组提取参数,对空值与越界情况进行保护。 - 对用户输入进行基本校验(如用户名、密码非空)。 - Markdown 渲染与长度限制 - 对长文本进行长度截断,避免 Telegram API 限制。 - 合理使用 Markdown 格式提升可读性。 章节来源 - [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L1-L6) - [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27) - [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132) - [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34) ### 命令注册最佳实践 - 集中式注册:将所有命令与监听规则集中在命令注册中心,便于维护与审计。 - 分离关注点:命令注册只做路由与转发,具体业务逻辑放入独立处理器。 - 统一环境注入:通过 Env 接口注入 KV 命名空间与 Bot 配置,保证处理器可测试性。 - 回调与正则命名规范:为回调动作与正则表达式建立清晰的命名约定,便于解析与扩展。 - 会话持久化:使用 KV Adapter 为对话提供持久化存储,确保多轮交互状态一致。 章节来源 - [src/command/index.ts](file://src/command/index.ts#L20-L52) - [src/command/index.ts](file://src/command/index.ts#L54-L57) - [src/command/index.ts](file://src/command/index.ts#L72-L109) ### 关键命令处理流程 #### /start 流程 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot" participant H as "start 处理器" U->>B : "/start" B->>H : 调用 handleStartCommand(ctx) H-->>U : 回复欢迎与可用命令列表 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L59-L61) - [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L4-L6) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L59-L61) - [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L1-L6) #### /login 交互式登录流程 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot" participant C as "conversations" participant L as "login 处理器" participant API as "CosmoeClient" U->>B : "/login" B->>C : 进入 "login" 会话 C->>L : 传入 conversation, ctx, env L->>U : 请求用户名 U-->>L : 发送用户名 L->>U : 请求密码 U-->>L : 发送密码 L->>API : getToken(username, password) API-->>L : 返回 token L->>U : 登录成功并保存凭证 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L64-L67) - [src/command/index.ts](file://src/command/index.ts#L54-L57) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L74) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L124-L140) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L54-L67) - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L140) #### /events 列表与 /event_{id} 详情流程 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot" participant E as "events 处理器" participant ED as "eventDetails 处理器" participant API as "CosmoeClient" U->>B : "/events" B->>E : 调用 handleEventsCommand(ctx) E->>API : getEvents() API-->>E : 返回事件列表 E-->>U : 发送活动列表含 /event_{id} 链接 U->>B : "/event_{id}" B->>ED : 调用 handleEventDetails(ctx) ED->>API : getEventDetail(id) API-->>ED : 返回活动详情 ED-->>U : 发送活动详情与时间段及 /book_{event_id}_{slot_id} 链接 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L68-L75) - [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L26) - [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L60) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L199) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L68-L75) - [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27) - [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L199) #### /book_{event_id}_{slot_index} 预约流程 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot" participant BE as "bookEvent 处理器" participant API as "CosmoeClient" U->>B : "/book_{event_id}_{slot_index}" B->>BE : 调用 handleBookEvent(ctx, env) BE->>API : getEventDetail(event_id) API-->>BE : 返回活动详情与时间段 BE->>BE : 校验 slotIndex 与剩余容量 alt 多个优惠券 BE-->>U : 展示优惠券选择键盘 U->>B : 回调 select_coupon_{event_id}_{slot_index}_{coupon_code} B->>BE : 调用 handleCouponSelection(ctx, env, action) else 单个或无优惠券 BE->>API : bookEvent({event_id, time_slot, coupon_code?}) API-->>BE : 返回预约结果 end BE-->>U : 成功/失败消息 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L77-L105) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L117) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L159-L226) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L191-L199) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L247-L270) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L329-L343) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L77-L105) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L191-L270) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L329-L343) #### /history 预约历史流程 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot" participant H as "history 处理器" participant API as "CosmoeClient" U->>B : "/history" B->>H : 调用 handleHistoryCommand(ctx, env) H->>H : 读取 KV 凭证并校验 H->>API : getMyBookings() API-->>H : 返回预约历史 H->>H : 格式化消息并添加取消链接 H-->>U : 发送历史消息 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L82-L84) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L106) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L226-L239) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L82-L84) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L226-L239) #### /cancel_{booking_id} 取消流程 ```mermaid sequenceDiagram participant U as "用户" participant B as "Bot" participant CA as "cancel 处理器" participant API as "CosmoeClient" U->>B : "/cancel_{booking_id}" B->>CA : 调用 handleCancelCommand(ctx, env) CA->>API : getMyBookings() API-->>CA : 返回预约列表 CA-->>U : 发送确认键盘 U->>B : 回调 confirm_cancel_{id} B->>CA : 调用 handleCancelConfirmation(ctx, env, action) CA->>API : cancelBooking(booking_id) API-->>CA : 返回取消结果 CA-->>U : 成功/失败消息 ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L86-L97) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L84) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L87-L131) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L405-L422) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L86-L97) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L405-L422) #### /logout 登出流程 ```mermaid flowchart TD Start(["开始"]) --> GetUserID["获取用户ID"] GetUserID --> HasCreds{"KV中是否存在凭证?"} HasCreds --> |否| ReplyNotLoggedIn["提示先登录"] HasCreds --> |是| DeleteCreds["删除KV中的凭证"] DeleteCreds --> ReplySuccess["回复登出成功"] ReplyNotLoggedIn --> End(["结束"]) ReplySuccess --> End ``` 图表来源 - [src/command/index.ts](file://src/command/index.ts#L107-L109) - [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L10-L33) 章节来源 - [src/command/index.ts](file://src/command/index.ts#L107-L109) - [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34) ## 依赖关系分析 - 运行时依赖:grammy、@grammyjs/conversations、@grammyjs/storage-cloudflare。 - 入口与命令注册:入口文件负责初始化 Bot、设置命令菜单、挂载命令与调度。 - 命令处理器:依赖 CosmoeClient 进行外部 API 调用,依赖 KV 命名空间进行凭证与会话存储。 - 调度模块:依赖 Bot API 向已注册用户推送新活动通知。 ```mermaid graph LR P["package.json"] --> G["grammy"] P --> C["@grammyjs/conversations"] P --> K["@grammyjs/storage-cloudflare"] IDX["src/index.ts"] --> CMD["src/command/index.ts"] CMD --> HSTART["handlers/start.ts"] CMD --> HLOGIN["handlers/login.ts"] CMD --> HEVENTS["handlers/events.ts"] CMD --> HEVENTD["handlers/eventDetails.ts"] CMD --> HBOOK["handlers/bookEvent.ts"] CMD --> HHIST["handlers/history.ts"] CMD --> HCANCEL["handlers/cancel.ts"] CMD --> HLOGOUT["handlers/logout.ts"] HLOGIN --> CC["src/client/cosmoe.ts"] HEVENTS --> CC HEVENTD --> CC HBOOK --> CC HHIST --> CC HCANCEL --> CC HLOGOUT --> CC IDX --> SCH["src/scheduler/index.ts"] SCH --> CC ``` 图表来源 - [package.json](file://package.json#L18-L22) - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L1-L110) - [src/command/handlers/*.ts](file://src/command/handlers/start.ts#L1-L6) - [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88) 章节来源 - [package.json](file://package.json#L1-L24) - [src/index.ts](file://src/index.ts#L1-L47) - [src/command/index.ts](file://src/command/index.ts#L1-L110) ## 性能考量 - KV 存储访问:对话与凭证均使用 KV,注意读写次数与延迟,建议: - 对频繁读取的数据进行本地缓存(如会话状态),减少 KV 访问。 - 批量操作时合并请求,避免多次往返。 - API 调用节流:对外部 API 的调用应进行幂等与去重,避免重复请求。 - 消息长度控制:历史与详情消息可能较长,需在发送前截断,防止 Telegram API 限制导致失败。 - 正则匹配优化:正则表达式尽量简单明确,避免回溯开销;必要时预编译正则对象。 - 会话持久化:使用 KV Adapter 时,确保序列化/反序列化稳定,避免大对象频繁写入。 ## 故障排查指南 - 登录失败 - 检查用户名与密码是否正确,确认 CosmoeClient.getToken 返回码。 - 检查 KV 写入是否成功,确认凭证字段完整。 - 预约失败 - 检查活动 ID 与时间段索引是否有效,确认时间段剩余容量。 - 检查用户凭证是否过期或被删除。 - 历史为空 - 确认用户已登录且凭证有效。 - 检查外部 API 返回码与数据结构。 - 取消失败 - 确认预约 ID 存在且状态允许取消。 - 检查回调解析是否正确。 - 回调无响应 - 确认回调查询已正确注册,answerCallbackQuery 是否被调用。 - 调度通知未送达 - 检查 KV 中用户列表是否为空,确认消息发送返回值。 章节来源 - [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L47-L74) - [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L137-L157) - [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L32-L44) - [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L117-L127) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L44-L68) ## 结论 该命令系统通过集中式路由与处理器分离的设计,实现了清晰的职责划分与良好的可维护性。借助 @grammyjs/conversations 与 KV 存储,系统支持交互式对话与状态持久化;通过正则表达式与回调查询,实现了灵活的消息与交互处理。建议在生产环境中进一步完善缓存策略、错误监控与日志追踪,以提升稳定性与可观测性。 ## 附录 - 命令菜单设置:入口文件在启动时设置命令菜单,便于用户发现可用命令。 - 定时任务:调度模块定期扫描新活动并向已注册用户推送通知。 章节来源 - [src/index.ts](file://src/index.ts#L24-L32) - [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L88)