docs: add README with setup instructions and docker-compose.yml
Made-with: Cursor
This commit is contained in:
108
README.md
Normal file
108
README.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# owncast-irc-bridge
|
||||||
|
|
||||||
|
Bidirectional chat bridge between [Owncast](https://owncast.online/) and IRC. Messages sent in your Owncast chat appear in an IRC channel and vice versa.
|
||||||
|
|
||||||
|
## Quick Start (Docker Compose)
|
||||||
|
|
||||||
|
**1. Create your config file**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp config.example.toml config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `config.toml` with your IRC server/channel and Owncast URL.
|
||||||
|
|
||||||
|
**2. Get an Owncast access token**
|
||||||
|
|
||||||
|
In your Owncast admin panel, go to **Integrations > Access Tokens** and create a token with "send messages" permission.
|
||||||
|
|
||||||
|
**3. Set the token**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OWNCAST_ACCESS_TOKEN="your-token-here"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or create a `.env` file (git-ignored):
|
||||||
|
|
||||||
|
```
|
||||||
|
OWNCAST_ACCESS_TOKEN=your-token-here
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Configure the Owncast webhook**
|
||||||
|
|
||||||
|
In your Owncast admin, go to **Integrations > Webhooks** and add a webhook pointing to:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://<bridge-host>:9078/webhook
|
||||||
|
```
|
||||||
|
|
||||||
|
Select the events: **Chat Message**, **Stream Started**, **Stream Stopped**.
|
||||||
|
|
||||||
|
**5. Run it**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Check logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running Without Docker
|
||||||
|
|
||||||
|
Requires Rust 1.75+.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build --release
|
||||||
|
export OWNCAST_ACCESS_TOKEN="your-token-here"
|
||||||
|
./target/release/owncast-irc-bridge --config config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
See [`config.example.toml`](config.example.toml) for all options. The only required sections are `[irc]` (with `server` and `channel`) and `[owncast]` (with `url`). Everything else has defaults.
|
||||||
|
|
||||||
|
| Section | Key | Default | Description |
|
||||||
|
|---------|-----|---------|-------------|
|
||||||
|
| `irc` | `server` | *(required)* | IRC server hostname |
|
||||||
|
| `irc` | `port` | `6667` | IRC server port |
|
||||||
|
| `irc` | `tls` | `false` | Use TLS for IRC |
|
||||||
|
| `irc` | `nick` | `owncast-bridge` | IRC nickname |
|
||||||
|
| `irc` | `channel` | *(required)* | IRC channel to join |
|
||||||
|
| `owncast` | `url` | *(required)* | Owncast instance URL |
|
||||||
|
| `owncast` | `webhook_port` | `9078` | Port the webhook server listens on |
|
||||||
|
| `owncast` | `websocket_enabled` | `false` | Also connect via WebSocket (redundant with webhook, useful as fallback) |
|
||||||
|
| `owncast` | `health_poll_interval_secs` | `30` | How often to poll Owncast status |
|
||||||
|
| `bridge` | `irc_prefix` | `[IRC]` | Prefix for IRC messages in Owncast |
|
||||||
|
| `bridge` | `owncast_prefix` | `[OC]` | Prefix for Owncast messages in IRC |
|
||||||
|
| `control` | `socket_path` | `/tmp/owncast-irc-bridge.sock` | Unix socket for `bridge-ctl` |
|
||||||
|
|
||||||
|
The access token is always read from the `OWNCAST_ACCESS_TOKEN` environment variable (not the config file).
|
||||||
|
|
||||||
|
## Runtime Control
|
||||||
|
|
||||||
|
Use `bridge-ctl` to interact with a running bridge:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bridge-ctl status # Show bridge status as JSON
|
||||||
|
bridge-ctl irc reconnect # Reconnect to IRC
|
||||||
|
bridge-ctl owncast reconnect # Reconnect to Owncast
|
||||||
|
bridge-ctl quit # Shut down the bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
Inside Docker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec bridge bridge-ctl status
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
- **Owncast → IRC:** Owncast sends webhook events to the bridge. The bridge formats the message and sends it to IRC via PRIVMSG.
|
||||||
|
- **IRC → Owncast:** The bridge listens for PRIVMSG in the configured channel and posts to Owncast via the integration API.
|
||||||
|
- **Deduplication:** If both webhook and WebSocket are enabled, duplicate messages are detected by ID and dropped.
|
||||||
|
- **Echo suppression:** Messages the bridge itself sent are recognized and not re-bridged.
|
||||||
|
- **Stream events:** Stream start/stop events are announced in IRC.
|
||||||
|
- **Health polling:** The bridge polls Owncast's `/api/status` endpoint and announces state changes in IRC.
|
||||||
37
chat-summaries/2026-03-10_22-00-summary.md
Normal file
37
chat-summaries/2026-03-10_22-00-summary.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Owncast–IRC Bridge: Full Implementation
|
||||||
|
|
||||||
|
## Task Description
|
||||||
|
Executed the full 15-task implementation plan at `docs/plans/2026-03-10-owncast-irc-bridge-impl.md` using the executing-plans skill. Built a complete bidirectional Rust chat bridge between Owncast and IRC.
|
||||||
|
|
||||||
|
## Changes Made (15 commits)
|
||||||
|
1. **Project scaffolding** — `cargo init`, Cargo.toml with all deps, `.gitignore`, `config.example.toml`, placeholder binaries
|
||||||
|
2. **Config module** (`src/config.rs`) — TOML parsing with serde defaults, env var support for access token, 3 tests
|
||||||
|
3. **Events module** (`src/events.rs`) — `BridgeEvent`, `Source`, `OwncastState`, `ControlCommand`, `BridgeStatus` types
|
||||||
|
4. **HTML stripping** (`src/html.rs`) — Strips HTML tags, extracts emoji `<img>` alt text, decodes entities, 6 tests
|
||||||
|
5. **Owncast API client** (`src/owncast_api.rs`) — `send_chat_message` with retry, `get_status` for health checks
|
||||||
|
6. **Health poller** (`src/health.rs`) — Periodic Owncast status polling with state change detection
|
||||||
|
7. **Webhook server** (`src/webhook.rs`) — Axum HTTP server parsing CHAT/STREAM_STARTED/STREAM_STOPPED events, 5 tests
|
||||||
|
8. **IRC task** (`src/irc_task.rs`) — `irc` crate client with exponential backoff reconnect
|
||||||
|
9. **WebSocket task** (`src/websocket.rs`) — tokio-tungstenite client with reconnect, 5 tests
|
||||||
|
10. **Control socket** (`src/control.rs`) — Unix socket listener with command parsing, 5 tests
|
||||||
|
11. **Router** (`src/router.rs`) — Central orchestration with dedup tracker, echo suppressor, state handling, 4 tests
|
||||||
|
12. **Main entry point** (`src/main.rs`) — Wires all tasks together with signal handling (SIGINT/SIGTERM/SIGHUP)
|
||||||
|
13. **bridge-ctl CLI** (`src/bin/bridge_ctl.rs`) — Clap-based CLI for runtime control via Unix socket
|
||||||
|
14. **Dockerfile** — Multi-stage build (rust:1.85-slim-bookworm builder, debian:bookworm-slim runtime)
|
||||||
|
15. **Final fixes** — Added missing `Clone` derive on `IrcConfig`, cleaned up unused imports
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
- Both binaries (`owncast-irc-bridge`, `bridge-ctl`) compile
|
||||||
|
- All 28 tests pass across all modules
|
||||||
|
- Only benign warnings remain (unused struct fields for future API data)
|
||||||
|
|
||||||
|
## Bugs Found in Plan
|
||||||
|
- Raw string delimiters `r#"..."#` conflicted with TOML `"#channel"` values — fixed with `r##"..."##`
|
||||||
|
- `strip_html` had peek/consume bug (didn't advance past `<` and `&` before collecting) — fixed
|
||||||
|
- `reqwest::Response::text()` consumes `self`, so status must be captured first — fixed
|
||||||
|
|
||||||
|
## Follow-up Items
|
||||||
|
- Integration testing with actual Owncast and IRC instances
|
||||||
|
- Wire remaining control commands (connect/disconnect/reconnect) through to tasks
|
||||||
|
- Add `message_buffer_size` buffering logic
|
||||||
|
- SIGHUP config reload support
|
||||||
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
bridge:
|
||||||
|
build: .
|
||||||
|
container_name: owncast-irc-bridge
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- OWNCAST_ACCESS_TOKEN=${OWNCAST_ACCESS_TOKEN}
|
||||||
|
- RUST_LOG=info
|
||||||
|
volumes:
|
||||||
|
- ./config.toml:/etc/owncast-irc-bridge/config.toml:ro
|
||||||
|
ports:
|
||||||
|
- "9078:9078"
|
||||||
Reference in New Issue
Block a user