核心模块.md 19 KB

核心模块

本文引用的文件

  • src/client/cosmoe.ts
  • src/command/index.ts
  • src/scheduler/index.ts
  • src/index.ts
  • src/command/handlers/start.ts
  • src/command/handlers/login.ts
  • src/command/handlers/events.ts
  • src/command/handlers/eventDetails.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/history.ts
  • src/command/handlers/cancel.ts
  • src/command/handlers/logout.ts
  • package.json
  • wrangler.jsonc
  • 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

    graph TB
    A["src/index.ts<br/>入口与 Webhook/定时触发"] --> B["src/command/index.ts<br/>命令注册与对话插件"]
    B --> C["src/command/handlers/*.ts<br/>命令处理器"]
    A --> D["src/scheduler/index.ts<br/>定时任务"]
    C --> E["src/client/cosmoe.ts<br/>API 客户端"]
    D --> E
    E --> F["外部 API: https://cos.cx/api/v1<br/>事件/预约/用户相关接口"]
    B --> G["KV: COSMOE_CREDENTIALS/COSMOE_STORAGE<br/>凭证与会话/状态存储"]
    D --> G
    

图表来源

  • src/index.ts
  • src/command/index.ts
  • src/scheduler/index.ts
  • src/client/cosmoe.ts

章节来源

  • src/index.ts
  • src/command/index.ts
  • src/scheduler/index.ts
  • src/client/cosmoe.ts

核心组件

  • API 客户端(CosmoeClient)
    • 职责:封装对 Cosmoe 后端 API 的调用,统一响应格式、认证参数传递与错误处理
    • 关键能力:登录、事件查询、活动详情、个人资料、预约历史、预约、改价/备注/取消/转赠等
    • 认证:支持手动设置 user_id/token 或通过 getToken 获取并缓存
  • 命令与对话系统
    • 职责:注册命令、建立对话(会话)、KV 存储对话状态、路由到具体处理器
    • 组件:命令注册器、登录对话、各命令处理器(活动列表、详情、预约、历史、取消、登出)
  • 定时任务
    • 职责:周期性检查新活动并推送通知给已登录用户
  • 配置与运行环境
    • 依赖:Grammy、@grammyjs/conversations、@grammyjs/storage-cloudflare
    • 部署:Wrangler(Cloudflare Workers),KV 命名空间绑定

章节来源

  • src/client/cosmoe.ts
  • src/command/index.ts
  • src/scheduler/index.ts
  • package.json
  • wrangler.jsonc

架构总览

整体交互链路如下:

  • 用户在 Telegram 中发送命令或回调,由入口函数接收并交由命令系统处理
  • 命令系统根据路由进入相应处理器,必要时读取 KV 中的用户凭证
  • 处理器通过 CosmoeClient 调用后端 API,返回结果并构造消息回复
  • 定时任务周期性拉取活动列表,筛选新活动并向已登录用户推送

    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
  • src/command/index.ts
  • src/command/handlers/login.ts
  • src/command/handlers/events.ts
  • src/command/handlers/bookEvent.ts
  • src/client/cosmoe.ts

详细组件分析

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:预约相关操作
  • 错误处理

    • 认证要求:需要登录的方法在未认证时抛出错误
    • 参数校验:修改密码长度校验、优惠券获取降级处理
    • 异常捕获:上层处理器统一打印日志并提示用户

      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

章节来源

  • src/client/cosmoe.ts
  • src/client/cosmoe.ts

命令处理器系统(路由与对话状态)

  • 路由机制
    • 命令:/start、/login、/events、/history、/logout
    • 文本匹配:/event{id}、/book{eventid}{slotindex}、/cancel{booking_id}
    • 回调查询:内联键盘确认取消、优惠券选择
  • 对话状态管理
    • 使用 @grammyjs/conversations 插件,结合 KV 存储对话状态
    • 登录对话:交互式输入用户名/密码,成功后写入 KV
  • 会话存储适配

    • 自定义 KV 适配器,负责 JSON 序列化/反序列化与异常处理

      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
  • src/command/handlers/login.ts
  • src/command/handlers/events.ts
  • src/command/handlers/eventDetails.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/history.ts
  • src/command/handlers/cancel.ts
  • src/command/handlers/logout.ts

章节来源

  • src/command/index.ts

用户认证系统(登录流程与会话管理)

  • 登录流程
    • 进入登录对话,提示输入用户名/密码
    • 调用 CosmoeClient.getToken 获取 user_id 与 token
    • 将凭证以 {user_id, token, timestamp} 形式写入 KV,键为 Telegram 用户 ID
  • 会话管理
    • 读取:每次需要认证的操作前从 KV 读取凭证并注入到 CosmoeClient
    • 清除:/logout 删除 KV 中的凭证
  • 安全与健壮性

    • 输入校验:用户名/密码非空判断
    • 异常处理:网络错误/解析错误统一捕获并提示用户

      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
  • src/client/cosmoe.ts

章节来源

  • src/command/handlers/login.ts
  • src/command/handlers/logout.ts

活动管理系统(数据获取与展示)

  • 功能点
    • /events:获取最新活动列表,限制展示数量,生成 Markdown 列表
    • /event_{id}:获取活动详情,渲染时间槽与预约入口;根据是否为活动当日或之前决定是否显示“预约”链接
  • 展示逻辑
    • 时间处理:转换为北京时间进行比较,确保展示一致性
    • 排序:按时间段字符串排序,保证输出稳定
  • 错误处理

    • API 失败时统一提示;无活动时友好提示

      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
  • src/command/handlers/eventDetails.ts
  • src/client/cosmoe.ts

章节来源

  • src/command/handlers/events.ts
  • src/command/handlers/eventDetails.ts

预约管理系统(业务流程与时间槽管理)

  • 业务流程
    • 解析 /book_{eventid}{slot_index}
    • 读取 KV 凭证并设置到 CosmoeClient
    • 获取活动详情,排序时间槽,校验索引与剩余容量
    • 查询可用优惠券,若多于一个则弹出内联键盘供选择;否则自动使用唯一优惠券或不使用
    • 调用 bookEvent 提交预约,返回成功/失败消息
  • 时间槽管理
    • 排序规则:按时间段字符串排序,确保索引稳定
    • 可用性判断:剩余容量>0 且活动尚未过期
  • 优惠券联动
    • 支持多优惠券选择与“不使用”选项
    • 自动回退:获取失败时降级为无优惠券继续流程
  • 取消流程

    • /cancel_{booking_id}:弹出确认内联键盘
    • 确认后调用 cancelBooking 并反馈结果

      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
  • src/client/cosmoe.ts
  • src/command/handlers/cancel.ts

章节来源

  • src/command/handlers/bookEvent.ts
  • src/command/handlers/cancel.ts

历史与概览命令

  • /start:欢迎与命令菜单提示
  • /history:读取凭证,获取预约历史,按时间倒序并截取最新若干条,标注可取消项

章节来源

  • src/command/handlers/start.ts
  • src/command/handlers/history.ts

依赖分析

  • 内部依赖
    • src/index.ts 依赖命令系统与定时任务
    • 命令系统依赖各处理器与 KV 存储
    • 处理器依赖 CosmoeClient
    • 定时任务依赖 CosmoeClient 与 KV
  • 外部依赖
    • GrammY 生态:bot、conversations、storage-cloudflare
    • Cloudflare Workers:KV、定时触发器
  • 配置依赖

    • Wrangler:KV 绑定、定时计划、变量
    • TypeScript:严格类型检查

      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
  • src/command/index.ts
  • src/scheduler/index.ts
  • src/client/cosmoe.ts

章节来源

  • package.json
  • wrangler.jsonc
  • tsconfig.json

性能考虑

  • 网络请求
    • 批量 API 调用建议合并或复用客户端实例,减少握手开销
    • 对外请求增加超时与重试策略(建议在生产环境增强)
  • KV 访问
    • 读写 KV 为异步 IO,尽量减少不必要的读写次数
    • 对话状态与凭证均使用 KV,注意键命名规范与序列化开销
  • 消息体积
    • 历史与活动列表消息可能较长,建议分页或截断,避免超过 Telegram API 限制
  • 定时任务
    • 当前每分钟触发一次,建议评估活动更新频率与推送阈值,避免冗余通知

故障排查指南

  • 认证相关
    • 未登录即进行需认证操作:提示“请先登录”
    • KV 中无凭证:/logout 后需重新 /login
    • 凭证失效:建议重新登录或检查后端返回
  • API 返回异常
    • code 非 200:检查用户名/密码、网络连通性与后端状态
    • 个别接口降级:如优惠券获取失败不影响主流程
  • 消息与键盘
    • 内联键盘点击无响应:确认回调查询正则匹配与回调处理
    • Markdown 渲染问题:检查特殊字符转义与长度限制
  • 定时任务
    • 未推送新活动:检查 latestEventId 是否正确更新、KV 可读写、用户是否已登录

章节来源

  • src/command/handlers/login.ts
  • src/command/handlers/bookEvent.ts
  • src/scheduler/index.ts

结论

本项目以清晰的功能域划分与模块化设计实现了完整的 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
  • src/command/index.ts
  • src/command/handlers/history.ts