2025-12-08 09:36:40 +01:00
2025-12-07 00:48:09 +01:00
2025-12-08 09:36:40 +01:00
2025-12-08 07:01:05 +01:00
2025-12-08 09:36:40 +01:00
2025-12-08 07:30:40 +01:00
2025-12-01 10:45:58 +01:00
2025-12-01 10:45:58 +01:00
2025-11-30 17:52:54 +00:00
2025-12-07 00:48:09 +01:00
2025-12-08 09:36:40 +01:00
2025-12-08 06:58:43 +01:00

HomesteadGateway

Gateway between multiple HomesteadRelay's and the HomesteadToGo Bot.


HomesteadGateway Developer Documentation

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

Quick Start

  1. Start the gateway (build/run your application that embeds the WebSocket gateway).
  2. Connect a client to the WebSocket endpoint:
    • URL: ws://<host>:<port>/sync?api_key=<your_api_key>
  3. Immediately send a handshake JSON with type mod or bot.
  4. On success, youll receive {"status":"connected","type":"mod|bot"}.
  5. Exchange messages as JSON.

See the full details below.


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 (Server) ←→ Gateway ←→ Bot (Discord)
     ↓                          ↓
  Channel A                 Channel A

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:

{
  "type": "mod",  // or "bot"
  "data": { ... }
}

Mod Handshake

For game server mods/plugins:

{
  "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.):

{
  "type": "bot",
  "data": {
    "bot_id": "discord-bot-123"
  }
}

Fields:

  • bot_id (string, required): The bots ID

Note: Only one bot connection is allowed at a time. Trying to connect a new bot will result in an 409 Conflict Error.

Step 3: Receive Acknowledgment

After sending the handshake, wait for an acknowledgment:

Success Response:

{
  "status": "connected",
  "type": "mod|bot"
}

Error Responses:

{
  "message": "Malformed handshake.",
  "code": 400
}
{
  "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

{
  "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

{
  "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)

{
  "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)

{
  "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:

{
  "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)

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 (only for bot handshakes)
  • 500 - Internal server error

Message Errors:

  • 400 - Malformed message (missing required fields)

Errors are sent as 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: 2 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.


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:

{
  "status": "healthy"
}

Configuration

Gateway configuration (config.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

Description
Gateway between multiple HomesteadRelay's and the HomesteadToGo Bot.
Readme GPL-3.0 100 KiB
Languages
Go 100%