chore: cleanup repo
This commit is contained in:
414
docs/setup/BOT_features.md
Normal file
414
docs/setup/BOT_features.md
Normal file
@@ -0,0 +1,414 @@
|
||||
# Bot Integration Guide
|
||||
|
||||
This guide explains how to integrate your bot with the Jackbox Game Picker API for live voting and game notifications.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
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)
|
||||
|
||||
---
|
||||
|
||||
## Live Voting (Bot → API)
|
||||
|
||||
Your bot can send real-time votes to the API when it detects "thisgame++" or "thisgame--" in Kosmi chat.
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
POST /api/votes/live
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
Requires JWT token in Authorization header:
|
||||
|
||||
```
|
||||
Authorization: Bearer YOUR_JWT_TOKEN
|
||||
```
|
||||
|
||||
### Request Body
|
||||
|
||||
```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",
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Webhook Headers
|
||||
|
||||
The API sends the following headers with each webhook:
|
||||
|
||||
- `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`
|
||||
|
||||
### Signature Verification
|
||||
|
||||
**IMPORTANT**: Always verify the webhook signature to ensure the request is authentic.
|
||||
|
||||
```javascript
|
||||
const crypto = require('crypto');
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
- 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
|
||||
|
||||
### Webhooks Not Being Received
|
||||
|
||||
- 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
|
||||
|
||||
### 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
|
||||
|
||||
277
docs/setup/BROWSER_AUTH_GUIDE.md
Normal file
277
docs/setup/BROWSER_AUTH_GUIDE.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# 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!
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Configure Email/Password
|
||||
Edit `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
Email="your-email@example.com"
|
||||
Password="your-password"
|
||||
```
|
||||
|
||||
### 2. Run the Bot
|
||||
```bash
|
||||
./irc-kosmi-relay -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)
|
||||
|
||||
## How It Works
|
||||
|
||||
### 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
|
||||
|
||||
### 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)
|
||||
|
||||
### Option 3: Anonymous
|
||||
```toml
|
||||
# Leave both empty
|
||||
Email=""
|
||||
Password=""
|
||||
Token=""
|
||||
```
|
||||
- ✅ No setup needed
|
||||
- ❌ Limited permissions
|
||||
- ❌ Can't access private rooms
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Browser automation failed"
|
||||
**Possible causes:**
|
||||
1. Chrome/Chromium not installed
|
||||
2. Chrome/Chromium not in PATH
|
||||
3. Network issues
|
||||
4. Kosmi website changed
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# Check if Chrome is installed
|
||||
which chromium || which google-chrome || which chrome
|
||||
|
||||
# Install Chrome (macOS)
|
||||
brew install chromium
|
||||
|
||||
# Install Chrome (Ubuntu/Debian)
|
||||
sudo apt install chromium-browser
|
||||
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# Set environment variable for debugging
|
||||
export CHROMEDP_DISABLE_GPU=1
|
||||
|
||||
# Or run with visible browser (for debugging)
|
||||
export CHROMEDP_NO_HEADLESS=1
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Credential Storage
|
||||
- Credentials are stored in **plain text** in `matterbridge.toml`
|
||||
- Ensure config file has restrictive 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 |
|
||||
|
||||
## Logs to Expect
|
||||
|
||||
### Successful Login
|
||||
```
|
||||
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 Successfully connected to Kosmi
|
||||
```
|
||||
|
||||
### Daily Token Check
|
||||
```
|
||||
DEBUG Checking token expiry...
|
||||
DEBUG Token check complete
|
||||
```
|
||||
|
||||
### Token Refresh (when expiring)
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
## 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**.
|
||||
|
||||
534
docs/setup/DOCKER_DEPLOYMENT.md
Normal file
534
docs/setup/DOCKER_DEPLOYMENT.md
Normal file
@@ -0,0 +1,534 @@
|
||||
# Docker Deployment Guide
|
||||
|
||||
Complete guide for deploying the Kosmi-IRC bridge using Docker.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Edit configuration
|
||||
nano matterbridge.toml
|
||||
|
||||
# 2. Build and run
|
||||
docker-compose up -d
|
||||
|
||||
# 3. View logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker (20.10+)
|
||||
- Docker Compose (1.29+)
|
||||
- A Kosmi room URL
|
||||
- IRC server access
|
||||
|
||||
## Step-by-Step Setup
|
||||
|
||||
### 1. Configure the Bridge
|
||||
|
||||
Edit `matterbridge.toml` and update these settings:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@YOUR_ROOM" # ← Change this
|
||||
Debug=false
|
||||
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667" # ← Change to your IRC server
|
||||
Nick="kosmi-relay" # ← Change your bot's nickname
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.hyperspaceout"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#your-channel" # ← Change to your IRC channel
|
||||
```
|
||||
|
||||
### 2. Build the Docker Image
|
||||
|
||||
```bash
|
||||
docker-compose build
|
||||
```
|
||||
|
||||
This will:
|
||||
- Install Chrome/Chromium in the container
|
||||
- Build the Matterbridge binary with Kosmi support
|
||||
- Create an optimized production image
|
||||
|
||||
**Build time**: ~5-10 minutes (first time)
|
||||
|
||||
### 3. Run the Container
|
||||
|
||||
```bash
|
||||
# Start in detached mode
|
||||
docker-compose up -d
|
||||
|
||||
# Or start with logs visible
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
### 4. Verify It's Working
|
||||
|
||||
```bash
|
||||
# Check container status
|
||||
docker-compose ps
|
||||
|
||||
# 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
|
||||
```
|
||||
|
||||
### 5. Test Message Relay
|
||||
|
||||
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`
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
```yaml
|
||||
services:
|
||||
matterbridge:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: kosmi-irc-relay
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./matterbridge.toml:/app/matterbridge.toml:ro
|
||||
- ./logs:/app/logs
|
||||
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
|
||||
```
|
||||
|
||||
### 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` |
|
||||
|
||||
### Volume Mounts
|
||||
|
||||
| Host Path | Container Path | Purpose |
|
||||
|-----------|----------------|---------|
|
||||
| `./matterbridge.toml` | `/app/matterbridge.toml` | Configuration file (read-only) |
|
||||
| `./logs` | `/app/logs` | Log files (optional) |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
**Check logs**:
|
||||
```bash
|
||||
docker-compose logs
|
||||
```
|
||||
|
||||
**Common issues**:
|
||||
- Configuration file syntax error
|
||||
- Missing `matterbridge.toml`
|
||||
- Port already in use
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
### Chrome/Chromium Not Found
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
ERROR Chrome binary not found
|
||||
```
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
### Messages Not Relaying
|
||||
|
||||
**Symptoms**:
|
||||
- Container running
|
||||
- Both bridges connected
|
||||
- But messages don't appear
|
||||
|
||||
**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")
|
||||
```
|
||||
|
||||
### High Memory Usage
|
||||
|
||||
**Symptoms**:
|
||||
- Container using >500MB RAM
|
||||
- System slowdown
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Add memory limits to docker-compose.yml
|
||||
services:
|
||||
matterbridge:
|
||||
mem_limit: 512m
|
||||
mem_reservation: 256m
|
||||
|
||||
# Restart
|
||||
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
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### Using Kubernetes
|
||||
|
||||
Create `kosmi-relay.yaml`:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Deploy:
|
||||
```bash
|
||||
kubectl create configmap matterbridge-config --from-file=matterbridge.toml
|
||||
kubectl apply -f kosmi-relay.yaml
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
#### Health Check
|
||||
|
||||
Add to `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
matterbridge:
|
||||
healthcheck:
|
||||
test: ["CMD", "pgrep", "-f", "matterbridge"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
```
|
||||
|
||||
#### Prometheus Metrics
|
||||
|
||||
Matterbridge doesn't expose Prometheus metrics by default, but you can monitor:
|
||||
|
||||
```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! 🎉
|
||||
|
||||
129
docs/setup/DOCKER_QUICKSTART.md
Normal file
129
docs/setup/DOCKER_QUICKSTART.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Docker Quick Start - 5 Minutes to Running Bridge
|
||||
|
||||
Get your Kosmi-IRC bridge running in Docker in 5 minutes!
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker installed
|
||||
- Docker Compose installed
|
||||
- A Kosmi room URL
|
||||
- An IRC channel
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Edit Configuration (2 minutes)
|
||||
|
||||
Open `matterbridge.toml` and change these 3 things:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
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
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#your-channel" # ← Your IRC channel
|
||||
```
|
||||
|
||||
### 2. Build & Run (2 minutes)
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 3. Check It's Working (1 minute)
|
||||
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
Look for:
|
||||
```
|
||||
INFO Successfully connected to Kosmi via Chrome
|
||||
INFO Successfully connected to IRC
|
||||
INFO Gateway(s) started successfully
|
||||
```
|
||||
|
||||
### 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!
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Stop bridge
|
||||
docker-compose down
|
||||
|
||||
# Restart bridge
|
||||
docker-compose restart
|
||||
|
||||
# Rebuild after code changes
|
||||
docker-compose build && docker-compose up -d
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Connection failed"
|
||||
|
||||
1. Check your configuration:
|
||||
```bash
|
||||
cat matterbridge.toml | grep -E "RoomURL|Server|channel"
|
||||
```
|
||||
|
||||
2. Enable debug logging:
|
||||
- Edit `matterbridge.toml`: Set `Debug=true`
|
||||
- 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"
|
||||
```
|
||||
|
||||
2. Verify channel names:
|
||||
- Kosmi channel must be `"main"`
|
||||
- IRC channel must include `#` (e.g., `"#your-channel"`)
|
||||
|
||||
## 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! 🚀
|
||||
|
||||
203
docs/setup/JACKBOX_INTEGRATION.md
Normal file
203
docs/setup/JACKBOX_INTEGRATION.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# 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.
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Vote Detection
|
||||
The relay automatically detects when users vote on games using the `thisgame++` or `thisgame--` syntax in either Kosmi or IRC chat.
|
||||
|
||||
**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!
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Add the following section to your `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[jackbox]
|
||||
# Enable Jackbox integration for vote detection and game notifications
|
||||
Enabled=true
|
||||
|
||||
# Jackbox API URL
|
||||
APIURL="http://localhost:5000"
|
||||
|
||||
# Admin password for API authentication
|
||||
AdminPassword="your_admin_password_here"
|
||||
|
||||
# Webhook server port (for receiving game notifications)
|
||||
WebhookPort=3001
|
||||
|
||||
# Webhook secret for signature verification
|
||||
WebhookSecret="your_webhook_secret_here"
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
- **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)
|
||||
|
||||
## Setup Steps
|
||||
|
||||
### 1. Configure the Relay
|
||||
|
||||
Edit `matterbridge.toml` and add the Jackbox configuration section with your API URL, admin password, and webhook secret.
|
||||
|
||||
### 2. Register the Webhook
|
||||
|
||||
After starting the relay, register the webhook with the Jackbox API:
|
||||
|
||||
```bash
|
||||
# Get JWT token
|
||||
curl -X POST "http://localhost:5000/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"apiKey": "your_admin_password"}'
|
||||
|
||||
# Register webhook (use the JWT token from above)
|
||||
curl -X POST "http://localhost:5000/api/webhooks" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Kosmi/IRC Relay",
|
||||
"url": "http://your-relay-host:3001/webhook/jackbox",
|
||||
"secret": "your_webhook_secret_here",
|
||||
"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`.
|
||||
|
||||
### 3. Test the Integration
|
||||
|
||||
#### Test Vote Detection
|
||||
|
||||
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
|
||||
|
||||
#### Test Game Notifications
|
||||
|
||||
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>!`
|
||||
|
||||
## 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
|
||||
|
||||
### Notification Flow
|
||||
|
||||
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)
|
||||
|
||||
## Security
|
||||
|
||||
### 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)
|
||||
|
||||
## 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
|
||||
|
||||
**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
|
||||
|
||||
### Webhooks Not Being Received
|
||||
|
||||
**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
|
||||
|
||||
**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
|
||||
|
||||
### 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!
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
225
docs/setup/MUTE_CONTROL.md
Normal file
225
docs/setup/MUTE_CONTROL.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Mute Control for Jackbox Announcements
|
||||
|
||||
The bot supports muting Jackbox announcements without restarting. This is useful when you want to test the Jackbox API or run games without spamming the chat.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Start the bot muted
|
||||
- ✅ Toggle mute/unmute while running
|
||||
- ✅ Works in terminal and Docker
|
||||
- ✅ Vote detection still works (votes are sent to API even when muted)
|
||||
- ✅ Only Jackbox announcements are muted (IRC ↔ Kosmi relay still works)
|
||||
|
||||
## Starting Muted
|
||||
|
||||
### Terminal
|
||||
```bash
|
||||
./matterbridge -conf matterbridge.toml -muted
|
||||
```
|
||||
|
||||
### Docker
|
||||
Update `docker-compose.yml`:
|
||||
```yaml
|
||||
services:
|
||||
kosmi-irc-relay:
|
||||
command: ["/app/matterbridge", "-conf", "/app/matterbridge.toml", "-muted"]
|
||||
```
|
||||
|
||||
Or run with override:
|
||||
```bash
|
||||
docker-compose run --rm kosmi-irc-relay /app/matterbridge -conf /app/matterbridge.toml -muted
|
||||
```
|
||||
|
||||
## Toggling Mute While Running
|
||||
|
||||
The bot listens for the `SIGUSR1` signal to toggle mute status.
|
||||
|
||||
### Terminal (Local Process)
|
||||
|
||||
**Find the process ID:**
|
||||
```bash
|
||||
ps aux | grep matterbridge
|
||||
# or
|
||||
pgrep matterbridge
|
||||
```
|
||||
|
||||
**Toggle mute:**
|
||||
```bash
|
||||
kill -SIGUSR1 <pid>
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
$ pgrep matterbridge
|
||||
12345
|
||||
|
||||
$ kill -SIGUSR1 12345
|
||||
# Bot logs: 🔇 Jackbox announcements MUTED
|
||||
|
||||
$ kill -SIGUSR1 12345
|
||||
# Bot logs: 🔊 Jackbox announcements UNMUTED
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
**Find the container name:**
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
|
||||
**Toggle mute:**
|
||||
```bash
|
||||
docker kill -s SIGUSR1 <container_name>
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND NAMES
|
||||
abc123def456 kosmi-irc-relay "/app/matterbridge -…" kosmi-irc-relay
|
||||
|
||||
$ docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
# Bot logs: 🔇 Jackbox announcements MUTED
|
||||
|
||||
$ docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
# Bot logs: 🔊 Jackbox announcements UNMUTED
|
||||
```
|
||||
|
||||
## What Gets Muted?
|
||||
|
||||
### Muted Messages ❌
|
||||
- 🎮 Game Night is starting!
|
||||
- 🎮 Coming up next: [Game] - Room Code [CODE]
|
||||
- 🗳️ Final votes for [Game]: X👍 Y👎
|
||||
- 🌙 Game Night has ended! Thanks for playing!
|
||||
|
||||
### Still Works ✅
|
||||
- Vote detection (`thisgame++` / `thisgame--`)
|
||||
- Votes sent to Jackbox API
|
||||
- IRC ↔ Kosmi message relay
|
||||
- All other bot functionality
|
||||
|
||||
## Log Messages
|
||||
|
||||
**When starting muted:**
|
||||
```
|
||||
INFO Jackbox announcements started MUTED (use SIGUSR1 to toggle)
|
||||
INFO Signal handler ready: Send SIGUSR1 to toggle mute (kill -SIGUSR1 <pid> or docker kill -s SIGUSR1 <container>)
|
||||
```
|
||||
|
||||
**When toggling to muted:**
|
||||
```
|
||||
WARN 🔇 Jackbox announcements MUTED
|
||||
```
|
||||
|
||||
**When toggling to unmuted:**
|
||||
```
|
||||
INFO 🔊 Jackbox announcements UNMUTED
|
||||
```
|
||||
|
||||
**When a message is suppressed:**
|
||||
```
|
||||
DEBUG Jackbox message suppressed (muted): 🎮 Coming up next: Drawful 2 - Room Code C0D3
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Testing Jackbox API
|
||||
```bash
|
||||
# Start muted
|
||||
docker-compose up -d
|
||||
|
||||
# Test vote detection without spamming chat
|
||||
# (votes are still sent to API)
|
||||
# In chat: "thisgame++"
|
||||
|
||||
# Check logs to see votes are being processed
|
||||
docker logs kosmi-irc-relay -f
|
||||
|
||||
# Unmute when ready
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
```
|
||||
|
||||
### Running Private Games
|
||||
```bash
|
||||
# Mute during game setup
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
|
||||
# Play games without announcements
|
||||
# (useful if you're testing or running a private session)
|
||||
|
||||
# Unmute for public game night
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
```
|
||||
|
||||
### Quick Mute Script
|
||||
Create a helper script `mute-toggle.sh`:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
docker kill -s SIGUSR1 kosmi-irc-relay
|
||||
docker logs kosmi-irc-relay --tail 1
|
||||
```
|
||||
|
||||
Make it executable:
|
||||
```bash
|
||||
chmod +x mute-toggle.sh
|
||||
```
|
||||
|
||||
Use it:
|
||||
```bash
|
||||
./mute-toggle.sh
|
||||
# 🔇 Jackbox announcements MUTED
|
||||
|
||||
./mute-toggle.sh
|
||||
# 🔊 Jackbox announcements UNMUTED
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Signal not working in Docker
|
||||
Make sure your Docker container is running:
|
||||
```bash
|
||||
docker ps | grep kosmi-irc-relay
|
||||
```
|
||||
|
||||
If the container is restarting, check logs:
|
||||
```bash
|
||||
docker logs kosmi-irc-relay
|
||||
```
|
||||
|
||||
### Signal not working locally
|
||||
Make sure the process is running:
|
||||
```bash
|
||||
ps aux | grep matterbridge
|
||||
```
|
||||
|
||||
Check you're using the correct PID:
|
||||
```bash
|
||||
pgrep -f matterbridge
|
||||
```
|
||||
|
||||
### Mute state not persisting after restart
|
||||
Mute state is **not persisted** across restarts. If you restart the bot:
|
||||
- Without `-muted` flag: Bot starts unmuted
|
||||
- With `-muted` flag: Bot starts muted
|
||||
|
||||
This is intentional - you probably want announcements by default.
|
||||
|
||||
## Advanced: Systemd Service
|
||||
|
||||
If running as a systemd service, you can use `systemctl`:
|
||||
|
||||
**Create a mute toggle script:**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /usr/local/bin/matterbridge-mute-toggle
|
||||
PID=$(systemctl show -p MainPID --value matterbridge.service)
|
||||
kill -SIGUSR1 $PID
|
||||
journalctl -u matterbridge.service -n 1 --no-pager
|
||||
```
|
||||
|
||||
**Use it:**
|
||||
```bash
|
||||
sudo /usr/local/bin/matterbridge-mute-toggle
|
||||
```
|
||||
|
||||
301
docs/setup/QUICKSTART.md
Normal file
301
docs/setup/QUICKSTART.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# Quick Start Guide
|
||||
|
||||
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
|
||||
- (Optional) IRC server access for full relay
|
||||
|
||||
## Step 1: Test Kosmi Connection
|
||||
|
||||
First, verify the bridge can connect to Kosmi:
|
||||
|
||||
```bash
|
||||
# Build the test program
|
||||
go build -o test-kosmi ./cmd/test-kosmi
|
||||
|
||||
# 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
|
||||
|
||||
# Build
|
||||
go build
|
||||
```
|
||||
|
||||
### Option B: Use This Repository
|
||||
|
||||
This repository has a minimal Matterbridge structure. To add IRC support:
|
||||
|
||||
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/
|
||||
```
|
||||
|
||||
2. Update dependencies:
|
||||
```bash
|
||||
cd /path/to/irc-kosmi-relay
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
## Step 3: Configure
|
||||
|
||||
Edit `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
# Kosmi configuration
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
|
||||
# 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
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.hyperspaceout"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#your-channel"
|
||||
```
|
||||
|
||||
**Important**: Replace:
|
||||
- `https://app.kosmi.io/room/@hyperspaceout` with your Kosmi room URL
|
||||
- `#your-channel` with your IRC channel
|
||||
|
||||
## Step 4: Run
|
||||
|
||||
```bash
|
||||
./matterbridge -conf matterbridge.toml
|
||||
```
|
||||
|
||||
Or with debug logging:
|
||||
```bash
|
||||
./matterbridge -conf matterbridge.toml -debug
|
||||
```
|
||||
|
||||
## Step 5: Test the Relay
|
||||
|
||||
1. **Kosmi → IRC**: Send a message in Kosmi. It should appear in IRC as:
|
||||
```
|
||||
[Kosmi] <username> your message here
|
||||
```
|
||||
|
||||
2. **IRC → Kosmi**: Send a message in IRC. It should appear in Kosmi as:
|
||||
```
|
||||
[IRC] <username> your message here
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Test program doesn't connect
|
||||
|
||||
**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
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Test Chrome installation
|
||||
which google-chrome chromium chromium-browser
|
||||
|
||||
# Test network connectivity
|
||||
curl -I https://app.kosmi.io
|
||||
|
||||
# Run with debug
|
||||
./test-kosmi -room "YOUR_ROOM_URL" -debug
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
## 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`.
|
||||
|
||||
237
docs/setup/QUICK_REFERENCE.md
Normal file
237
docs/setup/QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# Quick Reference Guide
|
||||
|
||||
## Testing the Bridge
|
||||
|
||||
### Build and Run Test Program
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### When Messages Arrive
|
||||
|
||||
```
|
||||
INFO Processing 1 messages from queue
|
||||
INFO Received message: [00:02:51] username: [Kosmi] <username> message text
|
||||
```
|
||||
|
||||
## 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 |
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: "No WebSocket connection detected yet"
|
||||
|
||||
**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"
|
||||
|
||||
## Configuration
|
||||
|
||||
### Minimal Test Configuration
|
||||
|
||||
```toml
|
||||
[kosmi.test]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
Debug=true
|
||||
```
|
||||
|
||||
### Full Matterbridge Configuration
|
||||
|
||||
```toml
|
||||
# Kosmi
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
|
||||
# IRC
|
||||
[irc.libera]
|
||||
Server="irc.libera.chat:6667"
|
||||
Nick="kosmi-relay"
|
||||
UseTLS=false
|
||||
|
||||
# Gateway
|
||||
[[gateway]]
|
||||
name="kosmi-irc"
|
||||
enable=true
|
||||
|
||||
[[gateway.inout]]
|
||||
account="kosmi.hyperspaceout"
|
||||
channel="main"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="irc.libera"
|
||||
channel="#your-channel"
|
||||
```
|
||||
|
||||
## Message Format
|
||||
|
||||
### Kosmi → IRC
|
||||
|
||||
```
|
||||
[Kosmi] <username> message text
|
||||
```
|
||||
|
||||
### IRC → Kosmi
|
||||
|
||||
```
|
||||
[IRC] <username> message text
|
||||
```
|
||||
|
||||
## 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 |
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
### WebSocket Hook Injection
|
||||
|
||||
**MUST** use `page.AddScriptToEvaluateOnNewDocument` to inject **before page load**:
|
||||
|
||||
```go
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
_, err := page.AddScriptToEvaluateOnNewDocument(script).Do(ctx)
|
||||
return err
|
||||
})
|
||||
```
|
||||
|
||||
### Hook Script
|
||||
|
||||
Wraps `window.WebSocket` constructor to intercept all WebSocket connections:
|
||||
|
||||
```javascript
|
||||
window.WebSocket = function(url, protocols) {
|
||||
const socket = new OriginalWebSocket(url, protocols);
|
||||
// ... interception logic ...
|
||||
return socket;
|
||||
};
|
||||
```
|
||||
|
||||
## Debugging Commands
|
||||
|
||||
```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 ./...
|
||||
```
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- **Chrome Startup**: ~1-2 seconds
|
||||
- **Page Load**: ~1-2 seconds
|
||||
- **Message Latency**: ~100-500ms
|
||||
- **Memory Usage**: ~100-200MB (Chrome process)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- 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 Considerations
|
||||
|
||||
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)
|
||||
|
||||
## 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
|
||||
|
||||
94
docs/setup/QUICK_START_AUTH.md
Normal file
94
docs/setup/QUICK_START_AUTH.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Quick Start: Testing Authentication
|
||||
|
||||
## Step 1: Create Bot Account
|
||||
|
||||
1. Go to https://app.kosmi.io
|
||||
2. Sign up with a dedicated email (e.g., `your-bot@example.com`)
|
||||
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
|
||||
|
||||
Edit `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[kosmi.hyperspaceout]
|
||||
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
|
||||
Email="your-bot@example.com"
|
||||
Password="your-secure-password"
|
||||
```
|
||||
|
||||
## Step 4: Test Connection
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [ ] Bot account created manually
|
||||
- [ ] Credentials documented securely
|
||||
- [ ] Monitor script captured login flow
|
||||
- [ ] Config file updated with credentials
|
||||
- [ ] Bridge logs show authenticated connection
|
||||
- [ ] Bot display name appears correctly in chat
|
||||
- [ ] Messages relay successfully
|
||||
|
||||
## 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:
|
||||
```bash
|
||||
grep -A 2 "Email=" matterbridge.toml
|
||||
```
|
||||
|
||||
### Token expired
|
||||
|
||||
The bridge should auto-refresh. If not:
|
||||
- Check logs for "Token refresh failed"
|
||||
- Verify credentials are still valid
|
||||
- Try manual login at app.kosmi.io
|
||||
|
||||
## 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.
|
||||
141
docs/setup/ROOM_CODE_IMAGE_FEATURE.md
Normal file
141
docs/setup/ROOM_CODE_IMAGE_FEATURE.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# Room Code Image Feature
|
||||
|
||||
## Overview
|
||||
|
||||
The bot now supports displaying Jackbox room codes as images in Kosmi chat (with fallback to IRC text formatting for IRC chat).
|
||||
|
||||
## How It Works
|
||||
|
||||
### For Kosmi Chat (with `EnableRoomCodeImage=true`)
|
||||
|
||||
1. **Generate**: When a new game is added, the bot generates a PNG image of the room code using a monospace font (black background, white text)
|
||||
2. **Upload**: The image is uploaded to Kosmi's CDN at `https://img.kosmi.io/`
|
||||
3. **Broadcast**: The bot sends two messages:
|
||||
- First: The game announcement (e.g., "🎮 Coming up next: Drawful 2!")
|
||||
- Second: The image URL (Kosmi automatically displays it as a thumbnail)
|
||||
|
||||
### For IRC Chat (always)
|
||||
|
||||
Room codes are displayed with IRC formatting:
|
||||
- **Bold** (`\x02`)
|
||||
- **Monospace** (`\x11`)
|
||||
- **Reset** (`\x0F`)
|
||||
|
||||
Example: `\x02\x11ROOM42\x0F` displays as **`ROOM42`** in IRC clients
|
||||
|
||||
### Fallback Behavior
|
||||
|
||||
If image generation or upload fails:
|
||||
- The bot falls back to IRC text formatting for all chats
|
||||
- An error is logged but the announcement still goes through
|
||||
|
||||
## Configuration
|
||||
|
||||
In `matterbridge.toml`:
|
||||
|
||||
```toml
|
||||
[jackbox]
|
||||
Enabled=true
|
||||
APIURL="https://your-jackbox-api.com"
|
||||
AdminPassword="your-password"
|
||||
UseWebSocket=true
|
||||
EnableRoomCodeImage=false # Set to true to enable image uploads
|
||||
```
|
||||
|
||||
## Files Involved
|
||||
|
||||
### New Files
|
||||
- `bridge/jackbox/roomcode_image.go` - PNG image generation
|
||||
- `bridge/jackbox/image_upload.go` - HTTP upload to Kosmi CDN
|
||||
- `bridge/irc/formatting.go` - IRC formatting helpers
|
||||
- `bridge/kosmi/image_upload.go` - (Duplicate, can be removed)
|
||||
- `KOSMI_IMAGE_UPLOAD.md` - Protocol documentation
|
||||
|
||||
### Modified Files
|
||||
- `bridge/jackbox/websocket_client.go` - Image upload integration
|
||||
- `bridge/jackbox/manager.go` - Config passing
|
||||
- `matterbridge.toml` - Added `EnableRoomCodeImage` setting
|
||||
|
||||
### Test Files
|
||||
- `cmd/test-roomcode-image/main.go` - Test image generation
|
||||
- `cmd/test-image-upload/main.go` - Test full upload flow
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Image Generation
|
||||
```bash
|
||||
./test-roomcode-image
|
||||
# Generates: roomcode_ABCD.png, roomcode_TEST.png, etc.
|
||||
```
|
||||
|
||||
### Test Image Upload
|
||||
```bash
|
||||
./test-image-upload
|
||||
# Generates image, uploads to Kosmi CDN, displays URL
|
||||
```
|
||||
|
||||
### Test Full Integration
|
||||
1. Set `EnableRoomCodeImage=true` in `matterbridge.toml`
|
||||
2. Start the bot: `./matterbridge -conf matterbridge.toml`
|
||||
3. Add a game in the Jackbox Picker with a room code
|
||||
4. Verify:
|
||||
- Kosmi chat shows the game announcement + image thumbnail
|
||||
- IRC chat shows the game announcement + formatted room code text
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Image Specifications
|
||||
- Format: PNG
|
||||
- Size: 200x80 pixels
|
||||
- Background: Black (`#000000`)
|
||||
- Text: White (`#FFFFFF`)
|
||||
- Font: `basicfont.Face7x13` (monospace)
|
||||
- Typical file size: ~400-500 bytes
|
||||
|
||||
### Upload Endpoint
|
||||
- URL: `https://img.kosmi.io/`
|
||||
- Method: `POST`
|
||||
- Content-Type: `multipart/form-data`
|
||||
- Authentication: None required (CORS-protected)
|
||||
- Response: `{"filename": "uuid.webp"}`
|
||||
- Full URL: `https://img.kosmi.io/{filename}`
|
||||
|
||||
### Performance
|
||||
- Image generation: <1ms
|
||||
- Image upload: ~300-600ms (network dependent)
|
||||
- Total delay: Minimal, upload happens asynchronously
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements:
|
||||
1. **Custom fonts**: Use a better monospace font (requires embedding TTF)
|
||||
2. **Styling**: Add Jackbox branding, colors, or borders
|
||||
3. **Caching**: Cache uploaded images to avoid re-uploading identical room codes
|
||||
4. **Retry logic**: Add retry mechanism for failed uploads
|
||||
5. **Compression**: Optimize PNG compression for smaller file sizes
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Images not appearing in Kosmi
|
||||
- Check that `EnableRoomCodeImage=true` in config
|
||||
- Check logs for upload errors
|
||||
- Verify network connectivity to `https://img.kosmi.io/`
|
||||
- Test manually with `./test-image-upload`
|
||||
|
||||
### IRC formatting not working
|
||||
- Ensure your IRC client supports formatting codes
|
||||
- Some clients require enabling "Show colors/formatting"
|
||||
- Fallback: The room code is still readable without formatting
|
||||
|
||||
### Build errors
|
||||
- Ensure all dependencies are installed: `go mod tidy`
|
||||
- Check Go version: Requires Go 1.19+
|
||||
- Verify `golang.org/x/image` is available
|
||||
|
||||
## References
|
||||
|
||||
- [Kosmi Image Upload Protocol](KOSMI_IMAGE_UPLOAD.md)
|
||||
- [IRC Formatting Codes](https://modern.ircdocs.horse/formatting.html)
|
||||
- [Go image package](https://pkg.go.dev/image)
|
||||
- [Jackbox Integration](JACKBOX_INTEGRATION.md)
|
||||
|
||||
255
docs/setup/TEST_INSTRUCTIONS.md
Normal file
255
docs/setup/TEST_INSTRUCTIONS.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# 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
|
||||
|
||||
## 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 🚀")
|
||||
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"
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
Or watch the Docker logs:
|
||||
```bash
|
||||
docker-compose logs -f | grep -E "(Received|Relaying|Sent)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test 2: IRC → Kosmi
|
||||
|
||||
### Steps:
|
||||
1. Connect to IRC: `irc.zeronode.net:6697`
|
||||
2. Join channel: `/join #cottongin`
|
||||
3. Send a message: "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
|
||||
```
|
||||
|
||||
### How to Verify:
|
||||
- Open Kosmi room in browser: https://app.kosmi.io/room/@hyperspaceout
|
||||
- Check if your IRC message appears in the chat
|
||||
|
||||
---
|
||||
|
||||
## Watch Logs in Real-Time
|
||||
|
||||
```bash
|
||||
# All logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Only message-related logs
|
||||
docker-compose logs -f | grep -E "(message|Message|Received|Sent|Relaying)"
|
||||
|
||||
# Last 50 lines
|
||||
docker-compose logs --tail=50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
### Message Formatting Issues
|
||||
|
||||
Messages are formatted as:
|
||||
```
|
||||
<username> message text
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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! 🎉
|
||||
|
||||
181
docs/setup/TOKEN_PERSISTENCE.md
Normal file
181
docs/setup/TOKEN_PERSISTENCE.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# Token Persistence Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The Kosmi bridge now caches JWT authentication tokens to avoid repeated browser automation on every startup. The token is stored in a local directory that persists across Docker container rebuilds and restarts.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Token Cache Location
|
||||
|
||||
The token cache is stored in a file called `kosmi_token_cache.json` in the following locations:
|
||||
|
||||
- **Docker (Production)**: `./data/kosmi_token_cache.json` (mounted from your host machine)
|
||||
- **Local Development**: `~/.matterbridge/kosmi_token_cache.json`
|
||||
|
||||
### Token Cache Structure
|
||||
|
||||
The cache file contains:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"email": "your-email@example.com",
|
||||
"expires_at": "2026-11-02T15:56:23Z",
|
||||
"saved_at": "2025-11-02T15:56:23Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
2. **Token Expiry**: Kosmi JWT tokens expire after 1 year
|
||||
- The bridge automatically refreshes tokens that expire within 7 days
|
||||
- You'll see a log message indicating how long until the token expires
|
||||
|
||||
3. **Token Storage**: After successful authentication, the token is saved to the cache file
|
||||
- File permissions are set to `0600` (read/write for owner only)
|
||||
- The cache directory is created automatically if it doesn't exist
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
### Volume Mount
|
||||
|
||||
The `docker-compose.yml` includes a volume mount for persistent storage:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./data:/app/data:z
|
||||
```
|
||||
|
||||
This mounts the `./data` directory from your host machine into the container at `/app/data`.
|
||||
|
||||
### Environment Variable
|
||||
|
||||
The container sets the `MATTERBRIDGE_DATA_DIR` environment variable:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- MATTERBRIDGE_DATA_DIR=/app/data
|
||||
```
|
||||
|
||||
This tells the bridge where to store persistent data like the token cache.
|
||||
|
||||
## Usage
|
||||
|
||||
### First Run
|
||||
|
||||
On the first run with email/password configured:
|
||||
|
||||
1. The bridge will launch a headless browser
|
||||
2. Authenticate with Kosmi using your credentials
|
||||
3. Extract and cache the JWT token
|
||||
4. Save it to `./data/kosmi_token_cache.json`
|
||||
|
||||
You'll see logs like:
|
||||
|
||||
```
|
||||
level=info msg="No cached token found, performing authentication..."
|
||||
level=info msg="Starting browser automation for authentication..."
|
||||
level=info msg="💾 Token cached (expires in 8760h)"
|
||||
```
|
||||
|
||||
### Subsequent Runs
|
||||
|
||||
On subsequent runs (container restarts, rebuilds, etc.):
|
||||
|
||||
1. The bridge checks the cached token
|
||||
2. If valid, uses it immediately (no browser needed)
|
||||
3. Connects to Kosmi in seconds
|
||||
|
||||
You'll see logs like:
|
||||
|
||||
```
|
||||
level=info msg="✅ Using cached token (expires in 8736h)"
|
||||
```
|
||||
|
||||
### Token Refresh
|
||||
|
||||
When the token is close to expiring (within 7 days):
|
||||
|
||||
1. The bridge automatically performs fresh authentication
|
||||
2. Updates the cached token
|
||||
3. Continues normal operation
|
||||
|
||||
You'll see logs like:
|
||||
|
||||
```
|
||||
level=info msg="Cached token expires soon (2025-11-09T15:56:23Z), will refresh"
|
||||
level=info msg="Starting browser automation for authentication..."
|
||||
level=info msg="💾 Token cached (expires in 8760h)"
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
After running with authentication, your directory structure will look like:
|
||||
|
||||
```
|
||||
irc-kosmi-relay/
|
||||
├── data/ # Persistent data directory
|
||||
│ └── kosmi_token_cache.json # Cached JWT token
|
||||
├── docker-compose.yml
|
||||
├── matterbridge.toml
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Token Cache Not Persisting
|
||||
|
||||
If the token cache doesn't persist across container restarts:
|
||||
|
||||
1. Check that the `./data` directory exists and is writable
|
||||
2. Verify the volume mount in `docker-compose.yml` is correct
|
||||
3. Check container logs for permission errors
|
||||
|
||||
### Force Token Refresh
|
||||
|
||||
To force a fresh authentication (e.g., if credentials changed):
|
||||
|
||||
```bash
|
||||
# Stop the container
|
||||
docker-compose down
|
||||
|
||||
# Remove the cached token
|
||||
rm ./data/kosmi_token_cache.json
|
||||
|
||||
# Start the container
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Check Token Status
|
||||
|
||||
To view the current cached token:
|
||||
|
||||
```bash
|
||||
cat ./data/kosmi_token_cache.json | jq .
|
||||
```
|
||||
|
||||
This will show you:
|
||||
- When the token was saved
|
||||
- When it expires
|
||||
- Which email it's associated with
|
||||
|
||||
## Security Notes
|
||||
|
||||
- The token cache file has restricted permissions (`0600`) for security
|
||||
- The token is a JWT that expires after 1 year
|
||||
- The cache file is stored locally and never transmitted
|
||||
- If you commit your code to version control, add `data/` to `.gitignore`
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Faster Startup**: No browser automation on every restart (saves 10-15 seconds)
|
||||
2. **Reduced Resource Usage**: No need to launch Chromium on every startup
|
||||
3. **Persistence**: Token survives container rebuilds, restarts, and host reboots
|
||||
4. **Automatic Refresh**: Token is automatically refreshed before expiry
|
||||
5. **Local Storage**: Token is stored on your host machine, not in the container
|
||||
Reference in New Issue
Block a user