Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions api/dbus/org.deepin.linglong.PackageManager1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ SPDX-License-Identifier: LGPL-3.0-or-later
<arg direction="in" name="parameters" type="a{sv}" />
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap" />
</method>
<method name="ReplyInteraction">
<arg direction="in" name="task" type="o" />
<arg direction="in" name="replies" type="a{sv}" />
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap" />
</method>
<property name="Configuration" type="a{sv}" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap" />
</property>
Expand All @@ -76,5 +81,11 @@ SPDX-License-Identifier: LGPL-3.0-or-later
<signal name="TaskRemoved">
<arg name="task" type="o" />
</signal>
<signal name="RequestInteraction">
<arg name="task" type="o" />
<arg name="messageID" type="i" />
<arg name="additionalMessage" type="a{sv}" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="QVariantMap" />
</signal>
</interface>
</node>
9 changes: 0 additions & 9 deletions api/dbus/org.deepin.linglong.Task1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,9 @@ SPDX-License-Identifier: LGPL-3.0-or-later
<node>
<interface name="org.deepin.linglong.Task1">
<method name="Cancel" />
<method name="ReplyInteraction">
<arg direction="in" name="replies" type="a{sv}" />
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap" />
</method>
<property name="State" type="i" access="read" />
<property name="Percentage" type="d" access="read" />
<property name="Message" type="s" access="read" />
<property name="Code" type="i" access="read" />
<signal name="RequestInteraction">
<arg name="messageID" type="i" />
<arg name="additionalMessage" type="a{sv}" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap" />
</signal>
</interface>
</node>
70 changes: 54 additions & 16 deletions libs/linglong/src/linglong/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@
#include "ocppi/types/ContainerListItem.hpp"

#include <fmt/ranges.h>
#include <linux/un.h>

Check warning on line 51 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <linux/un.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <nlohmann/json.hpp>

Check warning on line 52 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <nlohmann/json.hpp> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QDBusInterface>

Check warning on line 54 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QEventLoop> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDBusReply>

Check warning on line 55 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFileInfo> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QEventLoop>

Check warning on line 56 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QProcess> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFileInfo>
#include <QProcess>

Check warning on line 58 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <algorithm> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <algorithm>
#include <cassert>
Expand Down Expand Up @@ -293,9 +295,14 @@
handleTaskState();
}

void Cli::onTaskRequestInteraction(int messageID, const QVariantMap &additionalMessage)
void Cli::interaction(const QDBusObjectPath &object_path,
int messageID,
const QVariantMap &additionalMessage)
{
LINGLONG_TRACE("interactive with user")
if (object_path.path() != taskObjectPath) {
return;
}
Comment thread
reddevillg marked this conversation as resolved.

auto messageType = static_cast<api::types::v1::InteractionMessageType>(messageID);
auto msg = common::serialize::fromQVariantMap<
Expand Down Expand Up @@ -346,13 +353,14 @@
LogD("action: {}", action);

auto reply = api::types::v1::InteractionReply{ .action = action };
if (!this->task) {
this->printer.printErr(LINGLONG_ERRV("task object is null"));
auto pkgMan = this->getPkgMan();
if (!pkgMan) {
this->printer.printErr(pkgMan.error());
return;
}

QDBusPendingReply<void> dbusReply =
this->task->ReplyInteraction(common::serialize::toQVariantMap(reply));
(*pkgMan)->ReplyInteraction(object_path, common::serialize::toQVariantMap(reply));
dbusReply.waitForFinished();
if (dbusReply.isError()) {
this->printer.printErr(
Expand Down Expand Up @@ -535,7 +543,7 @@
if (!conn.connect(pkgMan->service(),
pkgMan->path(),
pkgMan->interface(),
"TaskAdd",
"TaskAdded",
this,
SLOT(onTaskAdded(QDBusObjectPath)))) {
return LINGLONG_ERR("couldn't connect to package manager signal 'TaskAdded'");
Expand All @@ -550,6 +558,16 @@
return LINGLONG_ERR("couldn't connect to package manager signal 'TaskRemoved'");
}

if (!conn.connect(pkgMan->service(),
pkgMan->path(),
pkgMan->interface(),
"RequestInteraction",
this,
SLOT(interaction(QDBusObjectPath, int, QVariantMap)))) {
return LINGLONG_ERR(fmt::format("Failed to connect signal RequestInteraction: {}",
conn.lastError().message().toStdString()));
}

this->pkgManSignalsInitialized = true;
return LINGLONG_OK;
}
Expand Down Expand Up @@ -2246,6 +2264,30 @@
return 0;
}

utils::error::Result<void> Cli::syncTaskProperties()
{
LINGLONG_TRACE("syncTaskProperties");

auto pkgMan = this->getPkgMan();
if (!pkgMan) {
return LINGLONG_ERR(pkgMan);
}

QDBusInterface properties((*pkgMan)->service(),
this->taskObjectPath,
"org.freedesktop.DBus.Properties",
(*pkgMan)->connection());
QDBusReply<QVariantMap> reply =
properties.call("GetAll", QStringLiteral("org.deepin.linglong.Task1"));
if (!reply.isValid()) {
return LINGLONG_ERR(
fmt::format("failed to get task properties: {}", reply.error().message().toStdString()));
}
Comment thread
reddevillg marked this conversation as resolved.

this->onTaskPropertiesChanged(QStringLiteral("org.deepin.linglong.Task1"), reply.value(), {});
return LINGLONG_OK;
}

utils::error::Result<void> Cli::waitTaskCreated(QDBusPendingReply<QVariantMap> &reply,
TaskType taskType)
{
Expand Down Expand Up @@ -2285,21 +2327,17 @@
conn.lastError().message().toStdString()));
}

if (!conn.connect((*pkgMan)->service(),
taskObjectPath,
"org.deepin.linglong.Task1",
"RequestInteraction",
this,
SLOT(onTaskRequestInteraction(int, QVariantMap)))) {
return LINGLONG_ERR(fmt::format("Failed to connect signal RequestInteraction: {}",
conn.lastError().message().toStdString()));
}

return LINGLONG_OK;
return this->syncTaskProperties();
}

void Cli::waitTaskDone()
{
if (this->taskState.state == api::types::v1::State::Failed
|| this->taskState.state == api::types::v1::State::Canceled
|| this->taskState.state == api::types::v1::State::Succeed) {
return;
}

QEventLoop loop;
if (QObject::connect(this, &Cli::taskDone, &loop, &QEventLoop::quit) == nullptr) {
LogE("connect taskDone failed");
Expand Down
5 changes: 4 additions & 1 deletion libs/linglong/src/linglong/cli/cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ class Cli : public QObject
void detectDrivers();
utils::error::Result<api::dbus::v1::PackageManager *> getPkgMan();
utils::error::Result<void> initPkgManSignals();
utils::error::Result<void> syncTaskProperties();
int runResolvedContext(runtime::RunContext &runContext,
const RunOptions &options,
std::optional<api::types::v1::RuntimeConfigure> runtimeConfig);
Expand Down Expand Up @@ -272,7 +273,9 @@ private Q_SLOTS:
void onTaskPropertiesChanged(const QString &interface,
const QVariantMap &changed_properties,
const QStringList &invalidated_properties);
void onTaskRequestInteraction(int messageID, const QVariantMap &additionalMessage);
void interaction(const QDBusObjectPath &object_path,
int messageID,
const QVariantMap &additionalMessage);

Q_SIGNALS:
void taskDone();
Expand Down
116 changes: 115 additions & 1 deletion libs/linglong/src/linglong/package_manager/package_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

#include "package_manager.h"

#include "configure.h"

Check warning on line 9 in libs/linglong/src/linglong/package_manager/package_manager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "configure.h" not found.
#include "linglong/api/types/helper.h"

Check warning on line 10 in libs/linglong/src/linglong/package_manager/package_manager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/api/types/helper.h" not found.
#include "linglong/api/types/v1/Generators.hpp" // IWYU pragma: keep

Check warning on line 11 in libs/linglong/src/linglong/package_manager/package_manager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/api/types/v1/Generators.hpp" not found.
#include "linglong/api/types/v1/InteractionReply.hpp"

Check warning on line 12 in libs/linglong/src/linglong/package_manager/package_manager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/api/types/v1/PackageInfoV2.hpp" not found.
#include "linglong/api/types/v1/PackageInfoV2.hpp"
#include "linglong/api/types/v1/PackageManager1JobInfo.hpp"
#include "linglong/api/types/v1/PackageManager1PruneResult.hpp"
Expand Down Expand Up @@ -45,12 +46,14 @@

#include <QDBusInterface>
#include <QDBusReply>
#include <QDBusServiceWatcher>
#include <QDBusUnixFileDescriptor>
#include <QEventLoop>
#include <QMetaObject>
#include <QTimer>

#include <algorithm>
#include <chrono>
#include <cstdint>
#include <functional>
#include <unordered_map>
Expand Down Expand Up @@ -655,7 +658,7 @@
PackageTask &taskRef = dynamic_cast<PackageTask &>(task);
if (msgType == api::types::v1::InteractionMessageType::Upgrade
&& !options.skipInteraction) {
if (!taskRef.waitConfirm(msgType, additionalMessage)) {
if (!this->waitConfirm(taskRef, msgType, additionalMessage)) {
return;
}
}
Expand Down Expand Up @@ -1887,6 +1890,117 @@
});
}

void PackageManager::ReplyInteraction(QDBusObjectPath object_path, const QVariantMap &replies)
{
Q_EMIT this->ReplyReceived(object_path, replies);
}

void PackageManager::onPeerDisconnected() noexcept
{
LogW("peer caller disconnected");
Q_EMIT CallerDisconnected();
}

bool PackageManager::waitConfirm(
PackageTask &taskRef,
api::types::v1::InteractionMessageType msgType,
const api::types::v1::PackageManager1RequestInteractionAdditionalMessage
&additionalMessage) noexcept
{
auto objectPath = QDBusObjectPath(taskRef.taskObjectPath().c_str());
QEventLoop loop;
QTimer timeoutTimer;
timeoutTimer.setSingleShot(true);

auto callerContext = taskRef.callerContext();
std::unique_ptr<QDBusServiceWatcher> watcher;

QMetaObject::Connection callerDisconnectedConn;

if (callerContext.isPeerMode()) {
callerDisconnectedConn =
connect(this, &PackageManager::CallerDisconnected, &loop, [&taskRef, &loop]() {
taskRef.updateState(linglong::api::types::v1::State::Canceled, "caller disconnected");
loop.exit(1);
});

auto connected = callerContext.connection.connect("",
"/org/freedesktop/DBus/Local",
"org.freedesktop.DBus.Local",
"Disconnected",
this,
SLOT(onPeerDisconnected()));
if (!connected) {
LogW("failed to connect to Disconnected signal for peer mode");
}
} else {
auto callerName = callerContext.callerBusName();
if (!callerName.isEmpty()) {
watcher =
std::make_unique<QDBusServiceWatcher>(callerName,
callerContext.connection,
QDBusServiceWatcher::WatchForUnregistration);
connect(watcher.get(),
&QDBusServiceWatcher::serviceUnregistered,
&loop,
[&taskRef, &loop, callerName]() {
LogW("caller {} disconnected", callerName.toStdString());
taskRef.updateState(linglong::api::types::v1::State::Canceled,
"caller disconnected");
loop.exit(1);
});
}
}

auto replyConn =
connect(this,
&PackageManager::ReplyReceived,
&loop,
[&taskRef, &loop, objectPath](const QDBusObjectPath &replyObjectPath,
const QVariantMap &reply) {
if (replyObjectPath.path() != objectPath.path()) {
return;
}

auto interactionReply =
common::serialize::fromQVariantMap<api::types::v1::InteractionReply>(reply);
if (!interactionReply || interactionReply->action != "yes") {
taskRef.updateState(linglong::api::types::v1::State::Canceled, "canceled");
}
loop.exit(0);
});

auto timeoutConn = connect(&timeoutTimer, &QTimer::timeout, &loop, [&taskRef, &loop]() {
auto msg = fmt::format("task {} confirm timeout", taskRef.taskID());
LogW(msg);
taskRef.updateState(linglong::api::types::v1::State::Canceled, msg);
loop.exit(1);
});

Q_EMIT RequestInteraction(objectPath,
static_cast<int>(msgType),
common::serialize::toQVariantMap(additionalMessage));
Comment thread
reddevillg marked this conversation as resolved.

timeoutTimer.start(std::chrono::milliseconds{ 180000 });
loop.exec();
timeoutTimer.stop();

disconnect(replyConn);
disconnect(timeoutConn);
disconnect(callerDisconnectedConn);

if (callerContext.isPeerMode()) {
callerContext.connection.disconnect("",
"/org/freedesktop/DBus/Local",
"org.freedesktop.DBus.Local",
"Disconnected",
this,
SLOT(onPeerDisconnected()));
}

return !taskRef.isTaskDone();
}

// no-op for now
utils::error::Result<void> PackageManager::tryGenerateCache(const package::Reference &ref) noexcept
{
Expand Down
16 changes: 16 additions & 0 deletions libs/linglong/src/linglong/package_manager/package_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "linglong/api/types/v1/CommonOptions.hpp"
#include "linglong/api/types/v1/ContainerProcessStateInfo.hpp"
#include "linglong/api/types/v1/InteractionMessageType.hpp"
#include "linglong/api/types/v1/PackageManager1RequestInteractionAdditionalMessage.hpp"
#include "linglong/api/types/v1/Repo.hpp"
#include "linglong/api/types/v1/UabLayer.hpp"
#include "linglong/package/fuzzy_reference.h"
Expand All @@ -20,6 +22,7 @@
#include <QDBusArgument>
#include <QDBusConnection>
#include <QDBusContext>
#include <QDBusObjectPath>
#include <QList>
#include <QObject>

Expand Down Expand Up @@ -58,6 +61,7 @@ public
auto Update(const QVariantMap &parameters) noexcept -> QVariantMap;
auto Search(const QVariantMap &parameters) noexcept -> QVariantMap;
auto Prune() noexcept -> QVariantMap;
void ReplyInteraction(QDBusObjectPath object_path, const QVariantMap &replies);

auto InitRunContext(const QString &runContextCfg, const QString &containerID) noexcept
-> QVariantMap;
Expand All @@ -73,6 +77,10 @@ public
virtual utils::error::Result<void> tryGenerateCache(const package::Reference &ref) noexcept;
utils::error::Result<void> executePostInstallHooks(const package::Reference &ref) noexcept;
utils::error::Result<void> executePostUninstallHooks(const package::Reference &ref) noexcept;
bool waitConfirm(PackageTask &taskRef,
api::types::v1::InteractionMessageType msgType,
const api::types::v1::PackageManager1RequestInteractionAdditionalMessage
&additionalMessage) noexcept;

virtual utils::error::Result<void> installAppDepends(Task &task,
const api::types::v1::PackageInfoV2 &app);
Expand Down Expand Up @@ -107,9 +115,17 @@ public
Q_SIGNALS:
void TaskAdded(QDBusObjectPath object_path);
void TaskRemoved(QDBusObjectPath object_path);
void RequestInteraction(QDBusObjectPath object_path,
int messageID,
QVariantMap additionalMessage);
void CallerDisconnected();
void SearchFinished(QString jobID, QVariantMap result);
void PruneFinished(QString jobID, QVariantMap result);
void InitRunContextFinished(QString jobID, bool success);
void ReplyReceived(QDBusObjectPath object_path, const QVariantMap &replies);

private Q_SLOTS:
void onPeerDisconnected() noexcept;

private:
QVariantMap installFromLayer(const QDBusUnixFileDescriptor &fd,
Expand Down
Loading
Loading