Watch
1
0
Fork
You've already forked souveraine
0

viewtop: hang up after a reply instead of discovering it

The compositor answers one request per connection and returns. `connected`
lags that close, so the 2 s poll's second tick wrote to a spent socket and
died as PeerClosedError — once per shell start, 4 of 4 loads on 2026-08-13,
while the same socket answered a hand-written request that second.
The error also blamed reachability, which it never established; it now names
the verb that was lost and how many were dropped behind it.
This commit is contained in:
Fimeg 2026-08-13 12:43:59 -04:00
commit a8a4aac2d5

View file

@ -449,8 +449,16 @@ Singleton {
const intent = (root._inflight && root._inflight.intent)
|| (root._inflight && root._inflight.op) || "?";
root.lastError = "viewtop socket unavailable";
console.error("[viewtop-control] could not reach the compositor at "
+ sock.path + " — the scene was NOT changed");
// Name the verb and the count. The old wording claimed the
// compositor could not be reached, which was the one thing it never
// established on 2026-08-13 this fired once per shell start while
// viewtop answered a hand-written request on that same socket in
// the same second. A transport error is not a diagnosis.
console.error("[viewtop-control] " + intent + " was not delivered:"
+ " the socket at " + sock.path + " closed with the request in"
+ " flight" + (root._queue.length > 0
? " (" + root._queue.length + " queued behind it dropped)"
: ""));
root._inflight = null;
root._queue = [];
root.refused(intent, root.lastError);
@ -471,7 +479,10 @@ Singleton {
console.error("[viewtop-control] unparseable reply: " + message);
root.lastError = "unparseable reply";
root.refused(intent, root.lastError);
root._pump();
if (sock.connected)
sock.connected = false;
else
root._pump();
return;
}
@ -492,7 +503,22 @@ Singleton {
root._ingest(reply);
root.succeeded(intent);
}
root._pump();
// Hang up rather than wait to discover we have been hung up on.
//
// `handle()` in control.rs answers one request and returns, so
// the connection is spent the moment the reply is parsed. But
// `connected` is this end's belief and it lags the peer's
// close: measured 2026-08-13, the poll's second tick wrote to
// the socket a full two seconds after the reply and the write
// still went out, dying as PeerClosedError. That surfaced as
// "could not reach the compositor" for a compositor that was
// answering by hand at that same moment, and it cost the queued
// verb. Closing here makes the next `_pump` start from a state
// we set rather than one we inferred.
if (sock.connected)
sock.connected = false; // the disconnect handler re-pumps
else
root._pump();
}
}
}