This repository has been archived on 2026-08-16. You can view files and clone it, but cannot push or open issues or pull requests.
ollie-kde/gui/ninepconnection.cpp

129 lines
3.5 KiB
C++

#include "ninepconnection.h"
NinePConnection::NinePConnection(QObject *parent)
: QObject(parent)
{
m_retryTimer.setSingleShot(true);
connect(&m_retryTimer, &QTimer::timeout, this, &NinePConnection::retry);
}
NinePConnection::~NinePConnection()
{
stop();
}
void NinePConnection::start(const QString &program, const QStringList &args, int retryMs, bool probe)
{
m_program = program;
m_args = args;
m_retryMs = retryMs;
m_probe = probe;
m_stopRequested = false;
m_openMarkerSeen = false;
m_retryTimer.stop();
if (!m_process)
startProcess();
}
void NinePConnection::stop()
{
m_stopRequested = true;
m_retryTimer.stop();
if (m_process) {
m_process->disconnect(this);
m_process->kill();
m_process->waitForFinished(1000);
m_process->deleteLater();
m_process = nullptr;
}
setState(Disconnected);
}
void NinePConnection::startProcess()
{
if (m_stopRequested || m_process)
return;
m_stderr.clear();
m_openMarkerSeen = false;
m_process = new QProcess(this);
connect(m_process, &QProcess::started, this, &NinePConnection::onStarted);
connect(m_process, &QProcess::readyReadStandardOutput, this, &NinePConnection::onStdout);
connect(m_process, &QProcess::readyReadStandardError, this, &NinePConnection::onStderr);
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &NinePConnection::onFinished);
// A finite probe refreshes an already connected agent. Keep the
// established state while the replacement probe is opening so a
// successful periodic probe does not flash disconnected in the UI.
if (!(m_probe && m_state == Connected))
setState(Connecting);
m_process->start(m_program, m_args);
}
void NinePConnection::onStarted()
{
// The helper emits the readiness marker only after the 9P open succeeds.
}
void NinePConnection::onStdout()
{
const QByteArray data = m_process->readAllStandardOutput();
if (!data.isEmpty())
emit readyRead(data);
}
void NinePConnection::onStderr()
{
m_stderr += m_process->readAllStandardError();
while (true) {
const int end = m_stderr.indexOf('\n');
if (end < 0) break;
const QByteArray line = m_stderr.left(end).trimmed();
m_stderr.remove(0, end + 1);
if (line == "OLLIE_9P_OPEN") {
m_openMarkerSeen = true;
setState(Connected);
}
}
}
void NinePConnection::onFinished(int exitCode, QProcess::ExitStatus)
{
if (!m_process) return;
m_process->deleteLater();
m_process = nullptr;
if (m_probe && m_state == Connected && m_openMarkerSeen && exitCode == 0 && !m_stopRequested) {
if (m_retryMs > 0)
m_retryTimer.start(m_retryMs);
else
startProcess(); // immediate re-probe
return;
}
if (m_stopRequested || m_retryMs <= 0) {
setState(Disconnected);
return;
}
setState(RetryWait);
m_retryTimer.start(m_retryMs);
}
void NinePConnection::retry()
{
if (!m_stopRequested)
startProcess();
}
void NinePConnection::setState(State state)
{
if (m_state == state) return;
const State previous = m_state;
m_state = state;
emit stateChanged(state);
if (state == Connected) {
emit connected();
if (m_probe && m_process)
m_process->closeWriteChannel();
}
else if (state != Connected && previous != Disconnected)
emit disconnected();
}