some more work

pull/341/head
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 <QPointer>
#include <QThread>
#pragma GCC diagnostic push
#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.");
return nullptr;
}
// FIXME: Needs blocking queued connection
PyObject *ret = PyUnicode_FromString(self->thing->name().toUtf8().data());
QString name;
// 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);
return ret;
}
static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){
// FIXME: Needs queued connection
self->thing->setName(QString(PyUnicode_AsUTF8(value)));
QString name = 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;
}
@ -77,6 +100,19 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args)
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)
{
char *eventTypeIdStr = nullptr;
@ -126,7 +162,9 @@ static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args)
}
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 */
};

View File

@ -27,8 +27,6 @@ static int PyThingActionInfo_init(PyThingActionInfo */*self*/, PyObject */*args*
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);
}
@ -54,6 +52,7 @@ static PyObject * PyThingActionInfo_finish(PyThingActionInfo* self, PyObject* ar
static PyMemberDef PyThingActionInfo_members[] = {
{"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"},
{"params", T_OBJECT_EX, offsetof(PyThingActionInfo, pyParams), 0, "The params for this action"},
{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
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();
}
@ -150,6 +150,8 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile)
}
m_metaData = PluginMetadata(jsonDoc.object());
qWarning() << "main thread" << QThread::currentThread();
PyGILState_STATE s = PyGILState_Ensure();
@ -229,10 +231,13 @@ void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
PyGILState_Release(s);
});
connect(info, &ThingSetupInfo::destroyed, this, [=](){
PyGILState_STATE s = PyGILState_Ensure();
PyEval_RestoreThread(s_mainThread);
// PyGILState_STATE s = PyGILState_Ensure();
pyInfo->info = nullptr;
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, [=](){
PyGILState_STATE s = PyGILState_Ensure();
pyInfo->pyActionTypeId = nullptr;
Py_DECREF(pyInfo->pyActionTypeId);
Py_XDECREF(pyInfo->pyActionTypeId);
pyInfo->info = nullptr;
Py_DECREF(pyInfo);
PyGILState_Release(s);
@ -435,7 +440,7 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje
dumpError();
PyObject *future = PyObject_CallFunctionObjArgs(pFunc, param, nullptr);
PyObject *result = PyObject_CallFunctionObjArgs(pFunc, param, nullptr);
Py_XDECREF(pFunc);
@ -446,36 +451,51 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje
return;
}
if (QByteArray(future->ob_type->tp_name) != "coroutine") {
if (QByteArray(result->ob_type->tp_name) != "coroutine") {
Py_DECREF(result);
PyGILState_Release(s);
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
PyObject *new_event_loop = PyObject_GetAttrString(s_asyncio, "new_event_loop");
PyObject *loop = PyObject_CallFunctionObjArgs(new_event_loop, nullptr);
PyObject *run_coroutine_threadsafe = PyObject_GetAttrString(loop, "create_task");
PyObject *task = PyObject_CallFunctionObjArgs(run_coroutine_threadsafe, future, nullptr);
Py_DECREF(new_event_loop);
PyObject *create_task = PyObject_GetAttrString(loop, "create_task");
PyObject *task = PyObject_CallFunctionObjArgs(create_task, result, nullptr);
dumpError();
Py_DECREF(result);
PyObject *add_done_callback = PyObject_GetAttrString(task, "add_done_callback");
dumpError();
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();
PyObject *run_until_complete = PyObject_GetAttrString(loop, "run_until_complete");
QtConcurrent::run([=](){
qWarning() << "new thread for func" << function << QThread::currentThread();
PyGILState_STATE s = PyGILState_Ensure();
PyObject_CallFunctionObjArgs(run_until_complete, task, nullptr);
PyGILState_Release(s);
});
Py_DECREF(new_event_loop);
Py_DECREF(loop);
Py_DECREF(run_coroutine_threadsafe);
Py_DECREF(create_task);
Py_DECREF(task);
Py_DECREF(add_done_callback);
Py_DECREF(result);

View File

@ -865,7 +865,6 @@ JsonReply *DeviceHandler::ExecuteAction(const QVariantMap &params, const JsonCon
ThingActionInfo *info = NymeaCore::instance()->executeAction(action);
connect(info, &ThingActionInfo::finished, jsonReply, [info, jsonReply, locale](){
qWarning() << "finished...";
QVariantMap data;
data.insert("deviceError", enumValueName(info->status()).replace("Thing", "Device"));
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. */
QString Thing::name() const
{
qWarning() << "thing name called";
return m_name;
}
@ -233,6 +234,7 @@ void Thing::setParamValue(const ParamTypeId &paramTypeId, const QVariant &value)
ParamList Thing::settings() const
{
qWarning() << "thing settings called";
return m_settings;
}

View File

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