overte/libraries/plugins/src/plugins/PluginManager.cpp
2017-06-24 22:22:47 -07:00

331 lines
11 KiB
C++

//
// Created by Bradley Austin Davis on 2015/08/08
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "PluginManager.h"
#include <mutex>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QPluginLoader>
#include <DependencyManager.h>
#include <UserActivityLogger.h>
#include "RuntimePlugin.h"
#include "CodecPlugin.h"
#include "DisplayPlugin.h"
#include "InputPlugin.h"
#include "PluginLogging.h"
void PluginManager::setDisplayPluginProvider(const DisplayPluginProvider& provider) {
_displayPluginProvider = provider;
}
void PluginManager::setInputPluginProvider(const InputPluginProvider& provider) {
_inputPluginProvider = provider;
}
void PluginManager::setCodecPluginProvider(const CodecPluginProvider& provider) {
_codecPluginProvider = provider;
}
void PluginManager::setInputPluginSettingsPersister(const InputPluginSettingsPersister& persister) {
_inputSettingsPersister = persister;
}
PluginManager* PluginManager::getInstance() {
static PluginManager _manager;
return &_manager;
}
QString getPluginNameFromMetaData(QJsonObject object) {
static const char* METADATA_KEY = "MetaData";
static const char* NAME_KEY = "name";
if (!object.contains(METADATA_KEY) || !object[METADATA_KEY].isObject()) {
return QString();
}
auto metaDataObject = object[METADATA_KEY].toObject();
if (!metaDataObject.contains(NAME_KEY) || !metaDataObject[NAME_KEY].isString()) {
return QString();
}
return metaDataObject[NAME_KEY].toString();
}
QString getPluginIIDFromMetaData(QJsonObject object) {
static const char* IID_KEY = "IID";
if (!object.contains(IID_KEY) || !object[IID_KEY].isString()) {
return QString();
}
return object[IID_KEY].toString();
}
QStringList preferredDisplayPlugins;
QStringList disabledDisplays;
QStringList disabledInputs;
bool isDisabled(QJsonObject metaData) {
auto name = getPluginNameFromMetaData(metaData);
auto iid = getPluginIIDFromMetaData(metaData);
if (iid == DisplayProvider_iid) {
return disabledDisplays.contains(name);
} else if (iid == InputProvider_iid) {
return disabledInputs.contains(name);
}
return false;
}
using Loader = QSharedPointer<QPluginLoader>;
using LoaderList = QList<Loader>;
const LoaderList& getLoadedPlugins() {
static std::once_flag once;
static LoaderList loadedPlugins;
std::call_once(once, [&] {
#ifdef Q_OS_MAC
QString pluginPath = QCoreApplication::applicationDirPath() + "/../PlugIns/";
#else
QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/";
#endif
QDir pluginDir(pluginPath);
pluginDir.setSorting(QDir::Name);
pluginDir.setFilter(QDir::Files);
if (pluginDir.exists()) {
qInfo() << "Loading runtime plugins from " << pluginPath;
auto candidates = pluginDir.entryList();
for (auto plugin : candidates) {
qCDebug(plugins) << "Attempting plugin" << qPrintable(plugin);
QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
if (isDisabled(loader->metaData())) {
qWarning() << "Plugin" << qPrintable(plugin) << "is disabled";
// Skip this one, it's disabled
continue;
}
if (loader->load()) {
qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "loaded successfully";
loadedPlugins.push_back(loader);
} else {
qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "failed to load:";
qCDebug(plugins) << " " << qPrintable(loader->errorString());
}
}
}
});
return loadedPlugins;
}
PluginManager::PluginManager() {
}
const CodecPluginList& PluginManager::getCodecPlugins() {
static CodecPluginList codecPlugins;
static std::once_flag once;
std::call_once(once, [&] {
codecPlugins = _codecPluginProvider();
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
CodecProvider* codecProvider = qobject_cast<CodecProvider*>(loader->instance());
if (codecProvider) {
for (auto codecPlugin : codecProvider->getCodecPlugins()) {
if (codecPlugin->isSupported()) {
codecPlugins.push_back(codecPlugin);
}
}
}
}
for (auto plugin : codecPlugins) {
plugin->setContainer(_container);
plugin->init();
qCDebug(plugins) << "init codec:" << plugin->getName();
}
});
return codecPlugins;
}
const SteamClientPluginPointer PluginManager::getSteamClientPlugin() {
static SteamClientPluginPointer steamClientPlugin;
static std::once_flag once;
std::call_once(once, [&] {
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
SteamClientProvider* steamClientProvider = qobject_cast<SteamClientProvider*>(loader->instance());
if (steamClientProvider) {
steamClientPlugin = steamClientProvider->getSteamClientPlugin();
break;
}
}
});
return steamClientPlugin;
}
#ifndef Q_OS_ANDROID
static DisplayPluginList displayPlugins;
const DisplayPluginList& PluginManager::getDisplayPlugins() {
static std::once_flag once;
static auto deviceAddedCallback = [](QString deviceName) {
qCDebug(plugins) << "Added device: " << deviceName;
UserActivityLogger::getInstance().connectedDevice("display", deviceName);
};
static auto subdeviceAddedCallback = [](QString pluginName, QString deviceName) {
qCDebug(plugins) << "Added subdevice: " << deviceName;
UserActivityLogger::getInstance().connectedDevice("display", pluginName + " | " + deviceName);
};
std::call_once(once, [&] {
// Grab the built in plugins
displayPlugins = _displayPluginProvider();
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
DisplayProvider* displayProvider = qobject_cast<DisplayProvider*>(loader->instance());
if (displayProvider) {
for (auto displayPlugin : displayProvider->getDisplayPlugins()) {
displayPlugins.push_back(displayPlugin);
}
}
}
for (auto plugin : displayPlugins) {
connect(plugin.get(), &Plugin::deviceConnected, this, deviceAddedCallback, Qt::QueuedConnection);
connect(plugin.get(), &Plugin::subdeviceConnected, this, subdeviceAddedCallback, Qt::QueuedConnection);
plugin->setContainer(_container);
plugin->init();
}
});
return displayPlugins;
}
void PluginManager::disableDisplayPlugin(const QString& name) {
for (size_t i = 0; i < displayPlugins.size(); ++i) {
if (displayPlugins[i]->getName() == name) {
displayPlugins.erase(displayPlugins.begin() + i);
break;
}
}
}
const InputPluginList& PluginManager::getInputPlugins() {
static InputPluginList inputPlugins;
static std::once_flag once;
static auto deviceAddedCallback = [](QString deviceName) {
qCDebug(plugins) << "Added device: " << deviceName;
UserActivityLogger::getInstance().connectedDevice("input", deviceName);
};
static auto subdeviceAddedCallback = [](QString pluginName, QString deviceName) {
qCDebug(plugins) << "Added subdevice: " << deviceName;
UserActivityLogger::getInstance().connectedDevice("input", pluginName + " | " + deviceName);
};
std::call_once(once, [&] {
inputPlugins = _inputPluginProvider();
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
if (inputProvider) {
for (auto inputPlugin : inputProvider->getInputPlugins()) {
if (inputPlugin->isSupported()) {
inputPlugins.push_back(inputPlugin);
}
}
}
}
for (auto plugin : inputPlugins) {
connect(plugin.get(), &Plugin::deviceConnected, this, deviceAddedCallback, Qt::QueuedConnection);
connect(plugin.get(), &Plugin::subdeviceConnected, this, subdeviceAddedCallback, Qt::QueuedConnection);
plugin->setContainer(_container);
plugin->init();
}
});
return inputPlugins;
}
void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) {
preferredDisplayPlugins = displays;
}
DisplayPluginList PluginManager::getPreferredDisplayPlugins() {
static DisplayPluginList displayPlugins;
static std::once_flag once;
std::call_once(once, [&] {
// Grab the built in plugins
auto plugins = getDisplayPlugins();
for (auto pluginName : preferredDisplayPlugins) {
auto it = std::find_if(plugins.begin(), plugins.end(), [&](DisplayPluginPointer plugin) {
return plugin->getName() == pluginName;
});
if (it != plugins.end()) {
displayPlugins.push_back(*it);
}
}
});
return displayPlugins;
}
void PluginManager::disableDisplays(const QStringList& displays) {
disabledDisplays << displays;
}
void PluginManager::disableInputs(const QStringList& inputs) {
disabledInputs << inputs;
}
void PluginManager::saveSettings() {
_inputSettingsPersister(getInputPlugins());
}
void PluginManager::shutdown() {
for (auto inputPlugin : getInputPlugins()) {
if (inputPlugin->isActive()) {
inputPlugin->deactivate();
}
}
for (auto displayPlugins : getDisplayPlugins()) {
if (displayPlugins->isActive()) {
displayPlugins->deactivate();
}
}
auto loadedPlugins = getLoadedPlugins();
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
if (inputProvider) {
inputProvider->destroyInputPlugins();
}
DisplayProvider* displayProvider = qobject_cast<DisplayProvider*>(loader->instance());
if (displayProvider) {
displayProvider->destroyDisplayPlugins();
}
}
}
#endif