135 lines
3.1 KiB
C++
135 lines
3.1 KiB
C++
#include "nativestreamer.h"
|
|
#include <QStandardPaths>
|
|
#include <QDebug>
|
|
|
|
QString NativeStreamer::ollie9pBin()
|
|
{
|
|
return QStandardPaths::findExecutable("ollie-9p");
|
|
}
|
|
|
|
QString NativeStreamer::serverAddr()
|
|
{
|
|
QString ns = qEnvironmentVariable("NAMESPACE");
|
|
if (ns.isEmpty()) {
|
|
// Plan 9 default: /tmp/ns.$USER.$DISPLAY
|
|
QString user = qEnvironmentVariable("USER");
|
|
QString display = qEnvironmentVariable("DISPLAY");
|
|
ns = "/tmp/ns." + user + "." + display;
|
|
}
|
|
return "unix!" + ns + "/ollie";
|
|
}
|
|
|
|
NativeStreamer::NativeStreamer(RestartPolicy policy, QObject *parent)
|
|
: QObject(parent)
|
|
, m_policy(policy)
|
|
{
|
|
m_restartTimer = new QTimer(this);
|
|
m_restartTimer->setSingleShot(true);
|
|
m_restartTimer->setInterval(500); // 500ms delay before restart
|
|
connect(m_restartTimer, &QTimer::timeout, this, [this]() {
|
|
if (!m_stopping && !m_path.isEmpty()) {
|
|
start(m_path);
|
|
}
|
|
});
|
|
}
|
|
|
|
NativeStreamer::~NativeStreamer()
|
|
{
|
|
stop();
|
|
}
|
|
|
|
void NativeStreamer::start(const QString &path)
|
|
{
|
|
if (m_process) {
|
|
stop();
|
|
}
|
|
|
|
m_path = path;
|
|
m_stopping = false;
|
|
|
|
m_process = new QProcess(this);
|
|
connect(m_process, &QProcess::readyReadStandardOutput, this, &NativeStreamer::onReadyRead);
|
|
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
|
this, &NativeStreamer::onProcessFinished);
|
|
|
|
m_process->start(ollie9pBin(), {"-a", serverAddr(), "read", path});
|
|
}
|
|
|
|
void NativeStreamer::stop()
|
|
{
|
|
m_stopping = true;
|
|
m_restartTimer->stop();
|
|
|
|
if (m_process) {
|
|
disconnect(m_process, nullptr, this, nullptr);
|
|
if (m_process->state() != QProcess::NotRunning) {
|
|
m_process->terminate(); // SIGTERM first
|
|
if (!m_process->waitForFinished(200)) {
|
|
m_process->kill(); // SIGKILL if still alive
|
|
m_process->waitForFinished(100);
|
|
}
|
|
}
|
|
m_process->deleteLater();
|
|
m_process = nullptr;
|
|
}
|
|
}
|
|
|
|
bool NativeStreamer::isRunning() const
|
|
{
|
|
return m_process && m_process->state() == QProcess::Running;
|
|
}
|
|
|
|
void NativeStreamer::setGuard(std::function<bool()> guard)
|
|
{
|
|
m_guard = guard;
|
|
}
|
|
|
|
void NativeStreamer::onReadyRead()
|
|
{
|
|
if (m_process) {
|
|
QByteArray data = m_process->readAllStandardOutput();
|
|
if (!data.isEmpty()) {
|
|
emit dataReady(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NativeStreamer::onProcessFinished(int exitCode, QProcess::ExitStatus status)
|
|
{
|
|
Q_UNUSED(exitCode)
|
|
Q_UNUSED(status)
|
|
|
|
if (m_process) {
|
|
m_process->deleteLater();
|
|
m_process = nullptr;
|
|
}
|
|
|
|
scheduleRestart();
|
|
}
|
|
|
|
void NativeStreamer::scheduleRestart()
|
|
{
|
|
if (m_stopping) {
|
|
return;
|
|
}
|
|
|
|
bool shouldRestart = false;
|
|
switch (m_policy) {
|
|
case Oneshot:
|
|
shouldRestart = false;
|
|
break;
|
|
case Looping:
|
|
shouldRestart = true;
|
|
break;
|
|
case Guarded:
|
|
shouldRestart = m_guard && m_guard();
|
|
break;
|
|
}
|
|
|
|
if (shouldRestart) {
|
|
m_restartTimer->start();
|
|
} else {
|
|
emit finished();
|
|
}
|
|
}
|