feat: watch systemd unit new and remove to sync state

add default values to XDG_DATA_DIRS if it dosen't set

Signed-off-by: ComixHe <heyuming@deepin.org>
Signed-off-by: black-desk <me@black-desk.cn>
This commit is contained in:
ComixHe
2023-08-08 15:10:32 +08:00
committed by Comix
parent 4687265e65
commit 799100436c
13 changed files with 313 additions and 52 deletions

View File

@ -22,6 +22,105 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
}
m_jobManager.reset(new JobManager1Service(this));
auto &dispatcher = SystemdSignalDispatcher::instance();
connect(&dispatcher,
&SystemdSignalDispatcher::SystemdUnitNew,
this,
[this](QString serviceName, QDBusObjectPath systemdUnitPath) {
auto [appId, instanceId] = processServiceName(serviceName);
if (appId.isEmpty()) {
return;
}
for (const auto &app : m_applicationList) {
if (app->id() == appId) [[unlikely]] {
const auto &applicationPath = app->m_applicationPath.path();
if (!app->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) {
qWarning() << "add Instance failed:" << applicationPath << serviceName << systemdUnitPath.path();
}
return;
}
}
qWarning() << "couldn't find application:" << serviceName << "in application manager.";
});
connect(&dispatcher,
&SystemdSignalDispatcher::SystemdUnitRemoved,
this,
[this](QString serviceName, QDBusObjectPath systemdUnitPath) {
auto pair = processServiceName(serviceName);
auto appId = pair.first, instanceId = pair.second;
if (appId.isEmpty()) {
return;
}
auto appIt = std::find_if(m_applicationList.cbegin(),
m_applicationList.cend(),
[&appId](const QSharedPointer<ApplicationService> &app) {
if (app->id() == appId) {
return true;
}
return false;
});
if (appIt == m_applicationList.cend()) [[unlikely]] {
qWarning() << "couldn't find app" << appId << "in application manager.";
return;
}
const auto &appRef = *appIt;
auto instanceIt = std::find_if(appRef->m_Instances.cbegin(),
appRef->m_Instances.cend(),
[&systemdUnitPath](const QSharedPointer<InstanceService> &value) {
if (value->systemdUnitPath() == systemdUnitPath) {
return true;
}
return false;
});
if (instanceIt != appRef->m_Instances.cend()) [[likely]] {
appRef->removeOneInstance(instanceIt.key());
}
});
}
QPair<QString, QString> ApplicationManager1Service::processServiceName(const QString &serviceName)
{
QString instanceId;
QString applicationId;
if (serviceName.endsWith(".service")) {
auto lastDotIndex = serviceName.lastIndexOf('.');
auto app = serviceName.sliced(0, lastDotIndex - 1); // remove suffix
if (app.contains('@')) {
auto atIndex = app.indexOf('@');
instanceId = app.sliced(atIndex + 1);
app.remove(atIndex, instanceId.length() + 1);
}
applicationId = app.split('-').last(); // drop launcher if it exists.
} else if (serviceName.endsWith(".scope")) {
auto lastDotIndex = serviceName.lastIndexOf('.');
auto app = serviceName.sliced(0, lastDotIndex - 1);
auto components = app.split('-');
instanceId = components.takeLast();
applicationId = components.takeLast();
} else {
qDebug() << "it's not service or slice or scope.";
return {};
}
if (instanceId.isEmpty()) {
instanceId = QUuid::createUuid().toString(QUuid::Id128);
}
return qMakePair(std::move(applicationId), std::move(instanceId));
}
QList<QDBusObjectPath> ApplicationManager1Service::list() const

View File

@ -60,6 +60,8 @@ private:
std::unique_ptr<Identifier> m_identifier;
QScopedPointer<JobManager1Service> m_jobManager{nullptr};
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
QPair<QString, QString> processServiceName(const QString &serviceName);
};
#endif

View File

@ -19,6 +19,16 @@ ApplicationService::~ApplicationService()
m_desktopSource.destruct(m_isPersistence);
}
qsizetype ApplicationService::applicationCheck(const QString &serviceName)
{
const auto &ApplicationId = id();
if (!serviceName.startsWith(ApplicationId)) [[likely]] {
return 0;
}
return ApplicationId.size();
}
QString ApplicationService::GetActionName(const QString &identifier, const QStringList &env)
{
const auto &supportedActions = actions();
@ -130,16 +140,16 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
auto resourceFile = variantValue.toString();
if (resourceFile.isEmpty()) {
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
commands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(
commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
this->id(), instanceRandomUUID)); // launcher should use this instanceId
QProcess process;
process.start(m_launcher, commands);
process.waitForFinished();
if (auto code = process.exitCode(); code != 0) {
qWarning() << "Launch Application Failed. exitCode:" << code;
return false;
return QString{""};
}
return addOneInstance(instanceRandomUUID, m_applicationPath.path()); // TODO: pass correct Systemd Unit Path
return DDEApplicationManager1InstanceObjectPath + instanceRandomUUID;
}
int location{0};
@ -167,8 +177,9 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
auto exitCode = process.exitCode();
if (exitCode != 0) {
qWarning() << "Launch Application Failed:" << binary << tmp;
return QString{""};
}
return addOneInstance(instanceRandomUUID, m_applicationPath.path());
return DDEApplicationManager1InstanceObjectPath + instanceRandomUUID;
},
std::move(res));
}
@ -254,8 +265,8 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString
void ApplicationService::removeOneInstance(const QDBusObjectPath &instance)
{
m_Instances.remove(instance);
unregisterObjectFromDBus(instance.path());
m_Instances.remove(instance);
}
void ApplicationService::removeAllInstance()

View File

@ -18,6 +18,7 @@
#include "global.h"
#include "desktopentry.h"
#include "desktopicons.h"
#include "systemdsignaldispatcher.h"
#include "dbus/jobmanager1service.h"
class ApplicationService : public QObject
@ -52,9 +53,9 @@ public:
const QString &getLauncher() const noexcept { return m_launcher; }
void setLauncher(const QString &launcher) noexcept { m_launcher = launcher; }
bool addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath = "/");
bool addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath);
void recoverInstances(const QList<QDBusObjectPath>) noexcept;
void removeOneInstance(const QDBusObjectPath &instance); // TODO: remove instance when app closed
void removeOneInstance(const QDBusObjectPath &instance);
void removeAllInstance();
public Q_SLOTS:
@ -133,6 +134,7 @@ private:
QSharedPointer<DesktopIcons> m_Icons{nullptr};
QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
QString userNameLookup(uid_t uid);
qsizetype applicationCheck(const QString &serviceName);
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields);
};

View File

@ -12,6 +12,7 @@
#include <QMutex>
#include <QMutexLocker>
#include <QtConcurrent>
#include <QDBusError>
#include <QFuture>
#include <QUuid>
#include "global.h"
@ -76,7 +77,7 @@ public:
QString result{job->status()};
for (const auto &val : future.result()) {
if (val.canConvert<QDBusError>()) {
if (val.metaType().id() == QMetaType::fromType<QDBusError>().id()) {
result = "failed";
}
break;