# 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)

