From a45cefe57a4daa3565a19ab1becb7e5d0185977b Mon Sep 17 00:00:00 2001 From: riccardom Date: Tue, 16 Jun 2026 17:10:51 +0200 Subject: [PATCH] IsRunning V0 --- client/internal/connect.go | 9 +++++++++ client/internal/connect_lifecycle.go | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/client/internal/connect.go b/client/internal/connect.go index 8a99bb1f9..3329c5cd2 100644 --- a/client/internal/connect.go +++ b/client/internal/connect.go @@ -465,6 +465,15 @@ func parseRelayInfo(loginResp *mgmProto.LoginResponse) ([]string, *hmac.Token) { return relayCfg.GetUrls(), token } +// IsRunning reports whether a client run is currently in flight. It is the +// single source of truth for "is the client running", owned by the supervisor. +func (c *ConnectClient) IsRunning() bool { + if c == nil || c.sup == nil { + return false + } + return c.sup.running.Load() +} + func (c *ConnectClient) Engine() *Engine { if c == nil { return nil diff --git a/client/internal/connect_lifecycle.go b/client/internal/connect_lifecycle.go index 090acd701..56854ee58 100644 --- a/client/internal/connect_lifecycle.go +++ b/client/internal/connect_lifecycle.go @@ -3,6 +3,7 @@ package internal import ( "context" "errors" + "sync/atomic" "github.com/netbirdio/netbird/client/internal/profilemanager" ) @@ -59,6 +60,10 @@ type supervisor struct { // runCancel cancels that run. curExecOp *lifecycleCmd runCancel context.CancelFunc + + // running mirrors "a run is in flight" for lock-free reads from outside the + // loop goroutine (the single source of truth for "is the client running"). + running atomic.Bool } func newSupervisor(ctx context.Context, run runFunc) *supervisor { @@ -101,6 +106,7 @@ func (s *supervisor) handleStart(cmd lifecycleCmd) { runCtx, cancel := context.WithCancel(s.ctx) s.runCancel = cancel s.curExecOp = &cmd + s.running.Store(true) go func(ctx context.Context, cfg *profilemanager.Config, m MobileDependency, rc chan struct{}, lp string) { err := s.run(ctx, cfg, m, rc, lp) @@ -127,6 +133,7 @@ func (s *supervisor) handleStop(cmd lifecycleCmd) { // error back to whoever asked to be notified of the start. func (s *supervisor) finishRun(err error) { s.runCancel = nil + s.running.Store(false) if s.curExecOp != nil { notify(s.curExecOp.done, err) s.curExecOp = nil