From dfbc1d8865c6f260f20e7881eb2846cfc846fb3a Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Fri, 29 Dec 2023 20:28:54 +0100 Subject: [PATCH] Server side entity script messages --- .../src/scripts/EntityScriptServer.cpp | 48 +++++++++---- .../src/scripts/EntityScriptServer.h | 27 ++++++++ .../src/EntityTreeRenderer.cpp | 16 +++++ .../src/EntityScriptServerLogClient.cpp | 58 +++++++++++++++- libraries/script-engine/src/ScriptEngines.h | 55 +++++++++++++++ libraries/script-engine/src/ScriptManager.cpp | 8 +-- libraries/script-engine/src/ScriptManager.h | 12 ++-- .../src/ScriptManagerScriptingInterface.cpp | 20 ++++-- .../src/ScriptManagerScriptingInterface.h | 67 ++++++------------- libraries/script-engine/src/ScriptMessage.cpp | 3 + libraries/script-engine/src/ScriptMessage.h | 13 +++- 11 files changed, 252 insertions(+), 75 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index b16e4561d6..59302d3696 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -44,16 +44,8 @@ using Mutex = std::mutex; using Lock = std::lock_guard; -static std::mutex logBufferMutex; -static std::string logBuffer; - void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { auto logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); - - if (!logMessage.isEmpty()) { - Lock lock(logBufferMutex); - logBuffer.append(logMessage.toStdString() + '\n'); - } } int EntityScriptServer::_entitiesScriptEngineCount = 0; @@ -217,10 +209,10 @@ void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer(); + QJsonDocument document; + document.setArray(buffer); + QString data(document.toJson()); for (auto uuid : _logListeners) { auto node = nodeList->nodeWithUUID(uuid); if (node && node->getActiveSocket()) { auto packet = NLPacketList::create(PacketType::EntityServerScriptLog, QByteArray(), true, true); - packet->write(buffer.data(), buffer.size()); + packet->write(data.toStdString().c_str(), data.size()); nodeList->sendPacketList(std::move(packet), *node); } } } +void EntityScriptServer::addLogEntry(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, ScriptMessage::Severity severity) { + ScriptMessage entry(message, fileName, lineNumber, entityID, ScriptMessage::ScriptType::TYPE_ENTITY_SCRIPT, severity); + Lock lock(_logBufferMutex); + _logBuffer.append(entry.toJson()); +} + void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode) { if (_entitiesScriptManager && _entityViewer.getTree() && !_shuttingDown) { @@ -469,6 +470,29 @@ void EntityScriptServer::resetEntitiesScriptEngine() { connect(newManager.get(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); connect(newManager.get(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); + // Make script engine messages available through ScriptDiscoveryService + connect(newManager.get(), &ScriptManager::infoEntityMessage, scriptEngines, &ScriptEngines::infoEntityMessage); + connect(newManager.get(), &ScriptManager::printedEntityMessage, scriptEngines, &ScriptEngines::printedEntityMessage); + connect(newManager.get(), &ScriptManager::errorEntityMessage, scriptEngines, &ScriptEngines::errorEntityMessage); + connect(newManager.get(), &ScriptManager::warningEntityMessage, scriptEngines, &ScriptEngines::warningEntityMessage); + + connect(newManager.get(), &ScriptManager::infoEntityMessage, + [this](const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID) { + addLogEntry(message, fileName, lineNumber, entityID, ScriptMessage::Severity::SEVERITY_INFO); + }); + connect(newManager.get(), &ScriptManager::printedEntityMessage, + [this](const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID) { + addLogEntry(message, fileName, lineNumber, entityID, ScriptMessage::Severity::SEVERITY_PRINT); + }); + connect(newManager.get(), &ScriptManager::errorEntityMessage, + [this](const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID) { + addLogEntry(message, fileName, lineNumber, entityID, ScriptMessage::Severity::SEVERITY_ERROR); + }); + connect(newManager.get(), &ScriptManager::warningEntityMessage, + [this](const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID) { + addLogEntry(message, fileName, lineNumber, entityID, ScriptMessage::Severity::SEVERITY_WARNING); + }); + connect(newManager.get(), &ScriptManager::update, this, [this] { _entityViewer.queryOctree(); _entityViewer.getTree()->preUpdate(); diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 3f15f5733c..2fba985ef4 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "../entities/EntityTreeHeadlessViewer.h" @@ -55,10 +57,32 @@ private slots: void handleSettings(); void updateEntityPPS(); + /** + * @brief Handles log subscribe/unsubscribe requests + * + * Clients can subscribe to logs by sending a script log packet. Entity Script Server keeps list of subscribers + * and sends them logs in JSON format. + */ + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + /** + * @brief Transmit logs + * + * This is called periodically through a timer to transmit logs from scripts. + */ + void pushLogs(); + /** + * @brief Adds log entry to the transmit buffer + * + * This is connected to entity script log events in the script manager and adds script log message to the buffer + * containing messages that will be sent to subscribed clients. + */ + + void addLogEntry(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, ScriptMessage::Severity severity); + void handleEntityScriptCallMethodPacket(QSharedPointer message, SharedNodePointer senderNode); @@ -85,6 +109,9 @@ private: EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; + QJsonArray _logBuffer; + std::mutex _logBufferMutex; + int _maxEntityPPS { DEFAULT_MAX_ENTITY_PPS }; int _entityPPSPerScript { DEFAULT_ENTITY_PPS_PER_SCRIPT }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4861bc6ecb..cdc31a3765 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -232,6 +232,14 @@ void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() { _persistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); DependencyManager::get()->runScriptInitializers(_persistentEntitiesScriptManager); + + // Make script engine messages available through ScriptDiscoveryService + auto scriptEngines = DependencyManager::get().data(); + connect(_persistentEntitiesScriptManager.get(), &ScriptManager::infoEntityMessage, scriptEngines, &ScriptEngines::infoEntityMessage); + connect(_persistentEntitiesScriptManager.get(), &ScriptManager::printedEntityMessage, scriptEngines, &ScriptEngines::printedEntityMessage); + connect(_persistentEntitiesScriptManager.get(), &ScriptManager::errorEntityMessage, scriptEngines, &ScriptEngines::errorEntityMessage); + connect(_persistentEntitiesScriptManager.get(), &ScriptManager::warningEntityMessage, scriptEngines, &ScriptEngines::warningEntityMessage); + _persistentEntitiesScriptManager->runInThread(); std::shared_ptr entitiesScriptEngineProvider = _persistentEntitiesScriptManager; auto entityScriptingInterface = DependencyManager::get(); @@ -255,6 +263,14 @@ void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() { _nonPersistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); DependencyManager::get()->runScriptInitializers(_nonPersistentEntitiesScriptManager); + + // Make script engine messages available through ScriptDiscoveryService + auto scriptEngines = DependencyManager::get().data(); + connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::infoEntityMessage, scriptEngines, &ScriptEngines::infoEntityMessage); + connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::printedEntityMessage, scriptEngines, &ScriptEngines::printedEntityMessage); + connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::errorEntityMessage, scriptEngines, &ScriptEngines::errorEntityMessage); + connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::warningEntityMessage, scriptEngines, &ScriptEngines::warningEntityMessage); + _nonPersistentEntitiesScriptManager->runInThread(); std::shared_ptr entitiesScriptEngineProvider = _nonPersistentEntitiesScriptManager; DependencyManager::get()->setNonPersistentEntitiesScriptEngine(entitiesScriptEngineProvider); diff --git a/libraries/entities/src/EntityScriptServerLogClient.cpp b/libraries/entities/src/EntityScriptServerLogClient.cpp index 5d7d4017cd..5c21f01776 100644 --- a/libraries/entities/src/EntityScriptServerLogClient.cpp +++ b/libraries/entities/src/EntityScriptServerLogClient.cpp @@ -9,7 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include "EntityScriptServerLogClient.h" +#include "ScriptMessage.h" +#include "ScriptEngines.h" EntityScriptServerLogClient::EntityScriptServerLogClient() { auto nodeList = DependencyManager::get(); @@ -62,7 +66,59 @@ void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) { } void EntityScriptServerLogClient::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { - emit receivedNewLogLines(QString::fromUtf8(message->readAll())); + QString messageText = QString::fromUtf8(message->readAll()); + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(messageText.toUtf8(), &error); + emit receivedNewLogLines(messageText); + if(document.isNull()) { + qWarning() << "EntityScriptServerLogClient::handleEntityServerScriptLogPacket: Cannot parse JSON: " << error.errorString() + << " Contents: " << messageText; + return; + } + // Iterate through contents and emit messages + if(!document.isArray()) { + qWarning() << "EntityScriptServerLogClient::handleEntityServerScriptLogPacket: JSON is not an array: " << messageText; + return; + } + + auto scriptEngines = DependencyManager::get().data(); + + auto array = document.array(); + for (int n = 0; n < array.size(); n++) { + if (!array[n].isObject()) { + qWarning() << "EntityScriptServerLogClient::handleEntityServerScriptLogPacket: message is not an object: " << messageText; + continue; + } + ScriptMessage scriptMessage; + if (!scriptMessage.fromJson(array[n].toObject())) { + qWarning() << "EntityScriptServerLogClient::handleEntityServerScriptLogPacket: message parsing failed: " << messageText; + continue; + } + switch (scriptMessage.getSeverity()) { + case ScriptMessage::Severity::SEVERITY_INFO: + emit scriptEngines->infoEntityMessage(scriptMessage.getMessage(), scriptMessage.getFileName(), + scriptMessage.getLineNumber(), scriptMessage.getEntityID(), true); + break; + + case ScriptMessage::Severity::SEVERITY_PRINT: + emit scriptEngines->printedEntityMessage(scriptMessage.getMessage(), scriptMessage.getFileName(), + scriptMessage.getLineNumber(), scriptMessage.getEntityID(), true); + break; + + case ScriptMessage::Severity::SEVERITY_WARNING: + emit scriptEngines->warningEntityMessage(scriptMessage.getMessage(), scriptMessage.getFileName(), + scriptMessage.getLineNumber(), scriptMessage.getEntityID(), true); + break; + + case ScriptMessage::Severity::SEVERITY_ERROR: + emit scriptEngines->errorEntityMessage(scriptMessage.getMessage(), scriptMessage.getFileName(), + scriptMessage.getLineNumber(), scriptMessage.getEntityID(), true); + break; + + default: + break; + } + } } void EntityScriptServerLogClient::nodeActivated(SharedNodePointer activatedNode) { diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 671789bd8e..d8d50a4c20 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -256,6 +256,57 @@ signals: */ void infoMessage(const QString& message, const QString& engineName); + /*@jsdoc + * Triggered when a client side entity script prints a message to the program log via {@link print}, {@link Script.print}, + * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or + * {@link console.timeEnd}. + * @function Script.printedMessage + * @param {string} message - The message. + * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. + * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. + * @param {Uuid} entityID - Entity ID. + * @param {boolean} isServerScript - true if entity script is server-side, false if it is client-side. + * @returns {Signal} + */ + void printedEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); + + /*@jsdoc + * Triggered when a client side entity script generates an error, {@link console.error} or {@link console.exception} is called, or + * {@link console.assert} is called and fails. + * @function Script.errorMessage + * @param {string} message - The error message. + * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. + * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. + * @param {Uuid} entityID - Entity ID. + * @param {boolean} isServerScript - true if entity script is server-side, false if it is client-side. + * @returns {Signal} + */ + void errorEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); + + /*@jsdoc + * Triggered when a client side entity script generates a warning or {@link console.warn} is called. + * @function Script.warningMessage + * @param {string} message - The warning message. + * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. + * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. + * @param {Uuid} entityID - Entity ID. + * @param {boolean} isServerScript - true if entity script is server-side, false if it is client-side. + * @returns {Signal} + */ + void warningEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); + + /*@jsdoc + * Triggered when a client side entity script generates an information message or {@link console.info} is called. + * @function Script.infoMessage + * @param {string} message - The information message. + * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. + * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. + * @param {Uuid} entityID - Entity ID. + * @param {boolean} isServerScript - true if entity script is server-side, false if it is client-side. + * @returns {Signal} + */ + void infoEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); + /*@jsdoc * @function ScriptDiscoveryService.errorLoadingScript * @param {string} url - URL. @@ -355,6 +406,10 @@ protected: bool _defaultScriptsLocationOverridden { false }; QString _debugScriptUrl; + // TODO: remove script managers when shutting them down + QSet _scriptManagersThatRequestedServerEntityMessages; + QMutex _serverEntityMessagesMutex; + // If this is set, defaultScripts.js will not be run if it is in the settings, // and this will be run instead. This script will not be persisted to settings. const QUrl _defaultScriptsOverride { }; diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index ccdc917f0b..0509978a74 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -584,7 +584,7 @@ void ScriptManager::scriptErrorMessage(const QString& message, const QString& fi qCCritical(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit errorMessage(message, getFilename()); if (!currentEntityIdentifier.isInvalidID()) { - emit errorEntityMessage(message, fileName, lineNumber, currentEntityIdentifier); + emit errorEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript()); } } @@ -592,7 +592,7 @@ void ScriptManager::scriptWarningMessage(const QString& message, const QString& qCWarning(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit warningMessage(message, getFilename()); if (!currentEntityIdentifier.isInvalidID()) { - emit warningEntityMessage(message, fileName, lineNumber, currentEntityIdentifier); + emit warningEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript()); } } @@ -600,7 +600,7 @@ void ScriptManager::scriptInfoMessage(const QString& message, const QString& fil qCInfo(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit infoMessage(message, getFilename()); if (!currentEntityIdentifier.isInvalidID()) { - emit infoEntityMessage(message, fileName, lineNumber, currentEntityIdentifier); + emit infoEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript()); } } @@ -608,7 +608,7 @@ void ScriptManager::scriptPrintedMessage(const QString& message, const QString& qCDebug(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit printedMessage(message, getFilename()); if (!currentEntityIdentifier.isInvalidID()) { - emit printedEntityMessage(message, fileName, lineNumber, currentEntityIdentifier); + emit printedEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript()); } } diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 0a25f9e2e3..623b51a43f 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -1336,8 +1336,9 @@ signals: * @param fileName Name of the file in which message was generated. * @param lineNumber Number of the line on which message was generated. * @param entityID + * @param isServerScript true if entity script is server-side, false if it is client-side. */ - void printedEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); + void printedEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); /** @@ -1347,8 +1348,9 @@ signals: * @param fileName Name of the file in which message was generated. * @param lineNumber Number of the line on which message was generated. * @param entityID + * @param isServerScript true if entity script is server-side, false if it is client-side. */ - void errorEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); + void errorEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); @@ -1359,8 +1361,9 @@ signals: * @param fileName Name of the file in which message was generated. * @param lineNumber Number of the line on which message was generated. * @param entityID + * @param isServerScript true if entity script is server-side, false if it is client-side. */ - void warningEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); + void warningEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); /** @@ -1370,8 +1373,9 @@ signals: * @param fileName Name of the file in which message was generated. * @param lineNumber Number of the line on which message was generated. * @param entityID + * @param isServerScript true if entity script is server-side, false if it is client-side. */ - void infoEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); + void infoEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID, bool isServerScript); /** diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp b/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp index 5ba59a26de..d41b53660d 100644 --- a/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp +++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp @@ -12,6 +12,7 @@ #include "ScriptManager.h" #include "ScriptManagerScriptingInterface.h" +#include "ScriptEngines.h" #include "ScriptEngine.h" #include @@ -35,10 +36,6 @@ connect(_manager, &ScriptManager::printedMessage, this, &ScriptManagerScriptingInterface::printedMessage); connect(_manager, &ScriptManager::errorMessage, this, &ScriptManagerScriptingInterface::errorMessage); connect(_manager, &ScriptManager::warningMessage, this, &ScriptManagerScriptingInterface::warningMessage); - connect(_manager, &ScriptManager::infoEntityMessage, this, &ScriptManagerScriptingInterface::infoEntityMessage); - connect(_manager, &ScriptManager::printedEntityMessage, this, &ScriptManagerScriptingInterface::printedEntityMessage); - connect(_manager, &ScriptManager::errorEntityMessage, this, &ScriptManagerScriptingInterface::errorEntityMessage); - connect(_manager, &ScriptManager::warningEntityMessage, this, &ScriptManagerScriptingInterface::warningEntityMessage); connect(_manager, &ScriptManager::infoMessage, this, &ScriptManagerScriptingInterface::infoMessage); connect(_manager, &ScriptManager::runningStateChanged, this, &ScriptManagerScriptingInterface::runningStateChanged); connect(_manager, &ScriptManager::clearDebugWindow, this, &ScriptManagerScriptingInterface::clearDebugWindow); @@ -92,3 +89,18 @@ void ScriptManagerScriptingInterface::startProfiling() { void ScriptManagerScriptingInterface::stopProfilingAndSave() { _manager->engine()->stopProfilingAndSave(); } + +void ScriptManagerScriptingInterface::requestServerEntityScriptMessages() { + if (_manager->isEntityServerScript() || _manager->isEntityServerScript() || _manager->isClientScript()) { + auto scriptEngines = DependencyManager::get().data(); + //TODO; + } +} + +void ScriptManagerScriptingInterface::removeServerEntityScriptMessagesRequest() { + if (_manager->isEntityServerScript() || _manager->isEntityServerScript() || _manager->isClientScript()) { + auto scriptEngines = DependencyManager::get().data(); + //TODO; + } +} + diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.h b/libraries/script-engine/src/ScriptManagerScriptingInterface.h index d25592d42e..13cacb07fb 100644 --- a/libraries/script-engine/src/ScriptManagerScriptingInterface.h +++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.h @@ -557,7 +557,25 @@ public: */ Q_INVOKABLE void stopProfilingAndSave(); -signals: + /*@jsdoc + * After calling this function current script engine will start receiving server-side entity script messages + * through signals such as errorEntityMessage. This function can be invoked both from client-side entity scripts + * and from interface scripts. + * @function Script.subscribeToServerEntityScriptMessages + */ + + Q_INVOKABLE void requestServerEntityScriptMessages(); + + /*@jsdoc + * Calling this function signalizes that current script doesn't require stop receiving server-side entity script messages + * through signals such as errorEntityMessage. This function can be invoked both from client-side entity scripts + * and from interface scripts. + * @function Script.unsubscribeFromServerEntityScriptMessages + */ + + Q_INVOKABLE void removeServerEntityScriptMessagesRequest(); + + signals: /*@jsdoc * @function Script.scriptLoaded @@ -644,53 +662,6 @@ signals: */ void infoMessage(const QString& message, const QString& scriptName); - /*@jsdoc - * Triggered when a client side entity script prints a message to the program log via {@link print}, {@link Script.print}, - * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or - * {@link console.timeEnd}. - * @function Script.printedMessage - * @param {string} message - The message. - * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. - * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. - * @param {Uuid} entityID - Entity ID. - * @returns {Signal} - */ - void printedEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); - - /*@jsdoc - * Triggered when a client side entity script generates an error, {@link console.error} or {@link console.exception} is called, or - * {@link console.assert} is called and fails. - * @function Script.errorMessage - * @param {string} message - The error message. - * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. - * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. - * @param {Uuid} entityID - Entity ID. - * @returns {Signal} - */ - void errorEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); - - /*@jsdoc - * Triggered when a client side entity script generates a warning or {@link console.warn} is called. - * @function Script.warningMessage - * @param {string} message - The warning message. - * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. - * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. - * @param {Uuid} entityID - Entity ID. - * @returns {Signal} - */ - void warningEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); - - /*@jsdoc - * Triggered when a client side entity script generates an information message or {@link console.info} is called. - * @function Script.infoMessage - * @param {string} message - The information message. - * @param {string} fileName - Name of the file in which message was generated. Empty string when no file name is available. - * @param {number} lineNumber - Number of the line on which message was generated. -1 if there line number is not available. - * @param {Uuid} entityID - Entity ID. - * @returns {Signal} - */ - void infoEntityMessage(const QString& message, const QString& fileName, int lineNumber, const EntityItemID& entityID); - /*@jsdoc * Triggered when the running state of the script changes, e.g., from running to stopping. * @function Script.runningStateChanged diff --git a/libraries/script-engine/src/ScriptMessage.cpp b/libraries/script-engine/src/ScriptMessage.cpp index cb920fa569..27ba05f31e 100644 --- a/libraries/script-engine/src/ScriptMessage.cpp +++ b/libraries/script-engine/src/ScriptMessage.cpp @@ -18,6 +18,7 @@ QJsonObject ScriptMessage::toJson() { object["message"] = _messageContent; object["lineNumber"] = _lineNumber; object["fileName"] = _fileName; + object["entityID"] = _entityID.toString(); object["type"] = static_cast(_scriptType); object["severity"] = static_cast(_severity); return object; @@ -27,6 +28,7 @@ bool ScriptMessage::fromJson(const QJsonObject &object) { if (!object["message"].isString() || !object["lineNumber"].isDouble() || !object["fileName"].isString() + || !object["entityID"].isString() || !object["type"].isDouble() || !object["severity"].isDouble()) { qDebug() << "ScriptMessage::fromJson failed to find required fields in JSON file"; @@ -35,6 +37,7 @@ bool ScriptMessage::fromJson(const QJsonObject &object) { _messageContent = object["message"].toString(); _lineNumber = object["lineNumber"].toInt(); _fileName = object["fileName"].toInt(); + _entityID = QUuid::fromString(object["entityID"].toString()); _scriptType = static_cast(object["type"].toInt()); _severity = static_cast(object["severity"].toInt()); } \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptMessage.h b/libraries/script-engine/src/ScriptMessage.h index a0a9f52615..6fa7892d08 100644 --- a/libraries/script-engine/src/ScriptMessage.h +++ b/libraries/script-engine/src/ScriptMessage.h @@ -18,6 +18,7 @@ #include #include +#include "EntityItemID.h" class ScriptMessage { public: @@ -35,16 +36,24 @@ public: }; ScriptMessage() {}; - ScriptMessage(QString messageContent, QString fileName, int lineNumber, ScriptType scriptType, Severity severity) - : _messageContent(messageContent), _fileName(fileName), _lineNumber(lineNumber), _scriptType(scriptType) {} + ScriptMessage(const QString &messageContent, const QString &fileName, int lineNumber, const EntityItemID& entityID, ScriptType scriptType, Severity severity) + : _messageContent(messageContent), _fileName(fileName), _lineNumber(lineNumber), _entityID(entityID), _scriptType(scriptType), _severity(severity) {} QJsonObject toJson(); bool fromJson(const QJsonObject &object); + QString getMessage() { return _messageContent; } + QString getFileName() { return _fileName; } + int getLineNumber() { return _lineNumber; } + ScriptType getScriptType() { return _scriptType; } + Severity getSeverity() { return _severity; } + EntityItemID getEntityID() { return _entityID; } + private: QString _messageContent; QString _fileName; int _lineNumber {-1}; + EntityItemID _entityID; ScriptType _scriptType {ScriptType::TYPE_NONE}; Severity _severity {Severity::SEVERITY_NONE}; };