docs: comprehensive documentation overhaul
Rewrite README.md and all setup guides to reflect the current native GraphQL WebSocket architecture (replacing stale headless Chrome/WebSocket interception descriptions). Add new docs/IRC.md with complete IRC command reference, vote syntax, and ticker symbol table. Archive pre-edit docs to docs/archive/setup-backup-2026-05-10/ and move historical development notes from docs/ root into docs/archive/. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,414 +1,145 @@
|
||||
# Bot Integration Guide
|
||||
# Bot Features Guide
|
||||
|
||||
This guide explains how to integrate your bot with the Jackbox Game Picker API for live voting and game notifications.
|
||||
This document describes the features available in the Kosmi-IRC relay bot when the Jackbox Game Picker integration is enabled.
|
||||
|
||||
## Table of Contents
|
||||
## Feature Summary
|
||||
|
||||
1. [Live Voting (Bot → API)](#live-voting-bot--api)
|
||||
2. [Game Notifications (API → Bot)](#game-notifications-api--bot)
|
||||
3. [Webhook Management](#webhook-management)
|
||||
4. [Testing](#testing)
|
||||
| Feature | Where | Description |
|
||||
|---------|-------|-------------|
|
||||
| Message relay | IRC + Kosmi | Bidirectional chat relay |
|
||||
| Vote detection | IRC + Kosmi | Automatic `thisgame++/--` and ticker votes |
|
||||
| `!votes` command | IRC + Kosmi | Query current game vote tally |
|
||||
| `!kreconnect` | IRC | Reconnect Kosmi bridge |
|
||||
| `!jreconnect` | IRC | Reconnect Jackbox WebSocket |
|
||||
| `!reconnect` | IRC | Reconnect all non-IRC services |
|
||||
| Game announcements | All bridges | Jackbox game/session notifications |
|
||||
| Room code images | All bridges | Generated room code images in chat |
|
||||
| Mute toggle | Operator (SIGUSR1) | Suppress Jackbox announcements |
|
||||
|
||||
---
|
||||
## Vote Detection
|
||||
|
||||
## Live Voting (Bot → API)
|
||||
The bot automatically detects votes in chat messages from both IRC and Kosmi. Votes are submitted to the Jackbox Game Picker API.
|
||||
|
||||
Your bot can send real-time votes to the API when it detects "thisgame++" or "thisgame--" in Kosmi chat.
|
||||
### Current Game Votes
|
||||
|
||||
### Endpoint
|
||||
- `thisgame++` -- Upvote the currently playing game
|
||||
- `thisgame--` -- Downvote the currently playing game
|
||||
|
||||
```
|
||||
POST /api/votes/live
|
||||
```
|
||||
Case-insensitive. Can appear anywhere in the message. The message is still relayed normally.
|
||||
|
||||
### Ticker Symbol Votes
|
||||
|
||||
- `SYMBOL++` -- Upvote a specific game by ticker symbol
|
||||
- `SYMBOL--` -- Downvote a specific game by ticker symbol
|
||||
|
||||
Symbols are 2-4 alphanumeric characters. See [IRC.md](../IRC.md) for the complete ticker table.
|
||||
|
||||
### Loop Prevention
|
||||
|
||||
Messages prefixed with `[irc]` or `[kosmi]` (relayed messages) are excluded from vote detection to prevent duplicate counting.
|
||||
|
||||
### Deduplication
|
||||
|
||||
The API rejects duplicate votes from the same user within 1 second.
|
||||
|
||||
## Game Announcements
|
||||
|
||||
When connected to the Jackbox API via WebSocket (default) or webhook, the bot broadcasts events to all bridges:
|
||||
|
||||
| Event | Example Message |
|
||||
|-------|----------------|
|
||||
| Session started | `🎮 Game Night is starting!` |
|
||||
| Game added | `🎮 Coming up next: Fibbage 4 - Room Code ABCD` |
|
||||
| Session ended | `🌙 Game Night has ended! Thanks for playing!` |
|
||||
|
||||
### Room Code Images
|
||||
|
||||
When `EnableRoomCodeImage=true`, game announcements include an uploaded image of the room code. The image is uploaded to the Kosmi CDN. Timing is controlled by `RoomCodeImageDelay` and `RoomCodePlaintextDelay` in config.
|
||||
|
||||
If image upload fails, the bot falls back to plaintext.
|
||||
|
||||
## IRC Commands
|
||||
|
||||
All commands are available to any user in the channel. See [IRC.md](../IRC.md) for complete details.
|
||||
|
||||
| Command | Effect |
|
||||
|---------|--------|
|
||||
| `!kreconnect` | Reconnect Kosmi bridge |
|
||||
| `!jreconnect` | Reconnect Jackbox WebSocket |
|
||||
| `!reconnect` | Reconnect all non-IRC services |
|
||||
| `!votes` | Show current game vote tally |
|
||||
|
||||
`!votes` is also available from Kosmi chat.
|
||||
|
||||
## Mute Control
|
||||
|
||||
Jackbox announcements can be suppressed without stopping the bot:
|
||||
|
||||
- **Start muted**: `./matterbridge -conf matterbridge.toml -muted`
|
||||
- **Toggle at runtime**: `kill -SIGUSR1 <pid>` or `docker kill -s SIGUSR1 <container>`
|
||||
|
||||
When muted, vote detection and normal message relay continue to work. Only Jackbox-driven announcements (session start/end, game added) are suppressed.
|
||||
|
||||
See [MUTE_CONTROL.md](MUTE_CONTROL.md) for full details.
|
||||
|
||||
## API Communication
|
||||
|
||||
### Authentication
|
||||
|
||||
Requires JWT token in Authorization header:
|
||||
The bot authenticates with `POST /api/auth/login` using the `AdminPassword` from config. The JWT is cached in memory and refreshed on 401 responses.
|
||||
|
||||
```
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
```
|
||||
### Vote Submission
|
||||
|
||||
### Request Body
|
||||
Votes are submitted via `POST /api/votes/live` with:
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "string", // Username of the voter
|
||||
"vote": "up" | "down", // "up" for thisgame++, "down" for thisgame--
|
||||
"timestamp": "string" // ISO 8601 timestamp (e.g., "2025-11-01T20:30:00Z")
|
||||
}
|
||||
```
|
||||
|
||||
### Response (Success)
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Vote recorded successfully",
|
||||
"session": {
|
||||
"id": 123,
|
||||
"games_played": 5
|
||||
},
|
||||
"game": {
|
||||
"id": 45,
|
||||
"title": "Fibbage 4",
|
||||
"upvotes": 46,
|
||||
"downvotes": 3,
|
||||
"popularity_score": 43
|
||||
},
|
||||
"vote": {
|
||||
"username": "TestUser",
|
||||
"type": "up",
|
||||
"timestamp": "2025-11-01T20:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Responses
|
||||
|
||||
- **400 Bad Request**: Invalid payload or timestamp format
|
||||
- **404 Not Found**: No active session or timestamp doesn't match any game
|
||||
- **409 Conflict**: Duplicate vote (within 1 second of previous vote from same user)
|
||||
- **500 Internal Server Error**: Server error
|
||||
|
||||
### Example Implementation (Node.js)
|
||||
|
||||
```javascript
|
||||
// When bot detects "thisgame++" or "thisgame--" in Kosmi chat
|
||||
async function handleVote(username, message) {
|
||||
const isUpvote = message.includes('thisgame++');
|
||||
const isDownvote = message.includes('thisgame--');
|
||||
|
||||
if (!isUpvote && !isDownvote) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('http://your-api-url/api/votes/live', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.JWT_TOKEN}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
vote: isUpvote ? 'up' : 'down',
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`Vote recorded for ${data.game.title}: ${data.game.upvotes}👍 ${data.game.downvotes}👎`);
|
||||
} else {
|
||||
console.error('Vote failed:', data.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending vote:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Important Notes
|
||||
|
||||
- **Deduplication**: Votes from the same user within 1 second are automatically rejected to prevent spam
|
||||
- **Timestamp Matching**: The API matches the vote timestamp to the correct game based on when games were played
|
||||
- **Active Session Required**: Votes can only be recorded when there's an active session with games played
|
||||
|
||||
---
|
||||
|
||||
## Game Notifications (API → Bot)
|
||||
|
||||
The API can send webhooks to your bot when games are added to a session, allowing you to announce "Coming up next: Game Title!" in Kosmi chat.
|
||||
|
||||
### Webhook Event: `game.added`
|
||||
|
||||
Triggered whenever a game is added to an active session (either via picker or manual selection).
|
||||
|
||||
### Webhook Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "game.added",
|
||||
"username": "voter_name",
|
||||
"vote": "up",
|
||||
"timestamp": "2025-11-01T20:30:00Z",
|
||||
"data": {
|
||||
"session": {
|
||||
"id": 123,
|
||||
"is_active": true,
|
||||
"games_played": 5
|
||||
},
|
||||
"game": {
|
||||
"id": 45,
|
||||
"title": "Fibbage 4",
|
||||
"pack_name": "The Jackbox Party Pack 9",
|
||||
"min_players": 2,
|
||||
"max_players": 8,
|
||||
"manually_added": false
|
||||
}
|
||||
}
|
||||
"ticker": "FBG4"
|
||||
}
|
||||
```
|
||||
|
||||
### Webhook Headers
|
||||
The `ticker` field is omitted for `thisgame++/--` votes.
|
||||
|
||||
The API sends the following headers with each webhook:
|
||||
### Event Transport
|
||||
|
||||
- `Content-Type: application/json`
|
||||
- `X-Webhook-Signature: sha256=<hmac_signature>` - HMAC-SHA256 signature for verification
|
||||
- `X-Webhook-Event: game.added` - Event type
|
||||
- `User-Agent: Jackbox-Game-Picker-Webhook/1.0`
|
||||
**WebSocket (default)**: Connects to `wss://<api>/api/sessions/live`, authenticates, and subscribes to the active session. Events arrive in real-time with auto-reconnect.
|
||||
|
||||
### Signature Verification
|
||||
**Webhook (fallback)**: Starts an HTTP server listening for `POST /webhook/jackbox` with HMAC-SHA256 signature verification.
|
||||
|
||||
**IMPORTANT**: Always verify the webhook signature to ensure the request is authentic.
|
||||
## Configuration
|
||||
|
||||
```javascript
|
||||
const crypto = require('crypto');
|
||||
See [JACKBOX_INTEGRATION.md](JACKBOX_INTEGRATION.md) for the full configuration reference.
|
||||
|
||||
function verifyWebhookSignature(signature, payload, secret) {
|
||||
if (!signature || !signature.startsWith('sha256=')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const expectedSignature = 'sha256=' + crypto
|
||||
.createHmac('sha256', secret)
|
||||
.update(JSON.stringify(payload))
|
||||
.digest('hex');
|
||||
|
||||
// Use timing-safe comparison
|
||||
try {
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(signature),
|
||||
Buffer.from(expectedSignature)
|
||||
);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Minimal setup:
|
||||
|
||||
```toml
|
||||
[jackbox]
|
||||
Enabled=true
|
||||
APIURL="https://your-jackbox-api.example.com"
|
||||
AdminPassword="your_password"
|
||||
UseWebSocket=true
|
||||
```
|
||||
|
||||
### Example Implementation (Express.js)
|
||||
|
||||
```javascript
|
||||
const express = require('express');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const app = express();
|
||||
|
||||
// IMPORTANT: Use express.json() with verify option to get raw body
|
||||
app.use(express.json({
|
||||
verify: (req, res, buf) => {
|
||||
req.rawBody = buf.toString('utf8');
|
||||
}
|
||||
}));
|
||||
|
||||
app.post('/webhook/jackbox', (req, res) => {
|
||||
const signature = req.headers['x-webhook-signature'];
|
||||
const secret = process.env.WEBHOOK_SECRET; // Your webhook secret
|
||||
|
||||
// Verify signature
|
||||
if (!signature || !signature.startsWith('sha256=')) {
|
||||
return res.status(401).send('Missing or invalid signature');
|
||||
}
|
||||
|
||||
const expectedSignature = 'sha256=' + crypto
|
||||
.createHmac('sha256', secret)
|
||||
.update(req.rawBody)
|
||||
.digest('hex');
|
||||
|
||||
// Timing-safe comparison
|
||||
try {
|
||||
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
|
||||
return res.status(401).send('Invalid signature');
|
||||
}
|
||||
} catch (err) {
|
||||
return res.status(401).send('Invalid signature');
|
||||
}
|
||||
|
||||
// Handle the event
|
||||
if (req.body.event === 'game.added') {
|
||||
const game = req.body.data.game;
|
||||
|
||||
// Send message to Kosmi chat
|
||||
sendKosmiMessage(`🎮 Coming up next: ${game.title}!`);
|
||||
|
||||
console.log(`Announced game: ${game.title} from ${game.pack_name}`);
|
||||
}
|
||||
|
||||
// Always respond with 200 OK
|
||||
res.status(200).send('OK');
|
||||
});
|
||||
|
||||
function sendKosmiMessage(message) {
|
||||
// Your Kosmi chat integration here
|
||||
console.log('Sending to Kosmi:', message);
|
||||
}
|
||||
|
||||
app.listen(3001, () => {
|
||||
console.log('Webhook receiver listening on port 3001');
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Webhook Management
|
||||
|
||||
You can manage webhooks through the API using the following endpoints (all require JWT authentication).
|
||||
|
||||
### List All Webhooks
|
||||
|
||||
```bash
|
||||
GET /api/webhooks
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
```
|
||||
|
||||
### Create Webhook
|
||||
|
||||
```bash
|
||||
POST /api/webhooks
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Kosmi Bot",
|
||||
"url": "http://your-bot-url/webhook/jackbox",
|
||||
"secret": "your_shared_secret_key",
|
||||
"events": ["game.added"]
|
||||
}
|
||||
```
|
||||
|
||||
### Update Webhook
|
||||
|
||||
```bash
|
||||
PATCH /api/webhooks/:id
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": false // Disable webhook
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Webhook
|
||||
|
||||
```bash
|
||||
DELETE /api/webhooks/:id
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
```
|
||||
|
||||
### Test Webhook
|
||||
|
||||
```bash
|
||||
POST /api/webhooks/test/:id
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
```
|
||||
|
||||
Sends a test `game.added` event to verify your webhook is working.
|
||||
|
||||
### View Webhook Logs
|
||||
|
||||
```bash
|
||||
GET /api/webhooks/:id/logs?limit=50
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
```
|
||||
|
||||
Returns recent webhook delivery attempts with status codes and errors.
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Live Voting
|
||||
|
||||
```bash
|
||||
# Get your JWT token first
|
||||
curl -X POST "http://localhost:5000/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"apiKey": "YOUR_API_KEY"}'
|
||||
|
||||
# Send a test vote
|
||||
curl -X POST "http://localhost:5000/api/votes/live" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "TestUser",
|
||||
"vote": "up",
|
||||
"timestamp": "2025-11-01T20:30:00Z"
|
||||
}'
|
||||
```
|
||||
|
||||
### Test Webhooks
|
||||
|
||||
```bash
|
||||
# Create a webhook
|
||||
curl -X POST "http://localhost:5000/api/webhooks" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Test Webhook",
|
||||
"url": "http://localhost:3001/webhook/jackbox",
|
||||
"secret": "test_secret_123",
|
||||
"events": ["game.added"]
|
||||
}'
|
||||
|
||||
# Test the webhook
|
||||
curl -X POST "http://localhost:5000/api/webhooks/test/1" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
||||
|
||||
# Check webhook logs
|
||||
curl -X GET "http://localhost:5000/api/webhooks/1/logs" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Events
|
||||
|
||||
Currently supported webhook events:
|
||||
|
||||
- `game.added` - Triggered when a game is added to an active session
|
||||
|
||||
More events may be added in the future (e.g., `session.started`, `session.ended`, `vote.recorded`).
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Always verify webhook signatures** - Never trust webhook payloads without verification
|
||||
2. **Use HTTPS in production** - Webhook URLs should use HTTPS to prevent man-in-the-middle attacks
|
||||
3. **Keep secrets secure** - Store webhook secrets in environment variables, never in code
|
||||
4. **Implement rate limiting** - Protect your webhook endpoints from abuse
|
||||
5. **Log webhook activity** - Keep logs of webhook deliveries for debugging
|
||||
6. **Use strong secrets** - Generate cryptographically secure random strings for webhook secrets
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Votes Not Being Recorded
|
||||
### Votes not registering
|
||||
|
||||
- Check that there's an active session with games played
|
||||
- Verify the timestamp is within the timeframe of a played game
|
||||
- Ensure you're not sending duplicate votes within 1 second
|
||||
- Check API logs for error messages
|
||||
- Check that Jackbox integration is enabled
|
||||
- Verify an active session exists
|
||||
- Look for `"Detected vote from"` in debug logs
|
||||
- Look for `"Failed to send vote"` errors
|
||||
|
||||
### Webhooks Not Being Received
|
||||
### Announcements not appearing
|
||||
|
||||
- Verify your webhook URL is publicly accessible
|
||||
- Check webhook logs via `/api/webhooks/:id/logs`
|
||||
- Test with `ngrok` or similar tool if developing locally
|
||||
- Ensure your webhook endpoint responds with 200 OK
|
||||
- Check that webhook is enabled in the database
|
||||
- Check that the Jackbox WebSocket is connected
|
||||
- Verify the bot is not muted (check logs for `MUTED`)
|
||||
- Use `!jreconnect` to force a WebSocket reconnection
|
||||
|
||||
### Signature Verification Failing
|
||||
|
||||
- Ensure you're using the raw request body for signature verification
|
||||
- Check that the secret matches what's stored in the database
|
||||
- Verify you're using HMAC-SHA256 algorithm
|
||||
- Make sure to prefix with "sha256=" when comparing
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions, contact: cottongin@cottongin.xyz
|
||||
### `!votes` returns nothing
|
||||
|
||||
- An active session must exist
|
||||
- A game must currently have "playing" status
|
||||
- The Jackbox integration must be enabled and authenticated
|
||||
|
||||
@@ -1,277 +1,160 @@
|
||||
# Browser-Based Authentication Guide
|
||||
|
||||
## Overview
|
||||
The Kosmi bridge now supports **fully automated email/password authentication** using headless Chrome via chromedp. No manual token extraction needed!
|
||||
|
||||
The Kosmi bridge supports **email/password authentication** using headless Chrome (chromedp). This is only needed if you want to connect with a specific Kosmi account instead of anonymous access. The JWT obtained via browser login is cached on disk, so the browser is only launched when needed.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Configure Email/Password
|
||||
|
||||
Edit `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
RoomURL="https://app.kosmi.io/room/@yourroom"
|
||||
Email="your-email@example.com"
|
||||
Password="your-password"
|
||||
```
|
||||
|
||||
### 2. Run the Bot
|
||||
|
||||
```bash
|
||||
./irc-kosmi-relay -conf matterbridge.toml
|
||||
./matterbridge -conf matterbridge.toml
|
||||
```
|
||||
|
||||
That's it! The bot will:
|
||||
1. Launch headless Chrome
|
||||
2. Navigate to Kosmi
|
||||
3. Log in with your credentials
|
||||
4. Extract the JWT token from localStorage
|
||||
5. Use the token for authenticated connections
|
||||
6. Automatically refresh the token daily (checks for expiry 7 days in advance)
|
||||
The bot will:
|
||||
1. Check for a cached token in the data directory
|
||||
2. If no valid cache exists, launch headless Chrome
|
||||
3. Navigate to Kosmi and log in with your credentials
|
||||
4. Extract the JWT from localStorage
|
||||
5. Cache the token for future use
|
||||
6. Connect to Kosmi with the authenticated token
|
||||
|
||||
## How It Works
|
||||
## Authentication Modes
|
||||
|
||||
### Initial Login
|
||||
When you start the bot with Email/Password configured:
|
||||
1. **Browser Launch**: Headless Chrome starts (no visible window)
|
||||
2. **Navigation**: Goes to https://app.kosmi.io
|
||||
3. **Login Flow**:
|
||||
- Clicks "Login" button
|
||||
- Clicks "Login with Email"
|
||||
- Fills in email and password
|
||||
- Submits the form
|
||||
4. **Token Extraction**: Reads `localStorage.getItem('token')`
|
||||
5. **Token Parsing**: Extracts expiry time from JWT
|
||||
6. **Connection**: Uses token for WebSocket authentication
|
||||
### Option 1: Email/Password (Recommended for Authenticated Access)
|
||||
|
||||
### Automatic Token Refresh
|
||||
- **Daily Check**: Every 24 hours, the bot checks if the token is still valid
|
||||
- **Expiry Buffer**: Refreshes 7 days before expiration
|
||||
- **Seamless**: Happens in the background without disconnecting
|
||||
- **Logging**: You'll see "Checking token expiry..." in debug logs
|
||||
|
||||
## Requirements
|
||||
|
||||
### System Requirements
|
||||
- **Chrome/Chromium**: Must be installed on your system
|
||||
- macOS: Usually pre-installed or via Homebrew: `brew install chromium`
|
||||
- Linux: `sudo apt install chromium-browser` or `sudo yum install chromium`
|
||||
- Windows: Download from https://www.chromium.org/getting-involved/download-chromium/
|
||||
|
||||
### Go Dependencies
|
||||
- `github.com/chromedp/chromedp` - Automatically installed with `go get`
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Option 1: Email/Password (Recommended)
|
||||
```toml
|
||||
Email="your-email@example.com"
|
||||
Password="your-password"
|
||||
```
|
||||
- ✅ Fully automated
|
||||
- ✅ Auto-refresh
|
||||
- ✅ No manual intervention
|
||||
- ⚠️ Requires Chrome/Chromium
|
||||
- ⚠️ Stores credentials in config file
|
||||
|
||||
### Option 2: Manual Token
|
||||
```toml
|
||||
Token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
- ✅ No browser required
|
||||
- ✅ No credentials in config
|
||||
- ❌ Manual extraction needed
|
||||
- ❌ Must update when expired (~1 year)
|
||||
- Fully automated with token caching
|
||||
- Browser only launches when cache is missing or expired
|
||||
- Token refreshes automatically before expiry (7-day buffer)
|
||||
- Requires Chrome/Chromium installed
|
||||
|
||||
### Option 2: Anonymous (Default)
|
||||
|
||||
### Option 3: Anonymous
|
||||
```toml
|
||||
# Leave both empty
|
||||
# Leave both empty or omit entirely
|
||||
Email=""
|
||||
Password=""
|
||||
Token=""
|
||||
```
|
||||
- ✅ No setup needed
|
||||
- ❌ Limited permissions
|
||||
- ❌ Can't access private rooms
|
||||
|
||||
- No setup needed, no browser required
|
||||
- Connects with an anonymous Kosmi identity
|
||||
- Cannot access private rooms
|
||||
|
||||
## Token Caching
|
||||
|
||||
Authenticated tokens are cached to avoid launching Chrome on every startup:
|
||||
|
||||
- **Docker**: `./data/kosmi_token_cache.json` (via `MATTERBRIDGE_DATA_DIR=/app/data`)
|
||||
- **Local**: `~/.matterbridge/kosmi_token_cache.json`
|
||||
|
||||
On startup, the bridge:
|
||||
1. Loads the cached token
|
||||
2. If valid (and not expiring within 7 days), uses it directly -- no browser
|
||||
3. If expired or expiring soon, performs browser authentication
|
||||
4. Saves the new token to cache
|
||||
|
||||
Kosmi JWT tokens are valid for approximately 1 year.
|
||||
|
||||
See [TOKEN_PERSISTENCE.md](TOKEN_PERSISTENCE.md) for full details on caching.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Chrome/Chromium
|
||||
|
||||
Must be installed and in PATH:
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install --cask chromium
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt install chromium-browser
|
||||
|
||||
# Verify
|
||||
which chromium chromium-browser google-chrome
|
||||
```
|
||||
|
||||
In Docker, Chromium is pre-installed in the image.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Browser automation failed"
|
||||
**Possible causes:**
|
||||
1. Chrome/Chromium not installed
|
||||
2. Chrome/Chromium not in PATH
|
||||
3. Network issues
|
||||
4. Kosmi website changed
|
||||
### "Browser automation failed" or "authentication failed"
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# Check if Chrome is installed
|
||||
which chromium || which google-chrome || which chrome
|
||||
1. Check Chrome/Chromium is installed and accessible
|
||||
2. Verify credentials by logging in manually at `app.kosmi.io`
|
||||
3. Delete the cached token to force fresh auth: `rm data/kosmi_token_cache.json`
|
||||
4. Enable debug logging for detailed browser automation output
|
||||
|
||||
# Install Chrome (macOS)
|
||||
brew install chromium
|
||||
### Token cache not persisting (Docker)
|
||||
|
||||
# Install Chrome (Ubuntu/Debian)
|
||||
sudo apt install chromium-browser
|
||||
- Verify the `./data` volume mount exists in `docker-compose.yml`
|
||||
- Check directory permissions: `ls -la ./data/`
|
||||
- Confirm `MATTERBRIDGE_DATA_DIR` is set to `/app/data`
|
||||
|
||||
# Install Chrome (CentOS/RHEL)
|
||||
sudo yum install chromium
|
||||
```
|
||||
|
||||
### "No token found in localStorage after login"
|
||||
**Possible causes:**
|
||||
1. Login failed (wrong credentials)
|
||||
2. Kosmi's login flow changed
|
||||
3. Page didn't fully load
|
||||
|
||||
**Solutions:**
|
||||
- Verify credentials are correct
|
||||
- Check bot logs for detailed error messages
|
||||
- Try manual token extraction as fallback
|
||||
|
||||
### "Token expired or expiring soon"
|
||||
This is normal! The bot will automatically refresh the token. If refresh fails:
|
||||
- Check Chrome is still installed
|
||||
- Check network connectivity
|
||||
- Restart the bot to force a fresh login
|
||||
|
||||
### Headless Chrome Issues
|
||||
If you see Chrome-related errors:
|
||||
### Force token refresh
|
||||
|
||||
```bash
|
||||
# Set environment variable for debugging
|
||||
export CHROMEDP_DISABLE_GPU=1
|
||||
# Local
|
||||
rm ~/.matterbridge/kosmi_token_cache.json
|
||||
./matterbridge -conf matterbridge.toml
|
||||
|
||||
# Or run with visible browser (for debugging)
|
||||
export CHROMEDP_NO_HEADLESS=1
|
||||
# Docker
|
||||
rm ./data/kosmi_token_cache.json
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Credential Storage
|
||||
- Credentials are stored in **plain text** in `matterbridge.toml`
|
||||
- Ensure config file has restrictive permissions:
|
||||
- Credentials are stored in **plain text** in `matterbridge.toml` -- restrict permissions:
|
||||
```bash
|
||||
chmod 600 matterbridge.toml
|
||||
```
|
||||
- Do not commit config with real credentials to version control
|
||||
- Consider using environment variables:
|
||||
```bash
|
||||
export KOSMI_EMAIL="your-email@example.com"
|
||||
export KOSMI_PASSWORD="your-password"
|
||||
```
|
||||
|
||||
### Browser Automation
|
||||
- Headless Chrome runs with minimal privileges
|
||||
- No data is stored or cached
|
||||
- Browser closes immediately after token extraction
|
||||
- Token is kept in memory only
|
||||
|
||||
### Token Security
|
||||
- Tokens are JWT (JSON Web Tokens) signed by Kosmi
|
||||
- Valid for ~1 year
|
||||
- Can be revoked by logging out in browser
|
||||
- Treat tokens like passwords
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Chrome Path
|
||||
If Chrome is installed in a non-standard location:
|
||||
|
||||
```go
|
||||
// In browser_auth.go, modify NewContext call:
|
||||
opts := append(chromedp.DefaultExecAllocatorOptions[:],
|
||||
chromedp.ExecPath("/path/to/chrome"),
|
||||
)
|
||||
ctx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
|
||||
```
|
||||
|
||||
### Timeout Adjustment
|
||||
If login takes longer than 60 seconds:
|
||||
|
||||
```go
|
||||
// In browser_auth.go, modify timeout:
|
||||
ctx, cancel = context.WithTimeout(ctx, 120*time.Second)
|
||||
```
|
||||
|
||||
### Refresh Interval
|
||||
To check token more/less frequently:
|
||||
|
||||
```go
|
||||
// In kosmi.go, modify ticker:
|
||||
ticker := time.NewTicker(12 * time.Hour) // Check twice daily
|
||||
```
|
||||
|
||||
## Comparison with Manual Token
|
||||
|
||||
| Feature | Browser Auth | Manual Token |
|
||||
|---------|-------------|--------------|
|
||||
| Setup Complexity | Easy | Medium |
|
||||
| Automation | Full | None |
|
||||
| Token Refresh | Automatic | Manual |
|
||||
| Dependencies | Chrome | None |
|
||||
| Security | Credentials in config | Token in config |
|
||||
| Maintenance | Low | Medium |
|
||||
- Do not commit config files with real credentials to version control
|
||||
- The cached token file has restricted permissions (`0600`)
|
||||
- Headless Chrome runs briefly and closes after token extraction
|
||||
- Tokens can be revoked by logging out in a browser
|
||||
|
||||
## Logs to Expect
|
||||
|
||||
### Successful Login
|
||||
### First run (no cache)
|
||||
|
||||
```
|
||||
INFO Using browser automation for email/password authentication
|
||||
INFO Obtaining authentication token via browser automation...
|
||||
INFO ✅ Successfully obtained token via browser automation
|
||||
INFO Token expires in: 365d
|
||||
INFO ✅ Browser authentication successful
|
||||
INFO No cached token found, performing authentication...
|
||||
INFO Authenticating with email/password...
|
||||
INFO ✅ Authentication successful
|
||||
INFO 💾 Token cached (expires in 8760h)
|
||||
INFO Successfully connected to Kosmi
|
||||
```
|
||||
|
||||
### Daily Token Check
|
||||
### Subsequent runs (cached token)
|
||||
|
||||
```
|
||||
DEBUG Checking token expiry...
|
||||
DEBUG Token check complete
|
||||
INFO ✅ Using cached token (expires in 8736h)
|
||||
INFO Successfully connected to Kosmi
|
||||
```
|
||||
|
||||
### Token Refresh (when expiring)
|
||||
### Token refresh (near expiry)
|
||||
|
||||
```
|
||||
INFO Token expired or expiring soon, will refresh
|
||||
INFO Obtaining authentication token via browser automation...
|
||||
INFO ✅ Successfully obtained token via browser automation
|
||||
INFO Token expires in: 365d
|
||||
INFO Cached token expires soon, will refresh
|
||||
INFO Authenticating with email/password...
|
||||
INFO ✅ Authentication successful
|
||||
INFO 💾 Token cached (expires in 8760h)
|
||||
```
|
||||
|
||||
## Migration from Manual Token
|
||||
|
||||
If you're currently using manual token:
|
||||
|
||||
1. **Add credentials** to config:
|
||||
```toml
|
||||
Email="your-email@example.com"
|
||||
Password="your-password"
|
||||
```
|
||||
|
||||
2. **Remove or comment out Token**:
|
||||
```toml
|
||||
#Token="..."
|
||||
```
|
||||
|
||||
3. **Restart the bot**
|
||||
|
||||
The bot will automatically switch to browser-based auth!
|
||||
|
||||
## Performance Impact
|
||||
|
||||
- **Initial Login**: ~5-10 seconds (one-time per start)
|
||||
- **Token Refresh**: ~5-10 seconds (once per year, or when expiring)
|
||||
- **Daily Check**: <1ms (just checks expiry time)
|
||||
- **Memory**: +50-100MB during browser operation (released after)
|
||||
- **CPU**: Minimal (browser runs briefly)
|
||||
|
||||
## Conclusion
|
||||
|
||||
Browser-based authentication provides the best balance of:
|
||||
- ✅ Full automation
|
||||
- ✅ Reliable token refresh
|
||||
- ✅ Simple configuration
|
||||
- ✅ Low maintenance
|
||||
|
||||
For production use, this is the **recommended authentication method**.
|
||||
|
||||
|
||||
@@ -5,13 +5,9 @@ Complete guide for deploying the Kosmi-IRC bridge using Docker.
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Edit configuration
|
||||
cp matterbridge.toml.example matterbridge.toml
|
||||
nano matterbridge.toml
|
||||
|
||||
# 2. Build and run
|
||||
docker-compose up -d
|
||||
|
||||
# 3. View logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
@@ -26,24 +22,20 @@ docker-compose logs -f
|
||||
|
||||
### 1. Configure the Bridge
|
||||
|
||||
Edit `matterbridge.toml` and update these settings:
|
||||
Copy `matterbridge.toml.example` to `matterbridge.toml` and update these settings:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM" # ← Change this
|
||||
Debug=false
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM"
|
||||
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667" # ← Change to your IRC server
|
||||
Nick="kosmi-relay" # ← Change your bot's nickname
|
||||
[irc.zeronode]
|
||||
Server="irc.libera.chat:6697"
|
||||
Nick="kosmi-relay"
|
||||
UseTLS=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.hyperspaceout"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#your-channel" # ← Change to your IRC channel
|
||||
account="irc.zeronode"
|
||||
channel="#your-channel"
|
||||
```
|
||||
|
||||
### 2. Build the Docker Image
|
||||
@@ -53,9 +45,10 @@ docker-compose build
|
||||
```
|
||||
|
||||
This will:
|
||||
- Install Chrome/Chromium in the container
|
||||
- Build the Matterbridge binary with Kosmi support
|
||||
- Create an optimized production image
|
||||
- Use the Go 1.23 Alpine base image
|
||||
- Install Chromium (used only for email/password authentication)
|
||||
- Build the Matterbridge binary
|
||||
- Create a production image
|
||||
|
||||
**Build time**: ~5-10 minutes (first time)
|
||||
|
||||
@@ -72,89 +65,51 @@ docker-compose up
|
||||
### 4. Verify It's Working
|
||||
|
||||
```bash
|
||||
# Check container status
|
||||
docker-compose ps
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f matterbridge
|
||||
|
||||
# Look for these messages:
|
||||
# INFO Successfully connected to Kosmi via Chrome
|
||||
# INFO Successfully connected to IRC
|
||||
# INFO Gateway(s) started successfully
|
||||
Look for:
|
||||
```
|
||||
INFO Successfully connected to Kosmi
|
||||
INFO Connection succeeded (IRC)
|
||||
INFO Gateway(s) started successfully. Now relaying messages
|
||||
```
|
||||
|
||||
### 5. Test Message Relay
|
||||
|
||||
1. **Kosmi → IRC**: Send a message in your Kosmi room
|
||||
- Should appear in IRC as: `[Kosmi] <username> message`
|
||||
1. **Kosmi --> IRC**: Send a message in your Kosmi room
|
||||
- Should appear in IRC as: `[kosmi] <username> message`
|
||||
|
||||
2. **IRC → Kosmi**: Send a message in your IRC channel
|
||||
- Should appear in Kosmi as: `[IRC] <username> message`
|
||||
2. **IRC --> Kosmi**: Send a message in your IRC channel
|
||||
- Should appear in Kosmi as: `[irc] <username> message`
|
||||
|
||||
## Docker Commands Reference
|
||||
|
||||
### Container Management
|
||||
|
||||
```bash
|
||||
# Start the bridge
|
||||
docker-compose up -d
|
||||
|
||||
# Stop the bridge
|
||||
docker-compose down
|
||||
|
||||
# Restart the bridge
|
||||
docker-compose restart
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# View last 100 lines of logs
|
||||
docker-compose logs --tail=100
|
||||
|
||||
# Check container status
|
||||
docker-compose ps
|
||||
|
||||
# Execute commands in running container
|
||||
docker-compose exec matterbridge sh
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
```bash
|
||||
# Enable debug logging (edit docker-compose.yml first)
|
||||
# Set Debug=true in matterbridge.toml, then:
|
||||
docker-compose restart
|
||||
|
||||
# Check Chrome is installed
|
||||
docker-compose exec matterbridge which chromium
|
||||
|
||||
# Check configuration
|
||||
docker-compose exec matterbridge cat /app/matterbridge.toml
|
||||
|
||||
# Test connectivity
|
||||
docker-compose exec matterbridge ping -c 3 app.kosmi.io
|
||||
docker-compose exec matterbridge ping -c 3 irc.libera.chat
|
||||
docker-compose up -d # Start
|
||||
docker-compose down # Stop
|
||||
docker-compose restart # Restart
|
||||
docker-compose logs -f # Follow logs
|
||||
docker-compose logs --tail=100 # Last 100 lines
|
||||
docker-compose ps # Container status
|
||||
docker-compose exec matterbridge sh # Shell into container
|
||||
```
|
||||
|
||||
### Updating
|
||||
|
||||
```bash
|
||||
# Pull latest code
|
||||
git pull
|
||||
|
||||
# Rebuild image
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Restart with new image
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### docker-compose.yml
|
||||
## docker-compose.yml Reference
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
matterbridge:
|
||||
build:
|
||||
@@ -162,241 +117,154 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: kosmi-irc-relay
|
||||
restart: unless-stopped
|
||||
command: ["-conf", "/app/matterbridge.toml"]
|
||||
volumes:
|
||||
- ./matterbridge.toml:/app/matterbridge.toml:ro
|
||||
- ./logs:/app/logs
|
||||
- ./matterbridge.toml:/app/matterbridge.toml:ro,z
|
||||
- ./logs:/app/logs:z
|
||||
- ./data:/app/data:z
|
||||
environment:
|
||||
- CHROME_BIN=/usr/bin/chromium
|
||||
- CHROME_PATH=/usr/bin/chromium
|
||||
- TZ=America/New_York # ← Change to your timezone
|
||||
security_opt:
|
||||
- seccomp:unconfined # Required for Chrome
|
||||
- TZ=America/New_York
|
||||
- MATTERBRIDGE_DATA_DIR=/app/data
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
```
|
||||
|
||||
### Starting Muted
|
||||
|
||||
To start with Jackbox announcements suppressed:
|
||||
|
||||
```yaml
|
||||
command: ["-conf", "/app/matterbridge.toml", "-muted"]
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `CHROME_BIN` | Path to Chrome binary | `/usr/bin/chromium` |
|
||||
| `CHROME_PATH` | Chrome executable path | `/usr/bin/chromium` |
|
||||
| `TZ` | Timezone for logs | `America/New_York` |
|
||||
| `DEBUG` | Enable debug logging | `0` |
|
||||
| `TZ` | Timezone for log timestamps | `America/New_York` |
|
||||
| `MATTERBRIDGE_DATA_DIR` | Directory for persistent data (token cache) | `/app/data` |
|
||||
| `DEBUG` | Set to `1` for debug logging | `0` |
|
||||
| `CHROME_BIN` | Path to Chrome binary (set in Dockerfile) | `/usr/bin/chromium-browser` |
|
||||
|
||||
Note: `CHROME_BIN` and `CHROME_PATH` are set in the Dockerfile. Chromium is installed in the container for email/password authentication. If you only use anonymous access, Chrome is present but unused.
|
||||
|
||||
### Volume Mounts
|
||||
|
||||
| Host Path | Container Path | Purpose |
|
||||
|-----------|----------------|---------|
|
||||
| `./matterbridge.toml` | `/app/matterbridge.toml` | Configuration file (read-only) |
|
||||
| `./matterbridge.toml` | `/app/matterbridge.toml` | Configuration (read-only) |
|
||||
| `./logs` | `/app/logs` | Log files (optional) |
|
||||
| `./data` | `/app/data` | Persistent data: token cache |
|
||||
|
||||
The `./data` volume is important for email/password auth -- it stores the cached JWT so the bot doesn't need to re-authenticate on every restart. See [TOKEN_PERSISTENCE.md](TOKEN_PERSISTENCE.md).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
**Check logs**:
|
||||
```bash
|
||||
docker-compose logs
|
||||
```
|
||||
|
||||
**Common issues**:
|
||||
- Configuration file syntax error
|
||||
- Missing `matterbridge.toml`
|
||||
- Port already in use
|
||||
Common causes:
|
||||
- TOML syntax error in `matterbridge.toml`
|
||||
- Missing configuration file
|
||||
- Port conflict (if webhook port is exposed)
|
||||
|
||||
### Kosmi Connection Fails
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Validate TOML syntax
|
||||
docker run --rm -v $(pwd)/matterbridge.toml:/config.toml alpine sh -c "apk add --no-cache go && go install github.com/pelletier/go-toml/cmd/tomll@latest && tomll /config.toml"
|
||||
|
||||
# Check if file exists
|
||||
ls -la matterbridge.toml
|
||||
# Check connectivity from inside the container
|
||||
docker-compose exec matterbridge wget -q -O - https://app.kosmi.io > /dev/null && echo "OK"
|
||||
```
|
||||
|
||||
### Chrome/Chromium Not Found
|
||||
- Verify `RoomURL` is correct
|
||||
- Enable debug logging (`Debug=true` in the Kosmi config section)
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
ERROR Chrome binary not found
|
||||
```
|
||||
### IRC Connection Fails
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Rebuild image
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Verify Chrome is installed
|
||||
docker-compose run --rm matterbridge which chromium
|
||||
```
|
||||
|
||||
### WebSocket Connection Failed
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
ERROR Failed to connect to Kosmi
|
||||
ERROR WebSocket connection failed
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Test network connectivity
|
||||
docker-compose exec matterbridge ping -c 3 app.kosmi.io
|
||||
|
||||
# Check if room URL is correct
|
||||
docker-compose exec matterbridge cat /app/matterbridge.toml | grep RoomURL
|
||||
|
||||
# Enable debug logging
|
||||
# Edit matterbridge.toml: Debug=true
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
### IRC Connection Failed
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
ERROR Failed to connect to IRC
|
||||
ERROR Connection refused
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Test IRC connectivity
|
||||
docker-compose exec matterbridge nc -zv irc.libera.chat 6667
|
||||
|
||||
# Check IRC configuration
|
||||
docker-compose exec matterbridge cat /app/matterbridge.toml | grep -A 10 "\[irc\]"
|
||||
|
||||
# Verify nickname isn't already in use
|
||||
# Try changing Nick in matterbridge.toml
|
||||
docker-compose exec matterbridge nc -zv irc.libera.chat 6697
|
||||
```
|
||||
|
||||
- Verify server address and port
|
||||
- Check TLS settings
|
||||
- Try a different nick if the current one is registered/in use
|
||||
|
||||
### Messages Not Relaying
|
||||
|
||||
**Symptoms**:
|
||||
- Container running
|
||||
- Both bridges connected
|
||||
- But messages don't appear
|
||||
1. Confirm both bridges are connected in logs
|
||||
2. Verify gateway config: Kosmi channel = `"main"`, IRC channel includes `#`
|
||||
3. Enable debug logging and watch for message routing
|
||||
|
||||
### Authentication Issues
|
||||
|
||||
If using email/password:
|
||||
- Delete cached token: `rm ./data/kosmi_token_cache.json`
|
||||
- Rebuild container: `docker-compose build --no-cache`
|
||||
- Check Chromium is working: `docker-compose exec matterbridge chromium-browser --version`
|
||||
|
||||
## Runtime Operations
|
||||
|
||||
### Mute Toggle
|
||||
|
||||
Toggle Jackbox announcements without restarting:
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Enable debug logging
|
||||
# Edit matterbridge.toml: Debug=true
|
||||
docker-compose restart
|
||||
|
||||
# Watch logs for message flow
|
||||
docker-compose logs -f | grep -E "Received|Sending|Forwarding"
|
||||
|
||||
# Verify gateway configuration
|
||||
docker-compose exec matterbridge cat /app/matterbridge.toml | grep -A 20 "\[\[gateway\]\]"
|
||||
|
||||
# Check channel names match exactly
|
||||
# Kosmi channel should be "main"
|
||||
# IRC channel should include # (e.g., "#your-channel")
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
```
|
||||
|
||||
### High Memory Usage
|
||||
See [MUTE_CONTROL.md](MUTE_CONTROL.md) for details.
|
||||
|
||||
**Symptoms**:
|
||||
- Container using >500MB RAM
|
||||
- System slowdown
|
||||
### Force Token Refresh
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Add memory limits to docker-compose.yml
|
||||
services:
|
||||
matterbridge:
|
||||
mem_limit: 512m
|
||||
mem_reservation: 256m
|
||||
|
||||
# Restart
|
||||
docker-compose down
|
||||
rm ./data/kosmi_token_cache.json
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Permission Denied Errors
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
ERROR Permission denied writing to /app/logs
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Create logs directory with correct permissions
|
||||
mkdir -p logs
|
||||
chmod 777 logs
|
||||
|
||||
# Or run container as root (not recommended)
|
||||
# Edit docker-compose.yml:
|
||||
# user: root
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### Using Docker Swarm
|
||||
### View Token Status
|
||||
|
||||
```bash
|
||||
# Initialize swarm
|
||||
docker swarm init
|
||||
|
||||
# Deploy stack
|
||||
docker stack deploy -c docker-compose.yml kosmi-relay
|
||||
|
||||
# Check status
|
||||
docker stack services kosmi-relay
|
||||
|
||||
# View logs
|
||||
docker service logs -f kosmi-relay_matterbridge
|
||||
cat ./data/kosmi_token_cache.json | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Using Kubernetes
|
||||
## Resource Usage
|
||||
|
||||
Create `kosmi-relay.yaml`:
|
||||
The bridge uses a native WebSocket connection, so resource requirements are modest:
|
||||
|
||||
- **Memory**: ~50-100MB typical (lower than browser-based approaches)
|
||||
- **CPU**: Minimal (event-driven, no polling)
|
||||
- **Network**: WebSocket to Kosmi + IRC connection
|
||||
|
||||
### Memory Limits (Optional)
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kosmi-irc-relay
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kosmi-irc-relay
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kosmi-irc-relay
|
||||
spec:
|
||||
containers:
|
||||
- name: matterbridge
|
||||
image: kosmi-irc-relay:latest
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /app/matterbridge.toml
|
||||
subPath: matterbridge.toml
|
||||
env:
|
||||
- name: CHROME_BIN
|
||||
value: /usr/bin/chromium
|
||||
- name: TZ
|
||||
value: America/New_York
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- SYS_ADMIN # Required for Chrome
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: matterbridge-config
|
||||
services:
|
||||
matterbridge:
|
||||
mem_limit: 256m
|
||||
mem_reservation: 64m
|
||||
```
|
||||
|
||||
Deploy:
|
||||
```bash
|
||||
kubectl create configmap matterbridge-config --from-file=matterbridge.toml
|
||||
kubectl apply -f kosmi-relay.yaml
|
||||
## Production Considerations
|
||||
|
||||
### Log Rotation
|
||||
|
||||
Already configured in `docker-compose.yml`:
|
||||
```yaml
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
#### Health Check
|
||||
### Health Check
|
||||
|
||||
Add to `docker-compose.yml`:
|
||||
|
||||
@@ -408,127 +276,20 @@ services:
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
start_period: 30s
|
||||
```
|
||||
|
||||
#### Prometheus Metrics
|
||||
### Security
|
||||
|
||||
Matterbridge doesn't expose Prometheus metrics by default, but you can monitor:
|
||||
- Configuration is mounted read-only (`:ro`)
|
||||
- Token cache directory has restricted access inside the container
|
||||
- Credentials in `matterbridge.toml` should be protected: `chmod 600 matterbridge.toml`
|
||||
- Do not commit `matterbridge.toml` with real credentials to version control
|
||||
|
||||
```bash
|
||||
# Container metrics
|
||||
docker stats kosmi-irc-relay
|
||||
|
||||
# Log-based monitoring
|
||||
docker-compose logs -f | grep -E "ERROR|WARN"
|
||||
```
|
||||
|
||||
### Backup and Restore
|
||||
|
||||
```bash
|
||||
# Backup configuration
|
||||
cp matterbridge.toml matterbridge.toml.backup
|
||||
|
||||
# Backup logs
|
||||
tar -czf logs-$(date +%Y%m%d).tar.gz logs/
|
||||
|
||||
# Restore configuration
|
||||
cp matterbridge.toml.backup matterbridge.toml
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Run as non-root user** (already configured in Dockerfile)
|
||||
2. **Use read-only configuration mount**
|
||||
3. **Limit container resources**
|
||||
4. **Keep Docker images updated**
|
||||
5. **Use secrets for sensitive data** (e.g., IRC passwords)
|
||||
|
||||
### Using Docker Secrets
|
||||
|
||||
```bash
|
||||
# Create secret
|
||||
echo "your_irc_password" | docker secret create irc_password -
|
||||
|
||||
# Update docker-compose.yml
|
||||
services:
|
||||
matterbridge:
|
||||
secrets:
|
||||
- irc_password
|
||||
|
||||
secrets:
|
||||
irc_password:
|
||||
external: true
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
### Resource Limits
|
||||
|
||||
```yaml
|
||||
services:
|
||||
matterbridge:
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.5'
|
||||
memory: 256M
|
||||
```
|
||||
|
||||
### Chrome Optimization
|
||||
|
||||
Add to `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
matterbridge:
|
||||
environment:
|
||||
- CHROME_FLAGS=--disable-dev-shm-usage --no-sandbox --disable-setuid-sandbox
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- ✅ Bridge is running in Docker
|
||||
- 🔄 Set up monitoring and alerts
|
||||
- 🔄 Configure log rotation
|
||||
- 🔄 Set up automatic backups
|
||||
- 🔄 Add more bridges (Discord, Slack, etc.)
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Check logs: `docker-compose logs -f`
|
||||
- Enable debug: Set `Debug=true` in `matterbridge.toml`
|
||||
- Review `LESSONS_LEARNED.md` for common issues
|
||||
- Check `QUICK_REFERENCE.md` for troubleshooting tips
|
||||
|
||||
## Example: Complete Setup
|
||||
|
||||
```bash
|
||||
# 1. Clone repository
|
||||
git clone <your-repo> kosmi-irc-relay
|
||||
cd kosmi-irc-relay
|
||||
|
||||
# 2. Edit configuration
|
||||
nano matterbridge.toml
|
||||
# Update RoomURL, IRC server, channel
|
||||
|
||||
# 3. Build and start
|
||||
docker-compose up -d
|
||||
|
||||
# 4. Watch logs
|
||||
docker-compose logs -f
|
||||
|
||||
# 5. Test by sending messages in both Kosmi and IRC
|
||||
|
||||
# 6. If issues, enable debug
|
||||
nano matterbridge.toml # Set Debug=true
|
||||
docker-compose restart
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
That's it! Your Kosmi-IRC bridge is now running in Docker! 🎉
|
||||
## Further Reading
|
||||
|
||||
- [README.md](../../README.md) -- Project overview
|
||||
- [DOCKER_QUICKSTART.md](DOCKER_QUICKSTART.md) -- 5-minute quick start
|
||||
- [JACKBOX_INTEGRATION.md](JACKBOX_INTEGRATION.md) -- Jackbox Game Picker setup
|
||||
- [TOKEN_PERSISTENCE.md](TOKEN_PERSISTENCE.md) -- Token caching details
|
||||
- [IRC.md](../IRC.md) -- IRC commands and voting
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Docker Quick Start - 5 Minutes to Running Bridge
|
||||
# Docker Quick Start -- 5 Minutes to Running Bridge
|
||||
|
||||
Get your Kosmi-IRC bridge running in Docker in 5 minutes!
|
||||
Get your Kosmi-IRC bridge running in Docker in 5 minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -13,22 +13,27 @@ Get your Kosmi-IRC bridge running in Docker in 5 minutes!
|
||||
|
||||
### 1. Edit Configuration (2 minutes)
|
||||
|
||||
Open `matterbridge.toml` and change these 3 things:
|
||||
```bash
|
||||
cp matterbridge.toml.example matterbridge.toml
|
||||
nano matterbridge.toml
|
||||
```
|
||||
|
||||
Change these 3 things:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM" # ← Your Kosmi room
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM" # <-- Your Kosmi room
|
||||
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667" # ← Your IRC server
|
||||
Nick="kosmi-relay" # ← Your bot's nickname
|
||||
[irc.zeronode]
|
||||
Server="irc.libera.chat:6697" # <-- Your IRC server
|
||||
Nick="kosmi-relay" # <-- Your bot's nickname
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#your-channel" # ← Your IRC channel
|
||||
account="irc.zeronode"
|
||||
channel="#your-channel" # <-- Your IRC channel
|
||||
```
|
||||
|
||||
### 2. Build & Run (2 minutes)
|
||||
### 2. Build and Run (2 minutes)
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
@@ -42,19 +47,15 @@ docker-compose logs -f
|
||||
|
||||
Look for:
|
||||
```
|
||||
INFO Successfully connected to Kosmi via Chrome
|
||||
INFO Successfully connected to IRC
|
||||
INFO Gateway(s) started successfully
|
||||
INFO Successfully connected to Kosmi
|
||||
INFO Connection succeeded (IRC)
|
||||
INFO Gateway(s) started successfully. Now relaying messages
|
||||
```
|
||||
|
||||
### 4. Test It!
|
||||
### 4. Test It
|
||||
|
||||
- Send a message in Kosmi → should appear in IRC
|
||||
- Send a message in IRC → should appear in Kosmi
|
||||
|
||||
## That's It! 🎉
|
||||
|
||||
Your bridge is running!
|
||||
- Send a message in Kosmi --> should appear in IRC
|
||||
- Send a message in IRC --> should appear in Kosmi
|
||||
|
||||
## Common Commands
|
||||
|
||||
@@ -78,52 +79,31 @@ docker-compose build && docker-compose up -d
|
||||
|
||||
1. Check your configuration:
|
||||
```bash
|
||||
cat matterbridge.toml | grep -E "RoomURL|Server|channel"
|
||||
grep -E "RoomURL|Server|channel" matterbridge.toml
|
||||
```
|
||||
|
||||
2. Enable debug logging:
|
||||
- Edit `matterbridge.toml`: Set `Debug=true`
|
||||
- Edit `matterbridge.toml`: Set `Debug=true` under the appropriate bridge section
|
||||
- Restart: `docker-compose restart`
|
||||
- Watch logs: `docker-compose logs -f`
|
||||
|
||||
### "Chrome not found"
|
||||
|
||||
```bash
|
||||
# Rebuild image
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### "Messages not relaying"
|
||||
|
||||
1. Check both bridges are connected:
|
||||
```bash
|
||||
docker-compose logs | grep -i "connected"
|
||||
docker-compose logs | grep -i "connected\|succeeded"
|
||||
```
|
||||
|
||||
2. Verify channel names:
|
||||
- Kosmi channel must be `"main"`
|
||||
- IRC channel must include `#` (e.g., `"#your-channel"`)
|
||||
|
||||
## Persistent Token Cache
|
||||
|
||||
If using email/password authentication, the JWT is cached in `./data/` which is mounted into the container. This survives container rebuilds and restarts. See [TOKEN_PERSISTENCE.md](TOKEN_PERSISTENCE.md) for details.
|
||||
|
||||
## Need More Help?
|
||||
|
||||
- Full guide: See `DOCKER_DEPLOYMENT.md`
|
||||
- Troubleshooting: See `QUICK_REFERENCE.md`
|
||||
- Implementation details: See `LESSONS_LEARNED.md`
|
||||
|
||||
## Example Output (Success)
|
||||
|
||||
```
|
||||
INFO[...] Starting Matterbridge
|
||||
INFO[...] Launching headless Chrome for Kosmi connection
|
||||
INFO[...] Injecting WebSocket interceptor (runs before page load)...
|
||||
INFO[...] ✓ WebSocket hook confirmed installed
|
||||
INFO[...] Status: WebSocket connection intercepted
|
||||
INFO[...] Successfully connected to Kosmi via Chrome
|
||||
INFO[...] Connecting to IRC server irc.libera.chat:6667
|
||||
INFO[...] Successfully connected to IRC
|
||||
INFO[...] Gateway(s) started successfully. Now relaying messages
|
||||
```
|
||||
|
||||
Now send a test message and watch it relay! 🚀
|
||||
|
||||
- Full Docker guide: [DOCKER_DEPLOYMENT.md](DOCKER_DEPLOYMENT.md)
|
||||
- Quick reference: [QUICK_REFERENCE.md](QUICK_REFERENCE.md)
|
||||
- IRC commands: [IRC.md](../IRC.md)
|
||||
|
||||
@@ -1,203 +1,226 @@
|
||||
# Jackbox Game Picker API Integration
|
||||
|
||||
This document describes how the Kosmi/IRC relay integrates with the Jackbox Game Picker API for live voting and game notifications.
|
||||
This document describes how the Kosmi/IRC relay integrates with the Jackbox Game Picker API for live voting, game announcements, and room code display.
|
||||
|
||||
## Features
|
||||
## Overview
|
||||
|
||||
### 1. Vote Detection
|
||||
The relay automatically detects when users vote on games using the `thisgame++` or `thisgame--` syntax in either Kosmi or IRC chat.
|
||||
When enabled, the relay:
|
||||
|
||||
**How it works:**
|
||||
- Users type `thisgame++` to upvote the current game
|
||||
- Users type `thisgame--` to downvote the current game
|
||||
- Votes are case-insensitive
|
||||
- The relay filters out relayed messages (messages with `[irc]` or `[kosmi]` prefix) to prevent duplicate votes
|
||||
- Only votes from actual users in each chat are sent to the API
|
||||
|
||||
### 2. Game Notifications
|
||||
When a new game is added to the Jackbox session via the API, the relay receives a webhook notification and broadcasts it to both Kosmi and IRC chats.
|
||||
|
||||
**Example notification:**
|
||||
```
|
||||
🎮 Coming up next: Fibbage 4!
|
||||
```
|
||||
1. **Detects votes** in chat (`thisgame++`/`thisgame--` and ticker-symbol votes) and submits them to the API
|
||||
2. **Receives game events** via WebSocket (or webhook fallback) and announces them to all bridges
|
||||
3. **Responds to `!votes`** with the current game's vote tally
|
||||
4. **Optionally generates room code images** and uploads them to Kosmi
|
||||
|
||||
## Configuration
|
||||
|
||||
Add the following section to your `matterbridge.toml`:
|
||||
Add the `[jackbox]` section to `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[jackbox]
|
||||
# Enable Jackbox integration for vote detection and game notifications
|
||||
# Enable Jackbox integration
|
||||
Enabled=true
|
||||
|
||||
# Jackbox API URL
|
||||
APIURL="http://localhost:5000"
|
||||
APIURL="https://your-jackbox-api.example.com"
|
||||
|
||||
# Admin password for API authentication
|
||||
AdminPassword="your_admin_password_here"
|
||||
# Admin password for API authentication (exchanged for JWT)
|
||||
AdminPassword="your_admin_password"
|
||||
|
||||
# Webhook server port (for receiving game notifications)
|
||||
# Use WebSocket for real-time game notifications (recommended, default: true)
|
||||
# Set to false to use webhook HTTP server instead
|
||||
UseWebSocket=true
|
||||
|
||||
# --- Webhook settings (only if UseWebSocket=false) ---
|
||||
# Port for the webhook HTTP server
|
||||
WebhookPort=3001
|
||||
# HMAC-SHA256 secret for webhook signature verification
|
||||
WebhookSecret="your_webhook_secret"
|
||||
|
||||
# Webhook secret for signature verification
|
||||
WebhookSecret="your_webhook_secret_here"
|
||||
# --- Room code image settings ---
|
||||
# Generate and upload a room code image to Kosmi chat
|
||||
EnableRoomCodeImage=true
|
||||
# Seconds to wait before sending the image announcement (default: 0)
|
||||
RoomCodeImageDelay=28
|
||||
# Seconds to wait before sending the plaintext room code follow-up (default: 29)
|
||||
RoomCodePlaintextDelay=22
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
### Configuration Reference
|
||||
|
||||
- **Enabled**: Set to `true` to enable the integration, `false` to disable
|
||||
- **APIURL**: The URL of your Jackbox Game Picker API (e.g., `http://localhost:5000`)
|
||||
- **AdminPassword**: Your API admin password (used to authenticate and get a JWT token)
|
||||
- **WebhookPort**: Port for the webhook server to listen on (default: 3001)
|
||||
- **WebhookSecret**: Shared secret for webhook signature verification (must match the secret configured in the API)
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `Enabled` | bool | `false` | Master switch for the integration |
|
||||
| `APIURL` | string | | Base URL of the Jackbox Game Picker API |
|
||||
| `AdminPassword` | string | | Admin password, exchanged for a JWT via `POST /api/auth/login` |
|
||||
| `UseWebSocket` | bool | `true` | Use WebSocket transport for events (recommended) |
|
||||
| `WebhookPort` | int | `3001` | HTTP listen port for webhook server |
|
||||
| `WebhookSecret` | string | | HMAC secret for webhook signature verification |
|
||||
| `EnableRoomCodeImage` | bool | `false` | Generate/upload room code images |
|
||||
| `RoomCodeImageDelay` | int | `0` | Seconds before image announcement |
|
||||
| `RoomCodePlaintextDelay` | int | `29` | Seconds before plaintext room code |
|
||||
|
||||
## Setup Steps
|
||||
## Transport: WebSocket vs. Webhook
|
||||
|
||||
### 1. Configure the Relay
|
||||
### WebSocket (Recommended)
|
||||
|
||||
Edit `matterbridge.toml` and add the Jackbox configuration section with your API URL, admin password, and webhook secret.
|
||||
When `UseWebSocket=true`, the relay connects to `wss://<APIURL>/api/sessions/live` and authenticates with its JWT. Events are received in real-time with automatic reconnection.
|
||||
|
||||
### 2. Register the Webhook
|
||||
Handled events:
|
||||
- `session.started` -- announces game night start
|
||||
- `game.added` -- announces next game with room code
|
||||
- `session.ended` -- announces game night end
|
||||
|
||||
After starting the relay, register the webhook with the Jackbox API:
|
||||
No additional setup is required beyond the config above.
|
||||
|
||||
### Webhook (Fallback)
|
||||
|
||||
When `UseWebSocket=false`, the relay starts an HTTP server on `WebhookPort` and listens for `POST /webhook/jackbox` requests from the API.
|
||||
|
||||
You must register the webhook with the API:
|
||||
|
||||
```bash
|
||||
# Get JWT token
|
||||
curl -X POST "http://localhost:5000/api/auth/login" \
|
||||
TOKEN=$(curl -s -X POST "$API_URL/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"apiKey": "your_admin_password"}'
|
||||
-d '{"key": "your_admin_password"}' | jq -r .token)
|
||||
|
||||
# Register webhook (use the JWT token from above)
|
||||
curl -X POST "http://localhost:5000/api/webhooks" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||
# Register webhook
|
||||
curl -X POST "$API_URL/api/webhooks" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Kosmi/IRC Relay",
|
||||
"url": "http://your-relay-host:3001/webhook/jackbox",
|
||||
"secret": "your_webhook_secret_here",
|
||||
"secret": "your_webhook_secret",
|
||||
"events": ["game.added"]
|
||||
}'
|
||||
```
|
||||
|
||||
**Important:** Replace `your-relay-host` with the actual hostname or IP address where your relay is running. If the API and relay are on the same machine, you can use `localhost`.
|
||||
Webhook requests include an `X-Webhook-Signature` header with an HMAC-SHA256 signature for verification.
|
||||
|
||||
### 3. Test the Integration
|
||||
## Vote Detection
|
||||
|
||||
#### Test Vote Detection
|
||||
The relay automatically detects vote patterns in non-relayed messages from both IRC and Kosmi.
|
||||
|
||||
1. Start an active session in the Jackbox API with some games played
|
||||
2. Send a message in Kosmi or IRC: `thisgame++`
|
||||
3. Check the relay logs for: `Detected vote from <username>: up`
|
||||
4. Verify the vote was recorded in the API
|
||||
### Supported Syntax
|
||||
|
||||
#### Test Game Notifications
|
||||
| Pattern | Effect |
|
||||
|---------|--------|
|
||||
| `thisgame++` | Upvote currently playing game |
|
||||
| `thisgame--` | Downvote currently playing game |
|
||||
| `SYMBOL++` | Upvote game by ticker symbol |
|
||||
| `SYMBOL--` | Downvote game by ticker symbol |
|
||||
|
||||
1. Add a game to the active session via the Jackbox API
|
||||
2. Both Kosmi and IRC chats should receive a notification: `🎮 Coming up next: <game title>!`
|
||||
- All patterns are case-insensitive
|
||||
- `thisgame` votes can appear anywhere in the message
|
||||
- Ticker symbols are 2-4 alphanumeric characters that map to specific games (see [IRC.md](../IRC.md) for the full ticker table)
|
||||
- Messages prefixed with `[irc]` or `[kosmi]` are treated as relayed and skip vote detection
|
||||
|
||||
Votes are submitted to `POST /api/votes/live` with the voter's username, vote type, timestamp, and optional ticker symbol.
|
||||
|
||||
### Deduplication
|
||||
|
||||
The API rejects duplicate votes from the same user within 1 second.
|
||||
|
||||
## IRC/Kosmi Commands
|
||||
|
||||
### `!votes`
|
||||
|
||||
Available in both IRC and Kosmi chat. Queries the current game's vote tally and broadcasts the result to all bridges:
|
||||
|
||||
```
|
||||
🗳️ Fibbage 4 • Today: 5👍 2👎 (Score: 3) • All-time: 46👍 3👎 (Score: 43)
|
||||
```
|
||||
|
||||
Requires an active session with a game currently "playing".
|
||||
|
||||
### Reconnect Commands (IRC only)
|
||||
|
||||
| Command | Effect |
|
||||
|---------|--------|
|
||||
| `!jreconnect` | Reconnect the Jackbox WebSocket |
|
||||
| `!kreconnect` | Reconnect the Kosmi bridge |
|
||||
| `!reconnect` | Reconnect all non-IRC services |
|
||||
|
||||
## Room Code Images
|
||||
|
||||
When `EnableRoomCodeImage=true` and a `game.added` event includes a room code, the relay:
|
||||
|
||||
1. Generates an image of the room code
|
||||
2. Uploads it to the Kosmi CDN (`img.kosmi.io`)
|
||||
3. Sends the image + announcement message after `RoomCodeImageDelay` seconds
|
||||
4. Sends a plaintext room code follow-up after `RoomCodePlaintextDelay` seconds
|
||||
|
||||
If image generation or upload fails, the relay falls back to plaintext-only announcement.
|
||||
|
||||
## Mute Control
|
||||
|
||||
Jackbox announcements (game start, game added, session end) can be suppressed without stopping the relay:
|
||||
|
||||
- Start muted: `./matterbridge -conf matterbridge.toml -muted`
|
||||
- Toggle at runtime: `kill -SIGUSR1 <pid>` or `docker kill -s SIGUSR1 <container>`
|
||||
|
||||
When muted:
|
||||
- Announcements are suppressed
|
||||
- Vote detection still works (votes are still sent to the API)
|
||||
- Normal IRC/Kosmi message relay is unaffected
|
||||
- `!votes` still works
|
||||
|
||||
See [MUTE_CONTROL.md](MUTE_CONTROL.md) for full details.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Vote Flow
|
||||
|
||||
1. User sends a message containing `thisgame++` or `thisgame--` in Kosmi or IRC
|
||||
2. The bridge detects the vote pattern (case-insensitive)
|
||||
3. The bridge checks if the message is relayed (has `[irc]` or `[kosmi]` prefix)
|
||||
4. If not relayed, the bridge extracts the username and vote type
|
||||
5. The bridge sends the vote to the Jackbox API via HTTP POST to `/api/votes/live`
|
||||
6. The API records the vote and associates it with the current game based on timestamp
|
||||
1. User sends a message containing `thisgame++` (or similar) in IRC or Kosmi
|
||||
2. The bridge detects the vote pattern (skipping relayed messages)
|
||||
3. The bridge submits `POST /api/votes/live` with username, vote type, and timestamp
|
||||
4. The API records the vote against the currently playing game
|
||||
|
||||
### Notification Flow
|
||||
### Event Flow (WebSocket)
|
||||
|
||||
1. A game is added to an active session in the Jackbox API
|
||||
2. The API sends a webhook POST request to `http://your-relay-host:3001/webhook/jackbox`
|
||||
3. The webhook includes an HMAC-SHA256 signature in the `X-Webhook-Signature` header
|
||||
4. The relay verifies the signature using the configured webhook secret
|
||||
5. If valid, the relay parses the `game.added` event
|
||||
6. The relay broadcasts the game announcement to all connected bridges (Kosmi and IRC)
|
||||
1. The relay authenticates with the Jackbox API and opens a WebSocket
|
||||
2. When a session starts, the relay subscribes to that session's events
|
||||
3. `game.added` events trigger game announcements broadcast to all bridges
|
||||
4. `session.ended` triggers the end-of-night message
|
||||
|
||||
## Security
|
||||
### Authentication
|
||||
|
||||
### Webhook Signature Verification
|
||||
|
||||
All incoming webhooks are verified using HMAC-SHA256 signatures to ensure they come from the legitimate Jackbox API.
|
||||
|
||||
**How it works:**
|
||||
1. The API computes `HMAC-SHA256(webhook_secret, request_body)`
|
||||
2. The signature is sent in the `X-Webhook-Signature` header as `sha256=<hex_signature>`
|
||||
3. The relay computes the expected signature using the same method
|
||||
4. The relay uses timing-safe comparison to verify the signatures match
|
||||
5. If verification fails, the webhook is rejected with a 401 Unauthorized response
|
||||
|
||||
### JWT Authentication
|
||||
|
||||
The relay authenticates with the Jackbox API using the admin password to obtain a JWT token. This token is:
|
||||
- Cached to avoid re-authentication on every vote
|
||||
- Automatically refreshed if it expires (detected via 401 response)
|
||||
- Valid for 24 hours (configurable in the API)
|
||||
The relay authenticates with `POST /api/auth/login` using the `AdminPassword` to get a JWT. The token is cached in memory and refreshed automatically on 401 responses.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Votes Not Being Recorded
|
||||
|
||||
**Possible causes:**
|
||||
- No active session in the Jackbox API
|
||||
- Vote timestamp doesn't match any played game
|
||||
- Duplicate vote within 1 second
|
||||
- Authentication failure
|
||||
- Verify an active session exists with games played
|
||||
- Check that the vote timestamp matches a played game's timeframe
|
||||
- Look for `"Detected vote from"` in debug logs
|
||||
- Look for `"Failed to send vote"` errors
|
||||
- Confirm the message isn't prefixed with `[irc]`/`[kosmi]` (relayed messages skip vote detection)
|
||||
|
||||
**Check:**
|
||||
1. Relay logs for vote detection: `grep "Detected vote" logs/matterbridge.log`
|
||||
2. Relay logs for API errors: `grep "Failed to send vote" logs/matterbridge.log`
|
||||
3. API logs for incoming vote requests
|
||||
### Announcements Not Appearing
|
||||
|
||||
### Webhooks Not Being Received
|
||||
- Verify `Enabled=true` in config
|
||||
- Check `APIURL` is accessible and `AdminPassword` is correct
|
||||
- Look for `"Jackbox WebSocket connected"` in logs (if using WebSocket)
|
||||
- If using webhooks, verify the webhook is registered and the port is accessible
|
||||
- Check mute state: look for `"MUTED"` in logs
|
||||
|
||||
**Possible causes:**
|
||||
- Webhook URL is not accessible from the API server
|
||||
- Webhook not registered in the API
|
||||
- Signature verification failing
|
||||
- Firewall blocking the webhook port
|
||||
### WebSocket Disconnects
|
||||
|
||||
**Check:**
|
||||
1. Verify webhook is registered: `GET /api/webhooks` (with JWT token)
|
||||
2. Test webhook manually: `POST /api/webhooks/test/:id` (with JWT token)
|
||||
3. Check webhook logs in API: `GET /api/webhooks/:id/logs` (with JWT token)
|
||||
4. Verify webhook server is listening: `curl http://localhost:3001/health`
|
||||
5. Check relay logs for signature verification errors
|
||||
- The relay auto-reconnects with exponential backoff
|
||||
- Use `!jreconnect` from IRC to force an immediate reconnection
|
||||
- Check API server availability
|
||||
|
||||
### Authentication Failures
|
||||
|
||||
**Possible causes:**
|
||||
- Incorrect admin password in configuration
|
||||
- API is not running or not accessible
|
||||
|
||||
**Check:**
|
||||
1. Verify API URL is correct and accessible
|
||||
2. Test authentication manually:
|
||||
```bash
|
||||
curl -X POST "http://localhost:5000/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"apiKey": "your_admin_password"}'
|
||||
```
|
||||
3. Check relay logs for authentication errors
|
||||
|
||||
## Logs
|
||||
|
||||
The relay logs all Jackbox-related activity with the `jackbox` prefix:
|
||||
|
||||
```
|
||||
[jackbox] Initializing Jackbox integration...
|
||||
[jackbox] Successfully authenticated with Jackbox API
|
||||
[jackbox] Starting Jackbox webhook server on port 3001
|
||||
[kosmi] Detected vote from Anonymous Llama: up
|
||||
[jackbox] Vote recorded for Fibbage 4: Anonymous Llama - 5👍 2👎
|
||||
[jackbox] Broadcasting Jackbox message: 🎮 Coming up next: Quiplash 3!
|
||||
```bash
|
||||
# Test authentication manually
|
||||
curl -X POST "$API_URL/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"key": "your_admin_password"}'
|
||||
```
|
||||
|
||||
## Disabling the Integration
|
||||
|
||||
To disable the Jackbox integration, set `Enabled=false` in the `[jackbox]` section of `matterbridge.toml` and restart the relay.
|
||||
|
||||
The relay will continue to function normally for Kosmi ↔ IRC message relay without any Jackbox features.
|
||||
## Disabling
|
||||
|
||||
Set `Enabled=false` in the `[jackbox]` section and restart. The relay continues to function normally for IRC/Kosmi message relay without any Jackbox features.
|
||||
|
||||
@@ -1,301 +1,130 @@
|
||||
# Quick Start Guide
|
||||
|
||||
Get the Kosmi-IRC bridge running in minutes!
|
||||
Get the Kosmi-IRC bridge running in minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.21 or higher
|
||||
- Chrome/Chromium browser installed (for headless browser automation)
|
||||
- Access to a Kosmi room
|
||||
- Go 1.23 or higher
|
||||
- Chrome/Chromium (only needed for email/password authentication)
|
||||
- A Kosmi room URL
|
||||
- (Optional) IRC server access for full relay
|
||||
|
||||
## Step 1: Test Kosmi Connection
|
||||
|
||||
First, verify the bridge can connect to Kosmi:
|
||||
## Step 1: Build the Bridge
|
||||
|
||||
```bash
|
||||
# Build the test program
|
||||
go build -o test-kosmi ./cmd/test-kosmi
|
||||
cd irc-kosmi-relay
|
||||
|
||||
# Run with your Kosmi room URL
|
||||
./test-kosmi -room "https://app.kosmi.io/room/@hyperspaceout" -debug
|
||||
```
|
||||
|
||||
You should see output like:
|
||||
```
|
||||
INFO[...] Starting Kosmi bridge test
|
||||
INFO[...] Launching headless Chrome for Kosmi connection
|
||||
INFO[...] Injecting WebSocket interceptor (runs before page load)...
|
||||
INFO[...] Navigating to Kosmi room: https://app.kosmi.io/room/@hyperspaceout
|
||||
INFO[...] ✓ WebSocket hook confirmed installed
|
||||
INFO[...] Status: WebSocket connection intercepted
|
||||
INFO[...] Successfully connected to Kosmi via Chrome
|
||||
INFO[...] Listening for messages... Press Ctrl+C to exit
|
||||
```
|
||||
|
||||
**Test it**: Send a message in the Kosmi room from your browser. You should see it appear in the terminal like:
|
||||
```
|
||||
INFO[...] Received message: [00:02:51] username: [Kosmi] <username> your message here
|
||||
```
|
||||
|
||||
## Step 2: Integrate with Full Matterbridge
|
||||
|
||||
### Option A: Copy into Existing Matterbridge
|
||||
|
||||
If you already have Matterbridge:
|
||||
|
||||
```bash
|
||||
# Navigate to your Matterbridge directory
|
||||
cd /path/to/matterbridge
|
||||
|
||||
# Copy the Kosmi bridge
|
||||
cp -r /path/to/irc-kosmi-relay/bridge/kosmi bridge/
|
||||
|
||||
# Copy the bridge registration
|
||||
cp /path/to/irc-kosmi-relay/gateway/bridgemap/bkosmi.go gateway/bridgemap/
|
||||
|
||||
# Add dependencies
|
||||
go get github.com/chromedp/chromedp@v0.11.2
|
||||
go mod tidy
|
||||
# Download dependencies
|
||||
go mod download
|
||||
|
||||
# Build
|
||||
go build
|
||||
go build -o matterbridge .
|
||||
```
|
||||
|
||||
### Option B: Use This Repository
|
||||
## Step 2: Configure
|
||||
|
||||
This repository has a minimal Matterbridge structure. To add IRC support:
|
||||
Copy and edit the example configuration:
|
||||
|
||||
1. Copy IRC bridge from Matterbridge:
|
||||
```bash
|
||||
# From the Matterbridge repo
|
||||
cp -r bridge/irc /path/to/irc-kosmi-relay/bridge/
|
||||
cp gateway/bridgemap/birc.go /path/to/irc-kosmi-relay/gateway/bridgemap/
|
||||
```
|
||||
```bash
|
||||
cp matterbridge.toml.example matterbridge.toml
|
||||
nano matterbridge.toml
|
||||
```
|
||||
|
||||
2. Update dependencies:
|
||||
```bash
|
||||
cd /path/to/irc-kosmi-relay
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
## Step 3: Configure
|
||||
|
||||
Edit `matterbridge.toml`:
|
||||
Update these values:
|
||||
|
||||
```toml
|
||||
# Kosmi configuration
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM"
|
||||
|
||||
# IRC configuration
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667"
|
||||
Nick="kosmi-bot"
|
||||
UseTLS=false
|
||||
|
||||
# Gateway to connect them
|
||||
[[gateway]]
|
||||
name="kosmi-irc-relay"
|
||||
enable=true
|
||||
[irc.zeronode]
|
||||
Server="irc.libera.chat:6697"
|
||||
Nick="your-bot-nick"
|
||||
UseTLS=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.hyperspaceout"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
account="irc.zeronode"
|
||||
channel="#your-channel"
|
||||
```
|
||||
|
||||
**Important**: Replace:
|
||||
- `https://app.kosmi.io/room/@hyperspaceout` with your Kosmi room URL
|
||||
- `#your-channel` with your IRC channel
|
||||
**Important**: The Kosmi channel is always `"main"` (one channel per room). The IRC channel must include `#`.
|
||||
|
||||
## Step 4: Run
|
||||
### Optional: Authenticated Kosmi Access
|
||||
|
||||
To use a Kosmi account instead of anonymous access, add credentials:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM"
|
||||
Email="your-email@example.com"
|
||||
Password="your-password"
|
||||
```
|
||||
|
||||
This requires Chrome/Chromium for the initial browser-based login. The JWT is cached locally for subsequent runs.
|
||||
|
||||
## Step 3: Run
|
||||
|
||||
```bash
|
||||
./matterbridge -conf matterbridge.toml
|
||||
```
|
||||
|
||||
Or with debug logging:
|
||||
|
||||
```bash
|
||||
./matterbridge -conf matterbridge.toml -debug
|
||||
```
|
||||
|
||||
## Step 5: Test the Relay
|
||||
### Expected Output (Success)
|
||||
|
||||
1. **Kosmi → IRC**: Send a message in Kosmi. It should appear in IRC as:
|
||||
```
|
||||
INFO Running version ...
|
||||
INFO Connecting to Kosmi
|
||||
INFO Extracted room ID: @YOUR_ROOM
|
||||
INFO No credentials provided, using anonymous access
|
||||
INFO Successfully connected to Kosmi
|
||||
INFO Connection succeeded (IRC)
|
||||
INFO Gateway(s) started successfully. Now relaying messages
|
||||
```
|
||||
|
||||
## Step 4: Test the Relay
|
||||
|
||||
1. **Kosmi --> IRC**: Send a message in your Kosmi room. It should appear in IRC as:
|
||||
```
|
||||
[Kosmi] <username> your message here
|
||||
[kosmi] <username> your message here
|
||||
```
|
||||
|
||||
2. **IRC → Kosmi**: Send a message in IRC. It should appear in Kosmi as:
|
||||
2. **IRC --> Kosmi**: Send a message in your IRC channel. It should appear in Kosmi as:
|
||||
```
|
||||
[IRC] <username> your message here
|
||||
[irc] <username> your message here
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Test program doesn't connect
|
||||
### Kosmi connection fails
|
||||
|
||||
**Check**:
|
||||
- Is Chrome/Chromium installed and accessible?
|
||||
- Is the room URL correct?
|
||||
- Can you access `app.kosmi.io` from your network?
|
||||
- Try with `-debug` flag for more details
|
||||
- Verify the room URL is correct (use the full URL from your browser)
|
||||
- Check network connectivity: `curl -I https://app.kosmi.io`
|
||||
- Run with `-debug` for detailed WebSocket connection logs
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Test Chrome installation
|
||||
which google-chrome chromium chromium-browser
|
||||
**Supported room URL formats:**
|
||||
- `https://app.kosmi.io/room/@roomname`
|
||||
- `https://app.kosmi.io/room/roomid`
|
||||
|
||||
# Test network connectivity
|
||||
curl -I https://app.kosmi.io
|
||||
### Authentication issues
|
||||
|
||||
# Run with debug
|
||||
./test-kosmi -room "YOUR_ROOM_URL" -debug
|
||||
```
|
||||
- Verify Chrome/Chromium is installed: `which chromium chromium-browser google-chrome`
|
||||
- Check credentials are correct by logging in manually at `app.kosmi.io`
|
||||
- Delete the token cache to force a fresh login: `rm -f data/kosmi_token_cache.json`
|
||||
- See [BROWSER_AUTH_GUIDE.md](BROWSER_AUTH_GUIDE.md) for detailed auth troubleshooting
|
||||
|
||||
### Messages not relaying
|
||||
|
||||
**Check**:
|
||||
- Are both bridges connected? Look for "Successfully connected" in logs
|
||||
- Is the gateway configuration correct?
|
||||
- Are the channel names correct?
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Run with debug to see message flow
|
||||
./matterbridge -conf matterbridge.toml -debug
|
||||
|
||||
# Look for lines like:
|
||||
# "Received message from Kosmi"
|
||||
# "Forwarding to Matterbridge"
|
||||
# "Sending to IRC"
|
||||
```
|
||||
|
||||
### "Room ID extraction failed"
|
||||
|
||||
**Check**: Room URL format
|
||||
|
||||
**Supported formats**:
|
||||
- `https://app.kosmi.io/room/@roomname`
|
||||
- `https://app.kosmi.io/room/roomid`
|
||||
- `@roomname`
|
||||
- `roomid`
|
||||
|
||||
**Solution**: Use the full URL from your browser's address bar
|
||||
|
||||
### Messages not appearing from Kosmi
|
||||
|
||||
**Check**:
|
||||
- Is the WebSocket hook installed? Look for "✓ WebSocket hook confirmed installed"
|
||||
- Is the WebSocket connection detected? Look for "Status: WebSocket connection intercepted"
|
||||
- Are messages being captured? Enable debug logging to see message processing
|
||||
|
||||
**Solution**:
|
||||
The bridge uses headless Chrome with a WebSocket interceptor that runs **before page load**. This is critical for capturing messages. The implementation uses `Page.addScriptToEvaluateOnNewDocument` to ensure the hook is installed before any page JavaScript executes.
|
||||
|
||||
If messages still aren't appearing:
|
||||
1. Check Chrome console logs in debug mode
|
||||
2. Verify the room URL is correct
|
||||
3. Try sending a test message and watch the debug output
|
||||
|
||||
### Cannot send messages to Kosmi
|
||||
|
||||
The send functionality uses the headless Chrome instance to inject messages into the Kosmi chat input field.
|
||||
|
||||
**To debug**:
|
||||
1. Enable debug logging with `-debug` flag
|
||||
2. Look for "Sending message to Kosmi" in logs
|
||||
3. Check for any JavaScript errors in the browser console logs
|
||||
- Confirm both bridges are connected (look for success messages in logs)
|
||||
- Verify channel names match in the gateway configuration
|
||||
- Enable debug logging to trace message flow
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **Customize message format**: Edit the format strings in `kosmi.go`
|
||||
- **Add more bridges**: Matterbridge supports Discord, Slack, Telegram, etc.
|
||||
- **Set up as a service**: Use systemd or similar to run automatically
|
||||
- **Monitor logs**: Set up log rotation and monitoring
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Check `INTEGRATION.md` for detailed integration steps
|
||||
- Check `README.md` for architecture details
|
||||
- Enable debug logging for detailed troubleshooting
|
||||
- Review the chrome extension code in `.examples/` for API details
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Home Server Setup
|
||||
|
||||
```toml
|
||||
# Bridge your Kosmi room with your home IRC server
|
||||
[kosmi.gamenight]
|
||||
RoomURL="https://app.kosmi.io/room/@gamenight"
|
||||
|
||||
[irc.home]
|
||||
Server="irc.home.local:6667"
|
||||
Nick="kosmi-relay"
|
||||
UseTLS=false
|
||||
|
||||
[[gateway]]
|
||||
name="gamenight"
|
||||
enable=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.gamenight"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.home"
|
||||
channel="#gamenight"
|
||||
```
|
||||
|
||||
### Multiple Rooms
|
||||
|
||||
```toml
|
||||
# Bridge multiple Kosmi rooms
|
||||
[kosmi.room1]
|
||||
RoomURL="https://app.kosmi.io/room/@room1"
|
||||
|
||||
[kosmi.room2]
|
||||
RoomURL="https://app.kosmi.io/room/@room2"
|
||||
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667"
|
||||
Nick="kosmi-bot"
|
||||
|
||||
# Gateway for room1
|
||||
[[gateway]]
|
||||
name="gateway1"
|
||||
enable=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.room1"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#room1"
|
||||
|
||||
# Gateway for room2
|
||||
[[gateway]]
|
||||
name="gateway2"
|
||||
enable=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.room2"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#room2"
|
||||
```
|
||||
|
||||
## Success!
|
||||
|
||||
If you see messages flowing both ways, congratulations! Your Kosmi-IRC bridge is working. 🎉
|
||||
|
||||
For advanced configuration and features, see the full documentation in `README.md` and `INTEGRATION.md`.
|
||||
|
||||
- [DOCKER_QUICKSTART.md](DOCKER_QUICKSTART.md) -- Deploy with Docker
|
||||
- [JACKBOX_INTEGRATION.md](JACKBOX_INTEGRATION.md) -- Enable Jackbox Game Picker
|
||||
- [IRC.md](../IRC.md) -- IRC commands and voting reference
|
||||
- [MUTE_CONTROL.md](MUTE_CONTROL.md) -- Control Jackbox announcement muting
|
||||
|
||||
@@ -1,237 +1,204 @@
|
||||
# Quick Reference Guide
|
||||
|
||||
## Testing the Bridge
|
||||
## Running the Bridge
|
||||
|
||||
### Build and Run Test Program
|
||||
### Build and Run Locally
|
||||
|
||||
```bash
|
||||
cd /Users/erikfredericks/dev-ai/HSO/irc-kosmi-relay
|
||||
go build -o test-kosmi ./cmd/test-kosmi
|
||||
./test-kosmi -room "https://app.kosmi.io/room/@hyperspaceout" -debug
|
||||
go build -o matterbridge .
|
||||
./matterbridge -conf matterbridge.toml
|
||||
```
|
||||
|
||||
### Run with Docker
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### Expected Output (Success)
|
||||
|
||||
```
|
||||
INFO Launching headless Chrome for Kosmi connection
|
||||
INFO Injecting WebSocket interceptor (runs before page load)...
|
||||
INFO Navigating to Kosmi room: https://app.kosmi.io/room/@hyperspaceout
|
||||
INFO ✓ WebSocket hook confirmed installed
|
||||
INFO Status: WebSocket connection intercepted
|
||||
INFO Successfully connected to Kosmi via Chrome
|
||||
INFO Listening for messages... Press Ctrl+C to exit
|
||||
INFO Connecting to Kosmi
|
||||
INFO Extracted room ID: @yourroom
|
||||
INFO No credentials provided, using anonymous access
|
||||
INFO Successfully connected to Kosmi
|
||||
INFO Connection succeeded (IRC)
|
||||
INFO Gateway(s) started successfully. Now relaying messages
|
||||
```
|
||||
|
||||
### When Messages Arrive
|
||||
|
||||
If using email/password authentication:
|
||||
```
|
||||
INFO Processing 1 messages from queue
|
||||
INFO Received message: [00:02:51] username: [Kosmi] <username> message text
|
||||
INFO Authenticating with email/password...
|
||||
INFO ✅ Authentication successful
|
||||
INFO Successfully connected to Kosmi
|
||||
```
|
||||
|
||||
## Key Status Indicators
|
||||
|
||||
| Status Message | Meaning | Action |
|
||||
|---------------|---------|--------|
|
||||
| `✓ WebSocket hook confirmed installed` | Hook script is active | ✅ Good |
|
||||
| `Status: WebSocket connection intercepted` | WebSocket is being captured | ✅ Good |
|
||||
| `Status: No WebSocket connection detected yet` | Hook missed the WebSocket | ❌ Check injection timing |
|
||||
| `Processing N messages from queue` | Messages are being captured | ✅ Good |
|
||||
| Log Message | Meaning |
|
||||
|-------------|---------|
|
||||
| `Successfully connected to Kosmi` | Native WebSocket connection established |
|
||||
| `Connection succeeded (IRC)` | IRC bridge is connected |
|
||||
| `Gateway(s) started successfully` | All bridges up, relay is active |
|
||||
| `✅ Using cached token` | Reusing saved JWT (no browser needed) |
|
||||
| `✅ Authentication successful` | Browser login completed |
|
||||
| `Kosmi connection lost unexpectedly` | WebSocket dropped, auto-reconnect triggered |
|
||||
|
||||
## Common Issues
|
||||
## IRC Commands
|
||||
|
||||
### Issue: "No WebSocket connection detected yet"
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `!kreconnect` | Reconnect Kosmi bridge |
|
||||
| `!jreconnect` | Reconnect Jackbox WebSocket |
|
||||
| `!reconnect` | Reconnect all non-IRC services |
|
||||
| `!votes` | Show current game vote tally |
|
||||
|
||||
**Cause**: WebSocket hook was injected too late
|
||||
|
||||
**Fix**: Verify `injectWebSocketHookBeforeLoad()` uses `page.AddScriptToEvaluateOnNewDocument`
|
||||
|
||||
### Issue: "Chrome not found"
|
||||
|
||||
**Cause**: Chrome/Chromium not installed or not in PATH
|
||||
|
||||
**Fix**:
|
||||
```bash
|
||||
# macOS
|
||||
brew install --cask google-chrome
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt install chromium-browser
|
||||
|
||||
# Verify installation
|
||||
which google-chrome chromium chromium-browser
|
||||
```
|
||||
|
||||
### Issue: Messages not appearing
|
||||
|
||||
**Cause**: Multiple possibilities
|
||||
|
||||
**Debug**:
|
||||
1. Check for "✓ WebSocket hook confirmed installed" ✓
|
||||
2. Check for "Status: WebSocket connection intercepted" ✓
|
||||
3. Enable debug logging: `-debug` flag
|
||||
4. Send a test message in the Kosmi room
|
||||
5. Look for "Processing N messages from queue"
|
||||
See [IRC.md](../IRC.md) for full details including vote syntax and ticker symbols.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Minimal Test Configuration
|
||||
### Minimal Configuration
|
||||
|
||||
```toml
|
||||
[kosmi.test]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
Debug=true
|
||||
```
|
||||
[kosmi.myroom]
|
||||
RoomURL="https://app.kosmi.io/room/@yourroom"
|
||||
|
||||
### Full Matterbridge Configuration
|
||||
|
||||
```toml
|
||||
# Kosmi
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
|
||||
# IRC
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667"
|
||||
[irc.myserver]
|
||||
Server="irc.libera.chat:6697"
|
||||
Nick="kosmi-relay"
|
||||
UseTLS=false
|
||||
UseTLS=true
|
||||
|
||||
# Gateway
|
||||
[[gateway]]
|
||||
name="kosmi-irc"
|
||||
enable=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.hyperspaceout"
|
||||
account="kosmi.myroom"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
account="irc.myserver"
|
||||
channel="#your-channel"
|
||||
```
|
||||
|
||||
### With Authentication
|
||||
|
||||
```toml
|
||||
[kosmi.myroom]
|
||||
RoomURL="https://app.kosmi.io/room/@yourroom"
|
||||
Email="your-email@example.com"
|
||||
Password="your-password"
|
||||
```
|
||||
|
||||
### With Jackbox Integration
|
||||
|
||||
```toml
|
||||
[jackbox]
|
||||
Enabled=true
|
||||
APIURL="https://your-jackbox-api.example.com"
|
||||
AdminPassword="your_password"
|
||||
UseWebSocket=true
|
||||
EnableRoomCodeImage=true
|
||||
```
|
||||
|
||||
## Message Format
|
||||
|
||||
### Kosmi → IRC
|
||||
### Kosmi --> IRC
|
||||
|
||||
```
|
||||
[Kosmi] <username> message text
|
||||
[kosmi] <username> message text
|
||||
```
|
||||
|
||||
### IRC → Kosmi
|
||||
### IRC --> Kosmi
|
||||
|
||||
```
|
||||
[IRC] <username> message text
|
||||
[irc] <username> message text
|
||||
```
|
||||
|
||||
Format is controlled by `RemoteNickFormat` in each bridge's config section.
|
||||
|
||||
## File Locations
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `bridge/kosmi/kosmi.go` | Main bridge implementation |
|
||||
| `bridge/kosmi/chromedp_client.go` | Headless Chrome client |
|
||||
| `bridge/kosmi/graphql.go` | GraphQL structures (legacy) |
|
||||
| `cmd/test-kosmi/main.go` | Standalone test program |
|
||||
| `matterbridge.toml` | Configuration file |
|
||||
| `bridge/kosmi/kosmi.go` | Main Kosmi bridge |
|
||||
| `bridge/kosmi/graphql_ws_client.go` | Native GraphQL WebSocket client |
|
||||
| `bridge/kosmi/auth.go` | Anonymous login |
|
||||
| `bridge/kosmi/browser_auth.go` | Chromedp browser login |
|
||||
| `bridge/kosmi/token_cache.go` | JWT token caching |
|
||||
| `bridge/irc/handlers.go` | IRC commands and vote detection |
|
||||
| `bridge/jackbox/client.go` | Jackbox API client |
|
||||
| `bridge/jackbox/votes.go` | Vote detection logic |
|
||||
| `matterbridge.toml` | Runtime configuration |
|
||||
|
||||
## Key Implementation Details
|
||||
## Common Issues
|
||||
|
||||
### WebSocket Hook Injection
|
||||
### Kosmi connection fails
|
||||
|
||||
**MUST** use `page.AddScriptToEvaluateOnNewDocument` to inject **before page load**:
|
||||
1. Verify `RoomURL` is correct and the room exists
|
||||
2. Check network connectivity: `curl -I https://app.kosmi.io`
|
||||
3. Enable debug logging: `-debug` flag
|
||||
4. Check logs for WebSocket handshake errors
|
||||
|
||||
```go
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
_, err := page.AddScriptToEvaluateOnNewDocument(script).Do(ctx)
|
||||
return err
|
||||
})
|
||||
```
|
||||
### Authentication fails
|
||||
|
||||
### Hook Script
|
||||
1. Verify Chrome/Chromium is installed: `which chromium chromium-browser google-chrome`
|
||||
2. Check credentials are correct
|
||||
3. Delete cached token to force fresh login: `rm data/kosmi_token_cache.json`
|
||||
4. Check for Kosmi UI changes that may break browser automation
|
||||
|
||||
Wraps `window.WebSocket` constructor to intercept all WebSocket connections:
|
||||
### Messages not appearing
|
||||
|
||||
```javascript
|
||||
window.WebSocket = function(url, protocols) {
|
||||
const socket = new OriginalWebSocket(url, protocols);
|
||||
// ... interception logic ...
|
||||
return socket;
|
||||
};
|
||||
```
|
||||
1. Confirm both bridges are connected (check logs)
|
||||
2. Verify gateway config: Kosmi channel must be `"main"`, IRC channel must have `#`
|
||||
3. Enable debug logging to trace message routing
|
||||
4. Check for `RemoteNickFormat` issues
|
||||
|
||||
## Debugging Commands
|
||||
### Jackbox votes not registering
|
||||
|
||||
1. Verify Jackbox integration is enabled in config
|
||||
2. Check that an active session exists with games played
|
||||
3. Confirm messages don't start with `[irc]` or `[kosmi]` prefix (relayed messages skip vote detection)
|
||||
|
||||
## CLI Flags
|
||||
|
||||
```bash
|
||||
# Test Chrome installation
|
||||
which google-chrome chromium chromium-browser
|
||||
|
||||
# Test network connectivity
|
||||
curl -I https://app.kosmi.io
|
||||
|
||||
# Build with verbose output
|
||||
go build -v -o test-kosmi ./cmd/test-kosmi
|
||||
|
||||
# Run with debug logging
|
||||
./test-kosmi -room "https://app.kosmi.io/room/@hyperspaceout" -debug
|
||||
|
||||
# Check for linter errors
|
||||
go vet ./...
|
||||
./matterbridge -conf matterbridge.toml # Specify config file
|
||||
./matterbridge -debug # Enable debug logging
|
||||
./matterbridge -muted # Start with Jackbox announcements muted
|
||||
./matterbridge -version # Show version info
|
||||
```
|
||||
|
||||
## Performance Notes
|
||||
## Mute Toggle
|
||||
|
||||
- **Chrome Startup**: ~1-2 seconds
|
||||
- **Page Load**: ~1-2 seconds
|
||||
- **Message Latency**: ~100-500ms
|
||||
- **Memory Usage**: ~100-200MB (Chrome process)
|
||||
Toggle Jackbox announcements at runtime:
|
||||
|
||||
## Security Considerations
|
||||
```bash
|
||||
# Local
|
||||
kill -SIGUSR1 $(pgrep matterbridge)
|
||||
|
||||
- Bridge runs Chrome in headless mode (no GUI)
|
||||
- No credentials stored (anonymous access)
|
||||
- WebSocket traffic is intercepted in memory only
|
||||
- Messages are not logged to disk (unless debug logging enabled)
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### systemd Service Example
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Kosmi-IRC Relay
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=matterbridge
|
||||
WorkingDirectory=/opt/matterbridge
|
||||
ExecStart=/opt/matterbridge/matterbridge -conf /etc/matterbridge/matterbridge.toml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
# Docker
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
```
|
||||
|
||||
### Docker Considerations
|
||||
## Docker Commands
|
||||
|
||||
When running in Docker, ensure:
|
||||
- Chrome/Chromium is installed in the container
|
||||
- `--no-sandbox` flag may be needed for Chrome
|
||||
- Sufficient memory allocation (512MB minimum)
|
||||
```bash
|
||||
docker-compose up -d # Start
|
||||
docker-compose down # Stop
|
||||
docker-compose restart # Restart
|
||||
docker-compose logs -f # Follow logs
|
||||
docker-compose logs --tail=100 # Last 100 lines
|
||||
docker-compose build --no-cache # Rebuild
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- **Documentation**: See `README.md`, `QUICKSTART.md`, `LESSONS_LEARNED.md`
|
||||
- **Integration Guide**: See `INTEGRATION.md`
|
||||
- **Implementation Details**: See `IMPLEMENTATION_SUMMARY.md`
|
||||
- **ChromeDP Guide**: See `CHROMEDP_IMPLEMENTATION.md`
|
||||
|
||||
## Support
|
||||
|
||||
For issues:
|
||||
1. Check this quick reference
|
||||
2. Review `LESSONS_LEARNED.md` for common patterns
|
||||
3. Enable debug logging for detailed output
|
||||
4. Check Chrome console logs in debug mode
|
||||
## Further Reading
|
||||
|
||||
- [README.md](../../README.md) -- Project overview and architecture
|
||||
- [IRC.md](../IRC.md) -- IRC command and voting reference
|
||||
- [DOCKER_QUICKSTART.md](DOCKER_QUICKSTART.md) -- 5-minute Docker setup
|
||||
- [JACKBOX_INTEGRATION.md](JACKBOX_INTEGRATION.md) -- Jackbox Game Picker setup
|
||||
- [BROWSER_AUTH_GUIDE.md](BROWSER_AUTH_GUIDE.md) -- Email/password authentication
|
||||
- [MUTE_CONTROL.md](MUTE_CONTROL.md) -- Mute toggle guide
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Quick Start: Testing Authentication
|
||||
# Quick Start: Authenticated Kosmi Access
|
||||
|
||||
## Step 1: Create Bot Account
|
||||
|
||||
@@ -7,88 +7,72 @@
|
||||
3. Choose a display name (e.g., "HSO Relay Bot")
|
||||
4. Save the credentials securely
|
||||
|
||||
## Step 2: Test with Monitor Script
|
||||
|
||||
```bash
|
||||
cd /Users/erikfredericks/dev-ai/HSO/irc-kosmi-relay
|
||||
|
||||
# Run monitor in login mode
|
||||
./bin/monitor-auth -login
|
||||
|
||||
# In the browser that opens:
|
||||
# 1. Log in with your bot credentials
|
||||
# 2. Navigate to a room
|
||||
# 3. Press Ctrl+C to stop
|
||||
|
||||
# Review the captured data
|
||||
cat auth-monitor.log | grep -A 5 "login"
|
||||
```
|
||||
|
||||
## Step 3: Configure Matterbridge
|
||||
## Step 2: Configure Matterbridge
|
||||
|
||||
Edit `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
RoomURL="https://app.kosmi.io/room/@yourroom"
|
||||
Email="your-bot@example.com"
|
||||
Password="your-secure-password"
|
||||
```
|
||||
|
||||
## Step 4: Test Connection
|
||||
## Step 3: Run and Verify
|
||||
|
||||
```bash
|
||||
# Build the bridge
|
||||
go build
|
||||
|
||||
# Run with your config
|
||||
./matterbridge -conf matterbridge.toml
|
||||
|
||||
# Watch the logs for:
|
||||
# - "Using authenticated connection"
|
||||
# - "Logged in as: HSO Relay Bot"
|
||||
# - "Successfully connected to Kosmi"
|
||||
```
|
||||
|
||||
Watch the logs for:
|
||||
- `"Authenticating with email/password..."` -- browser login starting
|
||||
- `"✅ Authentication successful"` -- login completed
|
||||
- `"💾 Token cached"` -- token saved for reuse
|
||||
- `"Successfully connected to Kosmi"` -- connected to room
|
||||
|
||||
On subsequent runs with a cached token:
|
||||
- `"✅ Using cached token"` -- no browser needed
|
||||
|
||||
## Step 4: Test
|
||||
|
||||
1. Send a message in the Kosmi room from a browser
|
||||
2. Verify it appears in your IRC channel
|
||||
3. Send a message from IRC
|
||||
4. Verify it appears in Kosmi with the bot's display name
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [ ] Bot account created manually
|
||||
- [ ] Credentials documented securely
|
||||
- [ ] Monitor script captured login flow
|
||||
- [ ] Config file updated with credentials
|
||||
- [ ] Bot account created at app.kosmi.io
|
||||
- [ ] Credentials added to `matterbridge.toml`
|
||||
- [ ] Bridge logs show authenticated connection
|
||||
- [ ] Bot display name appears correctly in chat
|
||||
- [ ] Messages relay successfully
|
||||
- [ ] Messages relay bidirectionally
|
||||
- [ ] Token cache file exists (`data/kosmi_token_cache.json` or `~/.matterbridge/kosmi_token_cache.json`)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Wrong account logged in
|
||||
|
||||
Check the log for "Logged in as: {name}". If it doesn't match your bot:
|
||||
- Verify email/password in config
|
||||
- Check for typos
|
||||
- Ensure you're using the correct credentials
|
||||
|
||||
### Anonymous connection despite credentials
|
||||
|
||||
Check that both Email AND Password are set:
|
||||
Check that both `Email` and `Password` are set and non-empty:
|
||||
```bash
|
||||
grep -A 2 "Email=" matterbridge.toml
|
||||
grep -E "Email|Password" matterbridge.toml
|
||||
```
|
||||
|
||||
### Authentication fails
|
||||
|
||||
- Verify Chrome/Chromium is installed
|
||||
- Test credentials by logging in manually at app.kosmi.io
|
||||
- Delete cached token to force fresh auth: `rm data/kosmi_token_cache.json`
|
||||
- Enable debug logging: `-debug`
|
||||
|
||||
### Token expired
|
||||
|
||||
The bridge should auto-refresh. If not:
|
||||
- Check logs for "Token refresh failed"
|
||||
The bridge automatically refreshes tokens expiring within 7 days. If refresh fails:
|
||||
- Check logs for authentication errors
|
||||
- Verify credentials are still valid
|
||||
- Try manual login at app.kosmi.io
|
||||
- Delete the token cache and restart
|
||||
|
||||
## Next Steps
|
||||
|
||||
Once authenticated connection works:
|
||||
- Test reconnection (simulate network failure)
|
||||
- Monitor for token refresh (wait 24 hours)
|
||||
- Test with multiple rooms
|
||||
- Set up as systemd service
|
||||
|
||||
See the monitoring script output and logs for detailed information about Kosmi's authentication behavior.
|
||||
- See [BROWSER_AUTH_GUIDE.md](BROWSER_AUTH_GUIDE.md) for full authentication details
|
||||
- See [TOKEN_PERSISTENCE.md](TOKEN_PERSISTENCE.md) for token caching behavior
|
||||
|
||||
@@ -129,7 +129,7 @@ Potential improvements:
|
||||
|
||||
### Build errors
|
||||
- Ensure all dependencies are installed: `go mod tidy`
|
||||
- Check Go version: Requires Go 1.19+
|
||||
- Check Go version: Requires Go 1.23+
|
||||
- Verify `golang.org/x/image` is available
|
||||
|
||||
## References
|
||||
|
||||
@@ -1,255 +1,126 @@
|
||||
# Message Relay Testing Instructions
|
||||
|
||||
**Bridge Status**: ✅ **ACTIVE AND READY**
|
||||
|
||||
Both Kosmi and IRC are connected. The gateway is relaying messages.
|
||||
|
||||
## Current Configuration
|
||||
|
||||
- **Kosmi Room**: https://app.kosmi.io/room/@hyperspaceout
|
||||
- **IRC Server**: irc.zeronode.net:6697
|
||||
- **IRC Channel**: #cottongin
|
||||
- **Status**: Both bridges connected and relaying
|
||||
- **Kosmi Room**: Configured via `RoomURL` in `matterbridge.toml`
|
||||
- **IRC Server**: Configured via `Server` in `matterbridge.toml`
|
||||
- **IRC Channel**: Configured via gateway `[[gateway.inout]]`
|
||||
|
||||
## Test 1: Kosmi → IRC
|
||||
## Test 1: Kosmi --> IRC
|
||||
|
||||
### Steps:
|
||||
1. Open the Kosmi room in your browser: https://app.kosmi.io/room/@hyperspaceout
|
||||
2. Type a message in the chat (e.g., "Test message from Kosmi 🚀")
|
||||
### Steps
|
||||
|
||||
1. Open your Kosmi room in a browser
|
||||
2. Type a test message (e.g., "Test message from Kosmi")
|
||||
3. Press Enter to send
|
||||
|
||||
### Expected Result:
|
||||
- The message should appear in IRC channel #cottongin
|
||||
- The logs will show:
|
||||
```
|
||||
level=info msg="📨 Received message from Kosmi: ..." prefix=kosmi
|
||||
level=info msg="Relaying message from kosmi to irc"
|
||||
```
|
||||
### Expected Logs
|
||||
|
||||
### How to Verify:
|
||||
Connect to IRC and join #cottongin:
|
||||
```bash
|
||||
# Using an IRC client (e.g., irssi, weechat, hexchat)
|
||||
/connect irc.zeronode.net 6697
|
||||
/join #cottongin
|
||||
```
|
||||
INFO Received message from Kosmi: [<timestamp>] username: message text
|
||||
DEBUG Forwarding to Matterbridge channel=main account=kosmi.hyperspaceout
|
||||
```
|
||||
|
||||
Or watch the Docker logs:
|
||||
```bash
|
||||
docker-compose logs -f | grep -E "(Received|Relaying|Sent)"
|
||||
### Verification
|
||||
|
||||
The message should appear in your IRC channel with the configured `RemoteNickFormat`, typically:
|
||||
```
|
||||
[kosmi] <username> Test message from Kosmi
|
||||
```
|
||||
|
||||
---
|
||||
## Test 2: IRC --> Kosmi
|
||||
|
||||
## Test 2: IRC → Kosmi
|
||||
### Steps
|
||||
|
||||
### Steps:
|
||||
1. Connect to IRC: `irc.zeronode.net:6697`
|
||||
2. Join channel: `/join #cottongin`
|
||||
3. Send a message: "Test message from IRC 👋"
|
||||
1. Connect to your IRC server and join the configured channel
|
||||
2. Send a test message (e.g., "Test message from IRC")
|
||||
|
||||
### Expected Result:
|
||||
- The message should appear in the Kosmi chat room
|
||||
- The logs will show:
|
||||
```
|
||||
level=info msg="Received message from IRC: ..." prefix=irc
|
||||
level=info msg="Relaying message from irc to kosmi"
|
||||
level=info msg="✅ Sent message via Playwright-assisted WebSocket: ..." prefix=kosmi
|
||||
```
|
||||
### Expected Logs
|
||||
|
||||
### How to Verify:
|
||||
- Open Kosmi room in browser: https://app.kosmi.io/room/@hyperspaceout
|
||||
- Check if your IRC message appears in the chat
|
||||
```
|
||||
DEBUG <= Sending message from #channel on irc.account to gateway
|
||||
DEBUG => Sending message to Kosmi
|
||||
```
|
||||
|
||||
---
|
||||
### Verification
|
||||
|
||||
## Watch Logs in Real-Time
|
||||
The message should appear in the Kosmi room with the configured format, typically:
|
||||
```
|
||||
[irc] <username> Test message from IRC
|
||||
```
|
||||
|
||||
## Test 3: Jackbox Vote Detection (if enabled)
|
||||
|
||||
### Steps
|
||||
|
||||
1. In IRC or Kosmi, type: `thisgame++`
|
||||
2. Check bot logs
|
||||
|
||||
### Expected Logs
|
||||
|
||||
```
|
||||
DEBUG Detected vote from username: up (ticker="")
|
||||
```
|
||||
|
||||
## Test 4: IRC Commands
|
||||
|
||||
### Steps
|
||||
|
||||
1. In IRC, type: `!votes`
|
||||
2. Check for broadcast response
|
||||
|
||||
### Expected Response (if active session)
|
||||
|
||||
```
|
||||
🗳️ Game Title • Today: X👍 Y👎 (Score: Z) • All-time: X👍 Y👎 (Score: Z)
|
||||
```
|
||||
|
||||
## Watching Logs
|
||||
|
||||
```bash
|
||||
# All logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Only message-related logs
|
||||
docker-compose logs -f | grep -E "(message|Message|Received|Sent|Relaying)"
|
||||
# Message-related logs only
|
||||
docker-compose logs -f | grep -E "(Received|Sending|Forwarding|Detected)"
|
||||
|
||||
# Last 50 lines
|
||||
docker-compose logs --tail=50
|
||||
```
|
||||
|
||||
---
|
||||
## Success Criteria
|
||||
|
||||
## Quick IRC Connection Methods
|
||||
|
||||
### Method 1: Web IRC Client
|
||||
1. Go to: https://web.libera.chat/
|
||||
2. Connect to: irc.zeronode.net (port 6697, SSL)
|
||||
3. Join: #cottongin
|
||||
|
||||
### Method 2: Command-Line (irssi)
|
||||
```bash
|
||||
# Install irssi (if not installed)
|
||||
brew install irssi # macOS
|
||||
# or
|
||||
apt-get install irssi # Linux
|
||||
|
||||
# Connect
|
||||
irssi -c irc.zeronode.net -p 6697
|
||||
/join #cottongin
|
||||
```
|
||||
|
||||
### Method 3: Command-Line (nc for quick test)
|
||||
```bash
|
||||
# Simple netcat connection (read-only)
|
||||
openssl s_client -connect irc.zeronode.net:6697
|
||||
# Then type:
|
||||
NICK testuser
|
||||
USER testuser 0 * :Test User
|
||||
JOIN #cottongin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What You Should See
|
||||
|
||||
### In Docker Logs (Normal Operation):
|
||||
|
||||
```
|
||||
✅ WebSocket established and ready!
|
||||
✅ Native client fully connected!
|
||||
Successfully connected to Kosmi
|
||||
Connection succeeded (IRC)
|
||||
irc.libera: joining #cottongin
|
||||
Gateway(s) started successfully. Now relaying messages
|
||||
```
|
||||
|
||||
### When a Message is Relayed (Kosmi → IRC):
|
||||
|
||||
```
|
||||
level=info msg="📨 Received message from Kosmi: username: message text" prefix=kosmi
|
||||
level=info msg="Handling message from kosmi.hyperspaceout" prefix=router
|
||||
level=info msg="Relaying message to irc.libera" prefix=router
|
||||
level=info msg="Sent message to #cottongin" prefix=irc
|
||||
```
|
||||
|
||||
### When a Message is Relayed (IRC → Kosmi):
|
||||
|
||||
```
|
||||
level=info msg="Received message from #cottongin: username: message text" prefix=irc
|
||||
level=info msg="Handling message from irc.libera" prefix=router
|
||||
level=info msg="Relaying message to kosmi.hyperspaceout" prefix=router
|
||||
level=info msg="✅ Sent message via Playwright-assisted WebSocket: message text" prefix=kosmi
|
||||
```
|
||||
|
||||
---
|
||||
1. Messages sent in Kosmi appear in IRC
|
||||
2. Messages sent in IRC appear in Kosmi
|
||||
3. Usernames are displayed correctly with bridge prefix
|
||||
4. Messages appear within 1-2 seconds
|
||||
5. No errors in logs during normal relay
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Messages Appearing
|
||||
|
||||
1. **Check bridge is running**:
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
Should show `kosmi-irc-relay` as "Up"
|
||||
|
||||
2. **Check logs for errors**:
|
||||
```bash
|
||||
docker-compose logs --tail=100
|
||||
```
|
||||
|
||||
3. **Verify connections**:
|
||||
```bash
|
||||
docker-compose logs | grep -E "(Connected|connected|joined)"
|
||||
```
|
||||
Should show both Kosmi WebSocket and IRC connected
|
||||
|
||||
4. **Restart if needed**:
|
||||
```bash
|
||||
docker-compose restart
|
||||
docker-compose logs -f
|
||||
```
|
||||
1. Check the container is running: `docker-compose ps`
|
||||
2. Check for errors: `docker-compose logs --tail=100`
|
||||
3. Verify both bridges are connected (look for success messages)
|
||||
4. Restart if needed: `docker-compose restart`
|
||||
|
||||
### Messages Only Going One Direction
|
||||
|
||||
- **If Kosmi → IRC works but IRC → Kosmi doesn't**:
|
||||
- Check Kosmi WebSocket is still connected: `docker-compose logs | grep WebSocket`
|
||||
- The native client might have disconnected
|
||||
- Restart: `docker-compose restart`
|
||||
|
||||
- **If IRC → Kosmi works but Kosmi → IRC doesn't**:
|
||||
- Check IRC connection: `docker-compose logs | grep irc`
|
||||
- Verify IRC authentication
|
||||
- **Kosmi --> IRC works, IRC --> Kosmi doesn't**: Check Kosmi WebSocket is connected
|
||||
- **IRC --> Kosmi works, Kosmi --> IRC doesn't**: Check IRC connection status
|
||||
|
||||
### Message Formatting Issues
|
||||
|
||||
Messages are formatted as:
|
||||
```
|
||||
<username> message text
|
||||
```
|
||||
Message format is controlled by `RemoteNickFormat` in each bridge's config section. Default: `[{PROTOCOL}] <{NICK}> `
|
||||
|
||||
This is configurable in `matterbridge.toml` under the gateway settings.
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
✅ **Full Success** means:
|
||||
1. Message sent in Kosmi appears in IRC #cottongin
|
||||
2. Message sent in IRC #cottongin appears in Kosmi room
|
||||
3. Usernames are preserved/displayed correctly
|
||||
4. Messages appear within 1-2 seconds
|
||||
5. No errors in logs
|
||||
|
||||
---
|
||||
|
||||
## Next Steps After Testing
|
||||
|
||||
Once both directions work:
|
||||
|
||||
1. **Monitor stability** - Let it run for a few hours
|
||||
2. **Check memory usage**: `docker stats kosmi-irc-relay`
|
||||
3. **Review message formatting** - Adjust in `matterbridge.toml` if needed
|
||||
4. **Set up log rotation** - For long-term operation
|
||||
5. **Consider adding more channels** - Edit `matterbridge.toml`
|
||||
|
||||
---
|
||||
|
||||
## Quick Commands Reference
|
||||
## Quick Commands
|
||||
|
||||
```bash
|
||||
# Start in background
|
||||
docker-compose up -d
|
||||
|
||||
# Follow logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Stop
|
||||
docker-compose down
|
||||
|
||||
# Restart
|
||||
docker-compose restart
|
||||
|
||||
# Rebuild
|
||||
docker-compose up --build -d
|
||||
|
||||
# Check status
|
||||
docker-compose ps
|
||||
|
||||
# View resource usage
|
||||
docker stats kosmi-irc-relay
|
||||
docker-compose up -d # Start
|
||||
docker-compose logs -f # Follow logs
|
||||
docker-compose down # Stop
|
||||
docker-compose restart # Restart
|
||||
docker-compose ps # Status
|
||||
docker stats kosmi-irc-relay # Resource usage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ready to Test!
|
||||
|
||||
The bridge is **running and connected**. You can start testing immediately:
|
||||
|
||||
1. 🌐 Open: https://app.kosmi.io/room/@hyperspaceout
|
||||
2. 💬 Send a test message
|
||||
3. 👀 Watch the logs: `docker-compose logs -f`
|
||||
4. 🔗 Connect to IRC and verify the message appeared
|
||||
5. 🔄 Send a message from IRC and check Kosmi
|
||||
|
||||
Good luck! 🎉
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ The Kosmi bridge now caches JWT authentication tokens to avoid repeated browser
|
||||
|
||||
### Token Cache Location
|
||||
|
||||
The token cache is stored in a file called `kosmi_token_cache.json` in the following locations:
|
||||
The token cache is stored in a file called `kosmi_token_cache.json`:
|
||||
|
||||
- **Docker (Production)**: `./data/kosmi_token_cache.json` (mounted from your host machine)
|
||||
- **Local Development**: `~/.matterbridge/kosmi_token_cache.json`
|
||||
- **Docker**: `./data/kosmi_token_cache.json` (mounted from host via `MATTERBRIDGE_DATA_DIR=/app/data`)
|
||||
- **Local**: `~/.matterbridge/kosmi_token_cache.json` (or `$MATTERBRIDGE_DATA_DIR/kosmi_token_cache.json` if set)
|
||||
|
||||
### Token Cache Structure
|
||||
|
||||
@@ -29,9 +29,9 @@ The cache file contains:
|
||||
### Token Lifecycle
|
||||
|
||||
1. **On Startup**: The bridge checks for a cached token
|
||||
- If found and valid, it uses the cached token (no browser automation needed)
|
||||
- If expired or expiring within 7 days, it performs fresh authentication
|
||||
- If not found, it performs fresh authentication
|
||||
- If found and valid, it uses the cached token (no browser launch needed)
|
||||
- If expired or expiring within 7 days, it performs fresh browser authentication
|
||||
- If not found, it performs fresh browser authentication
|
||||
|
||||
2. **Token Expiry**: Kosmi JWT tokens expire after 1 year
|
||||
- The bridge automatically refreshes tokens that expire within 7 days
|
||||
|
||||
Reference in New Issue
Block a user