kdeconnect-kde/core/dbushelper.cpp
Albert Vaca Cintora bbcbec7709 Refactor macOS startup code
Moves all the stuff that is needed to start DBus on macOS (which for some reason it needs several steps, involving the use of `launchctl`) into a single `startDBusDaemon()` function. Before, it was spread into `kdeconnectconfig.cpp`, `indicatorhelper_mac.cpp` and `dbushelper.cpp`.

It also removes checking for an existing DBus daemon and always starts our own, since in most cases we couldn't connect to it anyway. This, together with removing the sleep in the retries when polling for the DBus daemon from 3s to 100ms, makes the startup much faster, so I removed the loading splash screen.
2024-09-21 09:27:24 +00:00

164 lines
5.2 KiB
C++

/**
* SPDX-FileCopyrightText: 2014 Albert Vaca <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "dbushelper.h"
#include "core_debug.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QProcess>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QUrl>
#include "kdeconnectconfig.h"
#ifdef Q_OS_MAC
#include <KLocalizedString>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QStandardPaths>
#include <QThread>
#endif
namespace DBusHelper
{
void filterNonExportableCharacters(QString &s)
{
static QRegularExpression regexp(QStringLiteral("[^A-Za-z0-9_]"), QRegularExpression::CaseInsensitiveOption);
s.replace(regexp, QLatin1String("_"));
}
#ifdef Q_OS_MAC
const QString PrivateDbusAddr = QStringLiteral("unix:tmpdir=/tmp");
const QString PrivateDBusAddressPath = QStringLiteral("/tmp/private_dbus_address");
const QString DBUS_LAUNCHD_SESSION_BUS_SOCKET = QStringLiteral("DBUS_LAUNCHD_SESSION_BUS_SOCKET");
QProcess *m_dbusProcess = nullptr;
void setLaunchctlEnv(const QString &env)
{
QProcess setLaunchdDBusEnv;
setLaunchdDBusEnv.setProgram(QStringLiteral("launchctl"));
setLaunchdDBusEnv.setArguments({QStringLiteral("setenv"), DBUS_LAUNCHD_SESSION_BUS_SOCKET, env});
setLaunchdDBusEnv.start();
setLaunchdDBusEnv.waitForFinished();
}
void unsetLaunchctlEnv()
{
QProcess unsetLaunchdDBusEnv;
unsetLaunchdDBusEnv.setProgram(QStringLiteral("launchctl"));
unsetLaunchdDBusEnv.setArguments({QStringLiteral("unsetenv"), DBUS_LAUNCHD_SESSION_BUS_SOCKET});
unsetLaunchdDBusEnv.start();
unsetLaunchdDBusEnv.waitForFinished();
}
void stopDBusDaemon()
{
if (m_dbusProcess != nullptr) {
m_dbusProcess->terminate();
m_dbusProcess->waitForFinished();
delete m_dbusProcess;
m_dbusProcess = nullptr;
unsetLaunchctlEnv();
}
}
int startDBusDaemon()
{
if (m_dbusProcess) {
return 0;
}
qAddPostRoutine(stopDBusDaemon);
// Unset launchctl env and private dbus addr file, avoid block
unsetLaunchctlEnv();
QFile privateDBusAddressFile(PrivateDBusAddressPath);
if (privateDBusAddressFile.exists()) {
privateDBusAddressFile.resize(0);
}
QString kdeconnectDBusConfiguration;
QString dbusDaemonExecutable = QStandardPaths::findExecutable(QStringLiteral("dbus-daemon"), {QCoreApplication::applicationDirPath()});
if (!dbusDaemonExecutable.isNull()) {
kdeconnectDBusConfiguration = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("dbus-1/session.conf"));
} else {
// macOS Debug env
dbusDaemonExecutable = QLatin1String(qgetenv("craftRoot")) + QLatin1String("/../bin/dbus-daemon");
kdeconnectDBusConfiguration = QLatin1String(qgetenv("craftRoot")) + QLatin1String("/../share/dbus-1/session.conf");
}
m_dbusProcess = new QProcess();
m_dbusProcess->setProgram(dbusDaemonExecutable);
m_dbusProcess->setArguments({QStringLiteral("--print-address"),
QStringLiteral("--nofork"),
QStringLiteral("--config-file"),
kdeconnectDBusConfiguration,
QStringLiteral("--address"),
PrivateDbusAddr});
m_dbusProcess->setWorkingDirectory(QCoreApplication::applicationDirPath());
m_dbusProcess->setStandardOutputFile(PrivateDBusAddressPath);
m_dbusProcess->start();
m_dbusProcess->waitForStarted();
QFile dbusAddressFile(PrivateDBusAddressPath);
if (!dbusAddressFile.open(QFile::ReadOnly | QFile::Text)) {
qCCritical(KDECONNECT_CORE) << "Private DBus enabled but error read private dbus address conf";
return -1;
}
QTextStream in(&dbusAddressFile);
qCDebug(KDECONNECT_CORE) << "Waiting for private dbus";
int retry = 0;
QString addr = in.readLine();
while (addr.length() == 0 && retry < 150) {
qCDebug(KDECONNECT_CORE) << "Retry reading private DBus address";
QThread::msleep(100);
retry++;
addr = in.readLine(); // Read until first not empty line
}
if (addr.length() == 0) {
qCCritical(KDECONNECT_CORE) << "Private DBus enabled but read private dbus address failed";
return -2;
}
qCDebug(KDECONNECT_CORE) << "Private dbus address: " << addr;
QRegularExpressionMatch path;
if (!addr.contains(QRegularExpression(QStringLiteral("path=(?<path>/tmp/dbus-[A-Za-z0-9]+)")), &path)) {
qCCritical(KDECONNECT_CORE) << "Fail to parse dbus address";
return -3;
}
QString dbusAddress = path.captured(QStringLiteral("path"));
qCDebug(KDECONNECT_CORE) << "DBus address: " << dbusAddress;
if (dbusAddress.isEmpty()) {
qCCritical(KDECONNECT_CORE) << "Fail to extract dbus address";
return -4;
}
setLaunchctlEnv(dbusAddress);
if (!QDBusConnection::sessionBus().isConnected()) {
qCCritical(KDECONNECT_CORE) << "Invalid env:" << dbusAddress;
return -5;
}
qCDebug(KDECONNECT_CORE) << "Private D-Bus daemon launched and connected.";
return 0;
}
#endif // Q_OS_MAC
} // namespace DBusHelper