-
Notifications
You must be signed in to change notification settings - Fork 130
/
stremioprocess.cpp
118 lines (100 loc) · 4.28 KB
/
stremioprocess.cpp
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
#include "stremioprocess.h"
#ifdef WIN32
#include <windows.h>
#include <QDebug>
HANDLE jobMainProcess = NULL;
#endif
#define ERR_BUF_LINES 200
void Process::start(const QString &program, const QVariantList &arguments, QString mPattern) {
#ifdef WIN32
// On windows, Child processes by default survive death of their parent, unlike on *nix
// Only By default! We have to tell the kernel that we want something else
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161(v=vs.85).aspx
// NOTE: On Windows 7 process can only belong to single job.
// Qt Creator makes one thus you cannot debug Jobs on windows 7.
// Nested jobs were added in Windows 8
if (!jobMainProcess) {
jobMainProcess = CreateJobObject(NULL, NULL);
if(NULL == jobMainProcess)
{
qDebug() << "[WIN32] Could not create WIN32 Job. Node.exe will leak";
}
else
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |\
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
if(0 == SetInformationJobObject( jobMainProcess, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
qDebug() << "[WIN32] Failed to SetInformationJobObject";
}
}
}
#endif
QStringList args;
// convert QVariantList from QML to QStringList for QProcess
for (int i = 0; i < arguments.length(); i++)
args << arguments[i].toString();
if (!mPattern.isEmpty()) {
this->magicPattern = mPattern.toLatin1();
this->magicPatternFound = false;
}
// We will also proxy the error channel ourselves, because otherwise we have issues on Windows 7 because of
// the lack of stderr
//this->setProcessChannelMode(QProcess::ForwardedErrorChannel);
QObject::connect(this, &QProcess::errorOccurred, this, &Process::onError);
QObject::connect(this, &QProcess::readyReadStandardOutput, this, &Process::onOutput);
QObject::connect(this, &QProcess::readyReadStandardError, this, &Process::onStdErr);
QObject::connect(this, &QProcess::started, this, &Process::onStarted);
QProcess::start(program, args);
}
bool Process::waitForFinished(int msecs) {
return QProcess::waitForFinished(msecs);
}
void Process::onError(QProcess::ProcessError error) {
this->errorThrown(error);
}
void Process::onOutput() {
setReadChannel(QProcess::ProcessChannel::StandardOutput);
while (this->canReadLine()) {
// from http://doc.qt.io/qt-5/qiodevice.html#readLine
// The newline character ('\n') is included in the buffer. If a newline is not encountered before maxSize - 1 bytes are read, a newline will not be inserted into the buffer. On windows newline characters are replaced with '\n'.
QByteArray line = this->readLine();
std::cout << line.toStdString();
if (!this->magicPatternFound) checkServerAddressMessage(line);
}
}
void Process::onStdErr() {
setReadChannel(QProcess::ProcessChannel::StandardError);
while (this->canReadLine()) {
QByteArray line = this->readLine();
errBuff.append(line);
if(errBuff.size() > ERR_BUF_LINES) {
errBuff.removeFirst();
}
std::cerr << line.toStdString();
}
}
QByteArray Process::getErrBuff() {
return errBuff.join();
//return QString::fromUtf16((ushort *)(errBuff.join()).data());
}
void Process::onStarted() {
#ifdef WIN32
// On windows, Child processes by default survive death of their parent
// .... unless assigned to our job.
int err = AssignProcessToJobObject(jobMainProcess, ((_PROCESS_INFORMATION*)this->pid())->hProcess);
if (0 == err) {
qDebug() << "[WIN32] AssignProcessToJobObject failed with code: " << err;
};
#endif
}
void Process::checkServerAddressMessage(QByteArray message) {
if(message.startsWith(this->magicPattern)) {
this->magicPatternFound = true;
addressReady(QString(message.remove(0, this->magicPattern.size())));
// WARNING: we don't seem to be able to change process channel mode at runtime
//QObject::disconnect(this, &QProcess::readyReadStandardOutput, this, &Process::onOutput);
//this->setProcessChannelMode(QProcess::ForwardedChannels);
}
}