updated docs, minor changes
This commit is contained in:
53
README.md
53
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://<host>:<port>/sync?api_key=<your_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
|
## 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
4
bot.go
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -106,5 +106,5 @@ type ModHandshake struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BotHandshake struct {
|
type BotHandshake struct {
|
||||||
ChannelId string `json:"channel_id"`
|
BotID string `json:"bot_id"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user