feat: finish dbus service: job/jobManager

Log:
This commit is contained in:
heyuming 2023-07-18 15:55:29 +08:00 committed by Comix
parent 3a278bec79
commit d288752fb3
9 changed files with 72 additions and 41 deletions

View File

@ -13,7 +13,7 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Qt6 REQUIRED COMPONENTS Core DBus) find_package(Qt6 REQUIRED COMPONENTS Core DBus Concurrent)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
add_subdirectory(src) add_subdirectory(src)

View File

@ -7,7 +7,7 @@
value="Value of `Status` is one of value="Value of `Status` is one of
`started`, `running`, `finished`, `started`, `running`, `finished`,
`suspending`, `suspend`, `suspending`, `suspend`,
`canceled` and `failed`." `canceled`."
/> />
</property> </property>
@ -22,13 +22,13 @@
will be emitted." will be emitted."
/> />
</method> </method>
<method name="Pause"> <method name="Suspend">
<annotation <annotation
name="org.freedesktop.DBus.Description" name="org.freedesktop.DBus.Description"
value="Success call to this method will value="Success call to this method will
change the Status of this Job to `pausing`. change the Status of this Job to `suspending`.
Then after some time this method call return, Then after some time this method call return,
Status will change to `paused`." Status will change to `suspend`."
/> />
</method> </method>
@ -36,8 +36,7 @@
<annotation <annotation
name="org.freedesktop.DBus.Description" name="org.freedesktop.DBus.Description"
value="Success call to this method will value="Success call to this method will
change the Status of this Job to `resuming`. Resumes the asynchronous computation.
Resuming Jobs will be queued along with pending Jobs.
Then after some time this method call return, Then after some time this method call return,
Status will change to `working`." Status will change to `working`."
/> />

View File

@ -26,17 +26,16 @@
<signal name="JobRemoved"> <signal name="JobRemoved">
<arg type="o" name="job" /> <arg type="o" name="job" />
<arg type="s" name="status" /> <arg type="s" name="status" />
<arg type="s" name="message" /> <arg type="av" name="result" />
<arg type="v" name="result" />
<annotation <annotation
name="org.freedesktop.DBus.Description" name="org.freedesktop.DBus.Description"
value="This signal report the job remove event. value="This signal report the job remove event.
`status` is the `status` porperty of that Job `status` is the `status` porperty of that Job
when it got removed. when it got removed.
`message` is the human readable message `result` is the result which produce by this job,
for caller to report to user or just simple logging. and user needs to traverse the list to determine
`result` is the result this job produce if it success. if the values are valid or not.
Method that return an object of Job Method that return an object of Job
should always have document should always have document
about the type and meaning of the `result`." about the type and meaning of the `result`."

View File

@ -24,6 +24,7 @@ target_include_directories(${BIN_NAME} PRIVATE
target_link_libraries(${BIN_NAME} PRIVATE target_link_libraries(${BIN_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::DBus
Qt${QT_VERSION_MAJOR}::Concurrent
Threads::Threads Threads::Threads
) )

View File

@ -3,24 +3,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
#include "jobmanager1service.h" #include "jobmanager1service.h"
#include <QUuid>
#include "global.h"
JobManager1Service::JobManager1Service() = default; JobManager1Service::JobManager1Service() = default;
JobManager1Service::~JobManager1Service() = default; JobManager1Service::~JobManager1Service() = default;
template <typename F, typename... Args>
void addJob(const QDBusObjectPath &source, F func, Args &&...args)
{
// TODO: impl
}
bool JobManager1Service::removeJob(const QDBusObjectPath &job,
const QString &status,
const QString &message,
const QDBusVariant &result)
{
// TODO: impl
return false;
}

View File

@ -9,7 +9,14 @@
#include <QMap> #include <QMap>
#include <QDBusObjectPath> #include <QDBusObjectPath>
#include <QSharedPointer> #include <QSharedPointer>
#include "jobservice.h" #include <QMutex>
#include <QMutexLocker>
#include <QtConcurrent>
#include <QFuture>
#include <QUuid>
#include "jobadaptor.h"
#include "global.h"
class JobManager1Service final : public QObject class JobManager1Service final : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -21,15 +28,52 @@ public:
JobManager1Service &operator=(JobManager1Service &&) = delete; JobManager1Service &operator=(JobManager1Service &&) = delete;
~JobManager1Service() override; ~JobManager1Service() override;
template<typename F,typename ...Args> template <typename F>
void addJob(const QDBusObjectPath &source,F func, Args&& ...args); void addJob(const QDBusObjectPath &source, F func, QVariantList args)
bool removeJob(const QDBusObjectPath &job, const QString &status, const QString &message, const QDBusVariant &result); {
static_assert(std::is_invocable_v<F, QVariant>, "param type must be QVariant.");
QString objectPath{DDEApplicationManager1JobObjectPath + QUuid::createUuid().toString()};
QFuture<QVariantList> future = QtConcurrent::mappedReduced(
args.begin(), args.end(), func, &QVariantList::insert, QVariantList{}, QtConcurrent::ReduceOption::OrderedReduce);
QSharedPointer<JobService> job{new JobService{future}};
auto path = QDBusObjectPath{objectPath};
{
QMutexLocker locker{&m_mutex};
m_jobs.insert(path, job); // Insertion is always successful
}
emit JobNew(path, source);
registerObjectToDbus<decltype(job.data()), JobAdaptor>(job.data(), objectPath, getDBusInterface<JobAdaptor>());
auto emitRemove = [this, job, path, future] {
decltype(m_jobs)::size_type removeCount{0};
{
QMutexLocker locker{&m_mutex};
removeCount = m_jobs.remove(path);
}
// removeCount means m_jobs can't find value which corresponding with path
// and we shouldn't emit jobRemoved signal because this signal may already has been emit
if (removeCount == 0) {
qCritical() << "Job already has been removed: " << path.path();
return;
}
QString result{job->status()};
for (const auto &val : future.result()) {
if (val.canConvert<QDBusError>()) {
result = "failed";
}
break;
}
emit this->JobRemoved(path, result, future.result());
};
future.then(QtFuture::Launch::Sync, emitRemove);
}
Q_SIGNALS: Q_SIGNALS:
void JobNew(const QDBusObjectPath &job, const QDBusObjectPath &source); void JobNew(const QDBusObjectPath &job, const QDBusObjectPath &source);
void JobRemoved(const QDBusObjectPath &job, const QString &status, const QString &message, const QDBusVariant &result); void JobRemoved(const QDBusObjectPath &job, const QString &status, const QVariantList &result);
private: private:
QMutex m_mutex;
QMap<QDBusObjectPath, QSharedPointer<JobService>> m_jobs; QMap<QDBusObjectPath, QSharedPointer<JobService>> m_jobs;
}; };

View File

@ -4,7 +4,7 @@
#include "jobservice.h" #include "jobservice.h"
JobService::JobService(const QFuture<QVariant>& job) JobService::JobService(const QFuture<QVariantList>& job)
: m_job(job) : m_job(job)
{ {
} }
@ -31,7 +31,7 @@ QString JobService::status() const
if (m_job.isRunning()) { if (m_job.isRunning()) {
return "running"; return "running";
} }
return "failed"; Q_UNREACHABLE();
} }
void JobService::Cancel() void JobService::Cancel()
@ -39,7 +39,7 @@ void JobService::Cancel()
m_job.cancel(); m_job.cancel();
} }
void JobService::Pause() void JobService::Suspend()
{ {
m_job.suspend(); m_job.suspend();
} }

View File

@ -14,18 +14,23 @@ class JobService : public QObject
Q_OBJECT Q_OBJECT
public: public:
~JobService() override; ~JobService() override;
JobService(const JobService &) = delete;
JobService(JobService &&) = delete;
JobService &operator=(const JobService &) = delete;
JobService &operator=(JobService &&) = delete;
Q_PROPERTY(QString Status READ status) Q_PROPERTY(QString Status READ status)
QString status() const; QString status() const;
public Q_SLOTS: public Q_SLOTS:
void Cancel(); void Cancel();
void Pause(); void Suspend();
void Resume(); void Resume();
private: private:
explicit JobService(const QFuture<QVariant>& job); friend class JobManager1Service;
QFuture<QVariant> m_job; explicit JobService(const QFuture<QVariantList>& job);
QFuture<QVariantList> m_job;
}; };
#endif #endif

View File

@ -62,7 +62,7 @@ bool registerObjectToDbus(T parent, const QString &path, const QString &interfac
"param type must derive QObject"); "param type must derive QObject");
auto &con = ApplicationManager1DBus::instance().CustomBus(); auto &con = ApplicationManager1DBus::instance().CustomBus();
if (!con.registerObject(path, interface, new U{parent})) { if (!con.registerObject(path, interface, new U{parent})) {
qWarning() << "register object failed:" << path << interface << con.lastError(); qCritical() << "register object failed:" << path << interface << con.lastError();
return false; return false;
} }
return true; return true;