File indexing completed on 2024-04-28 16:51:33

0001 /*
0002     SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@privat.broulik.de>
0003 
0004     SPDX-License-Identifier: GPL-3.0-or-later
0005 */
0006 
0007 #include "pluginmanager.h"
0008 
0009 #include <QJsonObject>
0010 
0011 #include "abstractbrowserplugin.h"
0012 #include "connection.h"
0013 
0014 PluginManager::PluginManager()
0015     : QObject(nullptr)
0016 {
0017     connect(Connection::self(), &Connection::dataReceived, this, &PluginManager::onDataReceived);
0018 }
0019 
0020 PluginManager::~PluginManager() = default;
0021 
0022 PluginManager &PluginManager::self()
0023 {
0024     static PluginManager s_self;
0025     return s_self;
0026 }
0027 
0028 AbstractBrowserPlugin *PluginManager::pluginForSubsystem(const QString &subsystem) const
0029 {
0030     return m_plugins.value(subsystem);
0031 }
0032 
0033 void PluginManager::addPlugin(AbstractBrowserPlugin *plugin)
0034 {
0035     m_plugins.insert(plugin->m_subsystem, plugin);
0036 }
0037 
0038 bool PluginManager::loadPlugin(AbstractBrowserPlugin *plugin)
0039 {
0040     return setPluginLoaded(plugin, true);
0041 }
0042 
0043 bool PluginManager::unloadPlugin(AbstractBrowserPlugin *plugin)
0044 {
0045     return setPluginLoaded(plugin, false);
0046 }
0047 
0048 bool PluginManager::setPluginLoaded(AbstractBrowserPlugin *plugin, bool loaded)
0049 {
0050     if (!plugin) {
0051         return false;
0052     }
0053 
0054     if (plugin->isLoaded() == loaded) {
0055         return true;
0056     }
0057 
0058     bool ok = false;
0059     if (loaded && !plugin->isLoaded()) {
0060         ok = plugin->onLoad();
0061     } else if (!loaded && plugin->isLoaded()) {
0062         ok = plugin->onUnload();
0063     }
0064 
0065     if (!ok) {
0066         qDebug() << "plugin" << plugin->subsystem() << "refused to" << (loaded ? "load" : "unload");
0067         return false;
0068     }
0069 
0070     plugin->setLoaded(loaded);
0071 
0072     if (loaded) {
0073         Q_EMIT pluginLoaded(plugin);
0074     } else {
0075         Q_EMIT pluginUnloaded(plugin);
0076     }
0077 
0078     return true;
0079 }
0080 
0081 void PluginManager::settingsChanged(AbstractBrowserPlugin *plugin, const QJsonObject &settings)
0082 {
0083     plugin->onSettingsChanged(settings);
0084 }
0085 
0086 QStringList PluginManager::knownPluginSubsystems() const
0087 {
0088     return m_plugins.keys();
0089 }
0090 
0091 QStringList PluginManager::loadedPluginSubsystems() const
0092 {
0093     QStringList plugins;
0094     for (auto it = m_plugins.constBegin(), end = m_plugins.constEnd(); it != end; ++it) {
0095         if (it.value()->isLoaded()) {
0096             plugins << it.key();
0097         }
0098     }
0099     return plugins;
0100 }
0101 
0102 void PluginManager::onDataReceived(const QJsonObject &json)
0103 {
0104     const QString subsystem = json.value(QStringLiteral("subsystem")).toString();
0105 
0106     AbstractBrowserPlugin *plugin = m_plugins.value(subsystem);
0107     if (!plugin) {
0108         return;
0109     }
0110 
0111     if (!plugin->isLoaded()) {
0112         return;
0113     }
0114 
0115     const QString event = json.value(QStringLiteral("event")).toString();
0116     if (event.isEmpty()) {
0117         return;
0118     }
0119 
0120     const QJsonValue requestSerialVariant = json.value(QStringLiteral("serial"));
0121     if (!requestSerialVariant.isUndefined()) {
0122         const int requestSerial = requestSerialVariant.toInt();
0123 
0124         const auto reply = plugin->handleData(requestSerial, event, json);
0125         if (!reply.isEmpty()) {
0126             plugin->sendReply(requestSerial, reply);
0127         }
0128     } else {
0129         // design question, should we have a JSON of subsystem, event, payload, or have all data at the root level?
0130         plugin->handleData(event, json);
0131     }
0132 }