#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 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::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; }