syncthingtray/syncthingconnector/syncthingprocess.h

174 lines
5.5 KiB
C++

#ifndef DATA_SYNCTHINGPROCESS_H
#define DATA_SYNCTHINGPROCESS_H
#include "./global.h"
#include <c++utilities/chrono/datetime.h>
#include <QProcess>
#include <QStringList>
#include <QTimer>
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
#include <memory>
#endif
namespace Data {
class SyncthingConnection;
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
struct SyncthingProcessInternalData;
struct SyncthingProcessIOHandler;
using SyncthingProcessBase = QIODevice;
#else
using SyncthingProcessBase = QProcess;
#endif
class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingProcess : public SyncthingProcessBase {
Q_OBJECT
Q_PROPERTY(bool running READ isRunning)
Q_PROPERTY(CppUtilities::DateTime activeSince READ activeSince)
Q_PROPERTY(bool manuallyStopped READ isManuallyStopped)
public:
explicit SyncthingProcess(QObject *parent = nullptr);
~SyncthingProcess() override;
bool isRunning() const;
CppUtilities::DateTime activeSince() const;
bool isActiveFor(unsigned int atLeastSeconds) const;
bool isManuallyStopped() const;
static SyncthingProcess *mainInstance();
static void setMainInstance(SyncthingProcess *mainInstance);
static QStringList splitArguments(const QString &arguments);
void reportError(QProcess::ProcessError error, const QString &errorString);
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
QProcess::ProcessState state() const;
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode openMode = QIODevice::ReadOnly);
qint64 bytesAvailable() const override;
void close() override;
int exitCode() const;
bool waitForFinished(int msecs = 30000);
bool waitForReadyRead(int msecs) override;
qint64 processId() const;
QString program() const;
QStringList arguments() const;
QProcess::ProcessChannelMode processChannelMode() const;
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
#endif
public Q_SLOTS:
void restartSyncthing(const QString &program, const QStringList &arguments, Data::SyncthingConnection *currentConnection = nullptr);
void startSyncthing(const QString &program, const QStringList &arguments);
void stopSyncthing(Data::SyncthingConnection *currentConnection = nullptr);
void killSyncthing();
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
void terminate();
void kill();
#endif
Q_SIGNALS:
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
void started();
void finished(int exitCode, QProcess::ExitStatus exitStatus);
void errorOccurred(QProcess::ProcessError error);
void stateChanged(QProcess::ProcessState newState);
#endif
void confirmKill();
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
protected:
qint64 readData(char *data, qint64 maxSize) override;
qint64 writeData(const char *data, qint64 len) override;
#endif
private Q_SLOTS:
void handleStarted();
void handleFinished(int exitCode, QProcess::ExitStatus exitStatus);
void killToRestart();
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
void handleError(int error, const QString &errorMessage, bool closed);
void bufferOutput();
void handleLeftoverProcesses();
#endif
private:
QString m_program;
QStringList m_arguments;
CppUtilities::DateTime m_activeSince;
QTimer m_killTimer;
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
std::shared_ptr<SyncthingProcessInternalData> m_process;
std::unique_ptr<SyncthingProcessIOHandler> m_handler;
QProcess::ProcessChannelMode m_mode;
#endif
bool m_manuallyStopped;
static SyncthingProcess *s_mainInstance;
};
/// \brief Returns whether the process is running.
inline bool SyncthingProcess::isRunning() const
{
return state() != QProcess::NotRunning;
}
/// \brief Returns the last time when QProcess::started() has been emitted.
inline CppUtilities::DateTime SyncthingProcess::activeSince() const
{
return m_activeSince;
}
/// \brief Checks whether the process already runs for the specified number of seconds.
inline bool SyncthingProcess::isActiveFor(unsigned int atLeastSeconds) const
{
return !m_activeSince.isNull() && (CppUtilities::DateTime::gmtNow() - m_activeSince).totalSeconds() > atLeastSeconds;
}
/// \brief Returns whether the process has been manually stopped via SyncthingProcess::stopSyncthing(), SyncthingProcess::killSyncthing()
/// or SyncthingProcess::restartSyncthing().
/// \remarks Reset on SyncthingProcess::startSyncthing() and SyncthingProcess::restartSyncthing().
inline bool SyncthingProcess::isManuallyStopped() const
{
return m_manuallyStopped;
}
/*!
* \brief Returns the "main" instance assigned via SyncthingProcess::setMainInstance().
*/
inline SyncthingProcess *SyncthingProcess::mainInstance()
{
return s_mainInstance;
}
/*!
* \brief Sets the "main" instance.
*/
inline void SyncthingProcess::setMainInstance(SyncthingProcess *mainInstance)
{
s_mainInstance = mainInstance;
}
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
/*!
* \brief Returns the QProcess::ProcessChannelMode like QProcess::processChannelMode().
*/
inline QProcess::ProcessChannelMode SyncthingProcess::processChannelMode() const
{
return m_mode;
}
/*!
* \brief Sets the QProcess::ProcessChannelMode like QProcess::setProcessChannelMode().
* \remarks
* - Does not affect an already running process.
* - Supports only QProcess::MergedChannels, QProcess::SeparateChannels and QProcess::ForwardedChannels.
*/
inline void SyncthingProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
{
m_mode = mode;
}
#endif
} // namespace Data
#endif // DATA_SYNCTHINGPROCESS_H