Files
IRC-kosmi-relay/chat-summaries/2025-10-31_13-10-00_final-working-solution.md
2025-10-31 16:17:04 -04:00

8.1 KiB

Final Working Solution: Kosmi ↔ IRC Relay

Date: October 31, 2025, 1:10 PM
Status: FULLY FUNCTIONAL - BIDIRECTIONAL RELAY WORKING

Summary

Successfully implemented a fully working bidirectional message relay between Kosmi and IRC using a Playwright-based UI automation approach.

Test Results

IRC → Kosmi: Working
Kosmi → IRC: Working
Username formatting: Consistent with RemoteNickFormat
Message echo prevention: Working (messages with [irc] prefix filtered out)
Clean logging: Debug code removed, production-ready

Final Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    Matterbridge Gateway                         │
│                                                                 │
│  ┌──────────────────────┐         ┌──────────────────────┐    │
│  │   IRC Bridge         │◄───────►│   Kosmi Bridge       │    │
│  │  (irc.zeronode)      │         │  (kosmi.hyperspaceout)│    │
│  └──────────────────────┘         └──────────┬───────────┘    │
│                                               │                 │
└───────────────────────────────────────────────┼─────────────────┘
                                                │
                                    ┌───────────▼───────────┐
                                    │  Playwright Native     │
                                    │      Client            │
                                    │                        │
                                    │  • Browser automation  │
                                    │  • WebSocket (receive) │
                                    │  • UI automation (send)│
                                    └───────────┬────────────┘
                                                │
                                    ┌───────────▼───────────┐
                                    │   Kosmi Web UI        │
                                    │  (app.kosmi.io)       │
                                    └───────────────────────┘

Implementation Details

Message Receiving (Kosmi → IRC)

  • Method: WebSocket subscription via Playwright-intercepted connection
  • Mechanism: JavaScript injection captures WebSocket messages in the browser
  • Subscription: subscription { newMessage(roomId: "...") { body time user { displayName username } } }
  • Processing: Messages polled from JavaScript queue every 500ms

Message Sending (IRC → Kosmi)

  • Method: UI automation via Playwright
  • Mechanism: JavaScript evaluation to interact with DOM
  • Process:
    1. Find visible chat input element (textarea, contenteditable, or text input)
    2. Set input value to message text
    3. Dispatch input/change events
    4. Trigger send via button click or Enter key press

Why This Approach?

After extensive investigation, we discovered:

  1. Direct WebSocket Connection: Fails with 403 Forbidden (authentication/bot detection)
  2. HTTP POST GraphQL Mutation: API only supports auth mutations (anonLogin, slackLogin), not sendMessage
  3. WebSocket Mutation via Playwright: Connection closes immediately after sending mutation (protocol/auth issues)
  4. UI Automation: Works reliably because it mimics real user interaction

Key Files

1. bridge/kosmi/native_client.go

The Playwright-based client implementation:

  • Launches headless Chromium browser
  • Injects WebSocket access layer
  • Navigates to Kosmi room
  • Subscribes to messages via WebSocket
  • Sends messages via UI automation

2. bridge/kosmi/kosmi.go

The Matterbridge bridge implementation:

  • Implements bridge.Bridger interface
  • Manages NativeClient lifecycle
  • Handles message routing
  • Filters echo messages (prevents loops)

3. matterbridge.toml

Configuration file:

[kosmi.hyperspaceout]
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "

[irc.zeronode]
Server="irc.zeronode.net:6697"
Nick="kosmi-relay"
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
UseTLS=true

Message Flow

IRC → Kosmi

  1. User sends message in IRC: Testing from IRC
  2. IRC bridge receives PRIVMSG
  3. Matterbridge formats with RemoteNickFormat: [irc] <username> Testing from IRC
  4. Kosmi bridge receives message
  5. NativeClient.SendMessage() uses UI automation
  6. JavaScript finds chat input, sets value, triggers send
  7. Message appears in Kosmi chat

Kosmi → IRC

  1. User sends message in Kosmi: Testing from Kosmi
  2. WebSocket subscription receives newMessage event
  3. JavaScript queue captures the message
  4. pollMessages() retrieves from queue
  5. Kosmi bridge filters echo messages (checks for [irc] prefix)
  6. Matterbridge formats with RemoteNickFormat: [kosmi] <username> Testing from Kosmi
  7. IRC bridge sends to channel
  8. Message appears in IRC

Echo Prevention

Messages are tagged with protocol prefixes via RemoteNickFormat:

  • IRC messages sent to Kosmi: [irc] <username> message
  • Kosmi messages sent to IRC: [kosmi] <username> message

The Kosmi bridge filters out messages starting with [irc] to prevent echoing our own messages back.

Deployment

Docker Compose

services:
  matterbridge:
    build: .
    container_name: kosmi-irc-relay
    volumes:
      - ./matterbridge.toml:/app/matterbridge.toml:ro
    restart: unless-stopped

Running

docker-compose up -d --build
docker-compose logs -f

Performance Characteristics

  • Startup Time: ~10 seconds (Playwright browser launch + page load)
  • Message Latency:
    • IRC → Kosmi: ~100-500ms (UI automation)
    • Kosmi → IRC: ~500-1000ms (polling interval)
  • Resource Usage:
    • Memory: ~300-400 MB (Chromium browser)
    • CPU: Low after initialization

Future Improvements

Potential Optimizations

  1. Reduce Polling Interval: Could decrease from 500ms to 250ms for lower latency
  2. WebSocket Send: If Kosmi's auth/protocol can be reverse-engineered properly
  3. Direct GraphQL API: If Kosmi exposes a sendMessage mutation in the future

Known Limitations

  1. Browser Required: Must run full Chromium browser (can be headless)
  2. Polling Latency: 500ms delay for incoming messages
  3. UI Dependency: Breaks if Kosmi changes their UI structure (input selectors)

Troubleshooting

Common Issues

Problem: "Could not find chat input element"
Solution: Kosmi may have changed their UI. Update selectors in SendMessage() method.

Problem: Messages not appearing in Kosmi
Solution: Check browser console logs, verify UI automation script is working.

Problem: WebSocket not connecting
Solution: Check network connectivity, verify Kosmi URL is correct.

Problem: Echo loop (messages keep bouncing)
Solution: Verify RemoteNickFormat is set correctly and echo filter is working.

Conclusion

After extensive troubleshooting and multiple implementation attempts (direct WebSocket, HTTP POST, WebSocket mutations), we successfully achieved bidirectional message relay using Playwright UI automation. This approach is reliable, maintainable, and production-ready.

The relay now successfully: Sends messages from IRC to Kosmi
Receives messages from Kosmi to IRC
Prevents message echo loops
Formats usernames consistently
Runs in Docker with minimal configuration

Status: Production-ready