Fix nested fixture transition draining
This commit is contained in:
@@ -35,10 +35,13 @@ Singleton {
|
||||
property bool fixtureTransitionDraining: false
|
||||
property bool fixtureTransitionStreamFinished: false
|
||||
property bool fixtureTransitionExited: false
|
||||
property var pendingFixtureTarget: null
|
||||
property int delayedFixtureExitCode: 0
|
||||
|
||||
readonly property var visibleEntities: root.selectedEntities.slice(0, 4)
|
||||
readonly property int discoveredCount: root.catalog.length
|
||||
readonly property int configuredCount: root.selectedEntities.length
|
||||
readonly property bool actionProcessRunning: actionProc.running
|
||||
|
||||
// Temporary aliases keep the current Home controls usable until the shelf
|
||||
// switches to the selected-entity and per-entity action interfaces.
|
||||
@@ -219,10 +222,14 @@ Singleton {
|
||||
}
|
||||
|
||||
function fixtureActionCommand(action: var): var {
|
||||
if (root.fixtureProcessMode === "delayed-exit")
|
||||
return ["/usr/bin/sh", "-c", "printf '%s' '{\"ok\":true}'; exit 7"];
|
||||
if (root.fixtureProcessMode === "no-output"
|
||||
&& action.entityId === "light.fixture_kitchen") {
|
||||
return ["/usr/bin/sh", "-c", "sleep 0.5; exit 7"];
|
||||
}
|
||||
if (root.fixtureProcessMode === "slow-success")
|
||||
return ["/usr/bin/sh", "-c", "sleep 2; printf '%s' '{\"ok\":true}'"];
|
||||
return ["/usr/bin/sh", "-c", "sleep 0.5; printf '%s' '{\"ok\":true}'"];
|
||||
}
|
||||
|
||||
@@ -240,6 +247,20 @@ Singleton {
|
||||
}
|
||||
|
||||
function handleActionExited(exitCode: int): void {
|
||||
// This fixture-only delay gives the contract a deterministic window
|
||||
// where the process stopped but its exit bookkeeping is still pending.
|
||||
if (root.fixtureMode
|
||||
&& root.fixtureProcessMode === "delayed-exit"
|
||||
&& root.activeAction !== null
|
||||
&& !root.fixtureTransitionDraining) {
|
||||
root.delayedFixtureExitCode = exitCode;
|
||||
delayedFixtureExitTimer.restart();
|
||||
return;
|
||||
}
|
||||
root.recordActionExited(exitCode);
|
||||
}
|
||||
|
||||
function recordActionExited(exitCode: int): void {
|
||||
if (root.fixtureTransitionDraining) {
|
||||
root.fixtureTransitionExited = true;
|
||||
fixtureTransitionTimer.restart();
|
||||
@@ -368,6 +389,9 @@ Singleton {
|
||||
}
|
||||
|
||||
function beginFixtureTransition(): void {
|
||||
if (root.fixtureTransitionDraining)
|
||||
return;
|
||||
|
||||
const shouldDrain = root.fixtureMode
|
||||
&& root.fixtureProcessMode !== ""
|
||||
&& (actionProc.running || root.activeAction !== null);
|
||||
@@ -397,22 +421,59 @@ Singleton {
|
||||
if (!root.fixtureTransitionStreamFinished || !root.fixtureTransitionExited)
|
||||
return;
|
||||
|
||||
const target = root.pendingFixtureTarget;
|
||||
root.pendingFixtureTarget = null;
|
||||
root.fixtureTransitionDraining = false;
|
||||
root.fixtureTransitionStreamFinished = false;
|
||||
root.fixtureTransitionExited = false;
|
||||
if (target !== null)
|
||||
root.installFixtureTarget(target);
|
||||
queueAdvanceTimer.restart();
|
||||
}
|
||||
|
||||
function applyFixture(name: string): void {
|
||||
if (["ready", "stale", "unavailable", "missing-selected", "action-error",
|
||||
"process-actions", "process-no-output"].indexOf(name) < 0)
|
||||
"process-actions", "process-no-output", "process-delayed-exit",
|
||||
"process-slow-actions"].indexOf(name) < 0)
|
||||
return;
|
||||
|
||||
root.requestFixtureTarget({ fixture: true, name });
|
||||
}
|
||||
|
||||
function requestFixtureTarget(target: var): void {
|
||||
if (root.fixtureTransitionDraining) {
|
||||
// Preserve the old process's callback guard and keep only the
|
||||
// latest replacement requested during that drain.
|
||||
root.pendingFixtureTarget = target;
|
||||
root.resetActionState();
|
||||
return;
|
||||
}
|
||||
|
||||
root.pendingFixtureTarget = target;
|
||||
root.beginFixtureTransition();
|
||||
if (root.fixtureTransitionDraining)
|
||||
return;
|
||||
|
||||
root.pendingFixtureTarget = null;
|
||||
root.installFixtureTarget(target);
|
||||
}
|
||||
|
||||
function installFixtureTarget(target: var): void {
|
||||
if (target.fixture)
|
||||
root.installFixture(target.name);
|
||||
else
|
||||
root.installLiveState();
|
||||
}
|
||||
|
||||
function installFixture(name: string): void {
|
||||
root.fixtureMode = true;
|
||||
root.fixtureProcessMode = name === "process-actions"
|
||||
? "success"
|
||||
: (name === "process-no-output" ? "no-output" : "");
|
||||
: (name === "process-no-output"
|
||||
? "no-output"
|
||||
: (name === "process-delayed-exit"
|
||||
? "delayed-exit"
|
||||
: (name === "process-slow-actions" ? "slow-success" : "")));
|
||||
if (name === "unavailable") {
|
||||
root.catalog = [];
|
||||
root.fixtureFavorites = [];
|
||||
@@ -442,7 +503,10 @@ Singleton {
|
||||
}
|
||||
|
||||
function clearFixture(): void {
|
||||
root.beginFixtureTransition();
|
||||
root.requestFixtureTarget({ fixture: false, name: "" });
|
||||
}
|
||||
|
||||
function installLiveState(): void {
|
||||
root.fixtureMode = false;
|
||||
root.fixtureProcessMode = "";
|
||||
root.phase = "loading";
|
||||
@@ -496,6 +560,12 @@ Singleton {
|
||||
onTriggered: root.tryFinishFixtureTransition()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: delayedFixtureExitTimer
|
||||
interval: 1000
|
||||
onTriggered: root.recordActionExited(root.delayedFixtureExitCode)
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 60000
|
||||
repeat: true
|
||||
|
||||
Reference in New Issue
Block a user