gui: remove dead code (ninepconnection, streamfsm)
These were replaced by NativeStreamer which uses ollie-9p subprocess for streaming reads.
This commit is contained in:
parent
6fda37ae96
commit
e10912de08
|
|
@ -1,191 +0,0 @@
|
||||||
#include "ninepconnection.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TRANSITION TABLE
|
|
||||||
* ================
|
|
||||||
*
|
|
||||||
* State | Event | Guard | Next State | Actions
|
|
||||||
* -------------|--------------|------------------------|--------------|------------------
|
|
||||||
* Disconnected | EvStart | | Connecting | spawnProcess
|
|
||||||
* Connecting | EvOpenMarker | | Connected | emit connected
|
|
||||||
* Connecting | EvExitFail | canRetry | RetryWait | scheduleRetry
|
|
||||||
* Connecting | EvExitFail | !canRetry | Disconnected |
|
|
||||||
* Connected | EvExitOk | | Connected | scheduleRetry (silent)
|
|
||||||
* Connected | EvExitFail | canRetry | RetryWait | emit disconnected, scheduleRetry
|
|
||||||
* Connected | EvExitFail | !canRetry | Disconnected | emit disconnected
|
|
||||||
* RetryWait | EvRetryTimer | | Connecting | spawnProcess
|
|
||||||
* Any | EvStop | | Disconnected | killProcess, emit disconnected (if was Connected)
|
|
||||||
*
|
|
||||||
* Signals:
|
|
||||||
* - connected: emitted when entering Connected from any other state
|
|
||||||
* - disconnected: emitted when leaving Connected for any other state
|
|
||||||
*/
|
|
||||||
|
|
||||||
NinePConnection::NinePConnection(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
m_retryTimer.setSingleShot(true);
|
|
||||||
connect(&m_retryTimer, &QTimer::timeout, this, [this]() { dispatch(EvRetryTimer); });
|
|
||||||
}
|
|
||||||
|
|
||||||
NinePConnection::~NinePConnection()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::start(const QString &program, const QStringList &args, int retryMs, int maxRetries)
|
|
||||||
{
|
|
||||||
m_program = program;
|
|
||||||
m_args = args;
|
|
||||||
m_retryMs = retryMs;
|
|
||||||
m_maxRetries = maxRetries;
|
|
||||||
m_retryCount = 0;
|
|
||||||
dispatch(EvStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::stop()
|
|
||||||
{
|
|
||||||
dispatch(EvStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::dispatch(Event ev)
|
|
||||||
{
|
|
||||||
State next = m_state;
|
|
||||||
|
|
||||||
switch (m_state) {
|
|
||||||
case Disconnected:
|
|
||||||
if (ev == EvStart) {
|
|
||||||
next = Connecting;
|
|
||||||
spawnProcess();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Connecting:
|
|
||||||
if (ev == EvStop) {
|
|
||||||
next = Disconnected;
|
|
||||||
killProcess();
|
|
||||||
} else if (ev == EvOpenMarker) {
|
|
||||||
next = Connected;
|
|
||||||
} else if (ev == EvExitFail) {
|
|
||||||
bool canRetry = m_retryMs > 0 && (m_maxRetries == 0 || m_retryCount < m_maxRetries);
|
|
||||||
if (canRetry) {
|
|
||||||
next = RetryWait;
|
|
||||||
++m_retryCount;
|
|
||||||
scheduleRetry();
|
|
||||||
} else {
|
|
||||||
next = Disconnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Connected:
|
|
||||||
if (ev == EvStop) {
|
|
||||||
next = Disconnected;
|
|
||||||
killProcess();
|
|
||||||
} else if (ev == EvExitOk) {
|
|
||||||
// Silent restart - stay Connected
|
|
||||||
m_retryCount = 0;
|
|
||||||
scheduleRetry();
|
|
||||||
} else if (ev == EvExitFail) {
|
|
||||||
bool canRetry = m_retryMs > 0 && (m_maxRetries == 0 || m_retryCount < m_maxRetries);
|
|
||||||
if (canRetry) {
|
|
||||||
next = RetryWait;
|
|
||||||
++m_retryCount;
|
|
||||||
scheduleRetry();
|
|
||||||
} else {
|
|
||||||
next = Disconnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RetryWait:
|
|
||||||
if (ev == EvStop) {
|
|
||||||
next = Disconnected;
|
|
||||||
m_retryTimer.stop();
|
|
||||||
} else if (ev == EvRetryTimer) {
|
|
||||||
next = Connecting;
|
|
||||||
spawnProcess();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next != m_state)
|
|
||||||
enter(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::enter(State state)
|
|
||||||
{
|
|
||||||
State prev = m_state;
|
|
||||||
m_state = state;
|
|
||||||
emit stateChanged(state);
|
|
||||||
|
|
||||||
if (state == Connected && prev != Connected)
|
|
||||||
emit connected();
|
|
||||||
else if (prev == Connected && state != Connected)
|
|
||||||
emit disconnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::spawnProcess()
|
|
||||||
{
|
|
||||||
if (m_process) return;
|
|
||||||
m_stderr.clear();
|
|
||||||
m_openMarkerSeen = false;
|
|
||||||
m_process = new QProcess(this);
|
|
||||||
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);
|
|
||||||
m_process->start(m_program, m_args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::killProcess()
|
|
||||||
{
|
|
||||||
m_retryTimer.stop();
|
|
||||||
if (m_process) {
|
|
||||||
m_process->disconnect(this);
|
|
||||||
m_process->kill();
|
|
||||||
m_process->waitForFinished(1000);
|
|
||||||
m_process->deleteLater();
|
|
||||||
m_process = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::scheduleRetry()
|
|
||||||
{
|
|
||||||
if (m_retryMs > 0)
|
|
||||||
m_retryTimer.start(m_retryMs);
|
|
||||||
else
|
|
||||||
spawnProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
int end = m_stderr.indexOf('\n');
|
|
||||||
if (end < 0) break;
|
|
||||||
QByteArray line = m_stderr.left(end).trimmed();
|
|
||||||
m_stderr.remove(0, end + 1);
|
|
||||||
if (line == "OLLIE_9P_OPEN") {
|
|
||||||
m_openMarkerSeen = true;
|
|
||||||
dispatch(EvOpenMarker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NinePConnection::onFinished(int exitCode, QProcess::ExitStatus)
|
|
||||||
{
|
|
||||||
if (!m_process) return;
|
|
||||||
m_process->deleteLater();
|
|
||||||
m_process = nullptr;
|
|
||||||
|
|
||||||
bool success = (exitCode == 0 && m_openMarkerSeen);
|
|
||||||
dispatch(success ? EvExitOk : EvExitFail);
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
#ifndef NINEPCONNECTION_H
|
|
||||||
#define NINEPCONNECTION_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NinePConnection - Resilient 9P subprocess connection.
|
|
||||||
*
|
|
||||||
* State machine with explicit events and transition table.
|
|
||||||
*/
|
|
||||||
class NinePConnection : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum State { Disconnected, Connecting, Connected, RetryWait };
|
|
||||||
Q_ENUM(State)
|
|
||||||
|
|
||||||
enum Event { EvStart, EvStop, EvOpenMarker, EvExitOk, EvExitFail, EvRetryTimer };
|
|
||||||
Q_ENUM(Event)
|
|
||||||
|
|
||||||
explicit NinePConnection(QObject *parent = nullptr);
|
|
||||||
~NinePConnection() override;
|
|
||||||
|
|
||||||
void start(const QString &program, const QStringList &args, int retryMs = 4000, int maxRetries = 0);
|
|
||||||
void stop();
|
|
||||||
State state() const { return m_state; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void connected();
|
|
||||||
void disconnected();
|
|
||||||
void readyRead(const QByteArray &data);
|
|
||||||
void stateChanged(State state);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onStdout();
|
|
||||||
void onStderr();
|
|
||||||
void onFinished(int exitCode, QProcess::ExitStatus status);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void dispatch(Event ev);
|
|
||||||
void enter(State state);
|
|
||||||
void spawnProcess();
|
|
||||||
void killProcess();
|
|
||||||
void scheduleRetry();
|
|
||||||
|
|
||||||
QProcess *m_process = nullptr;
|
|
||||||
QTimer m_retryTimer;
|
|
||||||
QString m_program;
|
|
||||||
QStringList m_args;
|
|
||||||
QByteArray m_stderr;
|
|
||||||
State m_state = Disconnected;
|
|
||||||
int m_retryMs = 4000;
|
|
||||||
int m_maxRetries = 0;
|
|
||||||
int m_retryCount = 0;
|
|
||||||
bool m_openMarkerSeen = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // NINEPCONNECTION_H
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
#include "streamfsm.h"
|
|
||||||
|
|
||||||
StreamFsm::StreamFsm(RestartPolicy policy, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_policy(policy)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamFsm::~StreamFsm()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::start(const QString &program, const QStringList &args)
|
|
||||||
{
|
|
||||||
m_program = program;
|
|
||||||
m_args = args;
|
|
||||||
if (m_state == Idle)
|
|
||||||
startProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::stop()
|
|
||||||
{
|
|
||||||
if (m_state == Idle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_proc) {
|
|
||||||
// Disconnect before killing so onFinished doesn't fire during teardown.
|
|
||||||
m_proc->disconnect();
|
|
||||||
m_proc->kill();
|
|
||||||
m_proc->waitForFinished(1000);
|
|
||||||
m_proc->deleteLater();
|
|
||||||
m_proc = nullptr;
|
|
||||||
}
|
|
||||||
transitTo(Idle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::setGuard(std::function<bool()> guard)
|
|
||||||
{
|
|
||||||
m_guard = std::move(guard);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::startProcess()
|
|
||||||
{
|
|
||||||
if (m_state != Idle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_proc = new QProcess(this);
|
|
||||||
connect(m_proc, &QProcess::readyReadStandardOutput,
|
|
||||||
this, &StreamFsm::onReadyRead);
|
|
||||||
connect(m_proc,
|
|
||||||
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
|
||||||
this, &StreamFsm::onFinished);
|
|
||||||
m_proc->start(m_program, m_args);
|
|
||||||
transitTo(Running);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::onReadyRead()
|
|
||||||
{
|
|
||||||
QByteArray data = m_proc->readAllStandardOutput();
|
|
||||||
if (!data.isEmpty())
|
|
||||||
emit readyRead(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::onFinished(int, QProcess::ExitStatus)
|
|
||||||
{
|
|
||||||
// Clean up the finished process.
|
|
||||||
m_proc->deleteLater();
|
|
||||||
m_proc = nullptr;
|
|
||||||
transitTo(Idle);
|
|
||||||
|
|
||||||
// Decide what to do next based on policy.
|
|
||||||
switch (m_policy) {
|
|
||||||
case Oneshot:
|
|
||||||
emit died();
|
|
||||||
break;
|
|
||||||
case Looping:
|
|
||||||
startProcess();
|
|
||||||
break;
|
|
||||||
case Guarded:
|
|
||||||
if (m_guard && m_guard())
|
|
||||||
startProcess();
|
|
||||||
else
|
|
||||||
emit died();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamFsm::transitTo(State s)
|
|
||||||
{
|
|
||||||
m_state = s;
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
#ifndef STREAMFSM_H
|
|
||||||
#define STREAMFSM_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
/// A formal 2-state FSM wrapping a QProcess streaming lifecycle.
|
|
||||||
///
|
|
||||||
/// States: Idle ──start()──→ Running ──stop()──→ Idle
|
|
||||||
/// Running ──process exit──→ Idle ──[policy]──→ Running | emit died()
|
|
||||||
///
|
|
||||||
/// Three restart policies:
|
|
||||||
/// Oneshot — process runs once, then emits died()
|
|
||||||
/// Looping — process always restarts after exit
|
|
||||||
/// Guarded — process restarts only if guard() returns true
|
|
||||||
///
|
|
||||||
/// All signal connections are managed internally. stop() is safe to call
|
|
||||||
/// from any state; it disconnects before killing to prevent spurious signals.
|
|
||||||
class StreamFsm : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum State { Idle, Running };
|
|
||||||
enum RestartPolicy { Oneshot, Looping, Guarded };
|
|
||||||
|
|
||||||
explicit StreamFsm(RestartPolicy policy, QObject *parent = nullptr);
|
|
||||||
~StreamFsm();
|
|
||||||
|
|
||||||
State state() const { return m_state; }
|
|
||||||
RestartPolicy policy() const { return m_policy; }
|
|
||||||
|
|
||||||
/// Store program/args and start the process (no-op if already Running).
|
|
||||||
void start(const QString &program, const QStringList &args);
|
|
||||||
|
|
||||||
/// Kill the process and transition to Idle. Does not emit died().
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/// Guard predicate for Guarded policy — called after exit to decide
|
|
||||||
/// whether to restart. Not used for Oneshot or Looping.
|
|
||||||
void setGuard(std::function<bool()> guard);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
/// Emitted with data from the process's stdout (partial reads).
|
|
||||||
void readyRead(const QByteArray &data);
|
|
||||||
|
|
||||||
/// Emitted when the process has exited and will NOT be restarted
|
|
||||||
/// (Oneshot policy, or Guarded policy with a false guard).
|
|
||||||
void died();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onReadyRead();
|
|
||||||
void onFinished(int exitCode, QProcess::ExitStatus status);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void startProcess();
|
|
||||||
void transitTo(State s);
|
|
||||||
|
|
||||||
State m_state = Idle;
|
|
||||||
QProcess *m_proc = nullptr;
|
|
||||||
RestartPolicy m_policy;
|
|
||||||
std::function<bool()> m_guard;
|
|
||||||
QString m_program;
|
|
||||||
QStringList m_args;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // STREAMFSM_H
|
|
||||||
Reference in New Issue