Add scripts api namespace
This commit is contained in:
parent
6ab6f8a80b
commit
3a9a0a0abc
@ -52,6 +52,7 @@
|
|||||||
#include "devicehandler.h"
|
#include "devicehandler.h"
|
||||||
#include "actionhandler.h"
|
#include "actionhandler.h"
|
||||||
#include "ruleshandler.h"
|
#include "ruleshandler.h"
|
||||||
|
#include "scriptshandler.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "logginghandler.h"
|
#include "logginghandler.h"
|
||||||
#include "statehandler.h"
|
#include "statehandler.h"
|
||||||
|
|||||||
@ -72,10 +72,10 @@ public:
|
|||||||
void registerTransportInterface(TransportInterface *interface, bool authenticationRequired);
|
void registerTransportInterface(TransportInterface *interface, bool authenticationRequired);
|
||||||
void unregisterTransportInterface(TransportInterface *interface);
|
void unregisterTransportInterface(TransportInterface *interface);
|
||||||
|
|
||||||
|
bool registerHandler(JsonHandler *handler) override;
|
||||||
bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) override;
|
bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool registerHandler(JsonHandler *handler);
|
|
||||||
QHash<QString, JsonHandler *> handlers() const;
|
QHash<QString, JsonHandler *> handlers() const;
|
||||||
|
|
||||||
void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap(), const QString &deprecationWarning = QString());
|
void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap(), const QString &deprecationWarning = QString());
|
||||||
|
|||||||
106
libnymea-core/jsonrpc/scriptshandler.cpp
Normal file
106
libnymea-core/jsonrpc/scriptshandler.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include "scriptshandler.h"
|
||||||
|
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
|
#include "scriptengine/scriptengine.h"
|
||||||
|
|
||||||
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
ScriptsHandler::ScriptsHandler(ScriptEngine *scriptEngine, QObject *parent):
|
||||||
|
JsonHandler(parent),
|
||||||
|
m_engine(scriptEngine)
|
||||||
|
{
|
||||||
|
registerEnum<ScriptEngine::ScriptError>();
|
||||||
|
|
||||||
|
registerObject<Script, Scripts>();
|
||||||
|
|
||||||
|
QVariantMap params, returns;
|
||||||
|
QString description;
|
||||||
|
|
||||||
|
params.clear(); returns.clear();
|
||||||
|
description = "Get all script, that is, their names and properties, but no content.";
|
||||||
|
returns.insert("scripts", objectRef<Scripts>());
|
||||||
|
registerMethod("GetScripts", description, params, returns);
|
||||||
|
|
||||||
|
params.clear(); returns.clear();
|
||||||
|
description = "Add a script";
|
||||||
|
params.insert("name", enumValueName(String));
|
||||||
|
params.insert("content", enumValueName(String));
|
||||||
|
returns.insert("scriptError", enumRef<ScriptEngine::ScriptError>());
|
||||||
|
returns.insert("o:script", objectRef<Script>());
|
||||||
|
returns.insert("o:errors", enumValueName(StringList));
|
||||||
|
registerMethod("AddScript", description, params, returns);
|
||||||
|
|
||||||
|
params.clear(); returns.clear();
|
||||||
|
description = "Edit a script";
|
||||||
|
params.insert("id", enumValueName(Uuid));
|
||||||
|
params.insert("o:name", enumValueName(String));
|
||||||
|
params.insert("content", enumValueName(String));
|
||||||
|
returns.insert("scriptError", enumRef<ScriptEngine::ScriptError>());
|
||||||
|
returns.insert("o:errors", enumValueName(StringList));
|
||||||
|
registerMethod("EditScript", description, params, returns);
|
||||||
|
|
||||||
|
params.clear(); returns.clear();
|
||||||
|
description = "remove a script";
|
||||||
|
params.insert("id", enumValueName(Uuid));
|
||||||
|
returns.insert("scriptError", enumRef<ScriptEngine::ScriptError>());
|
||||||
|
registerMethod("RemoveScript", description, params, returns);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ScriptsHandler::name() const
|
||||||
|
{
|
||||||
|
return "Scripts";
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonReply *ScriptsHandler::GetScripts(const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
Q_UNUSED(params)
|
||||||
|
|
||||||
|
QVariantMap returns;
|
||||||
|
returns.insert("scripts", pack(m_engine->scripts()));
|
||||||
|
return createReply(returns);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonReply* ScriptsHandler::AddScript(const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
qWarning() << "Script:" << params.value("content").toString();
|
||||||
|
QVariantMap returns;
|
||||||
|
|
||||||
|
ScriptEngine::AddScriptReply scriptReply = m_engine->addScript(params.value("name").toString(), params.value("content").toByteArray());
|
||||||
|
|
||||||
|
returns.insert("scriptError", enumValueName(scriptReply.scriptError));
|
||||||
|
if (scriptReply.scriptError != ScriptEngine::ScriptErrorNoError) {
|
||||||
|
returns.insert("errors", scriptReply.errors);
|
||||||
|
} else {
|
||||||
|
returns.insert("script", pack(scriptReply.script));
|
||||||
|
}
|
||||||
|
return createReply(returns);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonReply *ScriptsHandler::EditScript(const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
QUuid scriptId = params.value("id").toUuid();
|
||||||
|
QByteArray content = params.value("content").toByteArray();
|
||||||
|
|
||||||
|
QVariantMap returns;
|
||||||
|
|
||||||
|
ScriptEngine::EditScriptReply reply = m_engine->editScript(scriptId, content);
|
||||||
|
returns.insert("scriptError", enumValueName(reply.scriptError));
|
||||||
|
if (reply.scriptError != ScriptEngine::ScriptErrorNoError) {
|
||||||
|
returns.insert("errors", reply.errors);
|
||||||
|
}
|
||||||
|
return createReply(returns);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonReply *ScriptsHandler::RemoveScript(const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
QUuid scriptId = params.value("id").toUuid();
|
||||||
|
ScriptEngine::ScriptError status = m_engine->removeScript(scriptId);
|
||||||
|
QVariantMap returns;
|
||||||
|
returns.insert("scriptError", enumValueName(status));
|
||||||
|
return createReply(returns);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
libnymea-core/jsonrpc/scriptshandler.h
Normal file
31
libnymea-core/jsonrpc/scriptshandler.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef SCRIPTSHANDLER_H
|
||||||
|
#define SCRIPTSHANDLER_H
|
||||||
|
|
||||||
|
#include "jsonrpc/jsonhandler.h"
|
||||||
|
|
||||||
|
#include "scriptengine/scriptengine.h"
|
||||||
|
|
||||||
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptsHandler : public JsonHandler
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ScriptsHandler(ScriptEngine *scriptEngine, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QString name() const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
JsonReply* GetScripts(const QVariantMap ¶ms);
|
||||||
|
JsonReply* AddScript(const QVariantMap ¶ms);
|
||||||
|
JsonReply* EditScript(const QVariantMap ¶ms);
|
||||||
|
JsonReply* RemoveScript(const QVariantMap ¶ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ScriptEngine *m_engine = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SCRIPTSHANDLER_H
|
||||||
@ -20,11 +20,13 @@ HEADERS += nymeacore.h \
|
|||||||
devices/translator.h \
|
devices/translator.h \
|
||||||
experiences/experiencemanager.h \
|
experiences/experiencemanager.h \
|
||||||
jsonrpc/jsonrpcserverimplementation.h \
|
jsonrpc/jsonrpcserverimplementation.h \
|
||||||
|
jsonrpc/scriptshandler.h \
|
||||||
ruleengine/ruleengine.h \
|
ruleengine/ruleengine.h \
|
||||||
ruleengine/rule.h \
|
ruleengine/rule.h \
|
||||||
ruleengine/stateevaluator.h \
|
ruleengine/stateevaluator.h \
|
||||||
ruleengine/ruleaction.h \
|
ruleengine/ruleaction.h \
|
||||||
ruleengine/ruleactionparam.h \
|
ruleengine/ruleactionparam.h \
|
||||||
|
scriptengine/script.h \
|
||||||
scriptengine/scriptaction.h \
|
scriptengine/scriptaction.h \
|
||||||
scriptengine/scriptengine.h \
|
scriptengine/scriptengine.h \
|
||||||
scriptengine/scriptevent.h \
|
scriptengine/scriptevent.h \
|
||||||
@ -98,11 +100,13 @@ SOURCES += nymeacore.cpp \
|
|||||||
devices/translator.cpp \
|
devices/translator.cpp \
|
||||||
experiences/experiencemanager.cpp \
|
experiences/experiencemanager.cpp \
|
||||||
jsonrpc/jsonrpcserverimplementation.cpp \
|
jsonrpc/jsonrpcserverimplementation.cpp \
|
||||||
|
jsonrpc/scriptshandler.cpp \
|
||||||
ruleengine/ruleengine.cpp \
|
ruleengine/ruleengine.cpp \
|
||||||
ruleengine/rule.cpp \
|
ruleengine/rule.cpp \
|
||||||
ruleengine/stateevaluator.cpp \
|
ruleengine/stateevaluator.cpp \
|
||||||
ruleengine/ruleaction.cpp \
|
ruleengine/ruleaction.cpp \
|
||||||
ruleengine/ruleactionparam.cpp \
|
ruleengine/ruleactionparam.cpp \
|
||||||
|
scriptengine/script.cpp \
|
||||||
scriptengine/scriptaction.cpp \
|
scriptengine/scriptaction.cpp \
|
||||||
scriptengine/scriptengine.cpp \
|
scriptengine/scriptengine.cpp \
|
||||||
scriptengine/scriptevent.cpp \
|
scriptengine/scriptevent.cpp \
|
||||||
|
|||||||
@ -98,7 +98,9 @@
|
|||||||
#include "tagging/tagsstorage.h"
|
#include "tagging/tagsstorage.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "experiences/experiencemanager.h"
|
#include "experiences/experiencemanager.h"
|
||||||
|
|
||||||
#include "scriptengine/scriptengine.h"
|
#include "scriptengine/scriptengine.h"
|
||||||
|
#include "jsonrpc/scriptshandler.h"
|
||||||
|
|
||||||
#include "devices/devicemanagerimplementation.h"
|
#include "devices/devicemanagerimplementation.h"
|
||||||
#include "devices/device.h"
|
#include "devices/device.h"
|
||||||
@ -161,7 +163,9 @@ void NymeaCore::init() {
|
|||||||
qCDebug(dcApplication) << "Creating Rule Engine";
|
qCDebug(dcApplication) << "Creating Rule Engine";
|
||||||
m_ruleEngine = new RuleEngine(this);
|
m_ruleEngine = new RuleEngine(this);
|
||||||
|
|
||||||
new ScriptEngine(m_deviceManager, this);
|
qCDebug(dcApplication()) << "Creating Script Engine";
|
||||||
|
m_scriptEngine = new ScriptEngine(m_deviceManager, this);
|
||||||
|
m_serverManager->jsonServer()->registerHandler(new ScriptsHandler(m_scriptEngine, m_scriptEngine));
|
||||||
|
|
||||||
qCDebug(dcApplication()) << "Creating Tags Storage";
|
qCDebug(dcApplication()) << "Creating Tags Storage";
|
||||||
m_tagsStorage = new TagsStorage(m_deviceManager, m_ruleEngine, this);
|
m_tagsStorage = new TagsStorage(m_deviceManager, m_ruleEngine, this);
|
||||||
|
|||||||
@ -55,6 +55,7 @@ class UserManager;
|
|||||||
class Platform;
|
class Platform;
|
||||||
class System;
|
class System;
|
||||||
class ExperienceManager;
|
class ExperienceManager;
|
||||||
|
class ScriptEngine;
|
||||||
|
|
||||||
class NymeaCore : public QObject
|
class NymeaCore : public QObject
|
||||||
{
|
{
|
||||||
@ -125,6 +126,7 @@ private:
|
|||||||
ServerManager *m_serverManager;
|
ServerManager *m_serverManager;
|
||||||
DeviceManagerImplementation *m_deviceManager;
|
DeviceManagerImplementation *m_deviceManager;
|
||||||
RuleEngine *m_ruleEngine;
|
RuleEngine *m_ruleEngine;
|
||||||
|
ScriptEngine *m_scriptEngine;
|
||||||
LogEngine *m_logger;
|
LogEngine *m_logger;
|
||||||
TimeManager *m_timeManager;
|
TimeManager *m_timeManager;
|
||||||
CloudManager *m_cloudManager;
|
CloudManager *m_cloudManager;
|
||||||
|
|||||||
51
libnymea-core/scriptengine/script.cpp
Normal file
51
libnymea-core/scriptengine/script.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "script.h"
|
||||||
|
|
||||||
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
Script::Script()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid Script::id() const
|
||||||
|
{
|
||||||
|
return m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Script::setId(const QUuid &id)
|
||||||
|
{
|
||||||
|
m_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Script::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Script::setName(const QString &name)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scripts::Scripts()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Scripts::Scripts(const QList<Script> &other):
|
||||||
|
QList<Script>(other)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Scripts::get(int index)
|
||||||
|
{
|
||||||
|
return QVariant::fromValue(at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scripts::put(const QVariant &value)
|
||||||
|
{
|
||||||
|
append(value.value<Script>());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
53
libnymea-core/scriptengine/script.h
Normal file
53
libnymea-core/scriptengine/script.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef SCRIPT_H
|
||||||
|
#define SCRIPT_H
|
||||||
|
|
||||||
|
#include <QMetaObject>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QQmlContext>
|
||||||
|
#include <QQmlComponent>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace nymeaserver {
|
||||||
|
|
||||||
|
class Script
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(QUuid id READ id)
|
||||||
|
Q_PROPERTY(QString name READ name WRITE setName)
|
||||||
|
public:
|
||||||
|
Script();
|
||||||
|
|
||||||
|
QUuid id() const;
|
||||||
|
void setId(const QUuid &id);
|
||||||
|
|
||||||
|
QString name() const;
|
||||||
|
void setName(const QString &name);
|
||||||
|
|
||||||
|
QStringList errors;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUuid m_id;
|
||||||
|
QString m_name;
|
||||||
|
|
||||||
|
friend class ScriptEngine;
|
||||||
|
QQmlContext *context = nullptr;
|
||||||
|
QQmlComponent *component = nullptr;
|
||||||
|
QObject *object = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Scripts: public QList<Script>
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(int count READ count)
|
||||||
|
public:
|
||||||
|
Scripts();
|
||||||
|
Scripts(const QList<Script> &other);
|
||||||
|
Q_INVOKABLE QVariant get(int index);
|
||||||
|
Q_INVOKABLE void put(const QVariant &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
Q_DECLARE_METATYPE(nymeaserver::Script)
|
||||||
|
Q_DECLARE_METATYPE(nymeaserver::Scripts)
|
||||||
|
|
||||||
|
#endif // SCRIPT_H
|
||||||
@ -5,7 +5,13 @@
|
|||||||
#include "scriptevent.h"
|
#include "scriptevent.h"
|
||||||
#include "scriptstate.h"
|
#include "scriptstate.h"
|
||||||
|
|
||||||
|
#include "nymeasettings.h"
|
||||||
|
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQmlContext>
|
||||||
|
#include <QQmlComponent>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
@ -18,18 +24,210 @@ ScriptEngine::ScriptEngine(DeviceManager *deviceManager, QObject *parent) : QObj
|
|||||||
qmlRegisterType<ScriptAction>("nymea", 1, 0, "Action");
|
qmlRegisterType<ScriptAction>("nymea", 1, 0, "Action");
|
||||||
qmlRegisterType<ScriptState>("nymea", 1, 0, "State");
|
qmlRegisterType<ScriptState>("nymea", 1, 0, "State");
|
||||||
|
|
||||||
|
m_engine = new QQmlApplicationEngine(this);
|
||||||
|
m_engine->setProperty("deviceManager", reinterpret_cast<quint64>(m_deviceManager));
|
||||||
|
|
||||||
|
|
||||||
loadScripts();
|
loadScripts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scripts ScriptEngine::scripts()
|
||||||
|
{
|
||||||
|
Scripts ret;
|
||||||
|
foreach (Script *script, m_scripts) {
|
||||||
|
ret.append(*script);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptEngine::AddScriptReply ScriptEngine::addScript(const QString &name, const QByteArray &content)
|
||||||
|
{
|
||||||
|
QUuid id = QUuid::createUuid();
|
||||||
|
QString fileName = baseName(id) + ".qml";
|
||||||
|
QString jsonFileName = baseName(id) + ".json";
|
||||||
|
|
||||||
|
AddScriptReply reply;
|
||||||
|
|
||||||
|
QFile jsonFile(jsonFileName);
|
||||||
|
if (!jsonFile.open(QFile::ReadWrite)) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Error opening script metadata" << jsonFileName;
|
||||||
|
reply.scriptError = ScriptErrorHardwareFailure;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
QVariantMap metadata;
|
||||||
|
metadata.insert("name", name);
|
||||||
|
jsonFile.write(QJsonDocument::fromVariant(metadata).toJson());
|
||||||
|
jsonFile.close();
|
||||||
|
|
||||||
|
QFile scriptFile(fileName);
|
||||||
|
if (!scriptFile.open(QFile::WriteOnly)) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Error opening script file:" << fileName;
|
||||||
|
reply.scriptError = ScriptErrorHardwareFailure;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 len = scriptFile.write(content);
|
||||||
|
if (len != content.length()) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Error writing script content";
|
||||||
|
reply.scriptError = ScriptErrorHardwareFailure;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
scriptFile.close();
|
||||||
|
|
||||||
|
Script *script = new Script();
|
||||||
|
script->setId(id);
|
||||||
|
script->setName(name);
|
||||||
|
bool loaded = loadScript(script);
|
||||||
|
if (!loaded) {
|
||||||
|
reply.scriptError = ScriptErrorInvalidScript;
|
||||||
|
reply.errors = script->errors;
|
||||||
|
delete script;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scripts.insert(script->id(), script);
|
||||||
|
|
||||||
|
reply.scriptError = ScriptErrorNoError;
|
||||||
|
reply.script = *m_scripts.value(id);
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptEngine::EditScriptReply ScriptEngine::editScript(const QUuid &id, const QByteArray &content)
|
||||||
|
{
|
||||||
|
QString scriptFileName = baseName(id) + ".qml";
|
||||||
|
QFile scriptFile(scriptFileName);
|
||||||
|
EditScriptReply reply;
|
||||||
|
|
||||||
|
if (!m_scripts.contains(id)) {
|
||||||
|
qCWarning(dcScriptEngine()) << "No script with id" << id;
|
||||||
|
reply.scriptError = ScriptErrorScriptNotFound;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
Script *script = m_scripts.value(id);
|
||||||
|
unloadScript(script);
|
||||||
|
|
||||||
|
// Deleted compiled qml file to make sure we're reloading the new one
|
||||||
|
QString compiledScriptFileName = baseName(id) + ".qmlc";
|
||||||
|
QFile::remove(compiledScriptFileName);
|
||||||
|
|
||||||
|
if (!scriptFile.open(QFile::ReadWrite | QFile::Truncate)) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Error opening script" << id;
|
||||||
|
reply.scriptError = ScriptErrorHardwareFailure;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray oldContent = scriptFile.readAll();
|
||||||
|
scriptFile.seek(0);
|
||||||
|
|
||||||
|
qint64 bytesWritten = scriptFile.write(content);
|
||||||
|
if (bytesWritten != content.length()) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Error writing script content";
|
||||||
|
reply.scriptError = ScriptErrorHardwareFailure;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loaded = loadScript(script);
|
||||||
|
if (!loaded) {
|
||||||
|
reply.scriptError = ScriptErrorInvalidScript;
|
||||||
|
reply.errors = script->errors;
|
||||||
|
|
||||||
|
// Restore old content
|
||||||
|
scriptFile.seek(0);
|
||||||
|
scriptFile.write(oldContent);
|
||||||
|
loadScript(script);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.scriptError = ScriptErrorNoError;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptEngine::ScriptError ScriptEngine::removeScript(const QUuid &id)
|
||||||
|
{
|
||||||
|
Script *script = m_scripts.take(id);
|
||||||
|
if (!script) {
|
||||||
|
return ScriptErrorScriptNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
unloadScript(script);
|
||||||
|
|
||||||
|
QString jsonFileName = baseName(id) + ".json";
|
||||||
|
QString scriptFileName = baseName(id) + ".qml";
|
||||||
|
QString compiledScriptFileName = baseName(id) + ".qmlc";
|
||||||
|
|
||||||
|
QFile::remove(scriptFileName);
|
||||||
|
QFile::remove(jsonFileName);
|
||||||
|
QFile::remove(compiledScriptFileName);
|
||||||
|
|
||||||
|
delete script;
|
||||||
|
return ScriptErrorNoError;
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptEngine::loadScripts()
|
void ScriptEngine::loadScripts()
|
||||||
{
|
{
|
||||||
QString fileName = "/home/micha/Develop/nymea/tests/script.qml";
|
|
||||||
|
|
||||||
QQmlApplicationEngine *engine = new QQmlApplicationEngine(this);
|
// QString fileName = "/home/micha/Develop/nymea/tests/script.qml";
|
||||||
engine->setProperty("deviceManager", reinterpret_cast<quint64>(m_deviceManager));
|
|
||||||
|
// loadScript(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptEngine::loadScript(Script *script)
|
||||||
|
{
|
||||||
|
QString fileName = baseName(script->id()) + ".qml";
|
||||||
|
QString jsonFileName = baseName(script->id()) + ".json";
|
||||||
|
|
||||||
|
QFile jsonFile(jsonFileName);
|
||||||
|
if (!jsonFile.open(QFile::ReadOnly)) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Failed to open script metadata";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonFile.readAll(), &error);
|
||||||
|
jsonFile.close();
|
||||||
|
|
||||||
|
if (error.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Failed to parse script metadata";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString name = jsonDoc.toVariant().toMap().value("name").toString();
|
||||||
|
|
||||||
qCWarning(dcScriptEngine()) << "Loading script";
|
qCWarning(dcScriptEngine()) << "Loading script";
|
||||||
engine->load(fileName);
|
|
||||||
|
script->component = new QQmlComponent(m_engine, QUrl::fromLocalFile(fileName), this);
|
||||||
|
script->context = new QQmlContext(m_engine, this);
|
||||||
|
script->object = script->component->create(script->context);
|
||||||
|
|
||||||
|
if (!script->object) {
|
||||||
|
qCWarning(dcScriptEngine()) << "Script failed to load:";
|
||||||
|
foreach (const QQmlError &error, script->component->errors()) {
|
||||||
|
qCWarning(dcScriptEngine()) << error.toString();
|
||||||
|
script->errors.append(QString("%1:%2: %3").arg(error.line()).arg(error.column()).arg(error.description()));
|
||||||
|
}
|
||||||
|
delete script->context;
|
||||||
|
delete script->component;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::unloadScript(Script *script)
|
||||||
|
{
|
||||||
|
delete script->object;
|
||||||
|
script->object = nullptr;
|
||||||
|
delete script->component;
|
||||||
|
script->component = nullptr;
|
||||||
|
delete script->context;
|
||||||
|
script->context = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ScriptEngine::baseName(const QUuid &id)
|
||||||
|
{
|
||||||
|
QString path = NymeaSettings::storagePath() + '/';
|
||||||
|
QString basename = id.toString().remove(QRegExp("[{}]"));
|
||||||
|
return path + basename;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
#include "devices/devicemanager.h"
|
#include "devices/devicemanager.h"
|
||||||
|
#include "script.h"
|
||||||
|
|
||||||
namespace nymeaserver {
|
namespace nymeaserver {
|
||||||
|
|
||||||
@ -13,15 +14,44 @@ class ScriptEngine : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum ScriptError {
|
||||||
|
ScriptErrorNoError,
|
||||||
|
ScriptErrorScriptNotFound,
|
||||||
|
ScriptErrorInvalidScript,
|
||||||
|
ScriptErrorHardwareFailure
|
||||||
|
};
|
||||||
|
Q_ENUM(ScriptError)
|
||||||
|
|
||||||
|
struct AddScriptReply {
|
||||||
|
ScriptError scriptError;
|
||||||
|
QStringList errors;
|
||||||
|
Script script;
|
||||||
|
};
|
||||||
|
struct EditScriptReply {
|
||||||
|
ScriptError scriptError;
|
||||||
|
QStringList errors;
|
||||||
|
};
|
||||||
|
|
||||||
explicit ScriptEngine(DeviceManager *deviceManager, QObject *parent = nullptr);
|
explicit ScriptEngine(DeviceManager *deviceManager, QObject *parent = nullptr);
|
||||||
|
|
||||||
signals:
|
Scripts scripts();
|
||||||
|
AddScriptReply addScript(const QString &name, const QByteArray &content);
|
||||||
|
EditScriptReply editScript(const QUuid &id, const QByteArray &content);
|
||||||
|
ScriptError removeScript(const QUuid &id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadScripts();
|
void loadScripts();
|
||||||
|
bool loadScript(Script *script);
|
||||||
|
void unloadScript(Script *script);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString baseName(const QUuid &id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeviceManager *m_deviceManager = nullptr;
|
DeviceManager *m_deviceManager = nullptr;
|
||||||
|
QQmlEngine *m_engine = nullptr;
|
||||||
|
|
||||||
|
QHash<QUuid, Script*> m_scripts;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public:
|
|||||||
explicit JsonRPCServer() = default;
|
explicit JsonRPCServer() = default;
|
||||||
virtual ~JsonRPCServer() = default;
|
virtual ~JsonRPCServer() = default;
|
||||||
|
|
||||||
|
virtual bool registerHandler(JsonHandler *handler) = 0;
|
||||||
virtual bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) = 0;
|
virtual bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user