File: syncthingprocess.h

package info (click to toggle)
syncthingtray 1.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,804 kB
  • sloc: cpp: 31,085; xml: 1,694; java: 570; sh: 81; javascript: 53; makefile: 25
file content (248 lines) | stat: -rw-r--r-- 9,423 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#ifndef DATA_SYNCTHINGPROCESS_H
#define DATA_SYNCTHINGPROCESS_H

#include "./global.h"

#include <c++utilities/chrono/datetime.h>

#include <QAbstractNativeEventFilter>
#include <QProcess>
#include <QStringList>
#include <QTimer>

#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
#include <memory>
#endif

#if defined(LIB_SYNCTHING_CONNECTOR_NO_PROCESS) || (!QT_CONFIG(process) && !defined(LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS))
#ifndef LIB_SYNCTHING_CONNECTOR_NO_PROCESS
#define LIB_SYNCTHING_CONNECTOR_NO_PROCESS
#endif
#if !QT_CONFIG(process)
namespace QProcess {
enum ProcessError { FailedToStart, Crashed, Timedout, ReadError, WriteError, UnknownError };
enum ProcessState { NotRunning, Starting, Running };
enum ProcessChannel { StandardOutput, StandardError };
enum ProcessChannelMode { SeparateChannels, MergedChannels, ForwardedChannels, ForwardedOutputChannel, ForwardedErrorChannel };
enum InputChannelMode { ManagedInputChannel, ForwardedInputChannel };
enum ExitStatus { NormalExit, CrashExit };
} // namespace QProcess
#endif
#endif

namespace Data {

class SyncthingConnection;
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
#define LIB_SYNCTHING_CONNECTOR_PROCESS_IO_DEV_BASED
struct SyncthingProcessInternalData;
struct SyncthingProcessIOHandler;
#elif defined(LIB_SYNCTHING_CONNECTOR_NO_PROCESS)
#define LIB_SYNCTHING_CONNECTOR_PROCESS_IO_DEV_BASED
#define LIB_SYNCTHING_CONNECTOR_NOOP_PROCESS
#endif

#ifdef LIB_SYNCTHING_CONNECTOR_PROCESS_IO_DEV_BASED
using SyncthingProcessBase = QIODevice;
#else
using SyncthingProcessBase = QProcess;
#endif

class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingProcess : public SyncthingProcessBase, private QAbstractNativeEventFilter {
    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;
    static bool isActiveFor(CppUtilities::DateTime activeSince, unsigned int atLeastSeconds);
    bool isActiveWithoutSleepFor(unsigned int atLeastSeconds) const;
    bool isActiveWithoutSleepFor(CppUtilities::DateTime activeSince, unsigned int atLeastSeconds) const;
    static bool isActiveWithoutSleepFor(
        CppUtilities::DateTime lastWakeUp, bool isFallingAsleep, CppUtilities::DateTime activeSince, unsigned int atLeastSeconds);
    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_PROCESS_IO_DEV_BASED
    QProcess::ProcessState state() const;
    void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode openMode = QIODevice::ReadOnly);
    void start(const QStringList &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_PROCESS_IO_DEV_BASED
    void terminate();
    void kill();
#endif

Q_SIGNALS:
#ifdef LIB_SYNCTHING_CONNECTOR_PROCESS_IO_DEV_BASED
    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_PROCESS_IO_DEV_BASED
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_PROCESS_IO_DEV_BASED
    void handleError(int error, const QString &errorMessage, bool closed);
    void bufferOutput();
    void handleLeftoverProcesses();
#endif

private:
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
    bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override;
#else
    bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override;
#endif

    QString m_program;
    QStringList m_arguments;
    CppUtilities::DateTime m_activeSince;
    CppUtilities::DateTime m_lastWakeUp;
    QTimer m_killTimer;
#ifdef LIB_SYNCTHING_CONNECTOR_BOOST_PROCESS
    std::shared_ptr<SyncthingProcessInternalData> m_process;
    std::unique_ptr<SyncthingProcessIOHandler> m_handler;
#endif
#ifdef LIB_SYNCTHING_CONNECTOR_PROCESS_IO_DEV_BASED
    QProcess::ProcessChannelMode m_mode;
#endif
    bool m_manuallyStopped;
    bool m_fallingAsleep;
    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 isActiveFor(m_activeSince, atLeastSeconds);
}

/// \brief Checks whether a process already runs for the specified number of seconds.
inline bool SyncthingProcess::isActiveFor(CppUtilities::DateTime activeSince, unsigned int atLeastSeconds)
{
    return !activeSince.isNull() && (CppUtilities::DateTime::gmtNow() - activeSince).totalSeconds() > atLeastSeconds;
}

/// \brief Checks whether the process already runs for the specified number of seconds.
/// \remarks Considers only the time since the last wakeup if known; otherwise it is identical to isActiveFor().
inline bool SyncthingProcess::isActiveWithoutSleepFor(unsigned int atLeastSeconds) const
{
    return isActiveWithoutSleepFor(m_activeSince, atLeastSeconds);
}

/// \brief Checks whether a process already runs for the specified number of seconds.
/// \remarks Considers only the time since the last wakeup if known; otherwise it is identical to isActiveFor().
inline bool SyncthingProcess::isActiveWithoutSleepFor(CppUtilities::DateTime activeSince, unsigned int atLeastSeconds) const
{
    return isActiveWithoutSleepFor(m_lastWakeUp, m_fallingAsleep, activeSince, atLeastSeconds);
}

/// \brief Checks whether a process already runs for the specified number of seconds.
/// \remarks Considers only the time since the last wakeup if known; otherwise it is identical to isActiveFor().
inline bool SyncthingProcess::isActiveWithoutSleepFor(
    CppUtilities::DateTime lastWakeUp, bool isFallingAsleep, CppUtilities::DateTime activeSince, unsigned int atLeastSeconds)
{
    if (!atLeastSeconds) {
        return true;
    }
    if (activeSince.isNull() || isFallingAsleep) {
        return false;
    }
    const auto now = CppUtilities::DateTime::gmtNow();
    return ((now - activeSince).totalSeconds() > atLeastSeconds) && (lastWakeUp.isNull() || ((now - lastWakeUp).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_PROCESS_IO_DEV_BASED
/*!
 * \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