load plugins dynamically

This commit is contained in:
Michael Zanetti 2014-10-11 03:24:52 +02:00 committed by Michael Zanetti
parent c14521fef5
commit c9e6b7ed81
8 changed files with 114 additions and 91 deletions

1
debian/guh.install vendored
View File

@ -1,2 +1,3 @@
usr/bin/guh
usr/lib/guh/
data/init/guhd /etc/init.d/

View File

@ -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 &paramName, 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 &paramName, 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 &paramType, 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 &paramType, 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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 \

View File

@ -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");
}
}

View File

@ -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),