refactor: replace Discord Gateway DO with Interaction Endpoint

This commit is contained in:
RhenCloud 2026-08-03 03:02:42 +08:00
parent 9bb9cb1444
commit d540d465d1
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
27 changed files with 834 additions and 964 deletions

View file

@ -19,9 +19,10 @@ WebHooker requires several secrets to function. For local development, store the
| Variable | Description | Default |
| ------------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------- |
| `DISCORD_PUBLIC_KEY` | Discord application public key (Developer Portal) — required for interactions | Unset → interactions return `401` |
| `DISCORD_APPLICATION_ID` | Discord application id; auto-resolved when omitted | Auto-resolved |
| `BASE_URL` | Public URL for OAuth callbacks | `http://localhost:8787` |
| `ADMIN_USER_IDS` | Comma-separated GitHub user IDs (or logins) allowed to access the Web UI | Disabled |
| `DISCORD_GATEWAY_ENABLED` | Set to `true` to connect the Discord Gateway (bot online status); messaging works without it via REST | `false` |
## Web UI
@ -180,4 +181,7 @@ Filters accept either a single string or an array of strings:
| `discord-link:{userId}` | GitHub user id linked to a Discord user | Permanent |
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId? }` | 600 seconds |
| `delivery:{id}` | Webhook delivery id (dedup marker) | 300 seconds |
| `cmd:guild:{id}` | Guild id whose commands were registered (dedup) | Permanent |
| `cmd:registered:global` | Global command registration marker (dedup) | 1 day |
| `config:discord-app-id` | Cached Discord application id | Permanent |
| `logs:send:{ts}-{hex}` | Send record | 1 hour |

View file

@ -30,6 +30,7 @@ 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_SECRET
npx wrangler secret put DISCORD_TOKEN
npx wrangler secret put DISCORD_PUBLIC_KEY # Discord app public key (Developer Portal) — required for interactions
npx wrangler secret put ADMIN_USER_IDS # comma-separated GitHub IDs/logins allowed into the Web UI
```
@ -48,7 +49,7 @@ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
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.
Discord interactions arrive via the HTTPS Interactions Endpoint, so set `DISCORD_PUBLIC_KEY` and point the **Interactions Endpoint URL** at `https://your-domain/discord/interactions`. See [Interactions Endpoint](#interactions-endpoint) below.
### 3. Deploy
@ -106,14 +107,17 @@ Your worker is now live at `https://webhooker.<your-subdomain>.workers.dev`.
5. Configure target channels **per route** in the Web UI (`/admin`) — no global channel ID is required.
### Gateway (optional)
### Interactions Endpoint
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.
Messages are sent via the Discord **REST API**, so pushing works with just `DISCORD_TOKEN`. Interactions (slash commands, buttons, modals) arrive through the HTTPS Interactions Endpoint:
- `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.
1. Copy the application **Public Key** (Developer Portal → General Information) to `DISCORD_PUBLIC_KEY`.
2. Set the **Interactions Endpoint URL** to `https://your-domain/discord/interactions`.
3. Every interaction request is verified with Ed25519 signatures (`X-Signature-Ed25519` over `X-Signature-Timestamp + body`).
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.
The `/gh` slash command and the `GitHub: 添加/编辑/删除评论` message commands are synced by the scheduled trigger (every 5 minutes): per-guild for instant availability, plus a global registration (24h dedup, ~1h propagation). The bot never connects to the Discord Gateway, so it shows as **offline** — messaging is unaffected (always REST).
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)
@ -132,4 +136,4 @@ docker build -t webhooker .
docker run -p 8787:8787 --env-file .env webhooker
```
Note: Docker mode runs without Durable Objects and KV. Use Cloudflare deployment for full functionality.
Note: Docker mode runs without KV and other Cloudflare storage. Use Cloudflare deployment for full functionality.

View file

@ -34,12 +34,13 @@ GITHUB_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret
DISCORD_TOKEN=your-bot-token
DISCORD_PUBLIC_KEY=your-public-key
ADMIN_USER_IDS=your-github-id,your-github-login
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`.
`GITHUB_PRIVATE_KEY` must be in **PKCS#8** format (`BEGIN PRIVATE KEY`). Convert a GitHub-issued PKCS#1 key with `openssl pkcs8 -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 enable `/gh` commands locally, copy the **Public Key** from the Developer Portal into `DISCORD_PUBLIC_KEY` and set the Interactions Endpoint URL to `http://localhost:8787/discord/interactions`.
:::
::: warning

View file

@ -1,6 +1,6 @@
# 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 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.
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. In-Discord `/gh` interactions arrive via an HTTPS Interactions Endpoint (Ed25519-verified). Routes are managed through a built-in Web UI.
## Architecture
@ -10,9 +10,9 @@ GitHub Webhook → Cloudflare Worker (Hono)
├── GET /auth/github → OAuth flow
├── 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
POST /discord/interactions → verify (Ed25519) → handle /gh slash & context commands
```
### Components
@ -20,7 +20,7 @@ GitHub Webhook → Cloudflare Worker (Hono)
| Component | Role |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **Cloudflare Worker** | HTTP ingress, signature verification, delivery dedup, event parsing, route matching, REST send |
| **Durable Object (DiscordGateway)** | _Optional._ Keeps the Gateway connection alive (bot online) and handles `/gh` interactions |
| **Interactions Endpoint** | Verifies Ed25519 signatures and handles `/gh` interactions (slash commands, context-menu commands, buttons, modals) |
| **KV** | Token storage (`token:{userId}`), OAuth state (`state:{hex}`), route config (`config:routes`), send logs, delivery dedup |
### Data Flow
@ -37,7 +37,7 @@ GitHub Webhook → Cloudflare Worker (Hono)
- **Runtime**: Cloudflare Workers
- **HTTP Framework**: Hono
- **Discord delivery**: Discord REST API (Gateway via optional Durable Object for online status + `/gh` commands)
- **Discord delivery**: Discord REST API (interactions via an Ed25519-verified HTTPS Interactions Endpoint)
- **Web UI**: Nuxt 3 static SPA served from Worker assets
- **Storage**: Cloudflare KV
- **Auth**: Web Crypto API (HMAC-SHA256), jose (JWT), octokit (GitHub API)