Files
IRC-kosmi-relay/README.md
2025-10-31 16:17:04 -04:00

277 lines
7.2 KiB
Markdown

# 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] <username> message`
- **IRC → Kosmi**: `[IRC] <username> 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 <repository-url>
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)