fix: HTML-escape IRC username in Owncast chat, fix WebSocket auth, fix echo suppression

- Escape angle brackets around IRC username so Owncast doesn't swallow
  them as HTML tags (&lt;nick&gt; instead of <nick>)
- Register a chat user via POST /api/chat/register to obtain an
  accessToken, then pass it as a query param when connecting to /ws
  (Owncast closes the WebSocket immediately without one)
- Cache the access token across reconnections; re-register only on
  rejection
- Add ws_display_name config option (default "IRC Bridge")
- Fix echo suppression: record_sent and is_echo now both compare
  raw body instead of mismatched formatted/raw values

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-12 14:06:41 -04:00
parent c24cef9d6d
commit 196997f728
7 changed files with 144 additions and 13 deletions

View File

@@ -0,0 +1,19 @@
# Debug: IRC + WebSocket connection failures
## Task
Investigated why both IRC and WebSocket connections were failing immediately after connecting, entering infinite reconnection loops with exponential backoff.
## Findings
Both issues were **external/environmental**, not code bugs:
1. **IRC** (`irc.zeronode.net`): Server was rejecting with `ERROR :Closing link: ... [No more connections allowed from your host via this connect class (global)]`. Too many existing connections from the same host IP.
2. **WebSocket** (`wss://owncast.bowlafterbowl.com/ws`): Caddy proxy successfully upgraded (101), but the Owncast backend immediately reset the connection. Owncast instance was offline.
## Changes Made
None (instrumentation added for debugging was fully reverted after diagnosis).
## Follow-up Items
- Consider logging the actual IRC ERROR message content instead of the generic "IRC stream ended" — would make future diagnosis faster without instrumentation.
- Consider detecting fatal IRC errors (connection class limits, K-lines) and stopping reconnection attempts rather than continuing to hammer the server.

View File

@@ -0,0 +1,29 @@
# Fix IRC-Owncast Bridge Issues
## Task
Fix three issues: IRC username stripped in Owncast chat, WebSocket connection always failing, and echo suppression bug.
## Changes Made
### 1. HTML-escape username in IRC->Owncast messages (`src/router.rs`)
- Changed `<username>` to `&lt;username&gt;` in the formatted message sent to Owncast's chat API
- Owncast renders chat as HTML, so bare angle brackets were being interpreted as HTML tags and swallowed
### 2. Fix WebSocket authentication (`src/websocket.rs`, `src/owncast_api.rs`, `src/main.rs`)
- **Root cause**: Owncast's `/ws` endpoint requires an `accessToken` query parameter from a registered chat user. The bridge was connecting without one.
- Added `register_chat_user()` to `OwncastApiClient` -- calls `POST /api/chat/register` to get a user-level access token
- Updated `run_websocket_task` to register a chat user, cache the token, and pass it as `?accessToken=` in the WebSocket URL
- Token is cached across reconnections; re-registration happens only if rejected
- Added `base_url()` accessor to `OwncastApiClient`
### 3. Add `ws_display_name` config field (`src/config.rs`, `config.toml`, `config.example.toml`)
- New `ws_display_name` field on `OwncastConfig` (default: "IRC Bridge") controls the display name of the WebSocket chat user in Owncast
### 4. Fix echo suppression bug (`src/router.rs`)
- `record_sent` was storing the full formatted string (`[IRC] <nick> body`) but `is_echo` compared against raw `body` -- they never matched
- Changed `record_sent` to store the raw `body` so echo suppression actually works
- Moved the `is_echo` check before formatting in the Owncast->IRC path to avoid unnecessary work
## Follow-up Items
- Owncast admin still needs to configure webhook URL pointing to the bridge's port 9078
- The bridge's WebSocket user will appear as "IRC Bridge" in Owncast's connected users list