updated docs, minor changes

This commit is contained in:
2025-12-08 09:36:40 +01:00
parent 0c7909a701
commit 709abb30fa
5 changed files with 30 additions and 46 deletions

View File

@@ -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://<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 ## Architecture
### Connection Types ### Connection Types
@@ -116,15 +129,15 @@ For bots (Discord bots, etc.):
{ {
"type": "bot", "type": "bot",
"data": { "data": {
"channel_id": "123456789" "bot_id": "discord-bot-123"
} }
} }
``` ```
**Fields:** **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 ### Step 3: Receive Acknowledgment
@@ -134,7 +147,7 @@ After sending the handshake, wait for an acknowledgment:
```json ```json
{ {
"status": "connected", "status": "connected",
"type": "mod" // or "bot" "type": "mod|bot"
} }
``` ```
@@ -344,7 +357,7 @@ conn.SetPongHandler(func(appData string) error {
**Handshake Errors:** **Handshake Errors:**
- `400` - Malformed handshake JSON - `400` - Malformed handshake JSON
- `401` - Invalid or missing API key - `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 - `500` - Internal server error
**Message Errors:** **Message Errors:**
@@ -378,9 +391,9 @@ Handle other WebSocket closures as unexpected errors.
## Rate Limits & Restrictions ## 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 - **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 - **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 ## API Reference

4
bot.go
View File

@@ -36,7 +36,7 @@ type Handshake struct {
} }
type BotHandshake struct { type BotHandshake struct {
ChannelId string `json:"channel_id"` BotID string `json:"bot_id"`
} }
type GatewayAck struct { type GatewayAck struct {
@@ -111,7 +111,7 @@ func main() {
return nil return nil
}) })
bhs := BotHandshake{ChannelId: channelID} bhs := BotHandshake{BotID: "discord-bot"}
data, err := json.Marshal(bhs) data, err := json.Marshal(bhs)
if err != nil { if err != nil {
_ = conn.Close() _ = conn.Close()

View File

@@ -68,7 +68,7 @@ func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request)
_ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "mod"}) _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "mod"})
wsg.registry.FlushChannelWithSender(mhs.ChannelID, wsg.flush) 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) go wsg.read(conn, "mod", mhs.ChannelID)
case "bot": case "bot":
@@ -78,12 +78,12 @@ func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request)
return return
} }
if bhs.ChannelId == "" { if bhs.BotID == "" {
wsg.sendWebsocketError(conn, "Malformed bot handshake.", 400, true) wsg.sendWebsocketError(conn, "Malformed bot handshake.", 400, true)
return return
} }
if !wsg.registerConn(conn, "bot", bhs.ChannelId, "") { if !wsg.registerConn(conn, "bot", "", "") {
wsg.sendWebsocketError(conn, "Bot already connected.", 409, true) wsg.sendWebsocketError(conn, "Bot already connected.", 409, true)
return return
} }
@@ -91,8 +91,8 @@ func (wsg *WebsocketGateway) handleSync(w http.ResponseWriter, r *http.Request)
_ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "bot"}) _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "connected", Type: "bot"})
wsg.registry.FlushAllToBotWithSender(wsg.flush) wsg.registry.FlushAllToBotWithSender(wsg.flush)
wsg.logger.Info("Bot connected via Websocket.", "remote", conn.RemoteAddr().String()) wsg.logger.Info("Bot connected via Websocket.", "remote", conn.RemoteAddr().String(), "id", bhs.BotID)
go wsg.read(conn, "bot", bhs.ChannelId) go wsg.read(conn, "bot", "")
default: default:
wsg.sendWebsocketError(conn, "Unknown handshake.", 400, true) wsg.sendWebsocketError(conn, "Unknown handshake.", 400, true)

View File

@@ -106,5 +106,5 @@ type ModHandshake struct {
} }
type BotHandshake struct { type BotHandshake struct {
ChannelId string `json:"channel_id"` BotID string `json:"bot_id"`
} }

View File

@@ -128,13 +128,10 @@ func (wsg *WebsocketGateway) read(conn *websocket.Conn, _type, channelId string)
ForwardedAt: time.Now().UTC(), ForwardedAt: time.Now().UTC(),
} }
delivered, queued, err := wsg.registry.Send(out.ID, out, func(c *websocket.Conn, m GatewayMessageOut) error { delivered, queued, err := wsg.registry.Send(outID, out, wsg.flush)
_ = c.SetWriteDeadline(time.Now().Add(5 * time.Second))
return c.WriteJSON(m)
})
if err != nil { 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}) _ = wsg.sendWebsocketResponse(conn, GatewayAck{Status: "failed", Type: message.Type})
continue continue
} }