gui: verify agent directory before starting statewait/chat streams

Add a run9p stat check before opening blocking reads on
statewait and chat. If the agent directory doesn't exist,
skip starting (prevents tight restart loops when a session
is killed while streams are active). Only one statewait
reader runs at a time.
This commit is contained in:
Levi Neely 2026-08-01 20:56:40 +02:00
parent 608127e4ac
commit dbbcc07934
1 changed files with 31 additions and 14 deletions

View File

@ -437,13 +437,19 @@ void Ollie9pClient::ensureRootDataLoaded()
void Ollie9pClient::startChatStream() void Ollie9pClient::startChatStream()
{ {
if (m_chatProc) return; if (m_chatProc) return;
if (m_activeSessionId.isEmpty() || m_agentId.isEmpty()) return; if (m_activeSessionId.isEmpty() || m_agentId.isEmpty()) return;
m_chatProc = new QProcess(this);
connect(m_chatProc, &QProcess::readyReadStandardOutput, this, &Ollie9pClient::onChatReadyRead); // Verify the agent directory exists before opening a blocking read
connect(m_chatProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), QString ap = agentPath();
this, &Ollie9pClient::onChatFinished); QByteArray verify = run9p({"stat", ap});
m_chatProc->start(ninepBin(), {"-a", serverAddr(), "read", agentPath() + "/chat"}); if (verify.isEmpty()) return; // directory gone
m_chatProc = new QProcess(this);
connect(m_chatProc, &QProcess::readyReadStandardOutput, this, &Ollie9pClient::onChatReadyRead);
connect(m_chatProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &Ollie9pClient::onChatFinished);
m_chatProc->start(ninepBin(), {"-a", serverAddr(), "read", ap + "/chat"});
} }
void Ollie9pClient::startStateStream() void Ollie9pClient::startStateStream()
@ -453,6 +459,16 @@ void Ollie9pClient::startStateStream()
// Check if session still exists before starting // Check if session still exists before starting
if (m_activeSessionId.isEmpty() || m_agentId.isEmpty()) return; if (m_activeSessionId.isEmpty() || m_agentId.isEmpty()) return;
// Verify the agent directory still exists before opening a blocking read
QString ap = agentPath();
QByteArray verify = run9p({"stat", ap});
if (verify.isEmpty()) {
// Directory gone — don't start spamming
m_agentId.clear();
emit activeAgentIdChanged();
return;
}
// Verify the current agent directory still exists // Verify the current agent directory still exists
QStringList agents = getAgents(m_activeSessionId); QStringList agents = getAgents(m_activeSessionId);
if (agents.isEmpty()) { if (agents.isEmpty()) {
@ -465,11 +481,11 @@ void Ollie9pClient::startStateStream()
emit activeAgentIdChanged(); emit activeAgentIdChanged();
} }
m_stateProc = new QProcess(this); m_stateProc = new QProcess(this);
connect(m_stateProc, &QProcess::readyReadStandardOutput, this, &Ollie9pClient::onStateReadyRead); connect(m_stateProc, &QProcess::readyReadStandardOutput, this, &Ollie9pClient::onStateReadyRead);
connect(m_stateProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(m_stateProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &Ollie9pClient::onStateFinished); this, &Ollie9pClient::onStateFinished);
m_stateProc->start(ninepBin(), {"-a", serverAddr(), "read", agentPath() + "/statewait"}); m_stateProc->start(ninepBin(), {"-a", serverAddr(), "read", ap + "/statewait"});
} }
void Ollie9pClient::stopStreams() void Ollie9pClient::stopStreams()
@ -529,8 +545,9 @@ void Ollie9pClient::onStateFinished(int, QProcess::ExitStatus)
{ {
m_stateProc->deleteLater(); m_stateProc->deleteLater();
m_stateProc = nullptr; m_stateProc = nullptr;
// Do NOT restart — statewait is only started when the user // Restart to pick up the next state change — statewait is a blocking
// explicitly selects an agent via setActiveSessionId or switchAgent. // read that returns once and closes the FD.
startStateStream();
} }
void Ollie9pClient::startEventStream() void Ollie9pClient::startEventStream()