From 709abb30fa4e61307eb16ce7d806e7bd73ef8fd5 Mon Sep 17 00:00:00 2001 From: Overlord Date: Mon, 8 Dec 2025 09:36:40 +0100 Subject: [PATCH] updated docs, minor changes --- README.md | 53 +++++++++++++++++++------------------------------ bot.go | 4 ++-- ws/handlers.go | 10 +++++----- ws/structs.go | 2 +- ws/websocket.go | 7 ++----- 5 files changed, 30 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index dc9c76b..181fbb8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,19 @@ HomesteadGateway is a WebSocket-based message routing gateway that facilitates b --- +## 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://:/sync?api_key=` +3. Immediately send a handshake JSON with type `mod` or `bot`. +4. On success, you’ll receive `{"status":"connected","type":"mod|bot"}`. +5. Exchange messages as JSON. + +See the full details below. + +--- + ## Architecture ### Connection Types @@ -116,15 +129,15 @@ For bots (Discord bots, etc.): { "type": "bot", "data": { - "channel_id": "123456789" + "bot_id": "discord-bot-123" } } ``` **Fields:** -- `channel_id` (string, required): The channel ID this bot monitors +- `bot_id` (string, required): The bots ID -**Note:** Only **one bot connection** is allowed at a time. Connecting a new bot will close the existing bot connection. +**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 @@ -134,7 +147,7 @@ After sending the handshake, wait for an acknowledgment: ```json { "status": "connected", - "type": "mod" // or "bot" + "type": "mod|bot" } ``` @@ -344,7 +357,7 @@ conn.SetPongHandler(func(appData string) error { **Handshake Errors:** - `400` - Malformed handshake JSON - `401` - Invalid or missing API key -- `409` - Bot already connected (for bot handshakes) +- `409` - Bot already connected (only for bot handshakes) - `500` - Internal server error **Message Errors:** @@ -378,9 +391,9 @@ Handle other WebSocket closures as unexpected errors. ## Rate Limits & Restrictions -- **Message Size Limit:** 1 MB per message (configurable) +- **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 Mods:** Multiple mods *can* connect to the same channel ID (different server IDs) - **Concurrent Bots:** Only **one bot connection** allowed globally --- @@ -426,32 +439,6 @@ 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 diff --git a/bot.go b/bot.go index 8dd5130..e10245d 100644 --- a/bot.go +++ b/bot.go @@ -36,7 +36,7 @@ type Handshake struct { } type BotHandshake struct { - ChannelId string `json:"channel_id"` + BotID string `json:"bot_id"` } type GatewayAck struct { @@ -111,7 +111,7 @@ func main() { return nil }) - bhs := BotHandshake{ChannelId: channelID} + bhs := BotHandshake{BotID: "discord-bot"} data, err := json.Marshal(bhs) if err != nil { _ = conn.Close() diff --git a/ws/handlers.go b/ws/handlers.go index 512bf9e..224a78b 100644 --- a/ws/handlers.go +++ b/ws/handlers.go @@ -68,7 +68,7 @@ func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request) _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "mod"}) wsg.registry.FlushChannelWithSender(mhs.ChannelID, wsg.flush) - wsg.logger.Info("Mod connected via Websocket.", "remote", conn.RemoteAddr().String()) + wsg.logger.Info("Mod connected via Websocket.", "remote", conn.RemoteAddr().String(), "id", mhs.ServerID) go wsg.read(conn, "mod", mhs.ChannelID) case "bot": @@ -78,12 +78,12 @@ func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request) return } - if bhs.ChannelId == "" { + if bhs.BotID == "" { wsg.sendWebsocketError(conn, "Malformed bot handshake.", 400, true) return } - if !wsg.registerConn(conn, "bot", bhs.ChannelId, "") { + if !wsg.registerConn(conn, "bot", "", "") { wsg.sendWebsocketError(conn, "Bot already connected.", 409, true) return } @@ -91,8 +91,8 @@ func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request) _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "bot"}) wsg.registry.FlushAllToBotWithSender(wsg.flush) - wsg.logger.Info("Bot connected via Websocket.", "remote", conn.RemoteAddr().String()) - go wsg.read(conn, "bot", bhs.ChannelId) + wsg.logger.Info("Bot connected via Websocket.", "remote", conn.RemoteAddr().String(), "id", bhs.BotID) + go wsg.read(conn, "bot", "") default: wsg.sendWebsocketError(conn, "Unknown handshake.", 400, true) diff --git a/ws/structs.go b/ws/structs.go index f601775..ab9c619 100644 --- a/ws/structs.go +++ b/ws/structs.go @@ -106,5 +106,5 @@ type ModHandshake struct { } type BotHandshake struct { - ChannelId string `json:"channel_id"` + BotID string `json:"bot_id"` } diff --git a/ws/websocket.go b/ws/websocket.go index d392fac..50cf64d 100644 --- a/ws/websocket.go +++ b/ws/websocket.go @@ -128,13 +128,10 @@ func (wsg *WebsocketGateway) read(conn *websocket.Conn, _type, channelId string) ForwardedAt: time.Now().UTC(), } - delivered, queued, err := wsg.registry.Send(out.ID, out, func(c *websocket.Conn, m GatewayMessageOut) error { - _ = c.SetWriteDeadline(time.Now().Add(5 * time.Second)) - return c.WriteJSON(m) - }) + delivered, queued, err := wsg.registry.Send(outID, out, wsg.flush) if err != nil { - wsg.logger.Error("registry send error", "err", err) + wsg.logger.Error("Registry queue/delivery error.", "remote", conn.RemoteAddr().String(), "err", err) _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "failed", Type: message.Type}) continue }