some more work

This commit is contained in:
Michael Zanetti 2020-06-25 12:23:33 +02:00
parent f97e5bf4d0
commit 3c47e59811
6 changed files with 84 additions and 26 deletions

View File

@ -10,6 +10,7 @@
#include "loggingcategories.h" #include "loggingcategories.h"
#include <QPointer> #include <QPointer>
#include <QThread>
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof" #pragma GCC diagnostic ignored "-Winvalid-offsetof"
@ -36,15 +37,37 @@ static PyObject *PyThing_getName(PyThing *self, void */*closure*/)
PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system."); PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system.");
return nullptr; return nullptr;
} }
// FIXME: Needs blocking queued connection QString name;
PyObject *ret = PyUnicode_FromString(self->thing->name().toUtf8().data()); // FIXME: Should not be a direct connection!
qWarning() << "name thread" << QThread::currentThread();
QMetaObject::invokeMethod(self->thing, "name", Qt::DirectConnection, Q_RETURN_ARG(QString, name));
PyObject *ret = PyUnicode_FromString(name.toUtf8().data());
Py_INCREF(ret); Py_INCREF(ret);
return ret; return ret;
} }
static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){ static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){
// FIXME: Needs queued connection QString name = QString(PyUnicode_AsUTF8(value));
self->thing->setName(QString(PyUnicode_AsUTF8(value))); QMetaObject::invokeMethod(self->thing, "setName", Qt::QueuedConnection, Q_ARG(QString, name));
return 0;
}
static PyObject *PyThing_getSettings(PyThing *self, void */*closure*/)
{
if (!self->thing) {
PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system.");
return nullptr;
}
qWarning() << "setting thread" << QThread::currentThread();
ParamList settings;
QMetaObject::invokeMethod(self->thing, "settings", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ParamList, settings));
PyObject *ret = PyParam_FromParamList(settings);
Py_INCREF(ret);
return ret;
}
static int PyThing_setSettings(PyThing */*self*/, PyObject */*value*/, void */*closure*/){
// self->thing->setName(QString(PyUnicode_AsUTF8(value)));
return 0; return 0;
} }
@ -77,6 +100,19 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *PyThing_settingChanged(PyThing *self, void */*closure*/)
{
if (!self->thing) {
PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system.");
return nullptr;
}
ParamList settings;
QMetaObject::invokeMethod(self->thing, "settings", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ParamList, settings));
PyObject *ret = PyParam_FromParamList(settings);
Py_INCREF(ret);
return ret;
}
static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args) static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args)
{ {
char *eventTypeIdStr = nullptr; char *eventTypeIdStr = nullptr;
@ -126,7 +162,9 @@ static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args)
} }
static PyGetSetDef PyThing_getseters[] = { static PyGetSetDef PyThing_getseters[] = {
{"name", (getter)PyThing_getName, (setter)PyThing_setName, "Thingname", nullptr}, {"name", (getter)PyThing_getName, (setter)PyThing_setName, "Thing name", nullptr},
{"settings", (getter)PyThing_getSettings, (setter)PyThing_setSettings, "Thing settings", nullptr},
{"settingChanged", (getter)PyThing_settingChanged, nullptr, "Signal for changed settings", nullptr},
{nullptr , nullptr, nullptr, nullptr, nullptr} /* Sentinel */ {nullptr , nullptr, nullptr, nullptr, nullptr} /* Sentinel */
}; };

View File

@ -27,8 +27,6 @@ static int PyThingActionInfo_init(PyThingActionInfo */*self*/, PyObject */*args*
static void PyThingActionInfo_dealloc(PyThingActionInfo * self) { static void PyThingActionInfo_dealloc(PyThingActionInfo * self) {
// FIXME: Why is this not called? Seems we're leaking...
Q_ASSERT(false);
Py_TYPE(self)->tp_free(self); Py_TYPE(self)->tp_free(self);
} }
@ -54,6 +52,7 @@ static PyObject * PyThingActionInfo_finish(PyThingActionInfo* self, PyObject* ar
static PyMemberDef PyThingActionInfo_members[] = { static PyMemberDef PyThingActionInfo_members[] = {
{"thing", T_OBJECT_EX, offsetof(PyThingActionInfo, pyThing), 0, "Thing this action is for"}, {"thing", T_OBJECT_EX, offsetof(PyThingActionInfo, pyThing), 0, "Thing this action is for"},
{"actionTypeId", T_OBJECT_EX, offsetof(PyThingActionInfo, pyActionTypeId), 0, "The action type id for this action"}, {"actionTypeId", T_OBJECT_EX, offsetof(PyThingActionInfo, pyActionTypeId), 0, "The action type id for this action"},
{"params", T_OBJECT_EX, offsetof(PyThingActionInfo, pyParams), 0, "The params for this action"},
{nullptr, 0, 0, 0, nullptr} /* Sentinel */ {nullptr, 0, 0, 0, nullptr} /* Sentinel */
}; };

View File

@ -129,7 +129,7 @@ void PythonIntegrationPlugin::initPython()
// We'll be using asyncio everywhere, so let's import it right away // We'll be using asyncio everywhere, so let's import it right away
s_asyncio = PyImport_ImportModule("asyncio"); s_asyncio = PyImport_ImportModule("asyncio");
// Need to release ths lock from the main thread before spawning new threads // Need to release the lock from the main thread before spawning new threads
s_mainThread = PyEval_SaveThread(); s_mainThread = PyEval_SaveThread();
} }
@ -150,6 +150,8 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile)
} }
m_metaData = PluginMetadata(jsonDoc.object()); m_metaData = PluginMetadata(jsonDoc.object());
qWarning() << "main thread" << QThread::currentThread();
PyGILState_STATE s = PyGILState_Ensure(); PyGILState_STATE s = PyGILState_Ensure();
@ -229,10 +231,13 @@ void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
PyGILState_Release(s); PyGILState_Release(s);
}); });
connect(info, &ThingSetupInfo::destroyed, this, [=](){ connect(info, &ThingSetupInfo::destroyed, this, [=](){
PyGILState_STATE s = PyGILState_Ensure(); PyEval_RestoreThread(s_mainThread);
// PyGILState_STATE s = PyGILState_Ensure();
pyInfo->info = nullptr; pyInfo->info = nullptr;
Py_DECREF(pyInfo); Py_DECREF(pyInfo);
PyGILState_Release(s); // PyGILState_Release(s);
s_mainThread = PyEval_SaveThread();
}); });
@ -262,7 +267,7 @@ void PythonIntegrationPlugin::executeAction(ThingActionInfo *info)
connect(info, &ThingActionInfo::destroyed, this, [=](){ connect(info, &ThingActionInfo::destroyed, this, [=](){
PyGILState_STATE s = PyGILState_Ensure(); PyGILState_STATE s = PyGILState_Ensure();
pyInfo->pyActionTypeId = nullptr; pyInfo->pyActionTypeId = nullptr;
Py_DECREF(pyInfo->pyActionTypeId); Py_XDECREF(pyInfo->pyActionTypeId);
pyInfo->info = nullptr; pyInfo->info = nullptr;
Py_DECREF(pyInfo); Py_DECREF(pyInfo);
PyGILState_Release(s); PyGILState_Release(s);
@ -435,7 +440,7 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje
dumpError(); dumpError();
PyObject *future = PyObject_CallFunctionObjArgs(pFunc, param, nullptr); PyObject *result = PyObject_CallFunctionObjArgs(pFunc, param, nullptr);
Py_XDECREF(pFunc); Py_XDECREF(pFunc);
@ -446,36 +451,51 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje
return; return;
} }
if (QByteArray(future->ob_type->tp_name) != "coroutine") { if (QByteArray(result->ob_type->tp_name) != "coroutine") {
Py_DECREF(result);
PyGILState_Release(s); PyGILState_Release(s);
return; return;
} }
// PyObject *coro = result;
// PyObject *get_running_loop = PyObject_GetAttrString(s_asyncio, "get_event_loop");
// PyObject *loop = PyObject_CallFunctionObjArgs(get_running_loop, nullptr);
// Py_DECREF(get_running_loop);
// PyObject *run_in_executor = PyObject_GetAttrString(loop, "run_in_executor");
// result = PyObject_CallFunctionObjArgs(run_in_executor, Py_None, coro);
// Py_DECREF(result);
// Py_DECREF(coro);
// Spawn a event loop for python // Spawn a event loop for python
PyObject *new_event_loop = PyObject_GetAttrString(s_asyncio, "new_event_loop"); PyObject *new_event_loop = PyObject_GetAttrString(s_asyncio, "new_event_loop");
PyObject *loop = PyObject_CallFunctionObjArgs(new_event_loop, nullptr); PyObject *loop = PyObject_CallFunctionObjArgs(new_event_loop, nullptr);
PyObject *run_coroutine_threadsafe = PyObject_GetAttrString(loop, "create_task"); Py_DECREF(new_event_loop);
PyObject *task = PyObject_CallFunctionObjArgs(run_coroutine_threadsafe, future, nullptr);
PyObject *create_task = PyObject_GetAttrString(loop, "create_task");
PyObject *task = PyObject_CallFunctionObjArgs(create_task, result, nullptr);
dumpError(); dumpError();
Py_DECREF(result);
PyObject *add_done_callback = PyObject_GetAttrString(task, "add_done_callback"); PyObject *add_done_callback = PyObject_GetAttrString(task, "add_done_callback");
dumpError(); dumpError();
PyObject *task_done = PyObject_GetAttrString(s_nymeaModule, "task_done"); PyObject *task_done = PyObject_GetAttrString(s_nymeaModule, "task_done");
PyObject *result = PyObject_CallFunctionObjArgs(add_done_callback, task_done, nullptr); result = PyObject_CallFunctionObjArgs(add_done_callback, task_done, nullptr);
dumpError(); dumpError();
PyObject *run_until_complete = PyObject_GetAttrString(loop, "run_until_complete"); PyObject *run_until_complete = PyObject_GetAttrString(loop, "run_until_complete");
QtConcurrent::run([=](){ QtConcurrent::run([=](){
qWarning() << "new thread for func" << function << QThread::currentThread();
PyGILState_STATE s = PyGILState_Ensure(); PyGILState_STATE s = PyGILState_Ensure();
PyObject_CallFunctionObjArgs(run_until_complete, task, nullptr); PyObject_CallFunctionObjArgs(run_until_complete, task, nullptr);
PyGILState_Release(s); PyGILState_Release(s);
}); });
Py_DECREF(new_event_loop);
Py_DECREF(loop); Py_DECREF(loop);
Py_DECREF(run_coroutine_threadsafe); Py_DECREF(create_task);
Py_DECREF(task); Py_DECREF(task);
Py_DECREF(add_done_callback); Py_DECREF(add_done_callback);
Py_DECREF(result); Py_DECREF(result);

View File

@ -865,7 +865,6 @@ JsonReply *DeviceHandler::ExecuteAction(const QVariantMap &params, const JsonCon
ThingActionInfo *info = NymeaCore::instance()->executeAction(action); ThingActionInfo *info = NymeaCore::instance()->executeAction(action);
connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){ connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){
qWarning() << "finished...";
QVariantMap data; QVariantMap data;
data.insert("deviceError", enumValueName(info->status()).replace("Thing", "Device")); data.insert("deviceError", enumValueName(info->status()).replace("Thing", "Device"));
if (!info->displayMessage().isEmpty()) { if (!info->displayMessage().isEmpty()) {

View File

@ -183,6 +183,7 @@ ThingClass Thing::thingClass() const
/*! Returns the name of this Thing. This is visible to the user. */ /*! Returns the name of this Thing. This is visible to the user. */
QString Thing::name() const QString Thing::name() const
{ {
qWarning() << "thing name called";
return m_name; return m_name;
} }
@ -233,6 +234,7 @@ void Thing::setParamValue(const ParamTypeId &paramTypeId, const QVariant &value)
ParamList Thing::settings() const ParamList Thing::settings() const
{ {
qWarning() << "thing settings called";
return m_settings; return m_settings;
} }

View File

@ -107,8 +107,8 @@ public:
ThingClass thingClass() const; ThingClass thingClass() const;
QString name() const; Q_INVOKABLE QString name() const;
void setName(const QString &name); Q_INVOKABLE void setName(const QString &name);
ParamList params() const; ParamList params() const;
bool hasParam(const ParamTypeId &paramTypeId) const; bool hasParam(const ParamTypeId &paramTypeId) const;
@ -117,12 +117,12 @@ public:
QVariant paramValue(const ParamTypeId &paramTypeId) const; QVariant paramValue(const ParamTypeId &paramTypeId) const;
void setParamValue(const ParamTypeId &paramName, const QVariant &value); void setParamValue(const ParamTypeId &paramName, const QVariant &value);
ParamList settings() const; Q_INVOKABLE ParamList settings() const;
bool hasSetting(const ParamTypeId &paramTypeId) const; Q_INVOKABLE bool hasSetting(const ParamTypeId &paramTypeId) const;
void setSettings(const ParamList &settings); Q_INVOKABLE void setSettings(const ParamList &settings);
QVariant setting(const ParamTypeId &paramTypeId) const; Q_INVOKABLE QVariant setting(const ParamTypeId &paramTypeId) const;
void setSettingValue(const ParamTypeId &paramTypeId, const QVariant &value); Q_INVOKABLE void setSettingValue(const ParamTypeId &paramTypeId, const QVariant &value);
States states() const; States states() const;
bool hasState(const StateTypeId &stateTypeId) const; bool hasState(const StateTypeId &stateTypeId) const;