CUB-200: resolve merge conflicts with dev — adopt dev's consolidated workflows and improved Go gateway code
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/handler"
|
||||
@@ -22,15 +23,17 @@ import (
|
||||
|
||||
// Client polls the OpenClaw gateway for agent status and keeps the database
|
||||
// and SSE broker in sync. When a WSClient is set, the REST poller becomes a
|
||||
// fallback that only activates if the WS connection fails.
|
||||
// fallback: it waits for the WS client to signal readiness, and only starts
|
||||
// polling if WS fails to connect after initial backoff retries.
|
||||
type Client struct {
|
||||
url string
|
||||
pollInterval time.Duration
|
||||
httpClient *http.Client
|
||||
agents repository.AgentRepo
|
||||
broker *handler.Broker
|
||||
wsClient *Client // optional WS client; when set, REST is fallback only
|
||||
wsReady chan struct{} // closed once WS connection is established
|
||||
wsClient *WSClient // optional WS client; when set, REST is fallback only
|
||||
wsReady chan struct{} // closed once WS connection is established
|
||||
wsReadyOnce sync.Once // protects wsReady close from double-close race
|
||||
}
|
||||
|
||||
// Config holds gateway client configuration, typically loaded from environment.
|
||||
@@ -63,36 +66,56 @@ func NewClient(cfg Config, agents repository.AgentRepo, broker *handler.Broker)
|
||||
// to it. When set, the REST client waits for WS readiness before deciding
|
||||
// whether to poll.
|
||||
func (c *Client) SetWSClient(ws *WSClient) {
|
||||
_ = ws // stored for future reconnection coordination
|
||||
c.wsClient = ws
|
||||
}
|
||||
|
||||
// MarkWSReady signals that the WS connection is live and the REST poller
|
||||
// should stand down. Called by WSClient after a successful handshake.
|
||||
func (c *Client) MarkWSReady() {
|
||||
select {
|
||||
case <-c.wsReady:
|
||||
// already closed
|
||||
default:
|
||||
c.wsReadyOnce.Do(func() {
|
||||
close(c.wsReady)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Start begins the gateway client loop. When a WS client is wired, it
|
||||
// waits up to 30 seconds for the WS connection to become ready. If WS
|
||||
// connects, the REST poller stands down. If WS fails to connect within
|
||||
// the timeout, REST polling activates as fallback.
|
||||
// connects, the REST poller stands down and only logs periodically. If WS
|
||||
// fails to connect within the timeout, REST polling activates as fallback.
|
||||
func (c *Client) Start(ctx context.Context) {
|
||||
slog.Info("gateway client starting",
|
||||
"url", c.url,
|
||||
"pollInterval", c.pollInterval.String())
|
||||
if c.wsClient != nil {
|
||||
slog.Info("gateway client waiting for WS connection", "timeout", "30s")
|
||||
|
||||
select {
|
||||
case <-c.wsReady:
|
||||
slog.Info("gateway client using WS — REST poller standing down")
|
||||
// WS is live; keep this goroutine alive but idle. If WS
|
||||
// disconnects later, we could re-enter polling, but for now
|
||||
// the WS client handles its own reconnection.
|
||||
<-ctx.Done()
|
||||
slog.Info("gateway client stopped (WS mode)")
|
||||
return
|
||||
case <-time.After(30 * time.Second):
|
||||
slog.Warn("gateway client: WS not ready after 30s — falling back to REST polling",
|
||||
"url", c.url,
|
||||
"pollInterval", c.pollInterval.String())
|
||||
case <-ctx.Done():
|
||||
slog.Info("gateway client stopped while waiting for WS")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
slog.Info("gateway client using REST polling (no WS client configured)",
|
||||
"url", c.url,
|
||||
"pollInterval", c.pollInterval.String())
|
||||
}
|
||||
|
||||
// REST fallback polling
|
||||
ticker := time.NewTicker(c.pollInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
slog.Info("gateway client stopped")
|
||||
slog.Info("gateway client stopped (REST fallback)")
|
||||
return
|
||||
case <-ticker.C:
|
||||
c.poll(ctx)
|
||||
|
||||
Reference in New Issue
Block a user