From 06ee5e589942df28d6f5345db73382db5ed93207 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 21 Aug 2023 16:02:26 +0800 Subject: [PATCH] refact: DesktopFile's method and structure Signed-off-by: ComixHe --- examples/launchApp/main.cpp | 4 +- src/dbus/applicationmanager1service.cpp | 41 +++++++++-------- src/dbus/applicationmanager1service.h | 7 +-- src/dbus/applicationservice.cpp | 45 +++++++++---------- src/dbus/applicationservice.h | 2 +- src/desktopentry.cpp | 50 +++++++++++---------- src/desktopentry.h | 59 ++++++++++++++++++++----- src/global.h | 38 ++++++++++++---- tests/ut_applicationmanager.cpp | 4 +- tests/ut_desktopentry.cpp | 4 +- 10 files changed, 155 insertions(+), 99 deletions(-) diff --git a/examples/launchApp/main.cpp b/examples/launchApp/main.cpp index 64ab0eb..99c173c 100644 --- a/examples/launchApp/main.cpp +++ b/examples/launchApp/main.cpp @@ -27,7 +27,7 @@ public: u8"JobNew", this, SLOT(jobNewForward(QDBusObjectPath, QDBusObjectPath)))) { - qFatal() << "connect JobNew failed."; + qFatal("connect JobNew failed."); } if (!con.connect(JobManager.service(), @@ -36,7 +36,7 @@ public: u8"JobRemoved", this, SLOT(jobRemovedForward(QDBusObjectPath, QString, QVariantList)))) { - qFatal() << "connect JobNew failed."; + qFatal("connect JobNew failed."); } connect(this, &Demo::applicationLaunched, [](QList apps) { diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 56f03fa..0475795 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -1,8 +1,9 @@ // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later - +#include "applicationadaptor.h" #include "dbus/applicationmanager1adaptor.h" +#include "applicationservice.h" #include "dbus/AMobjectmanager1adaptor.h" #include "systemdsignaldispatcher.h" #include @@ -10,17 +11,20 @@ ApplicationManager1Service::~ApplicationManager1Service() = default; -ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr ptr, QDBusConnection &connection) +ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr ptr, QDBusConnection &connection) noexcept : m_identifier(std::move(ptr)) { if (!connection.registerService(DDEApplicationManager1ServiceName)) { - qFatal() << connection.lastError(); + qFatal("%s", connection.lastError().message().toLocal8Bit().data()); } - new ApplicationManager1Adaptor{this}; - auto *tmp = new AMObjectManagerAdaptor{this}; + if (auto *tmp = new (std::nothrow) ApplicationManager1Adaptor{this}; tmp == nullptr) { + qCritical() << "new Application Manager Adaptor failed."; + std::terminate(); + } - if (tmp == nullptr) { + if (auto *tmp = new (std::nothrow) AMObjectManagerAdaptor{this}; tmp == nullptr) { + qCritical() << "new Object Manager of Application Manager Adaptor failed."; std::terminate(); } @@ -29,7 +33,12 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptrapplicationPath()) != m_applicationList.cend()) { - auto info = qInfo(); - info << "this application already exists."; - if (application->desktopFileSource().persistence()) { - info << "desktop source:" << application->desktopFileSource().fileSource(); - } + qInfo() << "this application already exists." + << "desktop source:" << application->desktopFileSource().sourcePath(); return false; } @@ -209,16 +215,9 @@ void ApplicationManager1Service::updateApplication(const QSharedPointerdesktopFileSource().modified(buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec)) { + if (destApp->desktopFileSource().modified(mtime)) { auto *newEntry = new (std::nothrow) DesktopEntry{}; if (newEntry == nullptr) { qCritical() << "new DesktopEntry failed."; diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index 6aa4296..4154efd 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -13,15 +13,16 @@ #include #include #include "dbus/jobmanager1service.h" -#include "dbus/APPobjectmanager1adaptor.h" -#include "dbus/applicationadaptor.h" +#include "desktopentry.h" #include "identifier.h" +class ApplicationService; + class ApplicationManager1Service final : public QObject { Q_OBJECT public: - explicit ApplicationManager1Service(std::unique_ptr ptr, QDBusConnection &connection); + explicit ApplicationManager1Service(std::unique_ptr ptr, QDBusConnection &connection) noexcept; ~ApplicationManager1Service() override; ApplicationManager1Service(const ApplicationManager1Service &) = delete; ApplicationManager1Service(ApplicationManager1Service &&) = delete; diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 26ed2fc..66b9dc2 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "dbus/applicationservice.h" +#include "APPobjectmanager1adaptor.h" #include "applicationmanager1service.h" #include "dbus/instanceadaptor.h" #include "pwd.h" @@ -34,28 +35,24 @@ ApplicationService::~ApplicationService() QSharedPointer ApplicationService::createApplicationService(DesktopFile source, ApplicationManager1Service *parent) noexcept { + QSharedPointer app{new (std::nothrow) ApplicationService{std::move(source), parent}}; + if (!app) { + qCritical() << "new application service failed."; + return nullptr; + } + QString objectPath; QTextStream sourceStream; - QFile sourceFile; - QString tempSource; - QSharedPointer app{nullptr}; - if (source.persistence()) { - objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(source.desktopId()); - sourceFile.setFileName(source.fileSource()); - if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) { - qCritical() << "desktop file can't open:" << source.fileSource() << sourceFile.errorString(); - return nullptr; - } + auto appId = app->desktopFileSource().desktopId(); - app.reset(new (std::nothrow) ApplicationService{std::move(source), parent}); - sourceStream.setDevice(&sourceFile); + if (!appId.isEmpty()) { + objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(appId); } else { - tempSource = source.fileSource(); objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128); - app.reset(new (std::nothrow) ApplicationService{std::move(source), parent}); - sourceStream.setString(&tempSource, QTextStream::ReadOnly | QTextStream::Text); } + + sourceStream.setDevice(app->desktopFileSource().sourceFile()); std::unique_ptr entry{std::make_unique()}; auto error = entry->parse(sourceStream); @@ -76,7 +73,11 @@ QSharedPointer ApplicationService::createApplicationService( app->m_applicationPath = QDBusObjectPath{std::move(objectPath)}; // TODO: icon lookup - new (std::nothrow) APPObjectManagerAdaptor{app.data()}; + if (auto *ptr = new (std::nothrow) APPObjectManagerAdaptor{app.data()}; ptr == nullptr) { + qCritical() << "new Object Manager of Application failed."; + return nullptr; + } + return app; } @@ -252,10 +253,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL auto resourceFile = variantValue.toString(); auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128); auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID; - - if (m_desktopSource.persistence()) { - commands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.fileSource())); - } + commands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath())); if (resourceFile.isEmpty()) { commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg( @@ -303,7 +301,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL QStringList ApplicationService::actions() const noexcept { if (m_entry.isNull()) { - qWarning() << "desktop entry is empty, isPersistence:" << m_desktopSource.persistence(); + qWarning() << "desktop entry is empty, source file:" << m_desktopSource.sourcePath(); return {}; } @@ -332,10 +330,7 @@ ObjectMap ApplicationService::GetManagedObjects() const QString ApplicationService::id() const noexcept { - if (m_desktopSource.persistence()) { - return m_desktopSource.desktopId(); - } - return {}; + return m_desktopSource.desktopId(); } IconMap ApplicationService::icons() const diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index b2a9d4d..b6562de 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -59,7 +59,7 @@ public: void removeOneInstance(const QDBusObjectPath &instance) noexcept; void removeAllInstance() noexcept; [[nodiscard]] const QDBusObjectPath &applicationPath() const noexcept { return m_applicationPath; } - [[nodiscard]] const DesktopFile &desktopFileSource() const noexcept { return m_desktopSource; } + [[nodiscard]] DesktopFile &desktopFileSource() noexcept { return m_desktopSource; } [[nodiscard]] const QMap> &applicationInstances() const noexcept { return m_Instances; diff --git a/src/desktopentry.cpp b/src/desktopentry.cpp index 68ebcf3..abdb09e 100644 --- a/src/desktopentry.cpp +++ b/src/desktopentry.cpp @@ -24,7 +24,11 @@ auto DesktopEntry::parserGroupHeader(const QString &str) noexcept return it; } -void functest(QMap p) {} +QString DesktopFile::sourcePath() const noexcept +{ + QFileInfo info(*m_fileSource); + return info.absoluteFilePath(); +} DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMap)::iterator ¤tGroup) noexcept { @@ -90,11 +94,14 @@ DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMa return DesktopErrorCode::NoError; } -std::optional DesktopFile::createTemporaryDesktopFile(QString content) noexcept +std::optional DesktopFile::createTemporaryDesktopFile(std::unique_ptr temporaryFile) noexcept { - auto now = std::chrono::high_resolution_clock::now().time_since_epoch(); - auto nano = std::chrono::duration_cast(now); - return DesktopFile{false, std::move(content), "", static_cast(nano.count())}; + auto mtime = getFileModifiedTime(*temporaryFile); + if (mtime == 0) { + qWarning() << "create temporary file failed."; + return std::nullopt; + } + return DesktopFile{std::move(temporaryFile), "", mtime}; } std::optional DesktopFile::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept @@ -134,17 +141,17 @@ std::optional DesktopFile::searchDesktopFileByPath(const QString &d id = FileId.chopped(1); // remove extra "-"" } - struct stat buf; - if (auto ret = stat(path.toLatin1().data(), &buf); ret == -1) { + auto filePtr = std::make_unique(std::move(path)); + + auto mtime = getFileModifiedTime(*filePtr); + + if (mtime == 0) { err = DesktopErrorCode::OpenFailed; - qWarning() << "get file" << path << "state failed:" << std::strerror(errno); return std::nullopt; } err = DesktopErrorCode::NoError; - constexpr std::size_t secToNano = 1e9; - - return DesktopFile{true, std::move(path), std::move(id), buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec}; + return DesktopFile{std::move(filePtr), std::move(id), mtime}; } std::optional DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept @@ -178,21 +185,18 @@ bool DesktopFile::modified(std::size_t time) const noexcept return time != m_mtime; } -DesktopErrorCode DesktopEntry::parse(const DesktopFile &file) noexcept +DesktopErrorCode DesktopEntry::parse(DesktopFile &file) noexcept { - QTextStream in; - if (file.persistence()) { - auto sourceFile = QFile(file.fileSource()); - if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) { - qWarning() << file.fileSource() << "can't open."; - return DesktopErrorCode::OpenFailed; - } - in.setDevice(&sourceFile); - } else { - in.setString(const_cast(&file.fileSource())); + DesktopFileGuard guard{file}; + + if (!guard.try_open()) { + qWarning() << file.sourcePath() << "can't open."; + return DesktopErrorCode::OpenFailed; } - return parse(in); + QTextStream stream; + stream.setDevice(file.sourceFile()); + return parse(stream); } DesktopErrorCode DesktopEntry::parse(QTextStream &stream) noexcept diff --git a/src/desktopentry.h b/src/desktopentry.h index 49cc425..b163498 100644 --- a/src/desktopentry.h +++ b/src/desktopentry.h @@ -2,13 +2,16 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later +#ifndef DESKTOPENTRY_H +#define DESKTOPENTRY_H + #include #include #include #include #include #include -#include +#include constexpr static auto defaultKeyStr = "default"; @@ -22,38 +25,68 @@ enum class DesktopErrorCode { EntryKeyInvalid }; +struct DesktopFileGuard; + struct DesktopFile { - DesktopFile(const DesktopFile &) = default; + friend struct DesktopFileGuard; + DesktopFile(const DesktopFile &) = delete; DesktopFile(DesktopFile &&) = default; - DesktopFile &operator=(const DesktopFile &) = default; + DesktopFile &operator=(const DesktopFile &) = delete; DesktopFile &operator=(DesktopFile &&) = default; ~DesktopFile() = default; - [[nodiscard]] const QString &fileSource() const noexcept { return m_fileSource; } + [[nodiscard]] QString sourcePath() const noexcept; + // WARNING: This raw pointer's ownership belong to DesktopFile, DO NOT MODIFY! + [[nodiscard]] QFile *sourceFile() const noexcept { return &sourceFileRef(); }; + [[nodiscard]] QFile &sourceFileRef() const noexcept { return *m_fileSource; }; [[nodiscard]] const QString &desktopId() const noexcept { return m_desktopId; } - [[nodiscard]] bool persistence() const noexcept { return m_isPersistence; } [[nodiscard]] bool modified(std::size_t time) const noexcept; static std::optional searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept; static std::optional searchDesktopFileByPath(const QString &desktopFilePath, DesktopErrorCode &err) noexcept; - static std::optional createTemporaryDesktopFile(QString content) noexcept; + static std::optional createTemporaryDesktopFile(std::unique_ptr temporaryFile) noexcept; private: - DesktopFile(bool persistence, QString &&source, QString &&fileId, std::size_t mtime) - : m_isPersistence(persistence) - , m_mtime(mtime) + DesktopFile(std::unique_ptr source, QString fileId, std::size_t mtime) + : m_mtime(mtime) , m_fileSource(std::move(source)) , m_desktopId(std::move(fileId)) { } - bool m_isPersistence; std::size_t m_mtime; - QString m_fileSource{""}; + std::unique_ptr m_fileSource{nullptr}; QString m_desktopId{""}; }; +struct DesktopFileGuard +{ + DesktopFileGuard(const DesktopFileGuard &) = delete; + DesktopFileGuard(DesktopFileGuard &&other) noexcept + : fileRef(other.fileRef) + { + } + DesktopFileGuard &operator=(const DesktopFileGuard &) = delete; + DesktopFileGuard &operator=(DesktopFileGuard &&) = delete; + + explicit DesktopFileGuard(DesktopFile &file) + : fileRef(file) + { + } + + bool try_open() { return fileRef.m_fileSource->open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text); } + ~DesktopFileGuard() + { + if (fileRef.m_fileSource->isOpen()) { + fileRef.m_fileSource->close(); + } + } + +private: + DesktopFile &fileRef; +}; + class DesktopEntry { public: @@ -86,7 +119,7 @@ public: DesktopEntry &operator=(DesktopEntry &&) = default; ~DesktopEntry() = default; - [[nodiscard]] DesktopErrorCode parse(const DesktopFile &file) noexcept; + [[nodiscard]] DesktopErrorCode parse(DesktopFile &file) noexcept; [[nodiscard]] DesktopErrorCode parse(QTextStream &stream) noexcept; [[nodiscard]] std::optional> group(const QString &key) const noexcept; [[nodiscard]] std::optional value(const QString &key, const QString &valueKey) const noexcept; @@ -100,3 +133,5 @@ private: QDebug operator<<(QDebug debug, const DesktopEntry::Value &v); QDebug operator<<(QDebug debug, const DesktopErrorCode &v); + +#endif diff --git a/src/global.h b/src/global.h index 041e077..a835f03 100644 --- a/src/global.h +++ b/src/global.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "constant.h" #include "config.h" @@ -103,7 +104,7 @@ public: } if (!m_initFlag) { - qFatal() << "invoke init at first."; + qFatal("invoke init at first."); } switch (m_serverType) { @@ -113,17 +114,17 @@ public: m_serverConnection.emplace(QDBusConnection::connectToBus(static_cast(m_serverType), ApplicationManagerServerDBusName)); if (!m_serverConnection->isConnected()) { - qFatal() << m_serverConnection->lastError(); + qFatal("%s", m_serverConnection->lastError().message().toLocal8Bit().data()); } return m_serverConnection.value(); } case DBusType::Custom: { if (m_serverBusAddress.isEmpty()) { - qFatal() << "connect to custom dbus must init this object by custom dbus address"; + qFatal("connect to custom dbus must init this object by custom dbus address"); } m_serverConnection.emplace(QDBusConnection::connectToBus(m_serverBusAddress, ApplicationManagerServerDBusName)); if (!m_serverConnection->isConnected()) { - qFatal() << m_serverConnection->lastError(); + qFatal("%s", m_serverConnection->lastError().message().toLocal8Bit().data()); } return m_serverConnection.value(); } @@ -140,7 +141,7 @@ public: QDBusConnection &globalDestBus() { if (!m_destConnection) { - qFatal() << "please set which bus should application manager to use to invoke other D-Bus service's method."; + qFatal("please set which bus should application manager to use to invoke other D-Bus service's method."); } return m_destConnection.value(); } @@ -157,18 +158,18 @@ public: m_destConnection.emplace( QDBusConnection::connectToBus(QDBusConnection::BusType::SessionBus, ApplicationManagerDestDBusName)); if (!m_destConnection->isConnected()) { - qFatal() << m_destConnection->lastError(); + qFatal("%s", m_destConnection->lastError().message().toLocal8Bit().data()); } return; } if (m_destBusAddress.isEmpty()) { - qFatal() << "connect to custom dbus must init this object by custom dbus address"; + qFatal("connect to custom dbus must init this object by custom dbus address"); } m_destConnection.emplace(QDBusConnection::connectToBus(m_destBusAddress, ApplicationManagerDestDBusName)); if (!m_destConnection->isConnected()) { - qFatal() << m_destConnection->lastError(); + qFatal("%s", m_destConnection->lastError().message().toLocal8Bit().data()); } } @@ -374,4 +375,25 @@ ObjectMap dumpDBusObject(const QMap> &map) return objs; } +inline std::size_t getFileModifiedTime(QFile &file) +{ + struct stat buf; + QFileInfo info{file}; + + if (!file.isOpen()) { + if (auto ret = file.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text); !ret) { + qWarning() << "open file" << info.absoluteFilePath() << "failed."; + return 0; + } + } + + if (auto ret = stat(info.absoluteFilePath().toLocal8Bit().data(), &buf); ret == -1) { + qWarning() << "get file" << info.absoluteFilePath() << "state failed:" << std::strerror(errno); + return 0; + } + + constexpr std::size_t secToNano = 1e9; + return buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec; +} + #endif diff --git a/tests/ut_applicationmanager.cpp b/tests/ut_applicationmanager.cpp index ba308bb..c829a17 100644 --- a/tests/ut_applicationmanager.cpp +++ b/tests/ut_applicationmanager.cpp @@ -32,8 +32,8 @@ public: bus.setDestBus(); m_am = new ApplicationManager1Service{std::make_unique(), bus.globalServerBus()}; - - DesktopFile file{true, "/usr/share/applications/test-Application.desktop", "test-Application", 0}; + auto ptr = std::make_unique(QString{"/usr/share/applications/test-Application.desktop"}); + DesktopFile file{std::move(ptr), "test-Application", 0}; QSharedPointer app = QSharedPointer::create(std::move(file), nullptr); QSharedPointer instance = QSharedPointer::create(InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}); diff --git a/tests/ut_desktopentry.cpp b/tests/ut_desktopentry.cpp index 539cba6..66d70a9 100644 --- a/tests/ut_desktopentry.cpp +++ b/tests/ut_desktopentry.cpp @@ -45,7 +45,7 @@ TEST_F(TestDesktopEntry, desktopFile) auto curDir = QDir::current(); QString path{curDir.absolutePath() + QDir::separator() + "data" + QDir::separator() + "applications" + QDir::separator() + "deepin-editor.desktop"}; - EXPECT_EQ(exampleFile->fileSource().toStdString(), path.toStdString()); + EXPECT_EQ(exampleFile->sourcePath(), path); EXPECT_EQ(exampleFile->desktopId().toStdString(), "deepin-editor"); } @@ -54,7 +54,7 @@ TEST_F(TestDesktopEntry, prase) const auto &exampleFile = file(); ASSERT_FALSE(exampleFile.isNull()); DesktopEntry entry; - QFile in{exampleFile->fileSource()}; + QFile in{exampleFile->sourcePath()}; ASSERT_TRUE(in.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)); QTextStream fs{&in}; auto err = entry.parse(fs);