garm/websocket/client.go
Mario Constanti bd0b27ab10 fix: gci section warnings
Signed-off-by: Mario Constanti <mario.constanti@mercedes-benz.com>
2024-02-22 15:06:53 +01:00

111 lines
2.5 KiB
Go

package websocket
import (
"log/slog"
"time"
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
const (
// Time allowed to write a message to the peer.
writeWait = 10 * time.Second
// Time allowed to read the next pong message from the peer.
pongWait = 60 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
// Maximum message size allowed from peer.
maxMessageSize = 1024
)
func NewClient(conn *websocket.Conn, hub *Hub) (*Client, error) {
clientID := uuid.New()
return &Client{
id: clientID.String(),
conn: conn,
hub: hub,
send: make(chan []byte, 100),
}, nil
}
type Client struct {
id string
conn *websocket.Conn
// Buffered channel of outbound messages.
send chan []byte
hub *Hub
}
func (c *Client) Go() {
go c.clientReader()
go c.clientWriter()
}
// clientReader waits for options changes from the client. The client can at any time
// change the log level and binary name it watches.
func (c *Client) clientReader() {
defer func() {
c.hub.unregister <- c
c.conn.Close()
}()
c.conn.SetReadLimit(maxMessageSize)
if err := c.conn.SetReadDeadline(time.Now().Add(pongWait)); err != nil {
slog.With(slog.Any("error", err)).Error("failed to set read deadline")
}
c.conn.SetPongHandler(func(string) error {
if err := c.conn.SetReadDeadline(time.Now().Add(pongWait)); err != nil {
return err
}
return nil
})
for {
mt, _, err := c.conn.ReadMessage()
if err != nil {
break
}
if mt == websocket.CloseMessage {
break
}
}
}
// clientWriter
func (c *Client) clientWriter() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
c.conn.Close()
}()
for {
select {
case message, ok := <-c.send:
if err := c.conn.SetWriteDeadline(time.Now().Add(writeWait)); err != nil {
slog.With(slog.Any("error", err)).Error("failed to set write deadline")
}
if !ok {
// The hub closed the channel.
if err := c.conn.WriteMessage(websocket.CloseMessage, []byte{}); err != nil {
slog.With(slog.Any("error", err)).Error("failed to write message")
}
return
}
if err := c.conn.WriteMessage(websocket.TextMessage, message); err != nil {
slog.With(slog.Any("error", err)).Error("error sending message")
return
}
case <-ticker.C:
if err := c.conn.SetWriteDeadline(time.Now().Add(writeWait)); err != nil {
slog.With(slog.Any("error", err)).Error("failed to set write deadline")
}
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
return
}
}
}
}