diff --git a/.env.example b/.env.example index 2489017..a900ce1 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,11 @@ SERVICE_PORT = 62050 NODE_HOST = "0.0.0.0" +# OFFLINE_GRACE_PERIOD extends the disconnect timeout beyond the panel's keepAlive value. +# If the panel goes offline, the node will keep running for this additional duration. +# Format: Go duration string (e.g. 1h, 30m, 24h). Default: disabled (0). +# OFFLINE_GRACE_PERIOD = 1h + # use absolute path # XRAY_EXECUTABLE_PATH = /usr/local/bin/xray diff --git a/controller/controller.go b/controller/controller.go index dd17f7b..35353fb 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -4,6 +4,7 @@ import ( "context" "errors" "log" + "os" "sync" "time" @@ -123,6 +124,21 @@ func (c *Controller) keepAliveTracker(ctx context.Context, keepAlive time.Durati ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() + // OFFLINE_GRACE_PERIOD extends the disconnect timeout on top of keepAlive. + // This allows the node to keep running if the panel goes temporarily offline. + // Format: Go duration string, e.g. "1h", "30m", "24h". + // Default: 0 (original behavior preserved). + effectiveTimeout := keepAlive + if gp := os.Getenv("OFFLINE_GRACE_PERIOD"); gp != "" { + if d, err := time.ParseDuration(gp); err == nil { + effectiveTimeout = keepAlive + d + log.Printf("offline grace period enabled: keepAlive=%s grace=%s effectiveTimeout=%s", + keepAlive, d, effectiveTimeout) + } else { + log.Printf("warning: invalid OFFLINE_GRACE_PERIOD value %q: %v", gp, err) + } + } + for { select { case <-ctx.Done(): @@ -131,7 +147,7 @@ func (c *Controller) keepAliveTracker(ctx context.Context, keepAlive time.Durati c.mu.RLock() lastRequest := c.lastRequest c.mu.RUnlock() - if time.Since(lastRequest) >= keepAlive { + if time.Since(lastRequest) >= effectiveTimeout { log.Println("disconnect automatically due to keep alive timeout") c.Disconnect() }