Gateway working, beta

This commit is contained in:
2025-12-07 17:11:37 +01:00
parent de03c1fe3d
commit 3d6774586e
13 changed files with 616 additions and 506 deletions

View File

@@ -4,9 +4,9 @@ import (
"context"
"encoding/json"
"errors"
"homestead/homestead_gateway/util/cache"
"log/slog"
"net/http"
"strings"
"time"
"github.com/gorilla/websocket"
@@ -36,6 +36,11 @@ func (wsg *WebsocketGateway) deafen(srv *http.Server) {
// responses
func (wsg *WebsocketGateway) flush(c *websocket.Conn, m GatewayMessageOut) error {
_ = c.SetWriteDeadline(time.Now().Add(5 * time.Second))
return c.WriteJSON(m)
}
func (wsg *WebsocketGateway) sendHttpError(w http.ResponseWriter, message string, code int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
@@ -94,15 +99,6 @@ func (wsg *WebsocketGateway) validateApiKey(r *http.Request) bool {
return !(apiKey == "" || apiKey != wsg.apiKey)
}
func writeJSONSafe(c *websocket.Conn, v interface{}) error {
_ = c.SetWriteDeadline(time.Now().Add(5 * time.Second))
if err := c.WriteJSON(v); err != nil {
// caller handles logging
return err
}
return nil
}
func loggingMiddleware(logger *slog.Logger, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
@@ -113,43 +109,112 @@ func loggingMiddleware(logger *slog.Logger, next http.Handler) http.Handler {
// connections
func (wsg *WebsocketGateway) registerConn(conn *websocket.Conn, meta cache.ConnectionMetaData, typ string) bool {
func (wsg *WebsocketGateway) registerConn(conn *websocket.Conn, typ, channelId, serverId string) bool {
if typ == "bot" {
if wsg.bot != nil {
wsg.registry.botMu.Lock()
if wsg.registry.bot != nil && wsg.registry.bot.Conn != nil {
wsg.registry.botMu.Unlock()
return false
}
wsg.registry.botMu.Unlock()
wsg.bot = conn
wsg.registry.RegisterBot(conn)
return true
}
wsg.conns.Set(meta.ID, conn, &meta)
wsg.registry.RegisterMod(channelId, serverId, conn)
return true
}
func (wsg *WebsocketGateway) unregisterConn(conn *websocket.Conn, meta cache.ConnectionMetaData, typ string) {
func (wsg *WebsocketGateway) unregisterConn(conn *websocket.Conn, typ, channelId string) {
if typ == "bot" {
_ = wsg.bot.Close()
wsg.bot = nil
wsg.registry.UnregisterBot()
if conn != nil {
_ = conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Disconnecting."), time.Now().Add(time.Second))
_ = conn.Close()
}
return
}
wsg.conns.RemoveById(meta.ID)
_ = conn.Close()
wsg.registry.UnregisterMod(channelId)
if conn != nil {
_ = conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Disconnecting."), time.Now().Add(time.Second))
_ = conn.Close()
}
}
func (wsg *WebsocketGateway) closeAll() {
wsg.logger.Info("Closing all websocket connections.")
if wsg.bot != nil {
_ = wsg.bot.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Shutting down."), time.Now().Add(time.Second))
_ = wsg.bot.Close()
wsg.registry.UnregisterBot()
wsg.registry.mu.RLock()
entries := make([]*ChannelEntry, 0, len(wsg.registry.entries))
for _, e := range wsg.registry.entries {
entries = append(entries, e)
}
wsg.registry.mu.RUnlock()
for _, e := range entries {
e.mu.Lock()
modConn := e.Mod
if modConn != nil {
e.Mod = nil
}
e.mu.Unlock()
if modConn != nil && modConn.Conn != nil {
_ = modConn.Conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Shutting down."), time.Now().Add(time.Second))
_ = modConn.Conn.Close()
}
}
}
//
func NewRegistry(queueCap int) *Registry {
return &Registry{
entries: make(map[string]*ChannelEntry),
queueCap: queueCap,
}
}
func NewBoundedQueue(cap int) *BoundedQueue {
if cap <= 0 {
cap = 128
}
return &BoundedQueue{buf: make([]GatewayMessageOut, cap), capacity: cap}
}
func newChannelEntry(channel string, cap int) *ChannelEntry {
return &ChannelEntry{
Channel: channel,
Queue: NewBoundedQueue(cap),
}
}
//
func (m *GatewayMessageIn) Validate() error {
if strings.TrimSpace(m.ID) == "" {
return errors.New("id missing")
}
if strings.TrimSpace(m.MsgID) == "" {
return errors.New("msg_id missing")
}
if strings.TrimSpace(m.Author.ID) == "" {
return errors.New("author.id missing")
}
if strings.TrimSpace(m.Content) == "" {
return errors.New("content missing")
}
wsg.conns.Range(func(id string, c *websocket.Conn, meta *cache.ConnectionMetaData) {
_ = c.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Shutting down."), time.Now().Add(time.Second))
_ = c.Close()
})
if m.Type == "mod" && strings.TrimSpace(m.Destination.ID) == "" {
return errors.New("destination.channel_id missing")
}
wsg.conns.Clear()
return nil
}
func (c *ConnWrapper) Alive() bool { return c != nil && c.Conn != nil }