From afa1126e6ef8819dd88084f6104dcd85a94d0a7e Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 18 May 2019 00:51:51 +0200 Subject: [PATCH] More work on the system management api --- libnymea-core/jsonrpc/jsontypes.cpp | 50 ++++ libnymea-core/jsonrpc/jsontypes.h | 7 + libnymea-core/jsonrpc/systemhandler.cpp | 214 +++++++++++++----- libnymea-core/jsonrpc/systemhandler.h | 18 +- libnymea-core/platform/platform.cpp | 112 +++++---- libnymea-core/platform/platform.h | 7 +- libnymea/libnymea.pro | 6 +- libnymea/loggingcategories.cpp | 1 + libnymea/loggingcategories.h | 1 + libnymea/platform/package.cpp | 98 ++++++++ libnymea/platform/package.h | 46 ++++ libnymea/platform/platformplugin.cpp | 37 --- libnymea/platform/platformplugin.h | 50 ---- libnymea/platform/platformsystemcontroller.h | 5 + .../platform/platformupdatecontroller.cpp | 46 ++-- libnymea/platform/platformupdatecontroller.h | 33 +-- libnymea/platform/repository.cpp | 34 +++ libnymea/platform/repository.h | 24 ++ server/main.cpp | 1 + tests/auto/api.json | 113 +++++++-- 20 files changed, 656 insertions(+), 247 deletions(-) create mode 100644 libnymea/platform/package.cpp create mode 100644 libnymea/platform/package.h delete mode 100644 libnymea/platform/platformplugin.cpp delete mode 100644 libnymea/platform/platformplugin.h create mode 100644 libnymea/platform/repository.cpp create mode 100644 libnymea/platform/repository.h diff --git a/libnymea-core/jsonrpc/jsontypes.cpp b/libnymea-core/jsonrpc/jsontypes.cpp index ddf3e851..39d1c21a 100644 --- a/libnymea-core/jsonrpc/jsontypes.cpp +++ b/libnymea-core/jsonrpc/jsontypes.cpp @@ -126,6 +126,8 @@ QVariantMap JsonTypes::s_serverConfiguration; QVariantMap JsonTypes::s_webServerConfiguration; QVariantMap JsonTypes::s_tag; QVariantMap JsonTypes::s_mqttPolicy; +QVariantMap JsonTypes::s_package; +QVariantMap JsonTypes::s_repository; void JsonTypes::init() { @@ -400,6 +402,19 @@ void JsonTypes::init() s_tag.insert("tagId", basicTypeToString(QVariant::String)); s_tag.insert("o:value", basicTypeToString(QVariant::String)); + s_package.insert("id", basicTypeToString(QVariant::String)); + s_package.insert("displayName", basicTypeToString(QVariant::String)); + s_package.insert("installedVersion", basicTypeToString(QVariant::String)); + s_package.insert("candidateVersion", basicTypeToString(QVariant::String)); + s_package.insert("changelog", basicTypeToString(QVariant::String)); + s_package.insert("updateAvailable", basicTypeToString(QVariant::Bool)); + s_package.insert("rollbackAvailable", basicTypeToString(QVariant::Bool)); + s_package.insert("canRemove", basicTypeToString(QVariant::Bool)); + + s_repository.insert("id", basicTypeToString(QVariant::String)); + s_repository.insert("displayName", basicTypeToString(QVariant::String)); + s_repository.insert("enabled", basicTypeToString(QVariant::Bool)); + s_initialized = true; } @@ -1268,6 +1283,29 @@ QVariantMap JsonTypes::packTokenInfo(const TokenInfo &tokenInfo) return ret; } +QVariantMap JsonTypes::packPackage(const Package &package) +{ + QVariantMap ret; + ret.insert("id", package.packageId()); + ret.insert("displayName", package.displayName()); + ret.insert("installedVersion", package.installedVersion()); + ret.insert("candidateVersion", package.candidateVersion()); + ret.insert("changelog", package.changelog()); + ret.insert("updateAvailable", package.updateAvailable()); + ret.insert("rollbackAvailable", package.rollbackAvailable()); + ret.insert("canRemove", package.canRemove()); + return ret; +} + +QVariantMap JsonTypes::packRepository(const Repository &repository) +{ + QVariantMap ret; + ret.insert("id", repository.id()); + ret.insert("displayName", repository.displayName()); + ret.insert("enabled", repository.enabled()); + return ret; +} + /*! Returns the type string for the given \a type. */ QString JsonTypes::basicTypeToString(const QVariant::Type &type) { @@ -2013,6 +2051,18 @@ QPair JsonTypes::validateVariant(const QVariant &templateVariant, qCWarning(dcJsonRpc) << "Tag not matching"; return result; } + } else if (refName == packageRef()) { + QPair result = validateMap(packageDescription(), variant.toMap()); + if (!result.first) { + qCWarning(dcJsonRpc) << "Package not matching"; + return result; + } + } else if (refName == repositoryRef()) { + QPair result = validateMap(repositoryDescription(), variant.toMap()); + if (!result.first) { + qCWarning(dcJsonRpc) << "Repository not matching"; + return result; + } } else if (refName == basicTypeRef()) { QPair result = validateBasicType(variant); if (!result.first) { diff --git a/libnymea-core/jsonrpc/jsontypes.h b/libnymea-core/jsonrpc/jsontypes.h index 6fc417eb..5be24709 100644 --- a/libnymea-core/jsonrpc/jsontypes.h +++ b/libnymea-core/jsonrpc/jsontypes.h @@ -57,6 +57,8 @@ #include "networkmanager/wirelessaccesspoint.h" #include "cloud/cloudmanager.h" +#include "platform/package.h" +#include "platform/repository.h" #include @@ -176,6 +178,8 @@ public: DECLARE_OBJECT(webServerConfiguration, "WebServerConfiguration") DECLARE_OBJECT(tag, "Tag") DECLARE_OBJECT(mqttPolicy, "MqttPolicy") + DECLARE_OBJECT(package, "Package") + DECLARE_OBJECT(repository, "Repository") // pack types static QVariantMap packEventType(const EventType &eventType, const PluginId &pluginId, const QLocale &locale); @@ -232,6 +236,9 @@ public: static QVariantMap packTokenInfo(const TokenInfo &tokenInfo); + static QVariantMap packPackage(const Package &package); + static QVariantMap packRepository(const Repository &repository); + static QString basicTypeToString(const QVariant::Type &type); // unpack Types diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index 63580213..23b184a6 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -53,42 +53,127 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): setReturns("Shutdown", returns); params.clear(); returns.clear(); - setDescription("GetUpdateStatus", "Get the current system status in regard to updates. That is, the currently installed version, any candidate version available etc."); - setParams("GetUpdateStatus", params); - returns.insert("updateAvailable", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("currentVersion", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("candidateVersion", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("availableChannels", JsonTypes::basicTypeToString(JsonTypes::StringList)); - returns.insert("currentChannel", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("updateInProgress", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("GetUpdateStatus", returns); + setDescription("GetPackages", "Get the list of packages currently available to the system. This includes installed and available but not installed packages."); + setParams("GetPackages", params); + returns.insert("packages", QVariantList() << JsonTypes::packageRef()); + setReturns("GetPackages", returns); params.clear(); returns.clear(); - setDescription("StartUpdate", "Starts a system update. Returns true if the upgrade has been started successfully."); - setParams("StartUpdate", params); + setDescription("UpdatePackages", "Starts updating/installing packages with the given ids. Returns true if the upgrade has been started successfully. Note that it might still fail later."); + params.insert("o:packageIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); + setParams("UpdatePackages", params); returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("StartUpdate", returns); + setReturns("UpdatePackages", returns); params.clear(); returns.clear(); - setDescription("SelectChannel", "Select an update channel."); - params.insert("channel", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SelectChannel", params); + setDescription("RollbackPackages", "Starts a rollback. Returns true if the rollback has been started successfully."); + params.insert("packageIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); + setParams("RollbackPackages", params); returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("SelectChannel", returns); + setReturns("RollbackPackages", returns); + + params.clear(); returns.clear(); + setDescription("RemovePackages", "Starts removing a package. Returns true if the removal has been started successfully."); + params.insert("packageIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); + setParams("RemovePackages", params); + returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); + setReturns("RemovePackages", returns); + + params.clear(); returns.clear(); + setDescription("GetRepositories", "Get the list of repositories currently available to the system."); + setParams("GetRepositories", params); + returns.insert("repositories", QVariantList() << JsonTypes::repositoryRef()); + setReturns("GetRepositories", returns); + + params.clear(); returns.clear(); + setDescription("EnableRepository", "Enable or disable a repository."); + params.insert("repositoryId", JsonTypes::basicTypeToString(JsonTypes::String)); + params.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + setParams("EnableRepository", params); + returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); + setReturns("EnableRepository", returns); // Notifications params.clear(); - setDescription("UpdateStatusChanged", "Emitted whenever there is a change in the information from GetUpdateStatus"); - params.insert("updateAvailable", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("currentVersion", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("candidateVersion", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("availableChannels", JsonTypes::basicTypeToString(JsonTypes::StringList)); - params.insert("currentChannel", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("updateInProgress", JsonTypes::basicTypeToString(JsonTypes::Bool)); + setDescription("CapabilitiesChanged", "Emitted whenever the system capabilities change."); + params.insert("powerManagement", JsonTypes::basicTypeToString(JsonTypes::Bool)); + params.insert("updateManagement", JsonTypes::basicTypeToString(JsonTypes::Bool)); + setParams("CapabilitiesChanged", params); + + params.clear(); + setDescription("UpdateStatusChanged", "Emitted whenever the update status changes."); + params.insert("updateRunning", JsonTypes::basicTypeToString(JsonTypes::Bool)); setParams("UpdateStatusChanged", params); - connect(m_platform->updateController(), &PlatformUpdateController::updateStatusChanged, this, &SystemHandler::onUpdateStatusChanged); + params.clear(); + setDescription("PackageAdded", "Emitted whenever a package is added to the list of packages."); + params.insert("package", JsonTypes::packageRef()); + setParams("PackageAdded", params); + + params.clear(); + setDescription("PackageChanged", "Emitted whenever a package in the list of packages changes."); + params.insert("package", JsonTypes::packageRef()); + setParams("PackageChanged", params); + + params.clear(); + setDescription("PackageRemoved", "Emitted whenever a package is removed from the list of packages."); + params.insert("packageId", JsonTypes::basicTypeToString(JsonTypes::String)); + setParams("PackageRemoved", params); + + params.clear(); + setDescription("RepositoryAdded", "Emitted whenever a repository is added to the list of repositories."); + params.insert("repository", JsonTypes::repositoryRef()); + setParams("RepositoryAdded", params); + + params.clear(); + setDescription("RepositoryChanged", "Emitted whenever a repository in the list of repositories changes."); + params.insert("repository", JsonTypes::repositoryRef()); + setParams("RepositoryChanged", params); + + params.clear(); + setDescription("RepositoryRemoved", "Emitted whenever a repository is removed from the list of repositories."); + params.insert("repository", JsonTypes::basicTypeToString(JsonTypes::String)); + setParams("RepositoryRemoved", params); + + + connect(m_platform->systemController(), &PlatformSystemController::availableChanged, this, &SystemHandler::onCapabilitiesChanged); + connect(m_platform->updateController(), &PlatformUpdateController::availableChanged, this, &SystemHandler::onCapabilitiesChanged); + connect(m_platform->updateController(), &PlatformUpdateController::updateRunningChanged, this, [this](){ + QVariantMap params; + params.insert("updateRunning", m_platform->updateController()->updateRunning()); + emit UpdateStatusChanged(params); + }); + connect(m_platform->updateController(), &PlatformUpdateController::packageAdded, this, [this](const Package &package){ + QVariantMap params; + params.insert("package", JsonTypes::packPackage(package)); + emit PackageAdded(params); + }); + connect(m_platform->updateController(), &PlatformUpdateController::packageChanged, this, [this](const Package &package){ + QVariantMap params; + params.insert("package", JsonTypes::packPackage(package)); + emit PackageChanged(params); + }); + connect(m_platform->updateController(), &PlatformUpdateController::packageRemoved, this, [this](const QString &packageId){ + QVariantMap params; + params.insert("packageId", packageId); + emit PackageRemoved(params); + }); + connect(m_platform->updateController(), &PlatformUpdateController::repositoryAdded, this, [this](const Repository &repository){ + QVariantMap params; + params.insert("repository", JsonTypes::packRepository(repository)); + emit RepositoryAdded(params); + }); + connect(m_platform->updateController(), &PlatformUpdateController::repositoryChanged, this, [this](const Repository &repository){ + QVariantMap params; + params.insert("repository", JsonTypes::packRepository(repository)); + emit RepositoryChanged(params); + }); + connect(m_platform->updateController(), &PlatformUpdateController::repositoryRemoved, this, [this](const QString &repositoryId){ + QVariantMap params; + params.insert("repositoryId", repositoryId); + emit RepositoryRemoved(params); + }); } QString SystemHandler::name() const @@ -125,50 +210,75 @@ JsonReply *SystemHandler::Shutdown(const QVariantMap ¶ms) const JsonReply *SystemHandler::GetUpdateStatus(const QVariantMap ¶ms) const { - Q_UNUSED(params); + Q_UNUSED(params) + QVariantMap ret; + ret.insert("updateRunning", m_platform->updateController()->updateRunning()); + return createReply(ret); +} + +JsonReply *SystemHandler::GetPackages(const QVariantMap ¶ms) const +{ + Q_UNUSED(params) + QVariantList packagelist; + foreach (const Package &package, m_platform->updateController()->packages()) { + packagelist.append(JsonTypes::packPackage(package)); + } QVariantMap returns; - returns.insert("updateAvailable", m_platform->updateController()->updateAvailable()); - returns.insert("currentVersion", m_platform->updateController()->currentVersion()); - returns.insert("candidateVersion", m_platform->updateController()->candidateVersion()); - returns.insert("availableChannels", m_platform->updateController()->availableChannels()); - returns.insert("currentChannel", m_platform->updateController()->currentChannel()); - returns.insert("updateInProgress", m_platform->updateController()->updateInProgress()); + returns.insert("packages", packagelist); return createReply(returns); } -JsonReply *SystemHandler::StartUpdate(const QVariantMap ¶ms) +JsonReply *SystemHandler::UpdatePackages(const QVariantMap ¶ms) const { - Q_UNUSED(params) + bool success = m_platform->updateController()->startUpdate(params.value("packageIds").toStringList()); QVariantMap returns; - bool success = m_platform->updateController()->startUpdate(); returns.insert("success", success); return createReply(returns); } -JsonReply *SystemHandler::SelectChannel(const QVariantMap ¶ms) +JsonReply *SystemHandler::RollbackPackages(const QVariantMap ¶ms) const { - QString channel = params.value("channel").toString(); - + bool success = m_platform->updateController()->rollback(params.value("packageIds").toStringList()); QVariantMap returns; - if (m_platform->updateController()->availableChannels().contains(channel)) { - bool success = m_platform->updateController()->selectChannel(channel); - returns.insert("success", success); - } else { - returns.insert("success", false); - } + returns.insert("success", success); return createReply(returns); } -void SystemHandler::onUpdateStatusChanged() +JsonReply *SystemHandler::RemovePackages(const QVariantMap ¶ms) const { - QVariantMap params; - params.insert("updateAvailable", m_platform->updateController()->updateAvailable()); - params.insert("currentVersion", m_platform->updateController()->currentVersion()); - params.insert("candidateVersion", m_platform->updateController()->candidateVersion()); - params.insert("availableChannels", m_platform->updateController()->availableChannels()); - params.insert("currentChannel", m_platform->updateController()->currentChannel()); - params.insert("updateInProgress", m_platform->updateController()->updateInProgress()); - emit UpdateStatusChanged(params); + bool success = m_platform->updateController()->removePackages(params.value("packageIds").toStringList()); + QVariantMap returns; + returns.insert("success", success); + return createReply(returns); +} + +JsonReply *SystemHandler::GetRepositories(const QVariantMap ¶ms) const +{ + Q_UNUSED(params); + QVariantList repos; + foreach (const Repository &repository, m_platform->updateController()->repositories()) { + repos.append(JsonTypes::packRepository(repository)); + } + QVariantMap returns; + returns.insert("repositories", repos); + return createReply(returns); + +} + +JsonReply *SystemHandler::EnableRepository(const QVariantMap ¶ms) const +{ + bool success = m_platform->updateController()->enableRepository(params.value("repositoryId").toString(), params.value("enabled").toBool()); + QVariantMap returns; + returns.insert("success", success); + return createReply(returns); +} + +void SystemHandler::onCapabilitiesChanged() +{ + QVariantMap caps; + caps.insert("powerManagement", m_platform->systemController()->powerManagementAvailable()); + caps.insert("updateManagement", m_platform->updateController()->updateManagementAvailable()); + emit CapabilitiesChanged(caps); } } diff --git a/libnymea-core/jsonrpc/systemhandler.h b/libnymea-core/jsonrpc/systemhandler.h index 27c9fd93..727d4465 100644 --- a/libnymea-core/jsonrpc/systemhandler.h +++ b/libnymea-core/jsonrpc/systemhandler.h @@ -43,14 +43,26 @@ public: Q_INVOKABLE JsonReply *Shutdown(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *GetUpdateStatus(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply *StartUpdate(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply *SelectChannel(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetPackages(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *UpdatePackages(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *RollbackPackages(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *RemovePackages(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetRepositories(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *EnableRepository(const QVariantMap ¶ms) const; signals: + void CapabilitiesChanged(const QVariantMap ¶ms); void UpdateStatusChanged(const QVariantMap ¶ms); + void PackageAdded(const QVariantMap ¶ms); + void PackageChanged(const QVariantMap ¶ms); + void PackageRemoved(const QVariantMap ¶ms); + void RepositoryAdded(const QVariantMap ¶ms); + void RepositoryChanged(const QVariantMap ¶ms); + void RepositoryRemoved(const QVariantMap ¶ms); private slots: - void onUpdateStatusChanged(); + void onCapabilitiesChanged(); + private: Platform *m_platform = nullptr; }; diff --git a/libnymea-core/platform/platform.cpp b/libnymea-core/platform/platform.cpp index 771b7461..445913a3 100644 --- a/libnymea-core/platform/platform.cpp +++ b/libnymea-core/platform/platform.cpp @@ -21,7 +21,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "platform.h" -#include "platform/platformplugin.h" +#include "platform/platformsystemcontroller.h" +#include "platform/platformupdatecontroller.h" #include "loggingcategories.h" @@ -38,54 +39,43 @@ Platform::Platform(QObject *parent) : QObject(parent) qCDebug(dcPlatform) << "Loading plugins from:" << dir.absolutePath(); foreach (const QString &entry, dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) { qCDebug(dcPlatform()) << "Found dir entry" << entry; - QFileInfo fi; - if (entry.startsWith("libnymea_platformplugin") && entry.endsWith(".so")) { - fi.setFile(path + "/" + entry); - } else { - fi.setFile(path + "/" + entry + "/libnymea_platformplugin" + entry + ".so"); + QFileInfo fi(path + "/" + entry); + if (fi.isFile()) { + if (entry.startsWith("libnymea_systemplugin") && entry.endsWith(".so")) { + loadSystemPlugin(path + "/" + entry); + } else if (entry.startsWith("libnymea_updateplugin") && entry.endsWith(".so")) { + loadUpdatePlugin(path + "/" + entry); + } + } else if (fi.isDir()) { + if (QFileInfo::exists(path + "/" + entry + "/libnymea_systemplugin" + entry + ".so")) { + loadSystemPlugin(path + "/" + entry + "/libnymea_systemplugin" + entry + ".so"); + } else if (QFileInfo::exists(path + "/" + entry + "/libnymea_platformplugin" + entry + ".so")) { + loadUpdatePlugin(path + "/" + entry + "/libnymea_platformplugin" + entry + ".so"); + } } - - if (!fi.exists()) - continue; - - - QPluginLoader loader; - loader.setFileName(fi.absoluteFilePath()); - loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); - - if (!loader.load()) { - qCWarning(dcPlatform) << "Could not load plugin data of" << entry << "\n" << loader.errorString(); - continue; - } - - m_platformPlugin = qobject_cast(loader.instance()); - if (!m_platformPlugin) { - qCWarning(dcPlatform) << "Could not get plugin instance of" << entry; - continue; - } - qCDebug(dcPlatform()) << "Loaded platform plugin:" << entry; - m_platformPlugin->setParent(this); - break; } - if (m_platformPlugin) { + if (m_platformSystemController && m_platformUpdateController) { break; } } - if (!m_platformPlugin) { - qCWarning(dcPlatform()) << "Could not load a platform plugin. Platform related features won't be available."; - m_platformPlugin = new PlatformPlugin(this); + if (!m_platformSystemController) { + qCWarning(dcPlatform()) << "Could not load a system plugin. System control features won't be available."; + m_platformSystemController = new PlatformSystemController(this); + } + if (!m_platformUpdateController) { + qCWarning(dcPlatform()) << "Could not load an update plugin. System update features won't be available."; + m_platformUpdateController = new PlatformUpdateController(this); } - } PlatformSystemController *Platform::systemController() const { - return m_platformPlugin->systemController(); + return m_platformSystemController; } PlatformUpdateController *Platform::updateController() const { - return m_platformPlugin->updateController(); + return m_platformUpdateController; } QStringList Platform::pluginSearchDirs() const @@ -97,12 +87,56 @@ QStringList Platform::pluginSearchDirs() const } foreach (QString libraryPath, QCoreApplication::libraryPaths()) { - searchDirs << libraryPath.replace("qt5", "nymea").replace("plugins", "platforms"); + searchDirs << libraryPath.replace("qt5", "nymea").replace("plugins", "platform"); } - searchDirs << QCoreApplication::applicationDirPath() + "/../lib/nymea/platforms"; - searchDirs << QCoreApplication::applicationDirPath() + "/../platforms/"; - searchDirs << QCoreApplication::applicationDirPath() + "/../../../platforms/"; + searchDirs << QCoreApplication::applicationDirPath() + "/../lib/nymea/platform"; + searchDirs << QCoreApplication::applicationDirPath() + "/../platform/"; + searchDirs << QCoreApplication::applicationDirPath() + "/../../../platform/"; return searchDirs; } +void Platform::loadSystemPlugin(const QString &file) +{ + if (m_platformSystemController) { + return; // Not loading another... + } + QPluginLoader loader; + loader.setFileName(file); + loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); + if (!loader.load()) { + qCWarning(dcPlatform) << "Could not load plugin data of" << file << "\n" << loader.errorString(); + return; + } + m_platformSystemController = qobject_cast(loader.instance()); + if (!m_platformSystemController) { + qCWarning(dcPlatform) << "Could not get plugin instance of" << file; + loader.unload(); + return; + } + qCDebug(dcPlatform()) << "Loaded system plugin:" << file; + m_platformSystemController->setParent(this); +} + +void Platform::loadUpdatePlugin(const QString &file) +{ + if (m_platformUpdateController) { + return; // Not loading another... + } + QPluginLoader loader; + loader.setFileName(file); + loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); + if (!loader.load()) { + qCWarning(dcPlatform) << "Could not load plugin data of" << file << "\n" << loader.errorString(); + return; + } + m_platformUpdateController = qobject_cast(loader.instance()); + if (!m_platformUpdateController) { + qCWarning(dcPlatform) << "Could not get plugin instance of" << file; + loader.unload(); + return; + } + qCDebug(dcPlatform()) << "Loaded update plugin:" << file; + m_platformUpdateController->setParent(this); +} + } diff --git a/libnymea-core/platform/platform.h b/libnymea-core/platform/platform.h index b7660fe3..2b8657b7 100644 --- a/libnymea-core/platform/platform.h +++ b/libnymea-core/platform/platform.h @@ -25,7 +25,6 @@ #include -class PlatformPlugin; class PlatformSystemController; class PlatformUpdateController; @@ -43,8 +42,12 @@ public: private: QStringList pluginSearchDirs() const; + void loadSystemPlugin(const QString &file); + void loadUpdatePlugin(const QString &file); + private: - PlatformPlugin *m_platformPlugin = nullptr; + PlatformSystemController *m_platformSystemController = nullptr; + PlatformUpdateController *m_platformUpdateController = nullptr; }; } diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 97b7d889..56e6a37e 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -12,6 +12,8 @@ LIBS += -lavahi-common -lavahi-client HEADERS += devicemanager.h \ libnymea.h \ + platform/package.h \ + platform/repository.h \ typeutils.h \ loggingcategories.h \ nymeasettings.h \ @@ -66,13 +68,14 @@ HEADERS += devicemanager.h \ network/mqtt/mqttprovider.h \ network/mqtt/mqttchannel.h \ translator.h \ - platform/platformplugin.h \ platform/platformsystemcontroller.h \ platform/platformupdatecontroller.h SOURCES += devicemanager.cpp \ loggingcategories.cpp \ nymeasettings.cpp \ + platform/package.cpp \ + platform/repository.cpp \ plugin/device.cpp \ plugin/deviceplugin.cpp \ plugin/devicedescriptor.cpp \ @@ -124,7 +127,6 @@ SOURCES += devicemanager.cpp \ network/mqtt/mqttprovider.cpp \ network/mqtt/mqttchannel.cpp \ translator.cpp \ - platform/platformplugin.cpp \ platform/platformsystemcontroller.cpp \ platform/platformupdatecontroller.cpp diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 019efb0e..657174a2 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -26,6 +26,7 @@ Q_LOGGING_CATEGORY(dcApplication, "Application") Q_LOGGING_CATEGORY(dcDeviceManager, "DeviceManager") Q_LOGGING_CATEGORY(dcSystem, "System") Q_LOGGING_CATEGORY(dcPlatform, "Platform") +Q_LOGGING_CATEGORY(dcPlatformUpdate, "PlatformUpdate") Q_LOGGING_CATEGORY(dcTimeManager, "TimeManager") Q_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine") Q_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug") diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index dd32e1ea..d9c8ef42 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -31,6 +31,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcApplication) Q_DECLARE_LOGGING_CATEGORY(dcDeviceManager) Q_DECLARE_LOGGING_CATEGORY(dcSystem) Q_DECLARE_LOGGING_CATEGORY(dcPlatform) +Q_DECLARE_LOGGING_CATEGORY(dcPlatformUpdate) Q_DECLARE_LOGGING_CATEGORY(dcTimeManager) Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine) Q_DECLARE_LOGGING_CATEGORY(dcRuleEngineDebug) diff --git a/libnymea/platform/package.cpp b/libnymea/platform/package.cpp new file mode 100644 index 00000000..982791ef --- /dev/null +++ b/libnymea/platform/package.cpp @@ -0,0 +1,98 @@ +#include "package.h" + +Package::Package(const QString &packageId, const QString &displayName, const QString &installedVersion, const QString &candidateVersion, const QString &changelog): + m_packageId(packageId), + m_displayName(displayName), + m_installedVersion(installedVersion), + m_candidateVersion(candidateVersion), + m_changeLog(changelog) +{ + +} + +QString Package::packageId() const +{ + return m_packageId; +} + +QString Package::displayName() const +{ + return m_displayName; +} + +QString Package::installedVersion() const +{ + return m_installedVersion; +} + +void Package::setInstalledVersion(const QString &installedVersion) +{ + m_installedVersion = installedVersion; +} + +QString Package::candidateVersion() const +{ + return m_candidateVersion; +} + +void Package::setCandidateVersion(const QString &candidateVersion) +{ + m_candidateVersion = candidateVersion; +} + +QString Package::changelog() const +{ + return m_changeLog; +} + +void Package::setChangelog(const QString &changelog) +{ + m_changeLog = changelog; +} + +bool Package::updateAvailable() const +{ + return m_updateAvailable; +} + +void Package::setUpdateAvailable(bool updateAvailable) +{ + m_updateAvailable = updateAvailable; +} + +bool Package::rollbackAvailable() const +{ + return m_rollbackAvailable; +} + +void Package::setRollbackAvailable(bool rollbackAvailable) +{ + m_rollbackAvailable = rollbackAvailable; +} + +bool Package::canRemove() const +{ + return m_canRemove; +} + +void Package::setCanRemove(bool canRemove) +{ + m_canRemove = canRemove; +} + +bool Package::operator==(const Package &other) const +{ + return m_packageId == other.packageId() && + m_displayName == other.displayName() && + m_installedVersion == other.installedVersion() && + m_candidateVersion == other.candidateVersion() && + m_changeLog == other.changelog() && + m_updateAvailable == other.updateAvailable() && + m_rollbackAvailable == other.rollbackAvailable() && + m_canRemove == other.canRemove(); +} + +bool Package::operator!=(const Package &other) const +{ + return !operator==(other); +} diff --git a/libnymea/platform/package.h b/libnymea/platform/package.h new file mode 100644 index 00000000..797faa2d --- /dev/null +++ b/libnymea/platform/package.h @@ -0,0 +1,46 @@ +#ifndef PACKAGE_H +#define PACKAGE_H + +#include + +class Package +{ +public: + explicit Package(const QString &packageId = QString(), const QString &displayName = QString(), const QString &installedVersion = QString(), const QString &candidateVersion = QString(), const QString &changelog = QString()); + + QString packageId() const; + QString displayName() const; + QString installedVersion() const; + void setInstalledVersion(const QString &installedVersion); + + QString candidateVersion() const; + void setCandidateVersion(const QString &candidateVersion); + + QString changelog() const; + void setChangelog(const QString &changelog); + + bool updateAvailable() const; + void setUpdateAvailable(bool updateAvailable); + + bool rollbackAvailable() const; + void setRollbackAvailable(bool rollbackAvailable); + + bool canRemove() const; + void setCanRemove(bool canRemove); + + bool operator==(const Package &other) const; + bool operator!=(const Package &other) const; + +private: + QString m_packageId; + QString m_displayName; + QString m_installedVersion; + QString m_candidateVersion; + QString m_changeLog; + + bool m_updateAvailable = false; + bool m_rollbackAvailable = false; + bool m_canRemove = false; +}; + +#endif // PACKAGE_H diff --git a/libnymea/platform/platformplugin.cpp b/libnymea/platform/platformplugin.cpp deleted file mode 100644 index fb43a61f..00000000 --- a/libnymea/platform/platformplugin.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "platformplugin.h" - -PlatformPlugin::PlatformPlugin(QObject *parent) : QObject(parent) -{ - -} - -PlatformSystemController *PlatformPlugin::systemController() const -{ - return m_systemStub; -} - -PlatformUpdateController *PlatformPlugin::updateController() const -{ - return m_updateStub; -} diff --git a/libnymea/platform/platformplugin.h b/libnymea/platform/platformplugin.h deleted file mode 100644 index 011aabb5..00000000 --- a/libnymea/platform/platformplugin.h +++ /dev/null @@ -1,50 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2019 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef PLATFORMPLUGIN_H -#define PLATFORMPLUGIN_H - -#include - -#include "libnymea.h" - -class PlatformSystemController; -class PlatformUpdateController; - -class LIBNYMEA_EXPORT PlatformPlugin: public QObject -{ - Q_OBJECT -public: - explicit PlatformPlugin(QObject *parent = nullptr); - virtual ~PlatformPlugin() = default; - - virtual PlatformSystemController *systemController() const; - virtual PlatformUpdateController *updateController() const; - -private: - PlatformSystemController *m_systemStub = nullptr; - PlatformUpdateController *m_updateStub = nullptr; -}; - -Q_DECLARE_INTERFACE(PlatformPlugin, "io.nymea.PlatformPlugin") - -#endif // PLATFORMPLUGIN_H diff --git a/libnymea/platform/platformsystemcontroller.h b/libnymea/platform/platformsystemcontroller.h index f0da5cb6..a1de5fa9 100644 --- a/libnymea/platform/platformsystemcontroller.h +++ b/libnymea/platform/platformsystemcontroller.h @@ -35,6 +35,11 @@ public: virtual bool powerManagementAvailable() const; virtual bool reboot(); virtual bool shutdown(); + +signals: + void availableChanged(); }; +Q_DECLARE_INTERFACE(PlatformSystemController, "io.nymea.PlatformSystemController") + #endif // PLATFORMSYSTEMCONTROLLER_H diff --git a/libnymea/platform/platformupdatecontroller.cpp b/libnymea/platform/platformupdatecontroller.cpp index 7c684827..34ba4635 100644 --- a/libnymea/platform/platformupdatecontroller.cpp +++ b/libnymea/platform/platformupdatecontroller.cpp @@ -36,14 +36,19 @@ bool PlatformUpdateController::updateManagementAvailable() return false; } -QString PlatformUpdateController::currentVersion() const +bool PlatformUpdateController::updateRunning() const { - return tr("N/A"); + return false; } -QString PlatformUpdateController::candidateVersion() const +QList PlatformUpdateController::packages() const { - return tr("N/A"); + return {}; +} + +QList PlatformUpdateController::repositories() const +{ + return {}; } void PlatformUpdateController::checkForUpdates() @@ -51,43 +56,28 @@ void PlatformUpdateController::checkForUpdates() // Nothing to do here } -bool PlatformUpdateController::updateAvailable() const +bool PlatformUpdateController::startUpdate(const QStringList &packageIds) { + Q_UNUSED(packageIds) return false; } -bool PlatformUpdateController::startUpdate() +bool PlatformUpdateController::rollback(const QStringList &packageIds) { + Q_UNUSED(packageIds) return false; } -bool PlatformUpdateController::rollbackAvailable() const +bool PlatformUpdateController::removePackages(const QStringList &packageIds) { + Q_UNUSED(packageIds) return false; } -bool PlatformUpdateController::startRollback() +bool PlatformUpdateController::enableRepository(const QString &repositoryId, bool enabled) { + Q_UNUSED(repositoryId) + Q_UNUSED(enabled) return false; } -bool PlatformUpdateController::updateInProgress() const -{ - return false; -} - -QStringList PlatformUpdateController::availableChannels() const -{ - return {}; -} - -QString PlatformUpdateController::currentChannel() const -{ - return tr("N/A"); -} - -bool PlatformUpdateController::selectChannel(const QString &channel) -{ - Q_UNUSED(channel) - return false; -} diff --git a/libnymea/platform/platformupdatecontroller.h b/libnymea/platform/platformupdatecontroller.h index fee426b4..cfcac33e 100644 --- a/libnymea/platform/platformupdatecontroller.h +++ b/libnymea/platform/platformupdatecontroller.h @@ -23,6 +23,9 @@ #ifndef PLATFORMUPDATECONTROLLER_H #define PLATFORMUPDATECONTROLLER_H +#include "package.h" +#include "repository.h" + #include class PlatformUpdateController : public QObject @@ -34,26 +37,30 @@ public: virtual bool updateManagementAvailable(); - virtual QString currentVersion() const; - virtual QString candidateVersion() const; + virtual bool updateRunning() const; -// virtual QMap changelog() const = 0; + virtual QList packages() const; + virtual QList repositories() const; virtual void checkForUpdates(); - virtual bool updateAvailable() const; - virtual bool startUpdate(); - virtual bool rollbackAvailable() const; - virtual bool startRollback(); + virtual bool startUpdate(const QStringList &packageIds = QStringList()); + virtual bool rollback(const QStringList &packageIds); + virtual bool removePackages(const QStringList &packageIds); - virtual bool updateInProgress() const; - - virtual QStringList availableChannels() const; - virtual QString currentChannel() const; - virtual bool selectChannel(const QString &channel); + virtual bool enableRepository(const QString &repositoryId, bool enabled); signals: - void updateStatusChanged(); + void availableChanged(); + void updateRunningChanged(); + void packageAdded(const Package &pacakge); + void packageChanged(const Package &package); + void packageRemoved(const QString &packageId); + void repositoryAdded(const Repository &repository); + void repositoryChanged(const Repository &repository); + void repositoryRemoved(const QString &repositoryId); }; +Q_DECLARE_INTERFACE(PlatformUpdateController, "io.nymea.PlatformUpdateController") + #endif // PLATFORMUPDATECONTROLLER_H diff --git a/libnymea/platform/repository.cpp b/libnymea/platform/repository.cpp new file mode 100644 index 00000000..986b03ca --- /dev/null +++ b/libnymea/platform/repository.cpp @@ -0,0 +1,34 @@ +#include "repository.h" + +Repository::Repository(const QString &id, const QString &displayName, bool enabled): + m_id(id), + m_displayName(displayName), + m_enabled(enabled) +{ + +} + +Repository::Repository() +{ + +} + +QString Repository::id() const +{ + return m_id; +} + +QString Repository::displayName() const +{ + return m_displayName; +} + +bool Repository::enabled() const +{ + return m_enabled; +} + +void Repository::setEnabled(bool enabled) +{ + m_enabled = enabled; +} diff --git a/libnymea/platform/repository.h b/libnymea/platform/repository.h new file mode 100644 index 00000000..f91825e9 --- /dev/null +++ b/libnymea/platform/repository.h @@ -0,0 +1,24 @@ +#ifndef REPOSITORY_H +#define REPOSITORY_H + +#include + +class Repository +{ +public: + Repository(); + Repository(const QString &id, const QString &displayName, bool enabled); + + QString id() const; + QString displayName() const; + + bool enabled() const; + void setEnabled(bool enabled); + +private: + QString m_id; + QString m_displayName; + bool m_enabled = false; +}; + +#endif // REPOSITORY_H diff --git a/server/main.cpp b/server/main.cpp index 5e68ac92..1633fc9a 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -103,6 +103,7 @@ int main(int argc, char *argv[]) "Application", "System", "Platform", + "PlatformUpdate", "DeviceManager", "RuleEngine", "RuleEngineDebug", diff --git a/tests/auto/api.json b/tests/auto/api.json index ac71eb7e..59a52349 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -867,6 +867,16 @@ "o:stateType": "$ref:StateType" } }, + "System.EnableRepository": { + "description": "Enable or disable a repository.", + "params": { + "enabled": "Bool", + "repositoryId": "String" + }, + "returns": { + "success": "Bool" + } + }, "System.GetCapabilities": { "description": "Get the list of capabilites on this system. This allows reading whether things like rebooting or shutting down the system running nymea:core is supported on this host.", "params": { @@ -876,17 +886,24 @@ "updateManagement": "Bool" } }, - "System.GetUpdateStatus": { - "description": "Get the current system status in regard to updates. That is, the currently installed version, any candidate version available etc.", + "System.GetPackages": { + "description": "Get the list of packages currently available to the system. This includes installed and available but not installed packages.", "params": { }, "returns": { - "availableChannels": "StringList", - "candidateVersion": "String", - "currentChannel": "String", - "currentVersion": "String", - "updateAvailable": "Bool", - "updateInProgress": "Bool" + "packages": [ + "$ref:Package" + ] + } + }, + "System.GetRepositories": { + "description": "Get the list of repositories currently available to the system.", + "params": { + }, + "returns": { + "repositories": [ + "$ref:Repository" + ] } }, "System.Reboot": { @@ -897,10 +914,23 @@ "success": "Bool" } }, - "System.SelectChannel": { - "description": "Select an update channel.", + "System.RemovePackages": { + "description": "Starts removing a package. Returns true if the removal has been started successfully.", "params": { - "channel": "String" + "packageIds": [ + "String" + ] + }, + "returns": { + "success": "Bool" + } + }, + "System.RollbackPackages": { + "description": "Starts a rollback. Returns true if the rollback has been started successfully.", + "params": { + "packageIds": [ + "String" + ] }, "returns": { "success": "Bool" @@ -914,9 +944,12 @@ "success": "Bool" } }, - "System.StartUpdate": { - "description": "Starts a system update. Returns true if the upgrade has been started successfully.", + "System.UpdatePackages": { + "description": "Starts updating/installing packages with the given ids. Returns true if the upgrade has been started successfully. Note that it might still fail later.", "params": { + "o:packageIds": [ + "String" + ] }, "returns": { "success": "Bool" @@ -1182,15 +1215,53 @@ "ruleId": "Uuid" } }, - "System.UpdateStatusChanged": { - "description": "Emitted whenever there is a change in the information from GetUpdateStatus", + "System.CapabilitiesChanged": { + "description": "Emitted whenever the system capabilities change.", "params": { - "availableChannels": "StringList", - "candidateVersion": "String", - "currentChannel": "String", - "currentVersion": "String", - "updateAvailable": "Bool", - "updateInProgress": "Bool" + "powerManagement": "Bool", + "updateManagement": "Bool" + } + }, + "System.PackageAdded": { + "description": "Emitted whenever a package is added to the list of packages.", + "params": { + "package": "$ref:Package" + } + }, + "System.PackageChanged": { + "description": "Emitted whenever a package in the list of packages changes.", + "params": { + "package": "$ref:Package" + } + }, + "System.PackageRemoved": { + "description": "Emitted whenever a package is removed from the list of packages.", + "params": { + "packageId": "String" + } + }, + "System.RepositoryAdded": { + "description": "Emitted whenever a repository is added to the list of repositories.", + "params": { + "repository": "$ref:Repository" + } + }, + "System.RepositoryChanged": { + "description": "Emitted whenever a repository in the list of repositories changes.", + "params": { + "repository": "$ref:Repository" + } + }, + "System.RepositoryRemoved": { + "description": "Emitted whenever a repository is removed from the list of repositories.", + "params": { + "repository": "String" + } + }, + "System.UpdateStatusChanged": { + "description": "Emitted whenever the update status changes.", + "params": { + "updateRunning": "Bool" } }, "Tags.TagAdded": {