Add support for the plugin storage to python plugins
This commit is contained in:
parent
96ae3cd01a
commit
9d30be2568
@ -11,6 +11,7 @@
|
|||||||
#include "pyparam.h"
|
#include "pyparam.h"
|
||||||
#include "pythingactioninfo.h"
|
#include "pythingactioninfo.h"
|
||||||
#include "pythingpairinginfo.h"
|
#include "pythingpairinginfo.h"
|
||||||
|
#include "pypluginstorage.h"
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||||
@ -27,6 +28,7 @@ static int nymea_exec(PyObject *m) {
|
|||||||
registerThingPairingInfoType(m);
|
registerThingPairingInfoType(m);
|
||||||
registerThingSetupInfoType(m);
|
registerThingSetupInfoType(m);
|
||||||
registerThingActionInfoType(m);
|
registerThingActionInfoType(m);
|
||||||
|
registerPluginStorageType(m);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
135
libnymea-core/integrations/python/pypluginstorage.h
Normal file
135
libnymea-core/integrations/python/pypluginstorage.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#ifndef PYPLUGINSTORAGE_H
|
||||||
|
#define PYPLUGINSTORAGE_H
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include "structmember.h"
|
||||||
|
#include "pyutils.h"
|
||||||
|
|
||||||
|
//#include "integrations/pythonintegrationplugin.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
#include "nymeasettings.h"
|
||||||
|
#include "typeutils.h"
|
||||||
|
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||||
|
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||||
|
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
QSettings *settings;
|
||||||
|
} PyPluginStorage;
|
||||||
|
|
||||||
|
|
||||||
|
static PyMemberDef PyPluginStorage_members[] = {
|
||||||
|
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject * PyPluginStorage_value(PyPluginStorage* self, PyObject* args) {
|
||||||
|
char *keyStr = nullptr;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &keyStr)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Invalid arguments in value call. Expected: value(key)");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant value = self->settings->value(keyStr);
|
||||||
|
return QVariantToPyObject(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject * PyPluginStorage_setValue(PyPluginStorage* self, PyObject* args) {
|
||||||
|
char *keyStr = nullptr;
|
||||||
|
PyObject *value = nullptr;
|
||||||
|
if (!PyArg_ParseTuple(args, "sO", &keyStr, &value)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Invalid arguments in value call. Expected: value(key, value)");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->settings->setValue(keyStr, PyObjectToQVariant(value));
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject * PyPluginStorage_beginGroup(PyPluginStorage* self, PyObject* args) {
|
||||||
|
char *groupStr = nullptr;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &groupStr)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Invalid arguments in value call. Expected: beginGroup(group)");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->settings->beginGroup(groupStr);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject * PyPluginStorage_endGroup(PyPluginStorage* self, PyObject* args) {
|
||||||
|
Q_UNUSED(args)
|
||||||
|
self->settings->endGroup();
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyMethodDef PyPluginStorage_methods[] = {
|
||||||
|
{ "value", (PyCFunction)PyPluginStorage_value, METH_VARARGS, "Get a value from the plugin storage" },
|
||||||
|
{ "setValue", (PyCFunction)PyPluginStorage_setValue, METH_VARARGS, "Set a value to the plugin storage"},
|
||||||
|
{ "beginGroup", (PyCFunction)PyPluginStorage_beginGroup, METH_VARARGS, "Begin a group in the plugin storage."},
|
||||||
|
{ "endGroup", (PyCFunction)PyPluginStorage_endGroup, METH_VARARGS, "End a group in the plugin storage."},
|
||||||
|
{nullptr, nullptr, 0, nullptr} // sentinel
|
||||||
|
};
|
||||||
|
|
||||||
|
static int PyPluginStorage_init(PyPluginStorage *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
Q_UNUSED(kwds)
|
||||||
|
char *pluginIdStr = nullptr;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &pluginIdStr)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Invalid arguments in constructor. Expected: PluginStorage(pluginId)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pluginIdStr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PluginId pluginId(pluginIdStr);
|
||||||
|
if (pluginId.isNull()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->settings = new QSettings(NymeaSettings::settingsPath() + "/pluginconfig-" + pluginId.toString().remove(QRegExp("[{}]")) + ".conf", QSettings::IniFormat);
|
||||||
|
|
||||||
|
qCDebug(dcPythonIntegrations()) << "+++ PyPluginStorage";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PyPluginStorage_dealloc(PyPluginStorage * self)
|
||||||
|
{
|
||||||
|
qCDebug(dcPythonIntegrations()) << "--- PyPluginStorage";
|
||||||
|
Py_TYPE(self)->tp_free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyTypeObject PyPluginStorageType = {
|
||||||
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
"nymea.PluginStorage", /* tp_name */
|
||||||
|
sizeof(PyPluginStorage), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
(destructor)PyPluginStorage_dealloc, /* tp_dealloc */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void registerPluginStorageType(PyObject *module)
|
||||||
|
{
|
||||||
|
PyPluginStorageType.tp_new = PyType_GenericNew;
|
||||||
|
PyPluginStorageType.tp_members = PyPluginStorage_members;
|
||||||
|
PyPluginStorageType.tp_methods = PyPluginStorage_methods;
|
||||||
|
PyPluginStorageType.tp_init = reinterpret_cast<initproc>(PyPluginStorage_init);
|
||||||
|
PyPluginStorageType.tp_doc = "PluginStorage can be used by plugins to store key-value pairs to a persistant place.";
|
||||||
|
PyPluginStorageType.tp_flags = Py_TPFLAGS_DEFAULT;
|
||||||
|
|
||||||
|
if (PyType_Ready(&PyPluginStorageType) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PyModule_AddObject(module, "PluginStorage", reinterpret_cast<PyObject*>(&PyPluginStorageType));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
#endif // PYPLUGINSTORAGE_H
|
||||||
@ -105,7 +105,7 @@ static PyObject * PyThingPairingInfo_finish(PyThingPairingInfo* self, PyObject*
|
|||||||
if (self->info) {
|
if (self->info) {
|
||||||
if (self->pyOAuthUrl) {
|
if (self->pyOAuthUrl) {
|
||||||
QString oAuthUrl = QString::fromUtf8(PyUnicode_AsUTF8AndSize(self->pyOAuthUrl, nullptr));
|
QString oAuthUrl = QString::fromUtf8(PyUnicode_AsUTF8AndSize(self->pyOAuthUrl, nullptr));
|
||||||
QMetaObject::invokeMethod(self->info, "setOAuthUrl", Qt::QueuedConnection, Q_ARG(QString, oAuthUrl));
|
QMetaObject::invokeMethod(self->info, "setOAuthUrl", Qt::QueuedConnection, Q_ARG(QUrl, oAuthUrl));
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
|
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "pythonintegrationplugin.h"
|
#include "pythonintegrationplugin.h"
|
||||||
#include "python/pynymeamodule.h"
|
#include "python/pynymeamodule.h"
|
||||||
#include "python/pystdouthandler.h"
|
#include "python/pystdouthandler.h"
|
||||||
|
#include "python/pypluginstorage.h"
|
||||||
|
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
@ -176,6 +177,14 @@ PyObject *PythonIntegrationPlugin::pyAutoThingDisappeared(PyObject *self, PyObje
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *PythonIntegrationPlugin::pyPluginStorage(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
Q_UNUSED(args)
|
||||||
|
PyObject *pluginStorage = s_plugins.key(self)->m_pyPluginStorage;
|
||||||
|
Py_INCREF(pluginStorage);
|
||||||
|
return pluginStorage;
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef plugin_methods[] =
|
static PyMethodDef plugin_methods[] =
|
||||||
{
|
{
|
||||||
{"configuration", PythonIntegrationPlugin::pyConfiguration, METH_VARARGS, "Get the plugin configuration."},
|
{"configuration", PythonIntegrationPlugin::pyConfiguration, METH_VARARGS, "Get the plugin configuration."},
|
||||||
@ -184,6 +193,7 @@ static PyMethodDef plugin_methods[] =
|
|||||||
{"myThings", PythonIntegrationPlugin::pyMyThings, METH_VARARGS, "Obtain a list of things owned by this plugin."},
|
{"myThings", PythonIntegrationPlugin::pyMyThings, METH_VARARGS, "Obtain a list of things owned by this plugin."},
|
||||||
{"autoThingsAppeared", PythonIntegrationPlugin::pyAutoThingsAppeared, METH_VARARGS, "Inform the system about auto setup things having appeared."},
|
{"autoThingsAppeared", PythonIntegrationPlugin::pyAutoThingsAppeared, METH_VARARGS, "Inform the system about auto setup things having appeared."},
|
||||||
{"autoThingDisappeared", PythonIntegrationPlugin::pyAutoThingDisappeared, METH_VARARGS, "Inform the system about auto setup things having disappeared."},
|
{"autoThingDisappeared", PythonIntegrationPlugin::pyAutoThingDisappeared, METH_VARARGS, "Inform the system about auto setup things having disappeared."},
|
||||||
|
{"pluginStorage", PythonIntegrationPlugin::pyPluginStorage, METH_VARARGS, "Obtain the plugin storage for this plugin."},
|
||||||
{nullptr, nullptr, 0, nullptr} // sentinel
|
{nullptr, nullptr, 0, nullptr} // sentinel
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -215,6 +225,7 @@ PythonIntegrationPlugin::~PythonIntegrationPlugin()
|
|||||||
|
|
||||||
s_plugins.take(this);
|
s_plugins.take(this);
|
||||||
Py_XDECREF(m_pluginModule);
|
Py_XDECREF(m_pluginModule);
|
||||||
|
Py_DECREF(m_pyPluginStorage);
|
||||||
Py_DECREF(m_nymeaModule);
|
Py_DECREF(m_nymeaModule);
|
||||||
|
|
||||||
Py_EndInterpreter(m_threadState);
|
Py_EndInterpreter(m_threadState);
|
||||||
@ -354,6 +365,11 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile)
|
|||||||
Py_DECREF(logger);
|
Py_DECREF(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args = Py_BuildValue("(s)", pluginId().toString().toUtf8().data());
|
||||||
|
m_pyPluginStorage = PyObject_CallObject((PyObject*)&PyPluginStorageType, args);
|
||||||
|
Py_DECREF(args);
|
||||||
|
Py_INCREF(m_pyPluginStorage);
|
||||||
|
|
||||||
// Export metadata ids into module
|
// Export metadata ids into module
|
||||||
exportIds();
|
exportIds();
|
||||||
|
|
||||||
|
|||||||
@ -45,6 +45,7 @@ public:
|
|||||||
static PyObject* pyMyThings(PyObject *self, PyObject* args);
|
static PyObject* pyMyThings(PyObject *self, PyObject* args);
|
||||||
static PyObject* pyAutoThingsAppeared(PyObject *self, PyObject* args);
|
static PyObject* pyAutoThingsAppeared(PyObject *self, PyObject* args);
|
||||||
static PyObject* pyAutoThingDisappeared(PyObject *self, PyObject* args);
|
static PyObject* pyAutoThingDisappeared(PyObject *self, PyObject* args);
|
||||||
|
static PyObject* pyPluginStorage(PyObject* self, PyObject* args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void exportIds();
|
void exportIds();
|
||||||
@ -89,6 +90,9 @@ private:
|
|||||||
// Need to keep a copy of plugin params and sync that in a thread-safe manner
|
// Need to keep a copy of plugin params and sync that in a thread-safe manner
|
||||||
ParamList m_pluginConfigCopy;
|
ParamList m_pluginConfigCopy;
|
||||||
|
|
||||||
|
// Keeping our own plugin storage for python
|
||||||
|
PyObject* m_pyPluginStorage = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PYTHONINTEGRATIONPLUGIN_H
|
#endif // PYTHONINTEGRATIONPLUGIN_H
|
||||||
|
|||||||
@ -127,7 +127,7 @@ void Translator::loadTranslator(IntegrationPlugin *plugin, const QLocale &locale
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!loaded && locale.name() != "en_US") {
|
if (!loaded && locale.name() != "en_US") {
|
||||||
qCWarning(dcTranslations()) << "* Could not load translation" << locale.name() << "for plugin" << plugin->pluginName() << "(" << pluginId << ")";
|
qCDebug(dcTranslations()) << "* Could not load translation" << locale.name() << "for plugin" << plugin->pluginName() << "(" << pluginId << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,7 @@ RESOURCES += $$top_srcdir/icons.qrc \
|
|||||||
HEADERS += nymeacore.h \
|
HEADERS += nymeacore.h \
|
||||||
integrations/apikeysprovidersloader.h \
|
integrations/apikeysprovidersloader.h \
|
||||||
integrations/plugininfocache.h \
|
integrations/plugininfocache.h \
|
||||||
|
integrations/python/pypluginstorage.h \
|
||||||
integrations/thingmanagerimplementation.h \
|
integrations/thingmanagerimplementation.h \
|
||||||
integrations/translator.h \
|
integrations/translator.h \
|
||||||
experiences/experiencemanager.h \
|
experiences/experiencemanager.h \
|
||||||
|
|||||||
@ -53,13 +53,13 @@ public:
|
|||||||
ThingId parentId() const;
|
ThingId parentId() const;
|
||||||
|
|
||||||
QUrl oAuthUrl() const;
|
QUrl oAuthUrl() const;
|
||||||
void setOAuthUrl(const QUrl &oAuthUrl);
|
|
||||||
|
|
||||||
Thing::ThingError status() const;
|
Thing::ThingError status() const;
|
||||||
QString displayMessage() const;
|
QString displayMessage() const;
|
||||||
QString translatedDisplayMessage(const QLocale &locale) const;
|
QString translatedDisplayMessage(const QLocale &locale) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void setOAuthUrl(const QUrl &oAuthUrl);
|
||||||
void finish(Thing::ThingError status, const QString &displayMessage = QString());
|
void finish(Thing::ThingError status, const QString &displayMessage = QString());
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
Reference in New Issue
Block a user