Ensure no ubuntu-server process is running at startup. Fixes #6584

Signed-off-by: Pedro Pombeiro <pombeirp@users.noreply.github.com>
This commit is contained in:
Pedro Pombeiro 2018-11-16 17:34:39 +01:00
parent 73ccb44663
commit 50200404ce
No known key found for this signature in database
GPG Key ID: A65DEB11E4BBC647
4 changed files with 131 additions and 45 deletions

1
.gitignore vendored
View File

@ -130,6 +130,7 @@ CMakeCache.txt
**/CMakeFiles/
/StatusImPackage/*
*.AppImage
Status-Windows-x86_64.zip
/desktop/bin/*
/desktop/lib/*
/desktop/modules/*

View File

@ -38,8 +38,9 @@ static QStringList consoleOutputStrings;
static QMutex consoleOutputMutex;
#ifdef BUILD_FOR_BUNDLE
bool ubuntuServerStarted = false;
QProcess *g_ubuntuServerProcess = nullptr;
bool nodeJsServerStarted = false;
QProcess *g_nodeJsServerProcess = nullptr;
#define NODEJS_SERVER_NAME "ubuntu-server"
#endif
const int MAIN_WINDOW_WIDTH = 1024;
@ -54,12 +55,12 @@ const char *LOG_FILE_PATH_ENV_VAR_NAME = "STATUS_LOG_PATH";
// TODO: some way to change while running
class ReactNativeProperties : public QObject {
Q_OBJECT
Q_PROPERTY(bool liveReload READ liveReload WRITE setLiveReload NOTIFY
liveReloadChanged)
Q_PROPERTY(QUrl codeLocation READ codeLocation WRITE setCodeLocation NOTIFY
codeLocationChanged)
Q_PROPERTY(QString pluginsPath READ pluginsPath WRITE setPluginsPath NOTIFY
pluginsPathChanged)
Q_PROPERTY(
bool liveReload READ liveReload WRITE setLiveReload NOTIFY liveReloadChanged)
Q_PROPERTY(
QUrl codeLocation READ codeLocation WRITE setCodeLocation NOTIFY codeLocationChanged)
Q_PROPERTY(
QString pluginsPath READ pluginsPath WRITE setPluginsPath NOTIFY pluginsPathChanged)
Q_PROPERTY(
QString executor READ executor WRITE setExecutor NOTIFY executorChanged)
public:
@ -155,26 +156,29 @@ void writeSingleLineLogFromJSServer(const QString &msg);
#ifdef BUILD_FOR_BUNDLE
void runUbuntuServer();
void killZombieJsServer();
bool runNodeJsServer();
#endif
void loadFontsFromResources() {
QDirIterator it(":", QDirIterator::Subdirectories);
while (it.hasNext()) {
QString resourceFile = it.next();
if (resourceFile.endsWith(".otf", Qt::CaseInsensitive) ||
resourceFile.endsWith(".ttf", Qt::CaseInsensitive)) {
QFontDatabase::addApplicationFont(resourceFile);
qint32 fontId = QFontDatabase::addApplicationFont(resourceFile);
if (Q_UNLIKELY(fontId == -1)) {
qCDebug(STATUS) << "Unable to install font" << resourceFile;
}
}
}
}
void exceptionPostHandledCallback() {
#ifdef BUILD_FOR_BUNDLE
if (g_ubuntuServerProcess) {
g_ubuntuServerProcess->kill();
if (g_nodeJsServerProcess) {
g_nodeJsServerProcess->kill();
}
#endif
}
@ -199,7 +203,6 @@ QString getDataStoragePath() {
}
int main(int argc, char **argv) {
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
@ -207,7 +210,9 @@ int main(int argc, char **argv) {
QString appPath = QCoreApplication::applicationDirPath();
QString dataStoragePath = getDataStoragePath();
#ifndef BUILD_FOR_BUNDLE
#ifdef BUILD_FOR_BUNDLE
killZombieJsServer();
#else
appPath.append(CRASH_REPORT_EXECUTABLE_RELATIVE_PATH);
dataStoragePath = "";
#endif
@ -227,7 +232,15 @@ int main(int argc, char **argv) {
}
#ifdef BUILD_FOR_BUNDLE
runUbuntuServer();
if (!runNodeJsServer()) {
if (g_nodeJsServerProcess->state() == QProcess::NotRunning) {
// If we failed to start the Node.js server (happens on Windows if the Node.js server process was previously running), let's do a final attempt
delete g_nodeJsServerProcess;
if (!runNodeJsServer()) {
return 1;
}
}
}
app.setWindowIcon(QIcon(":/icon.png"));
#endif
@ -285,11 +298,11 @@ int main(int argc, char **argv) {
QString getLogFilePath() {
QString logFilePath;
#ifdef BUILD_FOR_BUNDLE
logFilePath = getDataStoragePath() + "/Status.log";
logFilePath = getDataStoragePath() + QDir::separator() + "Status.log";
#else
logFilePath = qEnvironmentVariable(LOG_FILE_PATH_ENV_VAR_NAME, "");
if (logFilePath.isEmpty()) {
logFilePath = getDataStoragePath() + "/StatusDev.log";
logFilePath = getDataStoragePath() + QDir::separator() + "StatusDev.log";
}
#endif
return logFilePath;
@ -310,49 +323,112 @@ void writeLogsToFile() {
}
#ifdef BUILD_FOR_BUNDLE
void runUbuntuServer() {
g_ubuntuServerProcess = new QProcess();
g_ubuntuServerProcess->setWorkingDirectory(getDataStoragePath());
g_ubuntuServerProcess->setProgram(QGuiApplication::applicationDirPath() +
"/ubuntu-server");
QObject::connect(g_ubuntuServerProcess, &QProcess::errorOccurred,
#ifdef Q_OS_WIN
#include <windows.h>
#include <tlhelp32.h>
bool IsProcessRunning(const wchar_t *processName) {
bool exists = false;
PROCESSENTRY32 entry = { sizeof(PROCESSENTRY32) };
HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != NULL) {
if (::Process32First(snapshot, &entry)) {
do {
if (!wcsicmp(entry.szExeFile, processName)) {
exists = true;
break;
}
} while (::Process32Next(snapshot, &entry));
}
::CloseHandle(snapshot);
}
return exists;
}
#endif
void killZombieJsServer() {
// Ensure that a zombie Node.js server process is not still running in the background before we spawn a new one
QString cmd;
#ifdef Q_OS_LINUX
cmd = QString("pkill -f %1").arg(NODEJS_SERVER_NAME);
#elif defined(Q_OS_MAC)
cmd = QString("killall -9 %1").arg(NODEJS_SERVER_NAME);
#elif defined(Q_OS_WIN)
#define _CAT(A, B) A##B
#define _W(A) _CAT(L, #A)
WCHAR exeName[_MAX_PATH];
wsprintf(exeName, L"%s.exe", _W(NODEJS_SERVER_NAME));
if (IsProcessRunning(exeName)) {
qCDebug(STATUS) << NODEJS_SERVER_NAME << "is running, killing it";
::ShellExecuteW(NULL, NULL, L"tskill", _W(NODEJS_SERVER_NAME), NULL, SW_HIDE);
} else {
qCDebug(STATUS) << NODEJS_SERVER_NAME << "is not running";
}
#endif
if (!cmd.isEmpty()) {
qCDebug(STATUS) << "Running " << cmd;
QByteArray cmdArray = cmd.toLocal8Bit();
system(cmdArray.data());
}
}
bool runNodeJsServer() {
g_nodeJsServerProcess = new QProcess();
g_nodeJsServerProcess->setWorkingDirectory(getDataStoragePath());
g_nodeJsServerProcess->setProgram(QGuiApplication::applicationDirPath() + QDir::separator() + NODEJS_SERVER_NAME);
QObject::connect(g_nodeJsServerProcess, &QProcess::errorOccurred,
[=](QProcess::ProcessError) {
qCWarning(JSSERVER) << "process name: "
<< qUtf8Printable(g_ubuntuServerProcess->program());
<< qUtf8Printable(g_nodeJsServerProcess->program());
qCWarning(JSSERVER) << "process error: "
<< qUtf8Printable(g_ubuntuServerProcess->errorString());
<< qUtf8Printable(g_nodeJsServerProcess->errorString());
});
QObject::connect(
g_ubuntuServerProcess, &QProcess::readyReadStandardOutput, [=] {
writeLogFromJSServer(g_ubuntuServerProcess->readAllStandardOutput().trimmed());
g_nodeJsServerProcess, &QProcess::readyReadStandardOutput, [=] {
writeLogFromJSServer(g_nodeJsServerProcess->readAllStandardOutput().trimmed());
});
QObject::connect(
g_ubuntuServerProcess, &QProcess::readyReadStandardError, [=] {
g_nodeJsServerProcess, &QProcess::readyReadStandardError, [=] {
QString output =
g_ubuntuServerProcess->readAllStandardError().trimmed();
g_nodeJsServerProcess->readAllStandardError().trimmed();
writeLogFromJSServer(output);
if (output.contains("Server starting")) {
ubuntuServerStarted = true;
nodeJsServerStarted = true;
}
});
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit,
[=]() {
qCDebug(STATUS) << "Kill ubuntu server";
g_ubuntuServerProcess->kill();
qCDebug(STATUS) << "Kill node.js server process";
g_nodeJsServerProcess->kill();
});
qCDebug(STATUS) << "starting ubuntu server...";
g_ubuntuServerProcess->start();
qCDebug(STATUS) << "starting node.js server process...";
g_nodeJsServerProcess->start();
qCDebug(STATUS) << "wait for started...";
while (!ubuntuServerStarted) {
QGuiApplication::processEvents();
if (g_nodeJsServerProcess->waitForReadyRead(10000)) {
// We know that the process started, now wait until it communicates that it has started
while (!nodeJsServerStarted) {
QGuiApplication::processEvents();
}
qCDebug(STATUS) << "waiting finished";
return true;
} else {
qCDebug(STATUS) << "failed to start process";
}
qCDebug(STATUS) << "waiting finished";
return false;
}
#endif
void writeLogFromJSServer(const QString &msg) {

View File

@ -1,6 +1,6 @@
# Build
```
``` shell
docker-compose -f docker-build/docker-compose.yml build
```
@ -8,7 +8,7 @@ This will install all the required sdks, depending on the connection will take s
# Run
```
``` shell
docker-compose -f docker-build/docker-compose.yml up
```
@ -18,7 +18,7 @@ You need to connect your device and accept the key.
After the figwheel prompt you can install the application running:
```
``` shell
docker-compose -f docker-build/docker-compose.yml exec adbd make run-android
```

View File

@ -207,11 +207,12 @@ function compile() {
-DJS_BUNDLE_PATH="$JS_BUNDLE_PATH" \
-DCMAKE_CXX_FLAGS:='-DBUILD_FOR_BUNDLE=1' || exit 1
fi
make -j5 || exit 1
make -S -j5 || exit 1
popd
}
function bundleWindows() {
local buildType="$1"
# TODO: Produce a setup program instead of a ZIP
pushd $WORKFOLDER
rm -rf Windows
@ -227,9 +228,10 @@ function bundleWindows() {
pushd Windows
cp $STATUSREACTPATH/.env .
mkdir -p assets/resources notifier
cp $STATUSREACTPATH/node_modules/node-notifier/vendor/snoreToast/SnoreToast.exe \
$STATUSREACTPATH/node_modules/node-notifier/vendor/notifu/*.exe \
cp $STATUSREACTPATH/node_modules/node-notifier/vendor/notifu/*.exe \
notifier/
cp $STATUSREACTPATH/node_modules/node-notifier/vendor/snoreToast/SnoreToast.exe \
.
cp -r $STATUSREACTPATH/resources/fonts \
$STATUSREACTPATH/resources/icons \
$STATUSREACTPATH/resources/images \
@ -237,7 +239,14 @@ function bundleWindows() {
local _bin=$STATUSREACTPATH/desktop/bin
rm -rf $_bin/cmake_install.cmake $_bin/Makefile $_bin/CMakeFiles $_bin/Status_autogen && \
cp -r $_bin/* .
zip -mr9 ../../Status-Windows-x86_64.zip .
local zipOptions="-mr9"
if [ -z $buildType ]; then
zipOptions="-mr1"
elif [ "$buildType" = "pr" ]; then
zipOptions="-mr2"
fi
zip $zipOptions ../../Status-Windows-x86_64.zip .
popd
rm -rf Windows
popd