added docs

This commit is contained in:
2025-12-08 07:30:40 +01:00
parent 7c9a7eedf9
commit 0c7909a701
2 changed files with 482 additions and 7 deletions

487
README.md
View File

@@ -2,14 +2,489 @@
Gateway between multiple HomesteadRelay's and the HomesteadToGo Bot. Gateway between multiple HomesteadRelay's and the HomesteadToGo Bot.
---
## dev notes ## HomesteadGateway Developer Documentation
perhaps drop database, instead ## Overview
HomesteadGateway is a WebSocket-based message routing gateway that facilitates bidirectional communication between game server mods/plugins and external bots (e.g., Discord bots). It acts as a relay, routing messages based on channel identifiers and managing message queues when endpoints are offline.
**Key Features:**
- WebSocket-based real-time communication
- Channel-based message routing
- Automatic message queuing for offline recipients
- API key authentication
- Connection keep-alive via ping/pong
- Support for multiple concurrent mod connections per channel
---
## Architecture
### Connection Types
The gateway supports two types of connections:
1. **Mod Connection** - Game server mods/plugins that send and receive player messages
2. **Bot Connection** - External bots (typically Discord) that bridge messages to/from other platforms
### Message Flow
``` ```
Mod -> websocket /register { server_id, channel_id } // grabbed from mod config Mod (Server) ←→ Gateway ←→ Bot (Discord)
Bot -> websocket /ready { channel_id } // ready if Mod with fitting channel_id has called /register
Gateway -> memory cache (server_id -> channel_id; channel_id -> server_id) // mem enough Channel A Channel A
Mod/Bot -> websocket /ws { ... } -> Bot/Mod // sync
``` ```
Messages are routed based on `channel_id`:
- **Mod → Bot**: Messages from a mod are forwarded to the bot
- **Bot → Mod**: Messages from a bot are forwarded to the mod registered for that channel
---
## Connection Setup
### Endpoint
```
ws://<host>:<port>/sync?api_key=<your_api_key>
```
**Default Port:** 3333 (configurable)
### Authentication
Authentication is performed via API key, which can be provided in two ways:
1. **Query Parameter** (recommended):
```
ws://localhost:3333/sync?api_key=gateway
```
2. **HTTP Header**:
```
X-API-Key: gateway
```
### Connection Timeout
After connecting, you **must** send a handshake message within **60 seconds** or the connection will be closed.
---
## Handshake Protocol
### Step 1: Establish WebSocket Connection
Connect to the `/sync` endpoint with your API key.
### Step 2: Send Handshake Message
Immediately after connecting, send a JSON handshake message:
```json
{
"type": "mod", // or "bot"
"data": { ... }
}
```
#### Mod Handshake
For game server mods/plugins:
```json
{
"type": "mod",
"data": {
"server_id": "minecraft-server-001",
"channel_id": "123456789"
}
}
```
**Fields:**
- `server_id` (string, required): Unique identifier for your server instance
- `channel_id` (string, required): The Discord channel ID (or equivalent) this mod serves
#### Bot Handshake
For bots (Discord bots, etc.):
```json
{
"type": "bot",
"data": {
"channel_id": "123456789"
}
}
```
**Fields:**
- `channel_id` (string, required): The channel ID this bot monitors
**Note:** Only **one bot connection** is allowed at a time. Connecting a new bot will close the existing bot connection.
### Step 3: Receive Acknowledgment
After sending the handshake, wait for an acknowledgment:
**Success Response:**
```json
{
"status": "connected",
"type": "mod" // or "bot"
}
```
**Error Responses:**
```json
{
"message": "Malformed handshake.",
"code": 400
}
```
```json
{
"message": "Bot already connected.",
"code": 409
}
```
### Step 4: Begin Message Exchange
Once acknowledged, the connection is established and you can start sending/receiving messages.
---
## Message Protocol
### Sending Messages
After handshake, send messages as JSON:
#### From Mod to Bot
```json
{
"msg_id": "msg-unique-123",
"id": "minecraft-server-001",
"destination": {
"channel_id": "123456789"
},
"author": {
"id": "player-uuid-abc",
"name": "PlayerName"
},
"content": "Hello from the game server!",
"meta": {
"server_name": "Survival Server",
"world": "overworld"
},
"ts": "2025-12-08T10:30:00Z"
}
```
**Required Fields:**
- `msg_id` (string): Unique message identifier (generate client-side)
- `id` (string): Server ID (must match your handshake `server_id`)
- `destination.channel_id` (string): Target channel ID
- `author.id` (string): User/player identifier
- `content` (string): Message content (non-empty)
**Optional Fields:**
- `author.name` (string): Display name for the author
- `meta` (object): Additional metadata (arbitrary key-value pairs)
- `ts` (RFC3339 timestamp): Message timestamp (defaults to server time if omitted)
#### From Bot to Mod
```json
{
"msg_id": "discord-msg-456",
"id": "123456789",
"author": {
"id": "discord-user-789",
"name": "DiscordUser"
},
"content": "Hello from Discord!",
"meta": {
"platform": "discord",
"roles": ["admin"]
},
"ts": "2025-12-08T10:31:00Z"
}
```
**Required Fields:**
- `msg_id` (string): Unique message identifier
- `id` (string): Channel ID (from which channel the message originates)
- `author.id` (string): User identifier
- `content` (string): Message content (non-empty)
**Optional Fields:**
- `author.name` (string): Display name
- `meta` (object): Additional metadata
- `ts` (RFC3339 timestamp): Message timestamp
**Note:** Bot messages do **not** include a `destination` field, as the channel ID in `id` determines routing.
### Receiving Messages
Messages are received as JSON in the same format they were sent:
#### Mod Receives (from Bot)
```json
{
"type": "bot",
"channel_id": "123456789",
"author": {
"id": "discord-user-789",
"name": "DiscordUser"
},
"content": "Hello from Discord!",
"meta": {
"platform": "discord"
},
"ts": "2025-12-08T10:31:00Z",
"received_at": "2025-12-08T10:31:00.123Z",
"forwarded_at": "2025-12-08T10:31:00.125Z"
}
```
#### Bot Receives (from Mod)
```json
{
"type": "mod",
"channel_id": "123456789",
"author": {
"id": "player-uuid-abc",
"name": "PlayerName"
},
"content": "Hello from the game server!",
"meta": {
"server_name": "Survival Server"
},
"ts": "2025-12-08T10:30:00Z",
"received_at": "2025-12-08T10:30:00.100Z",
"forwarded_at": "2025-12-08T10:30:00.102Z"
}
```
**Additional Fields in Received Messages:**
- `type` (string): Origin type ("mod" or "bot")
- `channel_id` (string): The channel this message belongs to
- `received_at` (RFC3339): When gateway received the message
- `forwarded_at` (RFC3339): When gateway forwarded the message
### Message Acknowledgments
After sending each message, you'll receive an acknowledgment:
```json
{
"status": "completed",
"type": "mod"
}
```
**Status Values:**
- `completed`: Message was delivered immediately to recipient
- `queued`: Recipient is offline; message queued for later delivery
- `failed`: Message could not be delivered or queued
---
## Message Queuing
When a recipient is offline, messages are automatically queued:
- **Queue Size:** Configurable (default: 8 messages per channel)
- **Queue Behavior:** Circular buffer (oldest messages are overwritten when full)
- **Flush Trigger:** When recipient reconnects, all queued messages are delivered
### Example Flow
1. Mod sends message while bot is offline → Message queued
2. Bot connects and completes handshake → All queued messages flushed to bot
3. Bot sends message while mod is offline → Message queued
4. Mod connects → Queued messages flushed to mod
---
## Keep-Alive & Ping/Pong
The gateway sends **WebSocket ping messages every 30 seconds** to maintain connections.
**Client Responsibilities:**
1. **Respond to pings**: Your WebSocket library should automatically handle pong responses
2. **Handle pongs**: Set a pong handler to reset read deadlines
3. **Read Deadline**: The gateway sets a 60-second read deadline, reset on each pong
### Example (Go)
```go
conn.SetPongHandler(func(appData string) error {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
return nil
})
```
---
## Error Handling
### Connection Errors
**Handshake Errors:**
- `400` - Malformed handshake JSON
- `401` - Invalid or missing API key
- `409` - Bot already connected (for bot handshakes)
- `500` - Internal server error
**Message Errors:**
- `400` - Malformed message (missing required fields)
Errors are sent as JSON:
```json
{
"message": "Malformed message.",
"code": 400
}
```
### Validation Rules
Messages are validated on receipt:
- `id` must not be empty
- `msg_id` must not be empty
- `author.id` must not be empty
- `content` must not be empty
- For mod messages: `destination.channel_id` must not be empty
### Websocket Closures
- `1000` - Normal closure
- `1001` - Going away
Handle other WebSocket closures as unexpected errors.
---
## Rate Limits & Restrictions
- **Message Size Limit:** 1 MB per message (configurable)
- **Read Limit:** Messages exceeding the limit will close the connection
- **Concurrent Mods:** Multiple mods can connect to the same channel ID (different server IDs)
- **Concurrent Bots:** Only **one bot connection** allowed globally
---
## Best Practices
### 1. Generate Unique Message IDs
Always generate unique `msg_id` values for each message. Consider using:
- UUID v4
- Timestamp + random suffix
- Sequential counter with prefix
### 2. Handle Reconnections
Implement automatic reconnection logic with exponential backoff:
```
1st retry: 1 second
2nd retry: 2 seconds
3rd retry: 4 seconds
Max: 30 seconds
```
### 3. Set Appropriate Timeouts
- Write timeout: 5 seconds (same as Gateway)
- Read timeout: 60 seconds (reset on pong)
### 4. Validate Before Sending
Check required fields locally before sending to avoid validation errors.
### 5. Monitor Acknowledgments
Track acknowledgment statuses:
- `completed`: Message delivered
- `queued`: Message queued
- `failed`: Log and potentially retry
### 6. Use Metadata
The `meta` field is used for:
- Server information (server name, region, version)
- User context (roles, permissions)
- Message context (reply-to, thread-id)
### 7. Thread-Safe Writes
Use mutex/locks when writing to WebSocket from multiple threads.
---
## Troubleshooting
### Connection Refused
- Verify the gateway is running
- Check the port is correct (default: 3333)
- Ensure firewall allows connections
### 401 Unauthorized
- Verify API key is correct
- Check API key is properly URL-encoded in query string
### Handshake Timeout
- Ensure handshake is sent within 60 seconds of connection
- Verify handshake JSON is correctly formatted
### Messages Not Received
- Check `channel_id` matches between mod and bot
- Verify recipient is connected
- Check queue status in acknowledgments
### Connection Drops
- Ensure pong responses are sent to pings
- Check network stability
- Implement reconnection logic
---
## API Reference
### Endpoints
#### `GET /sync`
WebSocket upgrade endpoint for mod/bot connections.
**Query Parameters:**
- `api_key` (required): Authentication token
#### `GET /health`
Health check endpoint.
**Response:**
```json
{
"status": "healthy"
}
```
---
## Configuration
Gateway configuration (`config.toml`):
```toml
[gateway]
http_port = 3333 # WebSocket port
websocket = "gateway" # API key
body_size = 1 # Max message size in MB
queue_max = 8 # Messages per channel queue
```
---

View File

@@ -7,4 +7,4 @@ rotation = 3 # in days
http_port = 3333 http_port = 3333
websocket = "gateway" websocket = "gateway"
body_size = 2 # in MB body_size = 2 # in MB
queue_max = 32 queue_max = 8