# Kosmi-IRC Relay via Matterbridge A Matterbridge plugin that bridges Kosmi chat rooms with IRC channels, enabling bidirectional message relay. ## Features - ✅ Real-time message relay between Kosmi and IRC - ✅ Headless Chrome automation for reliable Kosmi connection - ✅ WebSocket interception using Chrome DevTools Protocol - ✅ Anonymous Kosmi access (no authentication required) - ✅ Message formatting with source indicators - ✅ Automatic reconnection handling - ✅ Support for any Kosmi room via URL configuration ## Architecture This implementation extends Matterbridge with a custom Kosmi bridge that: 1. Launches a headless Chrome instance using `chromedp` 2. Navigates to the Kosmi room and injects a WebSocket interceptor **before page load** 3. Captures GraphQL WebSocket messages (`wss://engine.kosmi.io/gql-ws`) from the page 4. Relays messages bidirectionally with proper formatting: - **Kosmi → IRC**: `[Kosmi] message` - **IRC → Kosmi**: `[IRC] message` ### Why Headless Chrome? Kosmi's WebSocket API requires browser session cookies and context that are difficult to replicate with a native WebSocket client. Using headless Chrome automation ensures: - ✅ Automatic session management - ✅ Proper cookie handling - ✅ Reliable WebSocket connection - ✅ No authentication complexity ## Installation ### Option 1: Docker (Recommended) 🐳 The easiest way to run the bridge: ```bash # 1. Edit configuration nano matterbridge.toml # 2. Build and run docker-compose up -d # 3. View logs docker-compose logs -f ``` **See**: `DOCKER_QUICKSTART.md` for 5-minute setup guide ### Option 2: Build from Source #### Prerequisites - Go 1.21 or higher - Chrome or Chromium browser installed - Access to an IRC server - A Kosmi room URL #### Building ```bash # Clone the repository git clone cd irc-kosmi-relay # Download dependencies go mod download # Build the bridge go build -o matterbridge ``` ## Configuration Edit `matterbridge.toml` to configure your bridge: ```toml # Kosmi configuration [kosmi.hyperspaceout] RoomURL="https://app.kosmi.io/room/@hyperspaceout" # IRC configuration [irc.libera] Server="irc.libera.chat:6667" Nick="kosmi-relay" UseTLS=false # Gateway to connect Kosmi and IRC [[gateway]] name="kosmi-irc-gateway" enable=true [[gateway.inout]] account="kosmi.hyperspaceout" channel="main" [[gateway.inout]] account="irc.libera" channel="#your-channel" ``` ### Configuration Options #### Kosmi Settings - `RoomURL` (required): Full URL to the Kosmi room - Format: `https://app.kosmi.io/room/@roomname` or `https://app.kosmi.io/room/roomid` - `Server` (optional): WebSocket endpoint (default: `wss://engine.kosmi.io/gql-ws`) - `Debug` (optional): Enable debug logging #### IRC Settings See [Matterbridge IRC documentation](https://github.com/42wim/matterbridge/wiki/Section-IRC-(basic)) for full IRC configuration options. ## Usage ```bash # Run the bridge ./matterbridge -conf matterbridge.toml # Run with debug logging ./matterbridge -conf matterbridge.toml -debug ``` ## How It Works ### Kosmi Connection The bridge connects to Kosmi using headless Chrome automation: 1. **Launch Chrome**: Starts a headless Chrome instance via `chromedp` 2. **Inject Hook**: Uses `Page.addScriptToEvaluateOnNewDocument` to inject a WebSocket interceptor **before any page scripts run** 3. **Navigate**: Loads the Kosmi room URL 4. **Intercept**: The injected script hooks `window.WebSocket` constructor to capture all WebSocket messages 5. **Poll**: Continuously polls the message queue populated by the interceptor 6. **Process**: Extracts chat messages from GraphQL subscription data ### Critical Implementation Detail The WebSocket hook **must** be injected before page load using `Page.addScriptToEvaluateOnNewDocument`. This ensures the hook is active when Kosmi's JavaScript creates the WebSocket connection. If injected after page load, the WebSocket will already be established and messages won't be captured. ### Message Flow ``` IRC User → IRC Server → Matterbridge → Headless Chrome → Kosmi Room Kosmi User → Kosmi Room → WebSocket → Chrome Interceptor → Matterbridge → IRC Server → IRC Channel ``` ### Message Filtering - The bridge ignores its own messages by checking for the `[IRC]` prefix - This prevents message loops between Kosmi and IRC ## Technical Details ### GraphQL API The Kosmi bridge uses the following GraphQL operations: **Subscription** (receiving messages): ```graphql subscription { newMessage(roomId: "roomId") { body time user { displayName username } } } ``` **Mutation** (sending messages): ```graphql mutation { sendMessage(roomId: "roomId", body: "message text") { id } } ``` ### File Structure ``` bridge/kosmi/ ├── kosmi.go # Main bridge implementation ├── chromedp_client.go # Headless Chrome client with WebSocket interception └── graphql.go # GraphQL message structures (deprecated native client) gateway/bridgemap/ └── bkosmi.go # Bridge registration cmd/test-kosmi/ └── main.go # Standalone test program matterbridge.toml # Configuration file go.mod # Go module dependencies ``` ## Troubleshooting ### Connection Issues **Problem**: Bridge fails to connect to Kosmi **Solutions**: - Verify Chrome/Chromium is installed: `which google-chrome chromium chromium-browser` - Verify the room URL is correct - Check network connectivity to `app.kosmi.io` - Enable debug logging to see detailed connection logs - Look for "✓ WebSocket hook confirmed installed" in logs - Look for "Status: WebSocket connection intercepted" in logs ### Message Not Relaying **Problem**: Messages aren't being relayed between Kosmi and IRC **Solutions**: - Verify both Kosmi and IRC connections are established - Check the gateway configuration in `matterbridge.toml` - Ensure channel names match in the gateway configuration - Check logs for errors ### Authentication Errors **Problem**: Kosmi connection fails with authentication error **Note**: Kosmi doesn't require authentication. If you see auth errors, verify: - The WebSocket URL is correct - The room ID is valid - Network isn't blocking WebSocket connections ## Development ### Adding Features The bridge follows Matterbridge's bridge interface: ```go type Bridger interface { Send(msg config.Message) (string, error) Connect() error JoinChannel(channel config.ChannelInfo) error Disconnect() error } ``` ### Testing To test the bridge: 1. Start the bridge with debug logging 2. Send a message in the Kosmi room 3. Verify it appears in IRC with `[Kosmi]` prefix 4. Send a message in IRC 5. Verify it appears in Kosmi with `[IRC]` prefix ## Known Limitations 1. **Anonymous Access**: The bridge connects anonymously to Kosmi, so it will have a randomly assigned username 2. **Message Sending**: The GraphQL mutation for sending messages may need adjustment based on Kosmi's actual API 3. **Room Discovery**: The bridge connects to a specific room; it doesn't support room discovery or listing ## Credits - Based on [Matterbridge](https://github.com/42wim/matterbridge) by 42wim - Kosmi API reverse engineering from chrome extension analysis ## License Same as Matterbridge (Apache 2.0)