diff --git a/dist/roverd b/dist/roverd index 58163d13..191e3bb7 100755 Binary files a/dist/roverd and b/dist/roverd differ diff --git a/dist/servoverifier b/dist/servoverifier index 18c9241d..584fcbc9 100755 Binary files a/dist/servoverifier and b/dist/servoverifier differ diff --git a/pi/roverd/wsclient.go b/pi/roverd/wsclient.go index a98a5d10..4188d600 100644 --- a/pi/roverd/wsclient.go +++ b/pi/roverd/wsclient.go @@ -49,7 +49,9 @@ func NewWSClient(cfg *Config, adapter *SerialAdapter, frames <-chan []byte, even } func (c *WSClient) Run(ctx context.Context) error { - conn, _, err := websocket.Dial(ctx, c.cfg.ServerURL, nil) + dialCtx, cancel := context.WithTimeout(ctx, dialTimeout) + conn, _, err := websocket.Dial(dialCtx, c.cfg.ServerURL, nil) + cancel() if err != nil { c.markDisconnected() return err @@ -65,11 +67,16 @@ func (c *WSClient) Run(ctx context.Context) error { c.log.Printf("sensor stream init failed: %v", err) } - errCh := make(chan error, 1) + errCh := make(chan error, 2) c.startTTSWorker(ctx) go func() { errCh <- c.readLoop(ctx, conn) }() + go func() { + if err := c.keepalive(ctx, conn); err != nil { + errCh <- err + } + }() go c.forwardSensors(ctx, conn) go c.forwardEvents(ctx, conn) @@ -352,6 +359,28 @@ func (c *WSClient) ensureSensorStream() error { } const disconnectSeekDelay = time.Minute +const dialTimeout = 10 * time.Second +const pingInterval = 15 * time.Second +const pingTimeout = 5 * time.Second + +func (c *WSClient) keepalive(ctx context.Context, conn *websocket.Conn) error { + ticker := time.NewTicker(pingInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + pingCtx, cancel := context.WithTimeout(ctx, pingTimeout) + err := conn.Ping(pingCtx) + cancel() + if err != nil { + return err + } + } + } +} func (c *WSClient) markConnected() { c.connMu.Lock()