diff --git a/neode-ui/src/views/settings/LightningCredentialsSection.vue b/neode-ui/src/views/settings/LightningCredentialsSection.vue index e2dbc320..87267742 100644 --- a/neode-ui/src/views/settings/LightningCredentialsSection.vue +++ b/neode-ui/src/views/settings/LightningCredentialsSection.vue @@ -36,12 +36,28 @@ let poll: ReturnType | null = null /// /// Bounded rather than a plain flag, so a request the node accepted but never /// acted on stops polling instead of hammering it forever. -let awaitUntil = 0 +const awaitUntil = ref(0) const AWAIT_START_MS = 120_000 const rotation = computed(() => status.value?.rotation ?? null) const isRunning = computed(() => rotation.value?.running === true) +/// Ticks while a rotation is being awaited, so `rotationInFlight` re-evaluates +/// as the await window expires instead of holding a stale value until the next +/// poll happens to touch a reactive dependency. +const now = ref(Date.now()) + +/// Is a rotation happening, INCLUDING the gap between asking for one and the +/// node reporting it? +/// +/// Rotation restarts LND, so `status.installed` goes false for a moment +/// mid-rotation. Read literally that says "Lightning is not set up on this +/// node" — which the screen then told the operator, seconds after they +/// rotated, on a node with a working Lightning wallet. The container being +/// briefly absent is what rotating LOOKS like, not evidence it was never +/// there. +const rotationInFlight = computed(() => isRunning.value || now.value < awaitUntil.value) + /** A finished rotation, successful or not. `ok` is null while running. */ const finished = computed( () => rotation.value !== null && !rotation.value.running && rotation.value.ok !== null, @@ -68,8 +84,9 @@ async function load() { /// waking the node every few seconds. function syncPolling() { const running = status.value?.rotation.running === true - if (running) awaitUntil = 0 - if (running || Date.now() < awaitUntil) startPolling() + if (running) awaitUntil.value = 0 + now.value = Date.now() + if (running || Date.now() < awaitUntil.value) startPolling() else stopPolling() } @@ -103,7 +120,8 @@ async function rotate() { try { await rpcClient.lndRotateMacaroons(password.value) closeConfirm() - awaitUntil = Date.now() + AWAIT_START_MS + awaitUntil.value = Date.now() + AWAIT_START_MS + now.value = Date.now() startPolling() await load() } catch (e) { @@ -155,8 +173,16 @@ onUnmounted(stopPolling)