数据流设计.md 18 KB

数据流设计

本文引用的文件

  • src/index.ts
  • src/command/index.ts
  • src/client/cosmoe.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
  • src/scheduler/index.ts
  • wrangler.jsonc
  • package.json
  • tsconfig.json
  • worker-configuration.d.ts

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论

简介

本设计文档围绕 Cosmoe Bot 的数据流进行系统性梳理,覆盖从 Telegram 用户消息进入 Cloudflare Workers,经由 grammY 框架解析与路由,到各命令处理器执行业务逻辑、调用 Cosmoe API 客户端访问外部服务,并通过 KV 存储完成状态持久化的完整链路。文档同时给出数据流向图、关键数据节点结构定义、缓存策略与一致性保障、异步处理与错误恢复机制等。

项目结构

该项目采用按功能模块组织的目录结构,核心入口在 Cloudflare Workers 中,使用 grammY 作为 Telegram Bot 框架,配合 @grammyjs/conversations 实现对话式交互,使用 @grammyjs/storage-cloudflare 将会话状态持久化至 KV。

graph TB
subgraph "Cloudflare Workers"
A["src/index.ts<br/>入口与webhook回调"]
B["src/command/index.ts<br/>命令注册与会话存储"]
C["src/scheduler/index.ts<br/>定时任务"]
end
subgraph "命令处理器"
H1["start.ts"]
H2["login.ts"]
H3["events.ts"]
H4["eventDetails.ts"]
H5["bookEvent.ts"]
H6["history.ts"]
H7["cancel.ts"]
H8["logout.ts"]
end
subgraph "外部服务"
E["Telegram API"]
F["Cosmoe API"]
end
subgraph "KV 存储"
K1["COSMOE_CREDENTIALS<br/>用户凭证"]
K2["COSMOE_STORAGE<br/>通用状态"]
end
A --> B
A --> C
B --> H1
B --> H2
B --> H3
B --> H4
B --> H5
B --> H6
B --> H7
B --> H8
H2 --> K1
H6 --> K1
H8 --> K1
H5 --> F
H6 --> F
H7 --> F
H3 --> F
H4 --> F
C --> F
C --> K2

图表来源

  • src/index.ts
  • src/command/index.ts
  • src/scheduler/index.ts
  • src/command/handlers/login.ts
  • src/command/handlers/history.ts
  • src/command/handlers/logout.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/events.ts
  • src/command/handlers/eventDetails.ts
  • src/client/cosmoe.ts

章节来源

  • src/index.ts
  • src/command/index.ts
  • wrangler.jsonc

核心组件

  • 入口与 Webhook 回调:初始化 grammY Bot,设置命令菜单,将请求交由 Cloudflare 的 webhookCallback 处理。
  • 命令注册与会话存储:安装 conversations 插件,使用 KV 适配器实现会话状态持久化;注册各类命令与回调处理器。
  • 命令处理器:按功能拆分,包括启动引导、登录(对话式)、活动列表、活动详情、预约、历史、取消、登出等。
  • Cosmoe API 客户端:封装认证、事件查询、个人资料、预约、取消、修改等 API 调用。
  • 定时任务:周期性扫描新活动并向已注册用户推送通知。
  • KV 存储:COSMOE_CREDENTIALS 保存用户凭证;COSMOE_STORAGE 保存通用状态(如最新活动 ID)。

章节来源

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

架构总览

下图展示从 Telegram 到 Cloudflare Workers、grammY、命令处理器、Cosmoe API 客户端以及 KV 存储的整体数据流。

sequenceDiagram
participant U as "用户"
participant T as "Telegram API"
participant W as "Cloudflare Workers<br/>src/index.ts"
participant G as "grammY 框架"
participant CMD as "命令处理器<br/>src/command/handlers/*"
participant KV as "KV 存储<br/>COSMOE_CREDENTIALS/COSMOE_STORAGE"
participant API as "Cosmoe API"
U->>T : "发送消息/命令"
T-->>W : "HTTP 请求"
W->>G : "webhookCallback 分发"
G->>CMD : "匹配命令/回调并执行"
CMD->>KV : "读取/写入用户凭证/状态"
CMD->>API : "调用 Cosmoe API"
API-->>CMD : "返回业务数据"
CMD-->>G : "构造响应"
G-->>W : "生成 Telegram 响应"
W-->>T : "回传消息"
T-->>U : "显示结果"

图表来源

  • src/index.ts
  • src/command/index.ts
  • src/command/handlers/login.ts
  • src/command/handlers/history.ts
  • src/command/handlers/bookEvent.ts
  • src/client/cosmoe.ts
  • wrangler.jsonc

详细组件分析

命令注册与会话存储(KV)

  • 会话存储:通过 @grammyjs/storage-cloudflare 的 KvAdapter 将会话状态序列化为 JSON 并写入 COSMOE_STORAGE。
  • 登录对话:使用 createConversation 定义交互式登录流程,完成后将用户凭证写入 COSMOE_CREDENTIALS。
  • 命令路由:注册 /start、/login、/events、/event{id}、/book{event}{slot}、/history、/cancel{id}、回调等。

    flowchart TD
    Start(["进入 setupCommands"]) --> KV["创建 KV 适配器<br/>绑定 COSMOE_STORAGE"]
    KV --> Conv["安装 conversations 插件<br/>指定 storage=KV"]
    Conv --> Login["注册 /login 对话<br/>enter('login')"]
    Login --> ReadCreds["读取用户凭证<br/>COSMOE_CREDENTIALS"]
    ReadCreds --> ExecCmd["执行命令处理器"]
    ExecCmd --> WriteKV["写入 KV 状态/凭证"]
    WriteKV --> End(["完成"])
    

图表来源

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

章节来源

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

登录流程(对话式)

  • 用户输入用户名/密码,调用 CosmoeClient.getToken 获取 token。
  • 将 user_id、token、timestamp 写入 COSMOE_CREDENTIALS,键为 Telegram 用户 ID。
  • 异常处理:输入缺失、认证失败、KV 写入异常均进行友好提示与日志记录。

    sequenceDiagram
    participant U as "用户"
    participant CMD as "handleInteractiveLogin"
    participant KV as "COSMOE_CREDENTIALS"
    participant API as "CosmoeClient.getToken"
    U->>CMD : "/login 进入对话"
    CMD->>U : "提示输入用户名"
    U-->>CMD : "用户名"
    CMD->>U : "提示输入密码"
    U-->>CMD : "密码"
    CMD->>API : "getToken(username,password)"
    API-->>CMD : "返回 {user_id,token}"
    CMD->>KV : "put(telegramUserId, JSON)"
    CMD-->>U : "登录成功提示"
    

图表来源

  • src/command/handlers/login.ts
  • src/client/cosmoe.ts

章节来源

  • src/command/handlers/login.ts
  • src/client/cosmoe.ts

活动列表与详情

  • /events:调用 getEvents 获取最新活动列表,拼接 Markdown 链接供用户点击 /event_{id}。
  • /event{id}:调用 getEventDetail 获取活动详情,渲染时间段、价格、剩余容量,并对可预约时间段提供 /book{event}_{slot} 链接。

    flowchart TD
    A["/events"] --> B["CosmoeClient.getEvents"]
    B --> C["筛选最新N条"]
    C --> D["拼装 Markdown 列表"]
    D --> E["发送消息"]
    F["/event_{id}"] --> G["CosmoeClient.getEventDetail"]
    G --> H["排序时间槽"]
    H --> I{"是否可预约"}
    I --> |是| J["生成 /book_{event}_{slot} 链接"]
    I --> |否| K["仅展示信息"]
    

图表来源

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

章节来源

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

预约流程(含优惠券选择)

  • 解析 /book{event}{slot},校验用户登录态,获取活动详情与时间槽。
  • 若存在多个可用优惠券,弹出内联键盘让用户选择;单个则自动使用。
  • 调用 bookEvent 提交预约,返回最终价格、预约编号等信息。

    sequenceDiagram
    participant U as "用户"
    participant CMD as "handleBookEvent"
    participant KV as "COSMOE_CREDENTIALS"
    participant API as "CosmoeClient"
    participant CB as "handleCouponSelection"
    U->>CMD : "/book_{event}_{slot}"
    CMD->>KV : "读取凭证"
    CMD->>API : "getEventDetail(eventId)"
    CMD->>API : "getAvailableCoupons(eventId)"
    alt 多个优惠券
    CMD-->>U : "显示内联键盘选择"
    U->>CB : "回调 : select_coupon_{...}"
    CB->>API : "bookEvent(带coupon)"
    else 单个/无优惠券
    CMD->>API : "bookEvent(直接提交)"
    end
    API-->>CMD : "返回预约结果"
    CMD-->>U : "发送成功/失败消息"
    

图表来源

  • src/command/handlers/bookEvent.ts
  • src/client/cosmoe.ts

章节来源

  • src/command/handlers/bookEvent.ts
  • src/client/cosmoe.ts

历史与取消

  • /history:读取用户凭证,调用 getMyBookings 获取预约历史,格式化 Markdown 并附带可取消链接。
  • /cancel_{id}:弹出确认内联键盘,确认后调用 cancelBooking 执行取消。

    flowchart TD
    H1["/history"] --> H2["读取凭证"]
    H2 --> H3["CosmoeClient.getMyBookings"]
    H3 --> H4["格式化 Markdown"]
    H4 --> H5["发送消息"]
    C1["/cancel_{id}"] --> C2["读取凭证"]
    C2 --> C3["获取预约详情"]
    C3 --> C4["内联键盘确认"]
    C4 --> C5["cancelBooking"]
    C5 --> C6["编辑消息反馈结果"]
    

图表来源

  • src/command/handlers/history.ts
  • src/command/handlers/cancel.ts
  • src/client/cosmoe.ts
  • src/client/cosmoe.ts

章节来源

  • src/command/handlers/history.ts
  • src/command/handlers/cancel.ts
  • src/client/cosmoe.ts
  • src/client/cosmoe.ts

定时任务与通知

  • 触发频率:每分钟一次(*/1 * * * *)。
  • 逻辑:读取 COSMOE_STORAGE 中的 latestEventId,拉取全部活动,过滤新增活动,遍历 COSMOE_CREDENTIALS 中的用户键,逐个发送通知,并更新 latestEventId。

    flowchart TD
    S["scheduled 触发"] --> L["读取 latestEventId"]
    L --> E["CosmoeClient.getEvents"]
    E --> F["过滤新活动"]
    F --> K["遍历已注册用户键"]
    K --> N["bot.api.sendMessage"]
    N --> U["更新 latestEventId"]
    

图表来源

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

章节来源

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

关键数据节点结构定义

  • 通用响应结构
    • 字段:code、msg、data
    • 用途:统一承载 API 返回状态与数据
  • 认证响应
    • 字段:user_id、token
    • 用途:登录成功后返回,后续请求需携带
  • 事件与活动详情
    • 字段:id、name、description、event_date、cover_image_url、slots、gallery 等
    • 用途:活动列表与详情展示
  • 时间槽
    • 字段:range、price、capacity、remaining
    • 用途:展示时间段、价格与剩余容量
  • 用户资料与统计
    • 字段:user_info、statistics
    • 用途:个人中心与历史记录
  • 预约
    • 字段:id、status、booking_date、time_slot、final_price、notes_by_user、event_name 等
    • 用途:历史记录与取消操作

章节来源

  • src/client/cosmoe.ts

缓存策略与一致性

  • KV 会话存储:使用 @grammyjs/storage-cloudflare 的 KvAdapter 将会话状态持久化至 COSMOE_STORAGE,确保多实例间会话一致性。
  • 用户凭证:COSMOE_CREDENTIALS 以 Telegram 用户 ID 为键,存储 user_id、token、timestamp,便于命令处理器快速读取与鉴权。
  • 通用状态:COSMOE_STORAGE 用于保存 latestEventId 等全局状态,避免重复推送。
  • 一致性保障:KV 写入在登录、历史查询、取消等关键路径均有错误捕获与日志输出,保证异常可追踪;会话读写封装在 KV 适配器中,避免直接 KV 操作分散。

章节来源

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

异步处理与错误恢复

  • 异步模型:grammY 与 Cloudflare Workers 均基于事件循环与 Promise,命令处理器与 API 调用均为异步。
  • 错误恢复:
    • 命令处理器内部 try/catch 包裹,出现异常时向用户发送“稍后重试”提示并记录日志。
    • KV 读写封装在会话存储中,异常时打印错误并继续执行,避免中断对话流程。
    • 定时任务对每个用户的发送单独 try/catch,失败不影响其他用户的通知。
  • 超时与可观测性:Wrangler 启用 observability,便于监控与排障。

章节来源

  • src/command/handlers/events.ts
  • src/command/handlers/history.ts
  • src/command/handlers/bookEvent.ts
  • src/scheduler/index.ts
  • wrangler.jsonc

依赖关系分析

  • grammY 生态:grammy、@grammyjs/conversations、@grammyjs/storage-cloudflare。
  • 运行时类型:通过 wrangler types 生成的 worker-configuration.d.ts 提供环境变量与运行时类型声明。
  • 构建与脚本:使用 TypeScript 与 Vitest,部署与开发通过 Wrangler CLI。

    graph LR
    P["package.json 依赖"] --> G["grammy"]
    P --> C["conversations"]
    P --> S["storage-cloudflare"]
    W["wrangler.jsonc 配置"] --> T["worker-configuration.d.ts 类型"]
    

图表来源

  • package.json
  • wrangler.jsonc
  • worker-configuration.d.ts

章节来源

  • package.json
  • wrangler.jsonc
  • worker-configuration.d.ts

性能考量

  • 会话存储:KV 读写为网络 IO,建议减少不必要的频繁写入;对话结束后及时清理临时状态。
  • API 调用:批量获取活动与用户历史时注意分页与限流,避免超时。
  • Markdown 渲染:历史消息长度限制在 4000 字符以内,防止 Telegram API 报错。
  • 定时任务:每分钟触发一次,注意控制通知数量与并发发送,避免触发速率限制。

故障排查指南

  • 登录失败:检查用户名/密码是否正确,确认 CosmoeClient.getToken 返回 code=200;查看 KV 写入是否成功。
  • 无凭证或凭证失效:确认 /login 是否执行成功,COSMOE_CREDENTIALS 中是否存在对应键;必要时执行 /logout 清理后重新登录。
  • 预约失败:核对时间槽剩余容量,确认优惠券有效性;查看 bookEvent 返回的 msg 信息。
  • 历史为空:确认用户是否有历史记录,或是否超过筛选条数上限。
  • 定时通知未送达:检查 COSMOE_STORAGE 中 latestEventId 是否更新,确认 COSMOE_CREDENTIALS 中用户键是否有效;查看定时任务日志。

章节来源

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

结论

该系统通过 grammY 与 Cloudflare Workers 实现高可用的 Telegram Bot 数据流:用户消息经由 webhook 进入 Worker,命令处理器负责业务编排,Cosmoe API 客户端承担外部数据交互,KV 存储贯穿凭证与会话状态管理。整体具备清晰的模块边界、完善的错误处理与可观测性配置,适合在生产环境中稳定运行与扩展。