diff --git a/.dockerignore b/.dockerignore index d0c8ea5..448b4fa 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,4 +7,4 @@ tests/ .env .env.* .dockerignore -bun.lock +docker-compose.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2305a0a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: + contents: read + packages: write + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/metadata-action@v5 + id: meta + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=semver,pattern={{version}} + type=raw,value=latest + + - uses: docker/build-push-action@v6 + with: + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 11f83ff..f3d3c1c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM oven/bun:latest +# Build stage — install dependencies +FROM oven/bun:latest AS builder WORKDIR /app @@ -7,6 +8,18 @@ RUN bun install --frozen-lockfile --production COPY *.ts ./ +# Runtime stage — slim image +FROM oven/bun:slim + +WORKDIR /app + +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/*.ts ./ + EXPOSE 3000 +HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \ + CMD bun -e "fetch('http://localhost:3000/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))" + CMD ["bun", "run", "index.ts"] diff --git a/README.md b/README.md index 561130c..9c43194 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,34 @@ Discord REST API caching proxy — polls Discord once, caches responses, serves ## Quick Start +### Docker + ```bash -# Run with Bun -DISCORD_BOT_TOKEN=your-token DISCORD_GUILD_ID=your-guild-id bun run start +docker run -d \ + -e DISCORD_BOT_TOKEN=your-token \ + -e DISCORD_GUILD_ID=your-guild-id \ + -p 3000:3000 \ + ghcr.io/wave-engineering/scream-hole:latest +``` + +### Docker Compose (local dev) -# Run with Docker -docker build -t scream-hole . -docker run -e DISCORD_BOT_TOKEN=your-token -e DISCORD_GUILD_ID=your-guild-id -p 3000:3000 scream-hole +Create a `.env` file: + +```env +DISCORD_BOT_TOKEN=your-token +DISCORD_GUILD_ID=your-guild-id +``` + +```bash +docker compose up +``` + +### Bun (direct) + +```bash +bun install +DISCORD_BOT_TOKEN=your-token DISCORD_GUILD_ID=your-guild-id bun run start ``` ## Configuration @@ -20,6 +41,7 @@ docker run -e DISCORD_BOT_TOKEN=your-token -e DISCORD_GUILD_ID=your-guild-id -p | `DISCORD_BOT_TOKEN` | Yes | — | Discord bot token (or `~/secrets/discord-bot-token`) | | `DISCORD_GUILD_ID` | Yes | — | Discord server ID to proxy | | `POLL_INTERVAL_MS` | No | `15000` | How often to poll Discord (ms) | +| `CACHE_WINDOW_MS` | No | `14400000` | Cache window — messages older than this are evicted (default 4h) | | `PORT` | No | `3000` | HTTP server port | | `LOG_LEVEL` | No | `info` | Log level: debug, info, warn, error | @@ -27,7 +49,10 @@ docker run -e DISCORD_BOT_TOKEN=your-token -e DISCORD_GUILD_ID=your-guild-id -p | Method | Path | Description | |--------|------|-------------| -| GET | `/health` | Health check — returns status, uptime, version | +| GET | `/health` | Health check — status, uptime, version, cache stats | +| GET | `/api/v10/guilds/{id}/channels` | Cached channel list | +| GET | `/api/v10/channels/{id}/messages?after=SNOWFLAKE` | Cached messages (`after` required) | +| POST | `/api/v10/channels/{id}/messages` | Write pass-through — forwards to Discord | ## Development @@ -46,6 +71,8 @@ Consumer C ──┘ │ cache ``` +Single poller fetches channels and messages on a configurable interval. Consumers read from the cache via Discord-compatible REST endpoints. Writes are forwarded to Discord and injected into the cache immediately. + ## License MIT diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7b07451 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +services: + scream-hole: + build: . + ports: + - "3000:3000" + env_file: .env + restart: unless-stopped