mirror of https://github.com/nymea/nymea.git
Add scripts api namespace
parent
6ab6f8a80b
commit
3a9a0a0abc
|
|
@ -52,6 +52,7 @@
|
|||
#include "devicehandler.h"
|
||||
#include "actionhandler.h"
|
||||
#include "ruleshandler.h"
|
||||
#include "scriptshandler.h"
|
||||
#include "eventhandler.h"
|
||||
#include "logginghandler.h"
|
||||
#include "statehandler.h"
|
||||
|
|
|
|||
|
|
@ -72,10 +72,10 @@ public:
|
|||
void registerTransportInterface(TransportInterface *interface, bool authenticationRequired);
|
||||
void unregisterTransportInterface(TransportInterface *interface);
|
||||
|
||||
bool registerHandler(JsonHandler *handler) override;
|
||||
bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) override;
|
||||
|
||||
private:
|
||||
bool registerHandler(JsonHandler *handler);
|
||||
QHash<QString, JsonHandler *> handlers() const;
|
||||
|
||||
void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap(), const QString &deprecationWarning = QString());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 \
|
||||
experiences/experiencemanager.h \
|
||||
jsonrpc/jsonrpcserverimplementation.h \
|
||||
jsonrpc/scriptshandler.h \
|
||||
ruleengine/ruleengine.h \
|
||||
ruleengine/rule.h \
|
||||
ruleengine/stateevaluator.h \
|
||||
ruleengine/ruleaction.h \
|
||||
ruleengine/ruleactionparam.h \
|
||||
scriptengine/script.h \
|
||||
scriptengine/scriptaction.h \
|
||||
scriptengine/scriptengine.h \
|
||||
scriptengine/scriptevent.h \
|
||||
|
|
@ -98,11 +100,13 @@ SOURCES += nymeacore.cpp \
|
|||
devices/translator.cpp \
|
||||
experiences/experiencemanager.cpp \
|
||||
jsonrpc/jsonrpcserverimplementation.cpp \
|
||||
jsonrpc/scriptshandler.cpp \
|
||||
ruleengine/ruleengine.cpp \
|
||||
ruleengine/rule.cpp \
|
||||
ruleengine/stateevaluator.cpp \
|
||||
ruleengine/ruleaction.cpp \
|
||||
ruleengine/ruleactionparam.cpp \
|
||||
scriptengine/script.cpp \
|
||||
scriptengine/scriptaction.cpp \
|
||||
scriptengine/scriptengine.cpp \
|
||||
scriptengine/scriptevent.cpp \
|
||||
|
|
|
|||
|
|
@ -98,7 +98,9 @@
|
|||
#include "tagging/tagsstorage.h"
|
||||
#include "platform/platform.h"
|
||||
#include "experiences/experiencemanager.h"
|
||||
|
||||
#include "scriptengine/scriptengine.h"
|
||||
#include "jsonrpc/scriptshandler.h"
|
||||
|
||||
#include "devices/devicemanagerimplementation.h"
|
||||
#include "devices/device.h"
|
||||
|
|
@ -161,7 +163,9 @@ void NymeaCore::init() {
|
|||
qCDebug(dcApplication) << "Creating Rule Engine";
|
||||
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";
|
||||
m_tagsStorage = new TagsStorage(m_deviceManager, m_ruleEngine, this);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class UserManager;
|
|||
class Platform;
|
||||
class System;
|
||||
class ExperienceManager;
|
||||
class ScriptEngine;
|
||||
|
||||
class NymeaCore : public QObject
|
||||
{
|
||||
|
|
@ -125,6 +126,7 @@ private:
|
|||
ServerManager *m_serverManager;
|
||||
DeviceManagerImplementation *m_deviceManager;
|
||||
RuleEngine *m_ruleEngine;
|
||||
ScriptEngine *m_scriptEngine;
|
||||
LogEngine *m_logger;
|
||||
TimeManager *m_timeManager;
|
||||
CloudManager *m_cloudManager;
|
||||
|
|
|
|||
|
|
@ -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>());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 "scriptstate.h"
|
||||
|
||||
#include "nymeasettings.h"
|
||||
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlComponent>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "loggingcategories.h"
|
||||
|
||||
|
|
@ -18,18 +24,210 @@ ScriptEngine::ScriptEngine(DeviceManager *deviceManager, QObject *parent) : QObj
|
|||
qmlRegisterType<ScriptAction>("nymea", 1, 0, "Action");
|
||||
qmlRegisterType<ScriptState>("nymea", 1, 0, "State");
|
||||
|
||||
m_engine = new QQmlApplicationEngine(this);
|
||||
m_engine->setProperty("deviceManager", reinterpret_cast<quint64>(m_deviceManager));
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
QString fileName = "/home/micha/Develop/nymea/tests/script.qml";
|
||||
|
||||
QQmlApplicationEngine *engine = new QQmlApplicationEngine(this);
|
||||
engine->setProperty("deviceManager", reinterpret_cast<quint64>(m_deviceManager));
|
||||
// QString fileName = "/home/micha/Develop/nymea/tests/script.qml";
|
||||
|
||||
// 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";
|
||||
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 "devices/devicemanager.h"
|
||||
#include "script.h"
|
||||
|
||||
namespace nymeaserver {
|
||||
|
||||
|
|
@ -13,15 +14,44 @@ class ScriptEngine : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
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);
|
||||
|
||||
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:
|
||||
void loadScripts();
|
||||
bool loadScript(Script *script);
|
||||
void unloadScript(Script *script);
|
||||
|
||||
private:
|
||||
QString baseName(const QUuid &id);
|
||||
|
||||
private:
|
||||
DeviceManager *m_deviceManager = nullptr;
|
||||
QQmlEngine *m_engine = nullptr;
|
||||
|
||||
QHash<QUuid, Script*> m_scripts;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public:
|
|||
explicit JsonRPCServer() = default;
|
||||
virtual ~JsonRPCServer() = default;
|
||||
|
||||
virtual bool registerHandler(JsonHandler *handler) = 0;
|
||||
virtual bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) = 0;
|
||||
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue