Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions devops/docker/compose/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
# LINEAR_WEBHOOK_TIMESTAMP_TOLERANCE_SECS=60
# LINEAR_NATS_ACK_TIMEOUT_MS=10000

# --- Discord Source ---
# DISCORD_MODE=gateway # "gateway" (WebSocket, all events) or "webhook" (HTTP, interactions only)
# DISCORD_BOT_TOKEN= # required when DISCORD_MODE=gateway
# DISCORD_GATEWAY_INTENTS=guilds,guild_members,guild_messages,guild_message_reactions,direct_messages,message_content,guild_voice_states
# DISCORD_PUBLIC_KEY= # required when DISCORD_MODE=webhook
# DISCORD_WEBHOOK_PORT=8080
# DISCORD_SUBJECT_PREFIX=discord
# DISCORD_STREAM_NAME=DISCORD
# DISCORD_STREAM_MAX_AGE_SECS=604800
# DISCORD_NATS_ACK_TIMEOUT_SECS=10
# DISCORD_NATS_REQUEST_TIMEOUT_SECS=2
# DISCORD_MAX_BODY_SIZE=4194304
Comment thread
yordis marked this conversation as resolved.

# --- Telegram Source ---
# TELEGRAM_WEBHOOK_SECRET=
# TELEGRAM_SOURCE_PORT=8080
Expand Down
38 changes: 38 additions & 0 deletions devops/docker/compose/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,37 @@ services:
start_period: 10s
retries: 3

trogon-source-discord:
build:
context: ../../../rsworkspace
dockerfile: ../devops/docker/compose/services/trogon-source-discord/Dockerfile
environment:
NATS_URL: "nats:4222"
DISCORD_MODE: "${DISCORD_MODE:-gateway}"
DISCORD_BOT_TOKEN: "${DISCORD_BOT_TOKEN:-}"
DISCORD_GATEWAY_INTENTS: "${DISCORD_GATEWAY_INTENTS:-}"
DISCORD_PUBLIC_KEY: "${DISCORD_PUBLIC_KEY:-}"
DISCORD_WEBHOOK_PORT: "${DISCORD_WEBHOOK_PORT:-8080}"
DISCORD_SUBJECT_PREFIX: "${DISCORD_SUBJECT_PREFIX:-discord}"
DISCORD_STREAM_NAME: "${DISCORD_STREAM_NAME:-DISCORD}"
DISCORD_STREAM_MAX_AGE_SECS: "${DISCORD_STREAM_MAX_AGE_SECS:-604800}"
DISCORD_NATS_ACK_TIMEOUT_SECS: "${DISCORD_NATS_ACK_TIMEOUT_SECS:-10}"
DISCORD_NATS_REQUEST_TIMEOUT_SECS: "${DISCORD_NATS_REQUEST_TIMEOUT_SECS:-2}"
DISCORD_MAX_BODY_SIZE: "${DISCORD_MAX_BODY_SIZE:-4194304}"
RUST_LOG: "${RUST_LOG:-info}"
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
yordis marked this conversation as resolved.
depends_on:
nats:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:${DISCORD_WEBHOOK_PORT:-8080}/health"]
interval: 10s
timeout: 3s
start_period: 10s
retries: 3
profiles:
- discord

trogon-source-gitlab:
build:
context: ../../../rsworkspace
Expand Down Expand Up @@ -147,6 +178,7 @@ services:
image: ngrok/ngrok:alpine
environment:
NGROK_AUTHTOKEN: "${NGROK_AUTHTOKEN:-}"
DISCORD_ADDR: "trogon-source-discord:${DISCORD_WEBHOOK_PORT:-8080}"
GITHUB_ADDR: "trogon-source-github:${GITHUB_WEBHOOK_PORT:-8080}"
GITLAB_ADDR: "trogon-source-gitlab:${GITLAB_WEBHOOK_PORT:-8080}"
LINEAR_ADDR: "trogon-source-linear:${LINEAR_WEBHOOK_PORT:-8080}"
Expand All @@ -159,6 +191,9 @@ services:
cat > /tmp/ngrok.yml <<EOF
version: 3
tunnels:
discord:
addr: $${DISCORD_ADDR}
proto: http
github:
addr: $${GITHUB_ADDR}
proto: http
Expand All @@ -177,6 +212,9 @@ services:
EOF
exec ngrok start --all --config /tmp/ngrok.yml
depends_on:
trogon-source-discord:
condition: service_healthy
Comment thread
yordis marked this conversation as resolved.
required: false
trogon-source-github:
condition: service_healthy
trogon-source-gitlab:
Expand Down
45 changes: 45 additions & 0 deletions devops/docker/compose/services/trogon-source-discord/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# ── Stage 1: chef — generate dependency recipe ──────────────────────────────
FROM rust:1.93-slim AS chef

RUN cargo install cargo-chef --locked

WORKDIR /build

# ── Stage 2: planner — capture dependency graph ─────────────────────────────
FROM chef AS planner

COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/

RUN cargo chef prepare --recipe-path recipe.json

# ── Stage 3: builder — cached dependency build + final compile ──────────────
FROM chef AS builder

COPY --from=planner /build/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json -p trogon-source-discord

COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/

RUN cargo build --release -p trogon-source-discord && \
strip target/release/trogon-source-discord

# ── Stage 4: runtime ────────────────────────────────────────────────────────
FROM debian:bookworm-20250317-slim AS runtime

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*

RUN useradd --no-create-home --shell /usr/sbin/nologin trogon

COPY --from=builder /build/target/release/trogon-source-discord /usr/local/bin/trogon-source-discord

USER trogon

EXPOSE 8080

STOPSIGNAL SIGTERM

ENTRYPOINT ["/usr/local/bin/trogon-source-discord"]
92 changes: 92 additions & 0 deletions devops/docker/compose/services/trogon-source-discord/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Receiving Discord Events Locally

`trogon-source-discord` is the inbound pipe for Discord events into NATS
JetStream. It runs in one of two mutually exclusive modes, controlled by
`DISCORD_MODE`:

| Mode | Transport | Events | Requires |
|---|---|---|---|
| `gateway` | WebSocket (you connect to Discord) | Everything — messages, reactions, members, voice, interactions, etc. | `DISCORD_BOT_TOKEN` |
| `webhook` | HTTP POST (Discord connects to you) | Interactions only — slash commands, buttons, modals, autocomplete | `DISCORD_PUBLIC_KEY` |

## Prerequisites

- Docker Compose
- A [Discord Application](https://discord.com/developers/applications)
- An [ngrok](https://ngrok.com) account (free tier, only needed for `webhook` mode)

## Gateway mode

### 1. Get your bot token

1. Go to **Discord Developer Portal → Applications → your app → Bot**
2. Copy the **Token**

### 2. Start the stack

```bash
DISCORD_MODE=gateway \
DISCORD_BOT_TOKEN=<your-bot-token> \
docker compose up
```

This connects to the Discord Gateway and publishes every event to NATS on
`discord.{event_name}` subjects (e.g. `discord.message_create`,
`discord.guild_member_add`).

## Webhook mode

### 1. Get your public key

1. Go to **Discord Developer Portal → Applications → your app → General Information**
2. Copy the **Public Key** (hex string)

### 2. Start the stack

```bash
DISCORD_MODE=webhook \
DISCORD_PUBLIC_KEY=<your-hex-public-key> \
docker compose --profile dev up
```

This starts NATS, the webhook receiver, and ngrok. Find the public tunnel URL
in the ngrok container logs:

```bash
docker compose logs ngrok
```

### 3. Configure your Discord Application

1. Go to **Discord Developer Portal → Applications → your app → General Information**
2. Set **Interactions Endpoint URL** to `https://<ngrok-url>/webhook`
3. Discord will send a PING to verify the endpoint — the receiver handles this
automatically

## Verify

Subscribe to NATS to see events flowing:

```bash
nats sub -s nats://nats.trogonai.orb.local:4222 "discord.>"
```

Without `--profile dev`, ngrok is excluded and only the core services start.

## Environment variables

| Variable | Required | Default | Description |
|---|---|---|---|
| `DISCORD_MODE` | yes | — | `gateway` or `webhook` |
| `DISCORD_BOT_TOKEN` | gateway mode | — | Bot token for Gateway WebSocket |
| `DISCORD_PUBLIC_KEY` | webhook mode | — | Ed25519 public key (hex) for Interactions |
| `DISCORD_GATEWAY_INTENTS` | no | see code | Comma-separated gateway intents |
| `NGROK_AUTHTOKEN` | webhook + dev | — | ngrok auth token |
| `DISCORD_WEBHOOK_PORT` | no | `8080` | HTTP port for the webhook receiver |
| `DISCORD_SUBJECT_PREFIX` | no | `discord` | NATS subject prefix |
| `DISCORD_STREAM_NAME` | no | `DISCORD` | JetStream stream name |
| `DISCORD_STREAM_MAX_AGE_SECS` | no | `604800` | Max age in seconds for JetStream messages (7 days) |
| `DISCORD_NATS_ACK_TIMEOUT_SECS` | no | `10` | NATS publish ack timeout in seconds |
| `DISCORD_NATS_REQUEST_TIMEOUT_SECS` | no | `2` | NATS request-reply timeout for autocomplete in seconds |
| `DISCORD_MAX_BODY_SIZE` | no | `4194304` | Max webhook body size in bytes (4 MB) |
| `RUST_LOG` | no | `info` | Log level |
Comment thread
yordis marked this conversation as resolved.
Loading
Loading