load plugins dynamically
This commit is contained in:
parent
c14521fef5
commit
c9e6b7ed81
1
debian/guh.install
vendored
1
debian/guh.install
vendored
@ -1,2 +1,3 @@
|
||||
usr/bin/guh
|
||||
usr/lib/guh/
|
||||
data/init/guhd /etc/init.d/
|
||||
|
||||
@ -88,6 +88,8 @@
|
||||
#include <QSettings>
|
||||
#include <QStringList>
|
||||
#include <QCoreApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
|
||||
/*! Constructs the DeviceManager with the given \a parent. There should only be one DeviceManager in the system created by \l{GuhCore}.
|
||||
Use \c GuhCore::instance()->deviceManager() instead to access the DeviceManager.
|
||||
@ -510,59 +512,75 @@ QPair<DeviceManager::DeviceError, QString> DeviceManager::executeAction(const Ac
|
||||
|
||||
void DeviceManager::loadPlugins()
|
||||
{
|
||||
foreach (const QStaticPlugin &staticPlugin, QPluginLoader::staticPlugins()) {
|
||||
DevicePlugin *pluginIface = qobject_cast<DevicePlugin*>(staticPlugin.instance());
|
||||
if (verifyPluginMetadata(staticPlugin.metaData().value("MetaData").toObject()) && pluginIface) {
|
||||
pluginIface->initPlugin(staticPlugin.metaData().value("MetaData").toObject(), this);
|
||||
qDebug() << "*** Loaded plugin" << pluginIface->pluginName();
|
||||
foreach (const Vendor &vendor, pluginIface->supportedVendors()) {
|
||||
qDebug() << "* Loaded vendor:" << vendor.name();
|
||||
if (m_supportedVendors.contains(vendor.id())) {
|
||||
qWarning() << "! Duplicate vendor. Ignoring vendor" << vendor.name();
|
||||
continue;
|
||||
}
|
||||
m_supportedVendors.insert(vendor.id(), vendor);
|
||||
}
|
||||
|
||||
foreach (const DeviceClass &deviceClass, pluginIface->supportedDevices()) {
|
||||
if (!m_supportedVendors.contains(deviceClass.vendorId())) {
|
||||
qWarning() << "! Vendor not found. Ignoring device. VendorId:" << deviceClass.vendorId() << "DeviceClass:" << deviceClass.name() << deviceClass.id();
|
||||
continue;
|
||||
}
|
||||
m_vendorDeviceMap[deviceClass.vendorId()].append(deviceClass.id());
|
||||
m_supportedDevices.insert(deviceClass.id(), deviceClass);
|
||||
qDebug() << "* Loaded device class:" << deviceClass.name();
|
||||
QStringList searchDirs;
|
||||
searchDirs << QCoreApplication::applicationDirPath() + "/../lib/guh";
|
||||
searchDirs << QCoreApplication::applicationDirPath() + "/../";
|
||||
searchDirs << QCoreApplication::applicationDirPath() + "/../../../";
|
||||
|
||||
foreach (const QString &path, searchDirs) {
|
||||
QDir dir(path + "/plugins/deviceplugins");
|
||||
qDebug() << "Loading plugins from:" << dir.absolutePath();
|
||||
foreach (const QString &entry, dir.entryList()) {
|
||||
QFileInfo fi(path + "/plugins/deviceplugins/" + entry + "/libguh_deviceplugin" + entry + ".so");
|
||||
if (!fi.exists()) {
|
||||
continue;
|
||||
}
|
||||
QSettings settings(m_settingsFile);
|
||||
settings.beginGroup("PluginConfig");
|
||||
ParamList params;
|
||||
if (settings.childGroups().contains(pluginIface->pluginId().toString())) {
|
||||
settings.beginGroup(pluginIface->pluginId().toString());
|
||||
foreach (const QString ¶mName, settings.allKeys()) {
|
||||
Param param(paramName, settings.value(paramName));
|
||||
params.append(param);
|
||||
QPluginLoader loader(fi.absoluteFilePath());
|
||||
|
||||
DevicePlugin *pluginIface = qobject_cast<DevicePlugin*>(loader.instance());
|
||||
if (verifyPluginMetadata(loader.metaData().value("MetaData").toObject()) && pluginIface) {
|
||||
pluginIface->initPlugin(loader.metaData().value("MetaData").toObject(), this);
|
||||
qDebug() << "*** Loaded plugin" << pluginIface->pluginName();
|
||||
foreach (const Vendor &vendor, pluginIface->supportedVendors()) {
|
||||
qDebug() << "* Loaded vendor:" << vendor.name();
|
||||
if (m_supportedVendors.contains(vendor.id())) {
|
||||
qWarning() << "! Duplicate vendor. Ignoring vendor" << vendor.name();
|
||||
continue;
|
||||
}
|
||||
m_supportedVendors.insert(vendor.id(), vendor);
|
||||
}
|
||||
|
||||
foreach (const DeviceClass &deviceClass, pluginIface->supportedDevices()) {
|
||||
if (!m_supportedVendors.contains(deviceClass.vendorId())) {
|
||||
qWarning() << "! Vendor not found. Ignoring device. VendorId:" << deviceClass.vendorId() << "DeviceClass:" << deviceClass.name() << deviceClass.id();
|
||||
continue;
|
||||
}
|
||||
m_vendorDeviceMap[deviceClass.vendorId()].append(deviceClass.id());
|
||||
m_supportedDevices.insert(deviceClass.id(), deviceClass);
|
||||
qDebug() << "* Loaded device class:" << deviceClass.name();
|
||||
}
|
||||
QSettings settings(m_settingsFile);
|
||||
settings.beginGroup("PluginConfig");
|
||||
ParamList params;
|
||||
if (settings.childGroups().contains(pluginIface->pluginId().toString())) {
|
||||
settings.beginGroup(pluginIface->pluginId().toString());
|
||||
foreach (const QString ¶mName, settings.allKeys()) {
|
||||
Param param(paramName, settings.value(paramName));
|
||||
params.append(param);
|
||||
}
|
||||
settings.endGroup();
|
||||
} else if (pluginIface->configurationDescription().count() > 0){
|
||||
// plugin requires config but none stored. Init with defaults
|
||||
foreach (const ParamType ¶mType, pluginIface->configurationDescription()) {
|
||||
Param param(paramType.name(), paramType.defaultValue());
|
||||
params.append(param);
|
||||
}
|
||||
}
|
||||
settings.endGroup();
|
||||
} else if (pluginIface->configurationDescription().count() > 0){
|
||||
// plugin requires config but none stored. Init with defaults
|
||||
foreach (const ParamType ¶mType, pluginIface->configurationDescription()) {
|
||||
Param param(paramType.name(), paramType.defaultValue());
|
||||
params.append(param);
|
||||
QPair<DeviceError, QString> status = pluginIface->setConfiguration(params);
|
||||
if (status.first != DeviceErrorNoError) {
|
||||
qWarning() << "Error setting params to plugin. Broken configuration?" << status.second;
|
||||
}
|
||||
}
|
||||
settings.endGroup();
|
||||
QPair<DeviceError, QString> status = pluginIface->setConfiguration(params);
|
||||
if (status.first != DeviceErrorNoError) {
|
||||
qWarning() << "Error setting params to plugin. Broken configuration?" << status.second;
|
||||
}
|
||||
|
||||
m_devicePlugins.insert(pluginIface->pluginId(), pluginIface);
|
||||
connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::eventTriggered);
|
||||
connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered);
|
||||
connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished);
|
||||
connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished);
|
||||
connect(pluginIface, &DevicePlugin::pairingFinished, this, &DeviceManager::slotPairingFinished);
|
||||
connect(pluginIface, &DevicePlugin::autoDevicesAppeared, this, &DeviceManager::autoDevicesAppeared);
|
||||
m_devicePlugins.insert(pluginIface->pluginId(), pluginIface);
|
||||
connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::eventTriggered);
|
||||
connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered);
|
||||
connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished);
|
||||
connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished);
|
||||
connect(pluginIface, &DevicePlugin::pairingFinished, this, &DeviceManager::slotPairingFinished);
|
||||
connect(pluginIface, &DevicePlugin::autoDevicesAppeared, this, &DeviceManager::autoDevicesAppeared);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -588,7 +606,7 @@ void DeviceManager::loadConfiguredDevices()
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
|
||||
qDebug() << "found stored device" << device->id() << device->name() << device->deviceClassId() << device->pluginId();
|
||||
//qDebug() << "found stored device" << device->id() << device->name() << device->deviceClassId() << device->pluginId();
|
||||
|
||||
// We always add the device to the list in this case. If its in the storedDevices
|
||||
// it means that it was working at some point so lets still add it as there might
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
include(../guh.pri)
|
||||
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin static c++11
|
||||
CONFIG += plugin c++11
|
||||
|
||||
INCLUDEPATH += ../../../libguh
|
||||
LIBS += -L../../../libguh -lguh
|
||||
|
||||
target.path = /usr/lib/guh/plugins/
|
||||
INSTALLS += target
|
||||
|
||||
@ -21,23 +21,6 @@
|
||||
|
||||
#include <QtPlugin>
|
||||
|
||||
Q_IMPORT_PLUGIN(DevicePluginElro)
|
||||
Q_IMPORT_PLUGIN(DevicePluginIntertechno)
|
||||
//Q_IMPORT_PLUGIN(DevicePluginMeisterAnker)
|
||||
Q_IMPORT_PLUGIN(DevicePluginWifiDetector)
|
||||
Q_IMPORT_PLUGIN(DevicePluginConrad)
|
||||
Q_IMPORT_PLUGIN(DevicePluginMock)
|
||||
Q_IMPORT_PLUGIN(DevicePluginOpenweathermap)
|
||||
Q_IMPORT_PLUGIN(DevicePluginLircd)
|
||||
Q_IMPORT_PLUGIN(DevicePluginWakeOnLan)
|
||||
Q_IMPORT_PLUGIN(DevicePluginMailNotification)
|
||||
Q_IMPORT_PLUGIN(DevicePluginPhilipsHue)
|
||||
Q_IMPORT_PLUGIN(DevicePluginLgSmartTv)
|
||||
|
||||
#if USE_BOBLIGHT
|
||||
Q_IMPORT_PLUGIN(DevicePluginBoblight)
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
@ -18,20 +18,6 @@ LIBS += -L$$top_builddir/libguh/ -lguh
|
||||
include(server.pri)
|
||||
SOURCES += main.cpp
|
||||
|
||||
# FIXME: Drop this and link them dynamically
|
||||
LIBS += -L../plugins/deviceplugins/elro/ -lguh_devicepluginelro
|
||||
LIBS += -L../plugins/deviceplugins/intertechno/ -lguh_devicepluginintertechno
|
||||
#LIBS += -L../plugins/deviceplugins/meisteranker/ -lguh_devicepluginmeisteranker
|
||||
LIBS += -L../plugins/deviceplugins/wifidetector/ -lguh_devicepluginwifidetector
|
||||
LIBS += -L../plugins/deviceplugins/conrad -lguh_devicepluginconrad
|
||||
LIBS += -L../plugins/deviceplugins/mock -lguh_devicepluginmock
|
||||
LIBS += -L../plugins/deviceplugins/openweathermap -lguh_devicepluginopenweathermap
|
||||
LIBS += -L../plugins/deviceplugins/lircd -lguh_devicepluginlircd
|
||||
LIBS += -L../plugins/deviceplugins/mailnotification -lguh_devicepluginmailnotification
|
||||
LIBS += -L../plugins/deviceplugins/wakeonlan -lguh_devicepluginwakeonlan
|
||||
LIBS += -L../plugins/deviceplugins/philipshue -lguh_devicepluginphilipshue
|
||||
LIBS += -L../plugins/deviceplugins/lgsmarttv -lguh_devicepluginlgsmarttv
|
||||
|
||||
boblight {
|
||||
xcompile {
|
||||
LIBS += -L../plugins/deviceplugins/boblight -lguh_devicepluginboblight -lboblight
|
||||
|
||||
@ -5,7 +5,7 @@ include($$top_srcdir/server/server.pri)
|
||||
|
||||
DEFINES += TESTING_ENABLED
|
||||
INCLUDEPATH += $$top_srcdir/server/ $$top_srcdir/server/jsonrpc $$top_srcdir/libguh $$top_srcdir/tests/auto/
|
||||
LIBS += -L$$top_builddir/libguh/ -lguh -L$$top_builddir/plugins/deviceplugins/mock/ -lguh_devicepluginmock
|
||||
LIBS += -L$$top_builddir/libguh/ -lguh -L$$top_builddir/plugins/deviceplugins/mock/
|
||||
|
||||
SOURCES += ../guhtestbase.cpp \
|
||||
../mocktcpserver.cpp \
|
||||
|
||||
@ -71,8 +71,14 @@ void TestDevices::getPlugins()
|
||||
|
||||
QVariantList plugins = response.toMap().value("params").toMap().value("plugins").toList();
|
||||
|
||||
QCOMPARE(plugins.count(), 1);
|
||||
QCOMPARE(PluginId(plugins.first().toMap().value("id").toString()), mockPluginId);
|
||||
QCOMPARE(plugins.count() > 0, true);
|
||||
bool found = false;
|
||||
foreach (const QVariant &listEntry, plugins) {
|
||||
if (PluginId(listEntry.toMap().value("id").toString()) == mockPluginId) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
QCOMPARE(found, true);
|
||||
}
|
||||
|
||||
void TestDevices::getPluginConfig_data()
|
||||
@ -144,9 +150,14 @@ void TestDevices::getSupportedVendors()
|
||||
|
||||
// Make sure there is exactly 1 supported Vendor named "guh"
|
||||
QVariantList vendorList = supportedVendors.toMap().value("params").toMap().value("vendors").toList();
|
||||
QCOMPARE(vendorList.count(), 1);
|
||||
VendorId vendorId = VendorId(vendorList.first().toMap().value("id").toString());
|
||||
QCOMPARE(vendorId, guhVendorId);
|
||||
QCOMPARE(vendorList.count() > 0, true);
|
||||
bool found = false;
|
||||
foreach (const QVariant &listEntry, vendorList) {
|
||||
if (VendorId(listEntry.toMap().value("id").toString()) == guhVendorId) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
QCOMPARE(found, true);
|
||||
}
|
||||
|
||||
void TestDevices::getSupportedDevices_data()
|
||||
@ -168,13 +179,19 @@ void TestDevices::getSupportedDevices()
|
||||
if (!vendorId.isNull()) {
|
||||
params.insert("vendorId", vendorId);
|
||||
}
|
||||
QVariant supportedDevices = injectAndWait("Devices.GetSupportedDevices", params);
|
||||
QVariant result = injectAndWait("Devices.GetSupportedDevices", params);
|
||||
|
||||
QVariantList supportedDevices = result.toMap().value("params").toMap().value("deviceClasses").toList();
|
||||
// Make sure there are the right amount of supported device classes with the name Mock Device
|
||||
QCOMPARE(supportedDevices.toMap().value("params").toMap().value("deviceClasses").toList().count(), resultCount);
|
||||
QCOMPARE(supportedDevices.count() >= resultCount, true);
|
||||
if (resultCount > 0) {
|
||||
QString deviceName = supportedDevices.toMap().value("params").toMap().value("deviceClasses").toList().first().toMap().value("name").toString();
|
||||
QVERIFY2(deviceName.startsWith(QString("Mock Device")), QString("Got: %1 Expected: %2").arg(deviceName).arg("Mock Device").toLatin1().data());
|
||||
bool found = false;
|
||||
foreach (const QVariant &listEntry, supportedDevices) {
|
||||
if (listEntry.toMap().value("name").toString().startsWith("Mock Device")) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
QVERIFY2(found, "Mock Device not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,23 @@
|
||||
#include <QtTest>
|
||||
#include <QMetaType>
|
||||
|
||||
Q_IMPORT_PLUGIN(DevicePluginMock)
|
||||
PluginId mockPluginId = PluginId("727a4a9a-c187-446f-aadf-f1b2220607d1");
|
||||
VendorId guhVendorId = VendorId("2062d64d-3232-433c-88bc-0d33c0ba2ba6");
|
||||
DeviceClassId mockDeviceClassId = DeviceClassId("753f0d32-0468-4d08-82ed-1964aab03298");
|
||||
DeviceClassId mockDeviceAutoClassId = DeviceClassId("ab4257b3-7548-47ee-9bd4-7dc3004fd197");
|
||||
DeviceClassId mockDeviceDiscoveryClassId = DeviceClassId("1bbaf751-36b7-4d3d-b05a-58dab2a3be8c");
|
||||
DeviceClassId mockDeviceAsyncSetupClassId = DeviceClassId("c08a8b27-8200-413d-b96b-4cff78b864d9");
|
||||
DeviceClassId mockDeviceBrokenClassId = DeviceClassId("ba5fb404-c9ce-4db4-8cd4-f48c61c24b13");
|
||||
DeviceClassId mockDeviceBrokenAsyncSetupClassId = DeviceClassId("bd5b78c5-53c9-4417-8eac-8ab2bce97bd0");
|
||||
EventTypeId mockEvent1Id = EventTypeId("45bf3752-0fc6-46b9-89fd-ffd878b5b22b");
|
||||
EventTypeId mockEvent2Id = EventTypeId("863d5920-b1cf-4eb9-88bd-8f7b8583b1cf");
|
||||
StateTypeId mockIntStateId = StateTypeId("80baec19-54de-4948-ac46-31eabfaceb83");
|
||||
StateTypeId mockBoolStateId = StateTypeId("9dd6a97c-dfd1-43dc-acbd-367932742310");
|
||||
ActionTypeId mockActionIdWithParams = ActionTypeId("dea0f4e1-65e3-4981-8eaa-2701c53a9185");
|
||||
ActionTypeId mockActionIdNoParams = ActionTypeId("defd3ed6-1a0d-400b-8879-a0202cf39935");
|
||||
ActionTypeId mockActionIdAsync = ActionTypeId("fbae06d3-7666-483e-a39e-ec50fe89054e");
|
||||
ActionTypeId mockActionIdFailing = ActionTypeId("df3cf33d-26d5-4577-9132-9823bd33fad0");
|
||||
ActionTypeId mockActionIdAsyncFailing = ActionTypeId("bfe89a1d-3497-4121-8318-e77c37537219");
|
||||
|
||||
GuhTestBase::GuhTestBase(QObject *parent) :
|
||||
QObject(parent),
|
||||
|
||||
Reference in New Issue
Block a user