1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
/*
* SPDX-FileCopyrightText: 2025 Lasath Fernando <devel@lasath.org>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "SystemdSysupdateTransaction.h"
#include "SystemdSysupdateBackend.h"
#include "libdiscover_systemdsysupdate_debug.h"
#include <QCoroDBusPendingReply>
#define SYSTEMDSYSUPDATE_LOG LIBDISCOVER_BACKEND_SYSTEMDSYSUPDATE_LOG
const auto PROGRESS_PROPERTY_NAME = QStringLiteral("Progress");
const QString SYSUPDATE_JOB_INTERFACE_NAME = QLatin1String(org::freedesktop::sysupdate1::Job::staticInterfaceName());
SystemdSysupdateTransaction::SystemdSysupdateTransaction(AbstractResource *resource, SystemdSysupdateUpdateReply &updateCall)
: Transaction(resource, resource, InstallRole)
{
// Can't cancel until we have a job ID
setCancellable(false);
setStatus(DownloadingStatus);
auto watcher = new QDBusPendingCallWatcher(updateCall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, resource](QDBusPendingCallWatcher *watcher) {
watcher->deleteLater();
const SystemdSysupdateUpdateReply reply = *watcher;
if (reply.isError()) {
qCCritical(SYSTEMDSYSUPDATE_LOG) << "Failed to create job:" << reply.error().message();
passiveMessage(reply.error().message());
setStatus(DoneWithErrorStatus);
return;
}
auto version = reply.argumentAt<0>();
auto id = reply.argumentAt<1>();
auto path = reply.argumentAt<2>();
qCDebug(SYSTEMDSYSUPDATE_LOG) << "Created sysupdate1::Job with path " << path;
// need to keep a reference to this to be able to cancel
m_job = new org::freedesktop::sysupdate1::Job(SYSUPDATE1_SERVICE, path.path(), SystemdSysupdateBackend::OUR_BUS(), this);
m_job->setInteractiveAuthorizationAllowed(true); // cancel may require authorization
setCancellable(true);
// Don't need to keep this around because we're just connecting to some signals (and it'll be deleted by Qt with the parent)
auto *properties = new org::freedesktop::DBus::Properties(SYSUPDATE1_SERVICE, path.path(), SystemdSysupdateBackend::OUR_BUS(), this);
connect(properties,
&org::freedesktop::DBus::Properties::PropertiesChanged,
this,
[this, properties](const QString &interface, const QVariantMap &changed, const QStringList &invalidated) -> QCoro::Task<> {
if (interface != SYSUPDATE_JOB_INTERFACE_NAME) {
co_return;
}
qCDebug(SYSTEMDSYSUPDATE_LOG) << "Properties changed:" << changed << "Invalidated:" << invalidated;
if (changed.contains(PROGRESS_PROPERTY_NAME)) {
setProgress(changed.value(PROGRESS_PROPERTY_NAME).toUInt());
}
if (invalidated.contains(PROGRESS_PROPERTY_NAME)) {
const auto reply = co_await properties->Get(SYSUPDATE_JOB_INTERFACE_NAME, PROGRESS_PROPERTY_NAME);
if (reply.isError()) {
qCCritical(SYSTEMDSYSUPDATE_LOG) << "Failed to get progress:" << reply.error().message();
co_return;
}
setProgress(reply.argumentAt(0).toUInt());
}
});
auto backend = qobject_cast<SystemdSysupdateBackend *>(resource->backend());
Q_ASSERT(backend);
connect(backend,
&SystemdSysupdateBackend::transactionRemoved,
this,
[id, resource, this](qulonglong jobId, const QDBusObjectPath &jobPath, int status) {
if (id != jobId) {
return;
}
qCInfo(SYSTEMDSYSUPDATE_LOG) << "Job" << jobPath.path() << "for target" << resource->name() << "finished with status" << status;
setStatus(status == 0 ? DoneStatus : DoneWithErrorStatus);
deleteLater();
});
});
}
void SystemdSysupdateTransaction::cancel()
{
if (!m_job) {
qWarning(SYSTEMDSYSUPDATE_LOG) << "Can't cancel transaction without a job";
return;
}
auto watcher = new QDBusPendingCallWatcher(m_job->Cancel(), this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [](QDBusPendingCallWatcher *watcher) {
watcher->deleteLater();
if (watcher->isError()) {
qWarning(SYSTEMDSYSUPDATE_LOG) << "Failed to cancel job:" << watcher->error().message();
return;
}
qDebug(SYSTEMDSYSUPDATE_LOG) << "Job cancelled";
});
}
|