package handlers import ( "encoding/json" "fmt" "statusServer/models" "sync" json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models" "github.com/gin-gonic/gin" ) // ClientHandler manages active websocket clients. // - Keeps a map of connected clients (thread-safe). // - Provides helper methods to connect, lookup, and send responses. type ClientHandler struct { sync.RWMutex // protects access to Clients map clients models.Clients // map[string]*Client (id → client) } // SendBroadcast sends a raw message to all clients in the global Broadcast list. // Note: uses `models.Broadcast` (separate global client slice). func SendBroadcast(data []byte) { for _, c := range models.Broadcast { c.SendData(data) } } // NewConnectionHandler creates and initializes a new ClientHandler // with an empty client map. func NewConnectionHandler() *ClientHandler { return &ClientHandler{ clients: models.NewClients(), } } // ConnectNewClient registers a new websocket client by ID. // - If client with same ID already exists, returns the existing client. // - Otherwise, creates a new connection and stores it in the handler map. func (cH *ClientHandler) ConnectNewClient(id string, c *gin.Context) (client *models.Client, err error) { // Check if client already exists (reuse connection). if _, exists := cH.clients[id]; exists { return cH.clients[id], nil } // Create a new websocket client instance. client, err = models.ConnectNewClient(id, c) if err != nil { return nil, err } // Ensure cleanup: when client disconnects, remove from map. client.OnClose = func(code int, reason string) { delete(cH.clients, id) } // Add client to handler map. cH.Lock() cH.clients[id] = client cH.Unlock() return client, nil } // GetClient retrieves a client by ID. // Returns nil if client does not exist. func (c *ClientHandler) GetClient(id string) *models.Client { if client, ok := c.clients[id]; ok { return client } return nil } func (cH *ClientHandler) RemoveClient(id string) { delete(cH.clients, id) } // SendResponse sends a structured JSON response to a given client by ID. // - If client is not found, returns error. // - Otherwise marshals the Response and sends via websocket. func (c *ClientHandler) SendResponse(id string, r *json_dataModels.Response) error { client, ok := c.clients[id] if !ok { return fmt.Errorf("client not found for id %s", id) } // Encode response to JSON. b, err := json.Marshal(*r) if err != nil { return err } // Send JSON payload over websocket. client.SendData(b) return nil } // --- Sending helpers (proxy to server messaging system) --- // SendInfo sends an "info" log message to the server. func (c *ClientHandler) SendInfo(id string, data any) error { return c.clients[id].SendInfo(data) } // SendInfo sends an "info" log message to the server. func (c *ClientHandler) SendStatus(id string, data any) error { return c.clients[id].SendStatus(data) } // SendDebug sends a "debug" log message to the server. func (c *ClientHandler) SendDebug(id string, data any) error { return c.clients[id].SendDebug(data) } // SendWarning sends a "warning" log message to the server. func (c *ClientHandler) SendWarning(id string, data any) error { return c.clients[id].SendWarning(data) } // SendError sends an "error" log message to the server. func (c *ClientHandler) SendError(id string, data any) error { return c.clients[id].SendError(data) }