mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
docs: align VitePress site with REST send, optional gateway and slash commands
- deployment: drop DISCORD_CHANNEL_ID, add ADMIN_USER_IDS, PKCS#8 key note, applications.commands invite scope, and an optional Gateway section - getting-started: PKCS#8 .dev.vars example, remove channel ID - introduction: REST delivery, optional DiscordGateway DO, delivery dedup, /admin Web UI in architecture and data flow - index: refresh Workers feature, add Web UI & slash commands feature
This commit is contained in:
parent
f456c979f7
commit
d996dbe45d
8 changed files with 133 additions and 55 deletions
|
|
@ -26,13 +26,30 @@ This outputs a namespace ID. Update `wrangler.jsonc` with the ID:
|
||||||
```bash
|
```bash
|
||||||
npx wrangler secret put GITHUB_WEBHOOK_SECRET
|
npx wrangler secret put GITHUB_WEBHOOK_SECRET
|
||||||
npx wrangler secret put GITHUB_APP_ID
|
npx wrangler secret put GITHUB_APP_ID
|
||||||
npx wrangler secret put GITHUB_PRIVATE_KEY
|
npx wrangler secret put GITHUB_PRIVATE_KEY # PKCS#8 PEM (BEGIN PRIVATE KEY)
|
||||||
npx wrangler secret put GITHUB_CLIENT_ID
|
npx wrangler secret put GITHUB_CLIENT_ID
|
||||||
npx wrangler secret put GITHUB_CLIENT_SECRET
|
npx wrangler secret put GITHUB_CLIENT_SECRET
|
||||||
npx wrangler secret put DISCORD_TOKEN
|
npx wrangler secret put DISCORD_TOKEN
|
||||||
npx wrangler secret put DISCORD_CHANNEL_ID
|
npx wrangler secret put ADMIN_USER_IDS # comma-separated GitHub IDs/logins allowed into the Web UI
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: tip Target channels are configured per route
|
||||||
|
There is no global channel secret. Each route in the [Web UI](/guide/configuration#web-ui) declares its own target channel (and optional thread), so `DISCORD_CHANNEL_ID` is not needed.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning GitHub App private key must be PKCS#8
|
||||||
|
GitHub issues private keys in PKCS#1 format (`BEGIN RSA PRIVATE KEY`). Cloudflare Workers' JWT signing requires PKCS#8. Convert first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
|
||||||
|
-in your-app.private-key.pem -out gh_pk_pkcs8.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
Then upload `gh_pk_pkcs8.pem` as `GITHUB_PRIVATE_KEY`.
|
||||||
|
:::
|
||||||
|
|
||||||
|
The Discord Gateway is optional. Set `DISCORD_GATEWAY_ENABLED` in `wrangler.jsonc` `vars` (`"false"` by default). See [Gateway (optional)](#gateway-optional) below.
|
||||||
|
|
||||||
### 3. Deploy
|
### 3. Deploy
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -81,8 +98,22 @@ Your worker is now live at `https://webhooker.<your-subdomain>.workers.dev`.
|
||||||
1. Go to <https://discord.com/developers/applications>
|
1. Go to <https://discord.com/developers/applications>
|
||||||
2. Create a new application → go to Bot section
|
2. Create a new application → go to Bot section
|
||||||
3. Copy the bot token to `DISCORD_TOKEN`
|
3. Copy the bot token to `DISCORD_TOKEN`
|
||||||
4. Invite the bot to your server with `bot` scope and `Send Messages` permission
|
4. Invite the bot with the `bot` and `applications.commands` scopes and the `View Channels` + `Send Messages` + `Send Messages in Threads` permissions (combined integer `274877910016`):
|
||||||
5. Copy the target channel ID to `DISCORD_CHANNEL_ID`
|
|
||||||
|
```text
|
||||||
|
https://discord.com/oauth2/authorize?client_id=YOUR_BOT_CLIENT_ID&permissions=274877910016&scope=bot+applications.commands
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Configure target channels **per route** in the Web UI (`/admin`) — no global channel ID is required.
|
||||||
|
|
||||||
|
### Gateway (optional)
|
||||||
|
|
||||||
|
Messages are sent via the Discord **REST API**, so pushing works with just `DISCORD_TOKEN`. The Gateway connection is only needed to (a) show the bot as **online** and (b) enable the in-Discord slash / context-menu commands.
|
||||||
|
|
||||||
|
- `DISCORD_GATEWAY_ENABLED=false` (default): REST-only, no Gateway connection.
|
||||||
|
- `DISCORD_GATEWAY_ENABLED=true`: a Durable Object holds the Gateway connection and registers the `/gh` slash command plus the `GitHub: 添加/编辑/删除评论` message commands per guild.
|
||||||
|
|
||||||
|
When enabled, users run `/gh login` to link their GitHub account and can then comment on issues/PRs as themselves. See the [README](https://github.com/ReCloudStudio/WebHooker#bot-commands-comment-on-github-as-yourself) for the full command reference.
|
||||||
|
|
||||||
## Custom Domain (Optional)
|
## Custom Domain (Optional)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,18 @@ Edit `.dev.vars` with your actual values:
|
||||||
```bash
|
```bash
|
||||||
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
||||||
GITHUB_APP_ID=your-app-id
|
GITHUB_APP_ID=your-app-id
|
||||||
GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
|
GITHUB_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
||||||
GITHUB_CLIENT_ID=your-client-id
|
GITHUB_CLIENT_ID=your-client-id
|
||||||
GITHUB_CLIENT_SECRET=your-client-secret
|
GITHUB_CLIENT_SECRET=your-client-secret
|
||||||
DISCORD_TOKEN=your-bot-token
|
DISCORD_TOKEN=your-bot-token
|
||||||
DISCORD_CHANNEL_ID=your-channel-id
|
ADMIN_USER_IDS=your-github-id,your-github-login
|
||||||
BASE_URL=http://localhost:8787
|
BASE_URL=http://localhost:8787
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
`GITHUB_PRIVATE_KEY` must be in **PKCS#8** format (`BEGIN PRIVATE KEY`). Convert a GitHub-issued PKCS#1 key with `openssl pkcs8 -topk8 -nocrypt -in app.pem -out pkcs8.pem`. Target channels are set per route in the Web UI, so no `DISCORD_CHANNEL_ID` is needed. To keep the bot online and enable `/gh` slash commands locally, also set `DISCORD_GATEWAY_ENABLED=true`.
|
||||||
|
:::
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
`.dev.vars` is gitignored and contains secrets. Never commit it.
|
`.dev.vars` is gitignored and contains secrets. Never commit it.
|
||||||
:::
|
:::
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,44 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
WebHooker is a GitHub webhook dispatcher built on Cloudflare Workers. It receives GitHub webhook events, applies configurable filters, formats them into rich Discord embeds, and routes messages to Discord channels or threads via a Durable Object-maintained Gateway connection.
|
WebHooker is a GitHub webhook dispatcher built on Cloudflare Workers. It receives GitHub webhook events, applies configurable filters, formats them into rich Discord embeds, and delivers them to Discord channels or threads through the Discord REST API. An optional Durable Object holds a Gateway connection to keep the bot online and power the in-Discord `/gh` commands. Routes are managed through a built-in Web UI.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```text
|
```text
|
||||||
GitHub Webhook → Cloudflare Worker (Hono)
|
GitHub Webhook → Cloudflare Worker (Hono)
|
||||||
├── POST /webhook → verify → filter → format → DO (Discord Gateway) → Discord
|
├── POST /webhook → verify → dedup → filter → format → Discord (REST API)
|
||||||
├── GET /auth/github → OAuth flow
|
├── GET /auth/github → OAuth flow
|
||||||
├── POST /api/* → user actions (Bearer token auth)
|
├── POST /api/* → user actions (Bearer token auth)
|
||||||
|
├── /admin → routes & send-log Web UI (admin session)
|
||||||
└── GET /health → status check
|
└── GET /health → status check
|
||||||
|
|
||||||
|
(optional) Durable Object ⇄ Discord Gateway → bot online + /gh slash & context commands
|
||||||
```
|
```
|
||||||
|
|
||||||
### Components
|
### Components
|
||||||
|
|
||||||
| Component | Role |
|
| Component | Role |
|
||||||
| ----------------------------------- | --------------------------------------------------------------------------------------------- |
|
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| **Cloudflare Worker** | HTTP ingress, signature verification, event parsing, route matching |
|
| **Cloudflare Worker** | HTTP ingress, signature verification, delivery dedup, event parsing, route matching, REST send |
|
||||||
| **Durable Object (DiscordGateway)** | Persistent WebSocket to Discord Gateway, channel cache, message dispatch with retry |
|
| **Durable Object (DiscordGateway)** | _Optional._ Keeps the Gateway connection alive (bot online) and handles `/gh` interactions |
|
||||||
| **KV** | Token storage (`token:{userId}`), OAuth state (`state:{hex}`), route config (`config:routes`) |
|
| **KV** | Token storage (`token:{userId}`), OAuth state (`state:{hex}`), route config (`config:routes`), send logs, delivery dedup |
|
||||||
|
|
||||||
### Data Flow
|
### Data Flow
|
||||||
|
|
||||||
1. GitHub sends a webhook to `POST /webhook`
|
1. GitHub sends a webhook to `POST /webhook`
|
||||||
2. Worker verifies the HMAC-SHA256 signature
|
2. Worker verifies the HMAC-SHA256 signature
|
||||||
3. Worker parses the event type and payload
|
3. Worker deduplicates by `X-GitHub-Delivery` (KV, short TTL) to drop repeat deliveries
|
||||||
4. Routes are evaluated against filters (event, repo, actor, action, branch, keyword)
|
4. Worker parses the event type and payload
|
||||||
5. Matching routes trigger formatter functions that produce Discord embeds
|
5. Routes are evaluated against filters (event, repo, actor, action, branch, keyword)
|
||||||
6. Messages are dispatched to the Durable Object, which maintains the Gateway connection
|
6. Matching routes trigger formatter functions that produce Discord embeds
|
||||||
7. DO sends messages to Discord via REST API with rate-limit retry
|
7. Each message is sent to its route's target channel/thread via the Discord REST API with rate-limit retry, and the result is recorded in the send log
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Runtime**: Cloudflare Workers
|
- **Runtime**: Cloudflare Workers
|
||||||
- **HTTP Framework**: Hono
|
- **HTTP Framework**: Hono
|
||||||
- **Discord Gateway**: Durable Object (persistent WebSocket + channel cache)
|
- **Discord delivery**: Discord REST API (Gateway via optional Durable Object for online status + `/gh` commands)
|
||||||
|
- **Web UI**: Nuxt 3 static SPA served from Worker assets
|
||||||
- **Storage**: Cloudflare KV
|
- **Storage**: Cloudflare KV
|
||||||
- **Auth**: Web Crypto API (HMAC-SHA256), jose (JWT), octokit (GitHub API)
|
- **Auth**: Web Crypto API (HMAC-SHA256), jose (JWT), octokit (GitHub API)
|
||||||
- **Language**: TypeScript
|
- **Language**: TypeScript
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ features:
|
||||||
- title: Flexible Filtering
|
- title: Flexible Filtering
|
||||||
details: Filter by event type, repo, actor, action, branch (including PRs), and keyword (with regex support). Exclude patterns with a flag.
|
details: Filter by event type, repo, actor, action, branch (including PRs), and keyword (with regex support). Exclude patterns with a flag.
|
||||||
- title: Cloudflare Workers
|
- title: Cloudflare Workers
|
||||||
details: Runs on Cloudflare's edge network with Durable Objects for persistent Discord Gateway connections and KV for storage.
|
details: Runs on Cloudflare's edge network. Sends via the Discord REST API, with an optional Durable Object Gateway connection for online status and slash commands.
|
||||||
- title: OAuth & User Actions
|
- title: Web UI & Slash Commands
|
||||||
details: "GitHub App OAuth flow enables user-initiated actions: comment on issues, merge PRs, add reactions — all via Bearer token auth."
|
details: "Manage routes and view send logs from a built-in admin console. Link your GitHub account and comment on issues/PRs as yourself via /gh commands."
|
||||||
- title: Signature Verification
|
- title: Signature Verification
|
||||||
details: HMAC-SHA256 webhook signature verification using the Web Crypto API with timing-safe comparison.
|
details: HMAC-SHA256 webhook signature verification using the Web Crypto API with timing-safe comparison.
|
||||||
- title: Graceful Degradation
|
- title: Graceful Degradation
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,30 @@ npx wrangler kv namespace create KV
|
||||||
```bash
|
```bash
|
||||||
npx wrangler secret put GITHUB_WEBHOOK_SECRET
|
npx wrangler secret put GITHUB_WEBHOOK_SECRET
|
||||||
npx wrangler secret put GITHUB_APP_ID
|
npx wrangler secret put GITHUB_APP_ID
|
||||||
npx wrangler secret put GITHUB_PRIVATE_KEY
|
npx wrangler secret put GITHUB_PRIVATE_KEY # PKCS#8 PEM(BEGIN PRIVATE KEY)
|
||||||
npx wrangler secret put GITHUB_CLIENT_ID
|
npx wrangler secret put GITHUB_CLIENT_ID
|
||||||
npx wrangler secret put GITHUB_CLIENT_SECRET
|
npx wrangler secret put GITHUB_CLIENT_SECRET
|
||||||
npx wrangler secret put DISCORD_TOKEN
|
npx wrangler secret put DISCORD_TOKEN
|
||||||
npx wrangler secret put DISCORD_CHANNEL_ID
|
npx wrangler secret put ADMIN_USER_IDS # 逗号分隔的 GitHub ID/登录名,允许进入 Web UI
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: tip 目标频道按路由配置
|
||||||
|
不存在全局频道密钥。每条路由在 [Web 控制台](/zh/guide/configuration#web-控制台) 中声明各自的目标频道(及可选的子区/thread),因此不需要 `DISCORD_CHANNEL_ID`。
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning GitHub App 私钥必须是 PKCS#8
|
||||||
|
GitHub 下发的私钥为 PKCS#1 格式(`BEGIN RSA PRIVATE KEY`)。Cloudflare Workers 的 JWT 签名要求 PKCS#8,需先转换:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
|
||||||
|
-in your-app.private-key.pem -out gh_pk_pkcs8.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
然后将 `gh_pk_pkcs8.pem` 作为 `GITHUB_PRIVATE_KEY` 上传。
|
||||||
|
:::
|
||||||
|
|
||||||
|
Discord Gateway 是可选的。在 `wrangler.jsonc` 的 `vars` 中设置 `DISCORD_GATEWAY_ENABLED`(默认为 `"false"`)。参见下方 [Gateway(可选)](#gateway可选)。
|
||||||
|
|
||||||
### 3. 部署
|
### 3. 部署
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -81,8 +98,22 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
|
||||||
1. 打开 <https://discord.com/developers/applications>
|
1. 打开 <https://discord.com/developers/applications>
|
||||||
2. 创建新应用 → 进入 Bot 部分
|
2. 创建新应用 → 进入 Bot 部分
|
||||||
3. 将 Bot Token 复制到 `DISCORD_TOKEN`
|
3. 将 Bot Token 复制到 `DISCORD_TOKEN`
|
||||||
4. 使用 `bot` 权限范围邀请 Bot 到你的服务器,并勾选 `Send Messages` 权限
|
4. 使用 `bot` 与 `applications.commands` 两个 scope 邀请 Bot,并勾选 `View Channels` + `Send Messages` + `Send Messages in Threads` 权限(组合整数 `274877910016`):
|
||||||
5. 将目标频道 ID 复制到 `DISCORD_CHANNEL_ID`
|
|
||||||
|
```text
|
||||||
|
https://discord.com/oauth2/authorize?client_id=YOUR_BOT_CLIENT_ID&permissions=274877910016&scope=bot+applications.commands
|
||||||
|
```
|
||||||
|
|
||||||
|
5. 在 Web UI(`/admin`)中**按路由**配置目标频道——无需全局频道 ID。
|
||||||
|
|
||||||
|
### Gateway(可选)
|
||||||
|
|
||||||
|
消息通过 Discord **REST API** 发送,因此仅凭 `DISCORD_TOKEN` 即可推送。Gateway 连接仅用于:(a) 让 Bot 显示为**在线**,(b) 启用 Discord 内的斜杠 / 右键菜单命令。
|
||||||
|
|
||||||
|
- `DISCORD_GATEWAY_ENABLED=false`(默认):仅 REST,不建立 Gateway 连接。
|
||||||
|
- `DISCORD_GATEWAY_ENABLED=true`:由一个 Durable Object 持有 Gateway 连接,并按服务器注册 `/gh` 斜杠命令以及 `GitHub: 添加/编辑/删除评论` 消息命令。
|
||||||
|
|
||||||
|
启用后,用户运行 `/gh login` 绑定自己的 GitHub 账号,即可以本人身份评论 issue/PR。完整命令说明见 [README](https://github.com/ReCloudStudio/WebHooker#bot-commands-comment-on-github-as-yourself)。
|
||||||
|
|
||||||
## 自定义域名(可选)
|
## 自定义域名(可选)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,18 @@ cp .env.example .dev.vars
|
||||||
```bash
|
```bash
|
||||||
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
||||||
GITHUB_APP_ID=your-app-id
|
GITHUB_APP_ID=your-app-id
|
||||||
GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
|
GITHUB_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
||||||
GITHUB_CLIENT_ID=your-client-id
|
GITHUB_CLIENT_ID=your-client-id
|
||||||
GITHUB_CLIENT_SECRET=your-client-secret
|
GITHUB_CLIENT_SECRET=your-client-secret
|
||||||
DISCORD_TOKEN=your-bot-token
|
DISCORD_TOKEN=your-bot-token
|
||||||
DISCORD_CHANNEL_ID=your-channel-id
|
ADMIN_USER_IDS=your-github-id,your-github-login
|
||||||
BASE_URL=http://localhost:8787
|
BASE_URL=http://localhost:8787
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
`GITHUB_PRIVATE_KEY` 必须是 **PKCS#8** 格式(`BEGIN PRIVATE KEY`)。用 `openssl pkcs8 -topk8 -nocrypt -in app.pem -out pkcs8.pem` 转换 GitHub 下发的 PKCS#1 私钥。目标频道在 Web UI 中按路由设置,因此不需要 `DISCORD_CHANNEL_ID`。若要让 Bot 保持在线并在本地启用 `/gh` 斜杠命令,可额外设置 `DISCORD_GATEWAY_ENABLED=true`。
|
||||||
|
:::
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
`.dev.vars` 已被 gitignore,包含敏感信息,请勿提交。
|
`.dev.vars` 已被 gitignore,包含敏感信息,请勿提交。
|
||||||
:::
|
:::
|
||||||
|
|
@ -59,14 +63,14 @@ curl http://localhost:8787/health
|
||||||
|
|
||||||
## 可用脚本
|
## 可用脚本
|
||||||
|
|
||||||
| 脚本 | 说明 |
|
| 脚本 | 说明 |
|
||||||
| --- | --- |
|
| ---------------------- | ----------------------------- |
|
||||||
| `npm run dev` | 启动本地开发服务器 (wrangler) |
|
| `npm run dev` | 启动本地开发服务器 (wrangler) |
|
||||||
| `npm run deploy` | 部署到 Cloudflare |
|
| `npm run deploy` | 部署到 Cloudflare |
|
||||||
| `npm run typecheck` | TypeScript 类型检查 |
|
| `npm run typecheck` | TypeScript 类型检查 |
|
||||||
| `npm run lint` | ESLint |
|
| `npm run lint` | ESLint |
|
||||||
| `npm run lint:md` | Markdownlint |
|
| `npm run lint:md` | Markdownlint |
|
||||||
| `npm run format` | 使用 Prettier 格式化 |
|
| `npm run format` | 使用 Prettier 格式化 |
|
||||||
| `npm run format:check` | 检查 Prettier 格式 |
|
| `npm run format:check` | 检查 Prettier 格式 |
|
||||||
| `npm run docs:dev` | 启动文档开发服务器 |
|
| `npm run docs:dev` | 启动文档开发服务器 |
|
||||||
| `npm run docs:build` | 构建文档站点 |
|
| `npm run docs:build` | 构建文档站点 |
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,44 @@
|
||||||
# 简介
|
# 简介
|
||||||
|
|
||||||
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为丰富的 Discord 嵌入消息,并通过 Durable Object 维护的 Gateway 连接将消息路由到 Discord 频道或帖子。
|
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为丰富的 Discord 嵌入消息,并通过 Discord REST API 投递到 Discord 频道或帖子。一个可选的 Durable Object 持有 Gateway 连接,用于让 Bot 保持在线并支持 Discord 内的 `/gh` 命令。路由通过内置的 Web UI 管理。
|
||||||
|
|
||||||
## 架构
|
## 架构
|
||||||
|
|
||||||
```text
|
```text
|
||||||
GitHub Webhook → Cloudflare Worker (Hono)
|
GitHub Webhook → Cloudflare Worker (Hono)
|
||||||
├── POST /webhook → 验证 → 过滤 → 格式化 → DO (Discord Gateway) → Discord
|
├── POST /webhook → 验证 → 去重 → 过滤 → 格式化 → Discord (REST API)
|
||||||
├── GET /auth/github → OAuth 流程
|
├── GET /auth/github → OAuth 流程
|
||||||
├── POST /api/* → 用户操作 (Bearer Token 鉴权)
|
├── POST /api/* → 用户操作 (Bearer Token 鉴权)
|
||||||
|
├── /admin → 路由与发送日志 Web UI(管理员会话)
|
||||||
└── GET /health → 健康检查
|
└── GET /health → 健康检查
|
||||||
|
|
||||||
|
(可选)Durable Object ⇄ Discord Gateway → Bot 在线 + /gh 斜杠与右键命令
|
||||||
```
|
```
|
||||||
|
|
||||||
### 组件
|
### 组件
|
||||||
|
|
||||||
| 组件 | 职责 |
|
| 组件 | 职责 |
|
||||||
| --- | --- |
|
| ----------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||||
| **Cloudflare Worker** | HTTP 入口、签名验证、事件解析、路由匹配 |
|
| **Cloudflare Worker** | HTTP 入口、签名验证、投递去重、事件解析、路由匹配、REST 发送 |
|
||||||
| **Durable Object (DiscordGateway)** | 持久 WebSocket 连接 Discord Gateway、频道缓存、带重试的消息分发 |
|
| **Durable Object (DiscordGateway)** | _可选。_ 保持 Gateway 连接(Bot 在线)并处理 `/gh` 交互 |
|
||||||
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`) |
|
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`)、发送日志、投递去重 |
|
||||||
|
|
||||||
### 数据流
|
### 数据流
|
||||||
|
|
||||||
1. GitHub 发送 webhook 到 `POST /webhook`
|
1. GitHub 发送 webhook 到 `POST /webhook`
|
||||||
2. Worker 验证 HMAC-SHA256 签名
|
2. Worker 验证 HMAC-SHA256 签名
|
||||||
3. Worker 解析事件类型和载荷
|
3. Worker 按 `X-GitHub-Delivery` 去重(KV,短 TTL),丢弃重复投递
|
||||||
4. 根据过滤器评估路由(event、repo、actor、action、branch、keyword)
|
4. Worker 解析事件类型和载荷
|
||||||
5. 匹配的路由触发格式化器函数生成 Discord 嵌入消息
|
5. 根据过滤器评估路由(event、repo、actor、action、branch、keyword)
|
||||||
6. 消息被分发到 Durable Object,由其维护 Gateway 连接
|
6. 匹配的路由触发格式化器函数生成 Discord 嵌入消息
|
||||||
7. DO 通过 REST API 将消息发送到 Discord,并处理速率限制重试
|
7. 每条消息通过 Discord REST API 发送到对应路由的目标频道/帖子,并处理速率限制重试,结果记录到发送日志
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
- **运行时**: Cloudflare Workers
|
- **运行时**: Cloudflare Workers
|
||||||
- **HTTP 框架**: Hono
|
- **HTTP 框架**: Hono
|
||||||
- **Discord Gateway**: Durable Object (持久 WebSocket + 频道缓存)
|
- **Discord 投递**: Discord REST API(Gateway 通过可选的 Durable Object 提供在线状态与 `/gh` 命令)
|
||||||
|
- **Web UI**: Nuxt 3 静态 SPA,由 Worker 资源托管
|
||||||
- **存储**: Cloudflare KV
|
- **存储**: Cloudflare KV
|
||||||
- **鉴权**: Web Crypto API (HMAC-SHA256)、jose (JWT)、octokit (GitHub API)
|
- **鉴权**: Web Crypto API (HMAC-SHA256)、jose (JWT)、octokit (GitHub API)
|
||||||
- **语言**: TypeScript
|
- **语言**: TypeScript
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ features:
|
||||||
- title: 灵活的过滤器
|
- title: 灵活的过滤器
|
||||||
details: 支持按事件类型、仓库、参与者、操作、分支(含 PR)和关键字(支持正则)过滤。支持排除模式。
|
details: 支持按事件类型、仓库、参与者、操作、分支(含 PR)和关键字(支持正则)过滤。支持排除模式。
|
||||||
- title: Cloudflare Workers
|
- title: Cloudflare Workers
|
||||||
details: 运行在 Cloudflare 边缘网络上,使用 Durable Objects 维持持久的 Discord Gateway 连接,使用 KV 进行存储。
|
details: 运行在 Cloudflare 边缘网络上。通过 Discord REST API 发送消息,并可选地用 Durable Object 维持 Gateway 连接以提供在线状态与斜杠命令。
|
||||||
- title: OAuth 与用户操作
|
- title: Web UI 与斜杠命令
|
||||||
details: "GitHub App OAuth 流程支持用户发起操作:评论议题、合并 PR、添加反应 — 全部通过 Bearer Token 鉴权。"
|
details: "在内置管理控制台中管理路由、查看发送日志。绑定你的 GitHub 账号,通过 /gh 命令以本人身份评论 issue/PR。"
|
||||||
- title: 签名验证
|
- title: 签名验证
|
||||||
details: 使用 Web Crypto API 进行 HMAC-SHA256 webhook 签名验证,支持时间安全比较。
|
details: 使用 Web Crypto API 进行 HMAC-SHA256 webhook 签名验证,支持时间安全比较。
|
||||||
- title: 优雅降级
|
- title: 优雅降级
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue