package statusServer import ( "encoding/json" "fmt" "statusServer/models" pubSubModels "gitea.tecamino.com/paadi/pubSub/models" logging "gitea.tecamino.com/paadi/tecamino-logger/logging" ) // StatusServerClient wraps a websocket client connection to the StatusServer. // - `id` is the client identifier (service name) // - `client` is the underlying websocket client // - `subs` is a map of topic → callback function, used when subscribed messages are received type StatusClient struct { id string client *models.Client subs map[string]func(data any) } // NewCStatuslient connects to a StatusServer websocket endpoint and sets up callbacks. // serviceName: unique ID/name for this client // ip, port: target server address // debug: enable debug logging func NewStatusClient(serviceName, ip string, port uint, debug bool) (*StatusClient, error) { config := models.Config{Log: logging.Config{Debug: debug}} config.Default() // create logger for this client logger, err := logging.NewLogger("statusServer.log", &config.Log) if err != nil { return nil, err } logger.Debug("NewClient", fmt.Sprintf("initialize new client id:%s to %s:%d", serviceName, ip, port)) // build client wrapper sc := StatusClient{ id: serviceName, subs: map[string]func(data any){}, // no subscriptions yet } // connect underlying websocket client sc.client, err = models.NewClient(ip, serviceName, port, logger) if err != nil { return nil, err } // --- EVENT HANDLERS --- // connection opened sc.client.OnOpen = func() { logger.Info("Client", fmt.Sprintf("id:%s connected to %s:%d", serviceName, ip, port)) } // message received from server sc.client.OnMessage = func(data []byte) { var p pubSubModels.Data err := json.Unmarshal(data, &p) if err != nil { logger.Error("OnMessage", err.Error()) return } // if we have a subscription callback for this topic, call it if f, ok := sc.subs[p.Topic]; ok { f(p.Data) } } // warning received sc.client.OnWarning = func(warn string) { logger.Warning("Client", warn) } // error received sc.client.OnError = func(err error) { logger.Error("Client", err.Error()) } // connection closed sc.client.OnClose = func(code int, reason string) { logger.Info("Client", fmt.Sprintf("id:%s closed connection to %s:%d", serviceName, ip, port)) } return &sc, err } // Subscribe sends a "subscribe" action for a topic to the server and registers // a local callback to handle messages for that topic. func (sc *StatusClient) Subscribe(topic string, cb func(any)) error { var data pubSubModels.Data data.Action = "subscribe" data.Topic = topic // send subscribe request to server b, err := json.Marshal(data) if err != nil { return err } sc.client.SendData(b) // register callback for topic sc.subs[topic] = cb return nil } // Publish sends a "publish" action with a payload to the server. // The server will then deliver this message to all subscribers of the topic. func (sc *StatusClient) Publish(topic string, data any) error { var payload pubSubModels.Data payload.Action = "publish" payload.Topic = topic payload.Data = data b, err := json.Marshal(payload) if err != nil { return err } sc.client.SendData(b) return nil } // --- Sending helpers (proxy to server messaging system) --- // SendInfo sends an "info" message to the server. func (sc *StatusClient) SendInfo(data any) error { return sc.client.SendInfo(data) } // SendInfo sends an "status" message to the server. func (sc *StatusClient) SendStatus(data any) error { return sc.client.SendStatus(data) } // SendDebug sends a "debug" message to the server. func (sc *StatusClient) SendDebug(data any) error { return sc.client.SendDebug(data) } // SendWarning sends a "warning" message to the server. func (sc *StatusClient) SendWarning(data any) error { return sc.client.SendWarning(data) } // SendError sends an "error" message to the server. func (sc *StatusClient) SendError(data any) error { return sc.client.SendError(data) }