Документация
ОС Аврора 5.2.1
Использование D-Bus интерфейса для взаимодействия с Market API
Ниже приведены фрагменты кода или же цельные файлы, которые реализуют клиент для работы с D-Bus API пакетного менеджера Market. Данный менеджер предоставляет функционал для получения свойств системы и установленных пакетов, управления операциями (установка, удаление) и обработки сигналов об изменении статусов операций через пользовательские D-Bus типы данных.
-
.spec-файл:
... # Указываем зависимость для сборки: требуется модуль Qt5DBus для работы с D-Bus BuildRequires: pkgconfig(Qt5DBus) ... -
.pro-файл:
... # Подключаем модуль Qt D-Bus к проекту QT += dbus \ ... # Добавляем исходный файл реализации интерфейса в сборку SOURCES += \ src/{путь_к_файлу}/dbusinterface.cpp \ ... # Добавляем заголовочные файлы: объявление пользовательского типа и самого интерфейса HEADERS += \ src/{путь_к_файлу}/customdbastype.h \ src/{путь_к_файлу}/dbusinterface.h \ ... -
customdbastype.h:// SPDX-FileCopyrightText: 2025 Open Mobile Platform LLC <community@omp.ru> // SPDX-License-Identifier: BSD-3-Clause #pragma once #include <QtDBus/QtDBus> // Данная структура служит для сериализации/десериализации данных операции (operation) // D-Bus структуры типа (ssiii) - (string, string, int, int, int). struct Operation { QString operationUuid; // Уникальный идентификатор операции QString packageId; // Идентификатор пакета, с которым производится операция int operationType; // Тип операции (например, установка или удаление) int operationStatus; // Текущий статус выполнения операции int operationErrorCode; // Код ошибки, если операция завершилась неудачно /*! Перегрузка оператора << для сериализации данных операции в формат аргумента D-Bus. Это необходимо, чтобы Qt мог передать структуру Operation через шину D-Bus. argument — объект QDBusArgument, в который записываются данные. data — постоянная ссылка на данные операции для преобразования. Возвращает ссылку на аргумент D-Bus с записанными данными. */ friend QDBusArgument &operator << (QDBusArgument &argument, const Operation &data) { argument.beginStructure(); // Начало записи структуры D-Bus // Последовательная запись полей структуры в строгом соответствии с сигнатурой (ssiii) argument << data.operationUuid << data.packageId << data.operationType << data.operationStatus << data.operationErrorCode; argument.endStructure(); // Конец записи структуры D-Bus return argument; } /*! Перегрузка оператора >> для десериализации (извлечения) данных операции из аргумента D-Bus. Это необходимо, чтобы Qt мог преобразовать полученные по D-Bus данные обратно в структуру Operation. argument — постоянная ссылка на QDBusArgument, из которого читаются данные. data — ссылка на объект Operation, который будет заполнен извлеченными данными. Возвращает постоянную ссылку на аргумент D-Bus. */ friend const QDBusArgument &operator >> (const QDBusArgument &argument, Operation &data) { argument.beginStructure(); // Начало чтения структуры D-Bus // Последовательное чтение полей в том же порядке, в котором они были записаны argument >> data.operationUuid >> data.packageId >> data.operationType >> data.operationStatus >> data.operationErrorCode; argument.endStructure(); // Конец чтения структуры D-Bus return argument; } /*! Перегрузка оператора вывода в QDebug для удобного логирования структуры Operation. debug — экземпляр класса QDebug. operation — постоянная ссылка на данные операции, предназначенные для вывода. Возвращает экземпляр класса QDebug для цепочки вызовов. */ friend QDebug operator << (QDebug debug, const Operation &operation) { debug << "operationUuid =" << operation.operationUuid << "packageId =" << operation.packageId << "operationType =" << operation.operationType << "operationStatus =" << operation.operationStatus << "operationErrorCode =" << operation.operationErrorCode; return debug; } }; // Регистрация пользовательского типа Operation в системе метаобъектов Qt. // Это обязательный шаг для использования типа в сигналах, слотах и свойствах Qt. Q_DECLARE_METATYPE(Operation) -
dbusinterface.h:// SPDX-FileCopyrightText: 2025 Open Mobile Platform LLC <community@omp.ru> // SPDX-License-Identifier: BSD-3-Clause #pragma once #include "customdbastype.h" /*! Класс DbusInterface предоставляет высокоуровневый C++ интерфейс для работы с D-Bus API сервиса пакетного менеджера ru.omp.Market. Наследование от QDBusAbstractInterface является стандартным способом обёртки D-Bus интерфейса в Qt. */ class DbusInterface final : public QDBusAbstractInterface { Q_OBJECT // Макрос, необходимый для поддержки сигналов, слотов и системы метаобъектов Qt public: // Конструктор инициализирует соединение с D-Bus сервисом. explicit DbusInterface(QObject *parent = nullptr); // Деструктор по умолчанию (final override гарантирует, что он не будет переопределён в наследниках) ~DbusInterface() final override = default; // Метод для асинхронного запроса всех свойств сервиса Market void allProperties(); // Метод для асинхронного запроса на удаление пакета по его идентификатору void removePackage(const QString &packageID); // Геттер для получения списка установленных пакетов (синхронный, возвращает кэшированные данные) QStringList installedPackages() const; public slots: // Слот-обработчик сигнала D-Bus об успешном удалении пакета void handlePackageRemoved(const QString &packageId); // Слот-обработчик сигнала D-Bus об изменении статуса операции void handleOperationStatusChanged(const Operation &operation); private: // Внутренний кэш списка установленных пакетов, обновляемый при запросе свойств QStringList m_installedPackages; }; -
dbusinterface.cpp:// SPDX-FileCopyrightText: 2025 Open Mobile Platform LLC <community@omp.ru> // SPDX-License-Identifier: BSD-3-Clause #include "dbusinterface.h" #include <QDebug> // Анонимное пространство имён для хранения констант D-Bus, чтобы избежать загрязнения глобальной области видимости namespace { const QString marketService = QStringLiteral("ru.omp.Market"); // Имя сервиса в шине D-Bus const QString marketObjectPath = QStringLiteral("/ru/omp/Market"); // Путь к объекту в сервисе const char *marketInterface = "ru.omp.Market"; // Имя интерфейса D-Bus } // Конструктор регистрирует типы и подключается к D-Bus сервису ru.omp.Market. // parent — родительский экземпляр QObject для управления временем жизни объекта. DbusInterface::DbusInterface(QObject *parent) // Инициализация базового класса QDBusAbstractInterface с параметрами подключения к сессионной шине (sessionBus) : QDBusAbstractInterface(marketService, marketObjectPath, marketInterface, QDBusConnection::sessionBus(), parent) { // Регистрация пользовательского типа Operation для использования в сигналах/слотах Qt qRegisterMetaType<Operation>("Operation"); // Регистрация типа Operation специально для системы D-Bus (для сериализации/десериализации) qDBusRegisterMetaType<Operation>(); // Подключение к сигналу D-Bus "PackageRemoved" // Связываем сигнал сервиса с локальным слотом handlePackageRemoved bool isConnected = connection().connect(marketService, marketObjectPath, marketInterface, QStringLiteral("PackageRemoved"), this, SLOT(handlePackageRemoved(const QString &))); if (!isConnected) { qWarning() << "Can't connect to PackageRemoved() signal !"; } // Подключение к сигналу D-Bus "OperationStatusChanged" // Связываем сигнал сервиса с локальным слотом handleOperationStatusChanged isConnected = connection().connect(marketService, marketObjectPath, marketInterface, QStringLiteral("OperationStatusChanged"), this, SLOT(handleOperationStatusChanged(const Operation &))); if (!isConnected) { qWarning() << "Can't connect to OperationStatusChanged() signal !"; } } /*! Запрашивает все свойства, необходимые для работы с пакетами, через D-Bus метод GetAllProperties(). Используя GetAllProperties(), можно получить словарь со всеми требуемыми свойствами: - a{sv}: { 'Architecture': String, 'AuroraVersion': String, 'Packages': List<Package> a(ssssa{sv}) 'Operations': List<Operations>, a(ssiii) 'CompletedOperations': List<Operations>, a(ssiii) } Данный метод не демонстрирует получение всех данных, а показывает принцип парсинга ответа. */ void DbusInterface::allProperties() { // Инициируем асинхронный вызов метода D-Bus. Он не блокирует основной поток. const QDBusPendingReply<QVariantMap> asyncReply = asyncCall(QStringLiteral("GetAllProperties")); // Создаем наблюдателя (watcher) для отслеживания завершения асинхронного вызова QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncReply, this); // Подключаемся к сигналу завершения вызова через лямбда-функцию QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { if (watcher->isError()) { // Если при вызове произошла ошибка D-Bus, логируем её qWarning() << "AllProperties: asyncCall() error: " << watcher->error().message(); } else { // Получаем результат вызова const QDBusPendingReply<QVariantMap> asyncReply = *watcher; QVariantMap properties = asyncReply.value(); // Извлекаем и логируем простые строковые свойства qDebug() << "AllProperties: Architecture = " << properties.value("Architecture", QVariant()).toString(); qDebug() << "AllProperties: AuroraVersion = " << properties.value("AuroraVersion", QVariant()).toString(); // Извлекаем список пакетов. qdbus_cast безопасно преобразует QVariant в QVariantList QVariantList packagesVariant = qdbus_cast<QVariantList>(properties.value("Packages", QVariant())); m_installedPackages.reserve(packagesVariant.size()); // Оптимизация выделения памяти // Проходим по списку и сохраняем идентификаторы пакетов в кэш for (const auto &package : std::as_const(packagesVariant)) { m_installedPackages.append(package.toString()); } qDebug() << "AllProperties: Packages: " << m_installedPackages; // Извлекаем список активных операций, используя qdbus_cast для преобразования в QList<Operation> QList<Operation> activeOperations = qdbus_cast<QList<Operation>>(properties.value("Operations", QVariant())); for (const auto &operation : std::as_const(activeOperations)) { qDebug() << "AllProperties: Operations: " << operation; // Использует перегруженный operator<< } // Извлекаем список завершённых операций аналогичным образом QList<Operation> completedOperations = qdbus_cast<QList<Operation>>(properties.value("CompletedOperations", QVariant())); for (const auto &completedOperation : std::as_const(completedOperations)) { qDebug() << "AllProperties: CompletedOperations: " << completedOperation; } } // Обязательно удаляем watcher после завершения обработки, чтобы избежать утечки памяти watcher->deleteLater(); }); } /*! Удаляет пакет по его packageID через D-Bus метод Remove(). Ответ на вызов метода удаления пакета будет содержать структуру с данными операции (ssiii). packageID — идентификатор пакета в формате: "ru.auroraos.ApplicationTemplate". */ void DbusInterface::removePackage(const QString &packageID) { // Инициируем асинхронный вызов метода "Remove", передавая packageID как QVariant const QDBusPendingReply<Operation> asyncReply = asyncCall(QStringLiteral("Remove"), QVariant::fromValue(packageID)); // Создаем наблюдателя для отслеживания завершения вызова QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncReply, this); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [](QDBusPendingCallWatcher *watcher) { if (watcher->isError()) { // Логируем ошибку, если удаление не удалось (например, пакет не найден или не хватает прав) qWarning() << "Remove: error deleting package: " << watcher->error().message(); } else { // Получаем структуру Operation, которую вернул сервис Market const QDBusPendingReply<Operation> asyncReply = *watcher; Operation reply = asyncReply.value(); qDebug() << "Remove: removed package operation: " << reply; } // Удаляем watcher после обработки watcher->deleteLater(); }); } /*! Геттер для установленных пакетов. Возвращает ссылку на внутренний список кэшированных установленных пакетов. */ QStringList DbusInterface::installedPackages() const { return m_installedPackages; } /*! Обработчик сигнала PackageRemoved. Вызывается автоматически шиной D-Bus, когда сервис Market удаляет пакет. packageId — идентификатор удалённого пакета. */ void DbusInterface::handlePackageRemoved(const QString &packageId) { qDebug() << "PackageRemoved, packageId = " << packageId; // Здесь можно добавить логику обновления UI или внутреннего кэша m_installedPackages } /*! Обработчик сигнала OperationStatusChanged. Вызывается автоматически шиной D-Bus при изменении статуса любой операции. operation — данные операции, содержащие новый статус. */ void DbusInterface::handleOperationStatusChanged(const Operation &operation) { qDebug() << "OperationStatusChanged: " << operation; // Здесь можно добавить логику обновления прогресс-баров или статуса операции в UI } -
main.cpp:... // Подключаем заголовочный файл нашего D-Bus интерфейса #include "{путь к файлу}/dbusinterface.h" ... int main(int argc, char *argv[]) { ... // Инициализация приложения (QGuiApplication/QCoreApplication и т.д.) // Создаём экземпляр интерфейса. // В конструкторе автоматически произойдёт подключение к сессионной шине D-Bus и подписка на сигналы. DbusInterface marketInterface; // Запрашиваем все свойства сервиса (вызов асинхронный, результат придёт в слот watcher'а) marketInterface.allProperties(); // Инициируем асинхронное удаление конкретного пакета по его ID marketInterface.removePackage(QStringLiteral("ru.auroraos.ApplicationTemplate")); /*! Пример: удаляет первый пакет из списка установленных пакетов (если список не пуст): if (marketInterface.installedPackages().size()) { marketInterface.removePackage(*marketInterface.installedPackages().constBegin()); } */ ... // Запуск event loop (app.exec()) }