fix connection dot indicators
This commit is contained in:
parent
41f95e84c2
commit
4dabab1f71
|
|
@ -228,6 +228,10 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
scrollTimer.start()
|
scrollTimer.start()
|
||||||
}
|
}
|
||||||
|
function onSessionConnected() {
|
||||||
|
chatModel.appendData("\n[[[info]]]\nsession connected\n[[[end]]]\n")
|
||||||
|
scrollTimer.start()
|
||||||
|
}
|
||||||
function onStreamingDone() {
|
function onStreamingDone() {
|
||||||
chatModel.appendData("\n[[[info]]]\nsession ended\n[[[end]]]\n")
|
chatModel.appendData("\n[[[info]]]\nsession ended\n[[[end]]]\n")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ void NinePConnection::start(const QString &program, const QStringList &args, int
|
||||||
m_retryMs = retryMs;
|
m_retryMs = retryMs;
|
||||||
m_probe = probe;
|
m_probe = probe;
|
||||||
m_stopRequested = false;
|
m_stopRequested = false;
|
||||||
|
m_openMarkerSeen = false;
|
||||||
m_retryTimer.stop();
|
m_retryTimer.stop();
|
||||||
if (!m_process)
|
if (!m_process)
|
||||||
startProcess();
|
startProcess();
|
||||||
|
|
@ -43,6 +44,7 @@ void NinePConnection::startProcess()
|
||||||
if (m_stopRequested || m_process)
|
if (m_stopRequested || m_process)
|
||||||
return;
|
return;
|
||||||
m_stderr.clear();
|
m_stderr.clear();
|
||||||
|
m_openMarkerSeen = false;
|
||||||
m_process = new QProcess(this);
|
m_process = new QProcess(this);
|
||||||
connect(m_process, &QProcess::started, this, &NinePConnection::onStarted);
|
connect(m_process, &QProcess::started, this, &NinePConnection::onStarted);
|
||||||
connect(m_process, &QProcess::readyReadStandardOutput, this, &NinePConnection::onStdout);
|
connect(m_process, &QProcess::readyReadStandardOutput, this, &NinePConnection::onStdout);
|
||||||
|
|
@ -77,8 +79,10 @@ void NinePConnection::onStderr()
|
||||||
if (end < 0) break;
|
if (end < 0) break;
|
||||||
const QByteArray line = m_stderr.left(end).trimmed();
|
const QByteArray line = m_stderr.left(end).trimmed();
|
||||||
m_stderr.remove(0, end + 1);
|
m_stderr.remove(0, end + 1);
|
||||||
if (line == "OLLIE_9P_OPEN")
|
if (line == "OLLIE_9P_OPEN") {
|
||||||
|
m_openMarkerSeen = true;
|
||||||
setState(Connected);
|
setState(Connected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +91,7 @@ void NinePConnection::onFinished(int exitCode, QProcess::ExitStatus)
|
||||||
if (!m_process) return;
|
if (!m_process) return;
|
||||||
m_process->deleteLater();
|
m_process->deleteLater();
|
||||||
m_process = nullptr;
|
m_process = nullptr;
|
||||||
if (m_probe && m_state == Connected && exitCode == 0 && !m_stopRequested) {
|
if (m_probe && m_state == Connected && m_openMarkerSeen && exitCode == 0 && !m_stopRequested) {
|
||||||
m_retryTimer.start(m_retryMs);
|
m_retryTimer.start(m_retryMs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ private:
|
||||||
bool m_stopRequested = false;
|
bool m_stopRequested = false;
|
||||||
int m_retryMs = 4000;
|
int m_retryMs = 4000;
|
||||||
bool m_probe = false;
|
bool m_probe = false;
|
||||||
|
bool m_openMarkerSeen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NINEPCONNECTION_H
|
#endif // NINEPCONNECTION_H
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,18 @@ Ollie9pClient::Ollie9pClient(QObject *parent)
|
||||||
emit chatReceived(QString::fromUtf8(data));
|
emit chatReceived(QString::fromUtf8(data));
|
||||||
});
|
});
|
||||||
connect(m_chat, &StreamFsm::died, this, [this]() {
|
connect(m_chat, &StreamFsm::died, this, [this]() {
|
||||||
// The chat stream closes when the selected session ends. Treat that
|
if (!m_activeSessionId.isEmpty()) {
|
||||||
// existing signal as an immediate disconnect for connection tracking;
|
for (const QVariant &value : std::as_const(m_sessions)) {
|
||||||
// the periodic connection probe will confirm or recover it later.
|
const QVariantMap session = value.toMap();
|
||||||
if (!m_activeSessionId.isEmpty() && !m_agentId.isEmpty())
|
if (session.value("id").toString() != m_activeSessionId) continue;
|
||||||
setAgentConnected(agentKey(m_activeSessionId, m_agentId), false);
|
for (const QVariant &agentValue : session.value("agents").toList()) {
|
||||||
|
const QString key = agentKey(m_activeSessionId,
|
||||||
|
agentValue.toMap().value("id").toString());
|
||||||
|
setAgentConnected(key, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
emit streamingDone();
|
emit streamingDone();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -204,22 +211,27 @@ QString Ollie9pClient::sessionConnectionColor(const QString &sessionId) const
|
||||||
|
|
||||||
void Ollie9pClient::setAgentConnected(const QString &key, bool connected)
|
void Ollie9pClient::setAgentConnected(const QString &key, bool connected)
|
||||||
{
|
{
|
||||||
if (m_agentConnected.value(key, false) == connected) return;
|
const bool cached = m_agentConnected.value(key, false);
|
||||||
m_agentConnected[key] = connected;
|
m_agentConnected[key] = connected;
|
||||||
|
bool modelChanged = false;
|
||||||
// Update the in-memory model without starting another round of probes.
|
// Update the in-memory model without starting another round of probes.
|
||||||
for (QVariant &value : m_sessions) {
|
for (QVariant &value : m_sessions) {
|
||||||
QVariantMap session = value.toMap();
|
QVariantMap session = value.toMap();
|
||||||
QVariantList agents = session.value("agents").toList();
|
QVariantList agents = session.value("agents").toList();
|
||||||
for (QVariant &agentValue : agents) {
|
for (QVariant &agentValue : agents) {
|
||||||
QVariantMap agent = agentValue.toMap();
|
QVariantMap agent = agentValue.toMap();
|
||||||
if (agentKey(session["id"].toString(), agent["id"].toString()) == key)
|
if (agentKey(session["id"].toString(), agent["id"].toString()) == key) {
|
||||||
|
if (agent.value("connected").toBool() != connected)
|
||||||
|
modelChanged = true;
|
||||||
agent["connected"] = connected;
|
agent["connected"] = connected;
|
||||||
|
}
|
||||||
agentValue = agent;
|
agentValue = agent;
|
||||||
}
|
}
|
||||||
session["agents"] = agents;
|
session["agents"] = agents;
|
||||||
value = session;
|
value = session;
|
||||||
}
|
}
|
||||||
emit sessionsChanged();
|
if (cached != connected || modelChanged)
|
||||||
|
emit sessionsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ollie9pClient::startAgentConnections()
|
void Ollie9pClient::startAgentConnections()
|
||||||
|
|
@ -244,7 +256,14 @@ void Ollie9pClient::reconcileAgentConnections()
|
||||||
auto *connection = new NinePConnection(this);
|
auto *connection = new NinePConnection(this);
|
||||||
m_agentConnections.insert(key, connection);
|
m_agentConnections.insert(key, connection);
|
||||||
connect(connection, &NinePConnection::connected, this, [this, key]() {
|
connect(connection, &NinePConnection::connected, this, [this, key]() {
|
||||||
|
const bool reconnected = m_seenAgentConnections.contains(key);
|
||||||
|
m_seenAgentConnections.insert(key);
|
||||||
setAgentConnected(key, true);
|
setAgentConnected(key, true);
|
||||||
|
if (key == agentKey(m_activeSessionId, m_agentId)) {
|
||||||
|
if (reconnected)
|
||||||
|
emit sessionConnected();
|
||||||
|
startActiveAgentStreams();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
connect(connection, &NinePConnection::disconnected, this, [this, key]() {
|
connect(connection, &NinePConnection::disconnected, this, [this, key]() {
|
||||||
setAgentConnected(key, false);
|
setAgentConnected(key, false);
|
||||||
|
|
@ -457,11 +476,7 @@ void Ollie9pClient::switchAgent(const QString &sessionId, const QString &agentId
|
||||||
emit activeAgentIdChanged();
|
emit activeAgentIdChanged();
|
||||||
emit activeStateChanged();
|
emit activeStateChanged();
|
||||||
|
|
||||||
// switchAgent is the ONLY path that starts per-agent streams.
|
startActiveAgentStreams();
|
||||||
QString srv = serverAddr();
|
|
||||||
QString bin = ninepBin();
|
|
||||||
m_chat->start(bin, {"-a", srv, "read", agentPath() + "/chat"});
|
|
||||||
m_state->start(bin, {"-a", srv, "read", agentPath() + "/statewait"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ollie9pClient::loadRootBackends()
|
void Ollie9pClient::loadRootBackends()
|
||||||
|
|
@ -691,6 +706,16 @@ void Ollie9pClient::ensureRootDataLoaded()
|
||||||
|
|
||||||
// --- Streaming ---
|
// --- Streaming ---
|
||||||
|
|
||||||
|
void Ollie9pClient::startActiveAgentStreams()
|
||||||
|
{
|
||||||
|
if (m_activeSessionId.isEmpty() || m_agentId.isEmpty()) return;
|
||||||
|
|
||||||
|
const QString srv = serverAddr();
|
||||||
|
const QString bin = ninepBin();
|
||||||
|
m_chat->start(bin, {"-a", srv, "read", agentPath() + "/chat"});
|
||||||
|
m_state->start(bin, {"-a", srv, "read", agentPath() + "/statewait"});
|
||||||
|
}
|
||||||
|
|
||||||
void Ollie9pClient::stopAgentStreams()
|
void Ollie9pClient::stopAgentStreams()
|
||||||
{
|
{
|
||||||
if (m_chat) m_chat->stop();
|
if (m_chat) m_chat->stop();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVariantList>
|
#include <QVariantList>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QSet>
|
||||||
#if QT_VERSION_MAJOR >= 6
|
#if QT_VERSION_MAJOR >= 6
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -93,6 +94,7 @@ signals:
|
||||||
void activeAgentIdChanged();
|
void activeAgentIdChanged();
|
||||||
void activeStateChanged();
|
void activeStateChanged();
|
||||||
void chatReceived(const QString &text);
|
void chatReceived(const QString &text);
|
||||||
|
void sessionConnected();
|
||||||
void streamingDone(); // chat process exited (session killed)
|
void streamingDone(); // chat process exited (session killed)
|
||||||
void rootBackendsLoadedChanged();
|
void rootBackendsLoadedChanged();
|
||||||
void availableBackendsChanged();
|
void availableBackendsChanged();
|
||||||
|
|
@ -112,6 +114,7 @@ private:
|
||||||
void ensureRootDataLoaded();
|
void ensureRootDataLoaded();
|
||||||
void setDaemonConnected(bool connected);
|
void setDaemonConnected(bool connected);
|
||||||
void startAgentConnections();
|
void startAgentConnections();
|
||||||
|
void startActiveAgentStreams();
|
||||||
void reconcileAgentConnections();
|
void reconcileAgentConnections();
|
||||||
void stopAgentConnections();
|
void stopAgentConnections();
|
||||||
|
|
||||||
|
|
@ -131,6 +134,7 @@ private:
|
||||||
bool m_daemonConnected = false;
|
bool m_daemonConnected = false;
|
||||||
QHash<QString, NinePConnection *> m_agentConnections;
|
QHash<QString, NinePConnection *> m_agentConnections;
|
||||||
QHash<QString, bool> m_agentConnected;
|
QHash<QString, bool> m_agentConnected;
|
||||||
|
QSet<QString> m_seenAgentConnections;
|
||||||
NinePConnection *m_daemon = nullptr;
|
NinePConnection *m_daemon = nullptr;
|
||||||
|
|
||||||
// Streaming FSMs — each wraps a QProcess lifecycle
|
// Streaming FSMs — each wraps a QProcess lifecycle
|
||||||
|
|
|
||||||
Reference in New Issue