mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 03:32:42 +02:00
Merge pull request #673 from overte-org/feature/entity_script_logging
Entity script logging for script editor
This commit is contained in:
commit
1fd3f80210
22 changed files with 747 additions and 65 deletions
|
@ -44,16 +44,8 @@
|
|||
using Mutex = std::mutex;
|
||||
using Lock = std::lock_guard<Mutex>;
|
||||
|
||||
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<Receiv
|
|||
}
|
||||
|
||||
void EntityScriptServer::pushLogs() {
|
||||
std::string buffer;
|
||||
QJsonArray buffer;
|
||||
{
|
||||
Lock lock(logBufferMutex);
|
||||
std::swap(logBuffer, buffer);
|
||||
Lock lock(_logBufferMutex);
|
||||
std::swap(_logBuffer, buffer);
|
||||
}
|
||||
|
||||
if (buffer.empty()) {
|
||||
|
@ -231,16 +223,27 @@ void EntityScriptServer::pushLogs() {
|
|||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QJsonDocument document;
|
||||
document.setArray(buffer);
|
||||
QString data(document.toJson());
|
||||
std::string string = data.toStdString();
|
||||
auto cstring = string.c_str();
|
||||
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(cstring, strlen(cstring));
|
||||
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> receivedMessage, SharedNodePointer senderNode) {
|
||||
|
||||
if (_entitiesScriptManager && _entityViewer.getTree() && !_shuttingDown) {
|
||||
|
@ -469,6 +472,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();
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <SimpleEntitySimulation.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <ScriptManager.h>
|
||||
#include <ScriptMessage.h>
|
||||
#include <QJsonArray>
|
||||
|
||||
#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<ReceivedMessage> 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<ReceivedMessage> 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 };
|
||||
|
||||
|
|
|
@ -902,7 +902,12 @@ bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted
|
|||
DependencyManager::set<CompositorHelper>();
|
||||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||
DependencyManager::set<EntityScriptClient>();
|
||||
|
||||
DependencyManager::set<EntityScriptServerLogClient>();
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
auto entityScriptServerLog = DependencyManager::get<EntityScriptServerLogClient>();
|
||||
QObject::connect(scriptEngines.data(), &ScriptEngines::requestingEntityScriptServerLog, entityScriptServerLog.data(), &EntityScriptServerLogClient::requestMessagesForScriptEngines);
|
||||
|
||||
DependencyManager::set<GooglePolyScriptingInterface>();
|
||||
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
|
||||
DependencyManager::set<AvatarBookmarks>();
|
||||
|
|
|
@ -232,6 +232,14 @@ void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() {
|
|||
_persistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
||||
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_persistentEntitiesScriptManager);
|
||||
|
||||
// Make script engine messages available through ScriptDiscoveryService
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().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> entitiesScriptEngineProvider = _persistentEntitiesScriptManager;
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
@ -255,6 +263,14 @@ void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() {
|
|||
_nonPersistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
||||
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_nonPersistentEntitiesScriptManager);
|
||||
|
||||
// Make script engine messages available through ScriptDiscoveryService
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().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> entitiesScriptEngineProvider = _nonPersistentEntitiesScriptManager;
|
||||
DependencyManager::get<EntityScriptingInterface>()->setNonPersistentEntitiesScriptEngine(entitiesScriptEngineProvider);
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include "EntityScriptServerLogClient.h"
|
||||
#include "ScriptMessage.h"
|
||||
#include "ScriptEngines.h"
|
||||
|
||||
EntityScriptServerLogClient::EntityScriptServerLogClient() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -35,9 +39,9 @@ void EntityScriptServerLogClient::disconnectNotify(const QMetaMethod& signal) {
|
|||
|
||||
void EntityScriptServerLogClient::connectionsChanged() {
|
||||
auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString)));
|
||||
if (!_subscribed && numReceivers > 0) {
|
||||
if (!_subscribed && (numReceivers > 0 || _areMessagesRequestedByScripts)) {
|
||||
enableToEntityServerScriptLog(DependencyManager::get<NodeList>()->getThisNodeCanRez());
|
||||
} else if (_subscribed && numReceivers == 0) {
|
||||
} else if (_subscribed && (numReceivers == 0 && !_areMessagesRequestedByScripts)) {
|
||||
enableToEntityServerScriptLog(false);
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +66,59 @@ void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) {
|
|||
}
|
||||
|
||||
void EntityScriptServerLogClient::handleEntityServerScriptLogPacket(QSharedPointer<ReceivedMessage> 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<ScriptEngines>().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) {
|
||||
|
@ -84,3 +140,8 @@ void EntityScriptServerLogClient::canRezChanged(bool canRez) {
|
|||
enableToEntityServerScriptLog(canRez);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityScriptServerLogClient::requestMessagesForScriptEngines(bool areMessagesRequested) {
|
||||
_areMessagesRequestedByScripts = areMessagesRequested;
|
||||
connectionsChanged();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,12 @@ class EntityScriptServerLogClient : public QObject, public Dependency {
|
|||
public:
|
||||
EntityScriptServerLogClient();
|
||||
|
||||
/**
|
||||
* @brief This is called by ScriptEngines when scripts need access to entity server script messages and when access
|
||||
* is not needed anymore.
|
||||
*/
|
||||
void requestMessagesForScriptEngines(bool areMessagesRequested);
|
||||
|
||||
signals:
|
||||
|
||||
/*@jsdoc
|
||||
|
@ -66,7 +72,10 @@ private slots:
|
|||
void connectionsChanged();
|
||||
|
||||
private:
|
||||
std::atomic<bool> _areMessagesRequestedByScripts {false};
|
||||
bool _subscribed { false };
|
||||
|
||||
friend class ScriptEngines;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityScriptServerLogClient_h
|
||||
|
|
|
@ -34,7 +34,7 @@ QList<QString> ConsoleScriptingInterface::_groupDetails = QList<QString>();
|
|||
|
||||
ScriptValue ConsoleScriptingInterface::info(ScriptContext* context, ScriptEngine* engine) {
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptInfoMessage(appendArguments(context));
|
||||
scriptManager->scriptInfoMessage(appendArguments(context), context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
return engine->nullValue();
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ ScriptValue ConsoleScriptingInterface::log(ScriptContext* context, ScriptEngine*
|
|||
QString message = appendArguments(context);
|
||||
if (_groupDetails.count() == 0) {
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptPrintedMessage(message);
|
||||
scriptManager->scriptPrintedMessage(message, context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
} else {
|
||||
logGroupMessage(message, engine);
|
||||
|
@ -53,28 +53,28 @@ ScriptValue ConsoleScriptingInterface::log(ScriptContext* context, ScriptEngine*
|
|||
|
||||
ScriptValue ConsoleScriptingInterface::debug(ScriptContext* context, ScriptEngine* engine) {
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptPrintedMessage(appendArguments(context));
|
||||
scriptManager->scriptPrintedMessage(appendArguments(context), context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
return engine->nullValue();
|
||||
}
|
||||
|
||||
ScriptValue ConsoleScriptingInterface::warn(ScriptContext* context, ScriptEngine* engine) {
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptWarningMessage(appendArguments(context));
|
||||
scriptManager->scriptWarningMessage(appendArguments(context), context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
return engine->nullValue();
|
||||
}
|
||||
|
||||
ScriptValue ConsoleScriptingInterface::error(ScriptContext* context, ScriptEngine* engine) {
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptErrorMessage(appendArguments(context));
|
||||
scriptManager->scriptErrorMessage(appendArguments(context), context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
return engine->nullValue();
|
||||
}
|
||||
|
||||
ScriptValue ConsoleScriptingInterface::exception(ScriptContext* context, ScriptEngine* engine) {
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptErrorMessage(appendArguments(context));
|
||||
scriptManager->scriptErrorMessage(appendArguments(context), context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
return engine->nullValue();
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ void ConsoleScriptingInterface::time(QString labelName) {
|
|||
QString message = QString("%1: Timer started").arg(labelName);
|
||||
Q_ASSERT(engine);
|
||||
if (ScriptManager* scriptManager = engine()->manager()) {
|
||||
scriptManager->scriptPrintedMessage(message);
|
||||
scriptManager->scriptPrintedMessage(message, context()->currentFileName(), context()->currentLineNumber());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,13 +92,13 @@ void ConsoleScriptingInterface::timeEnd(QString labelName) {
|
|||
Q_ASSERT(engine);
|
||||
if (ScriptManager* scriptManager = engine()->manager()) {
|
||||
if (!_timerDetails.contains(labelName)) {
|
||||
scriptManager->scriptErrorMessage("No such label found " + labelName);
|
||||
scriptManager->scriptErrorMessage("No such label found " + labelName, context()->currentFileName(), context()->currentLineNumber());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_timerDetails.value(labelName).isNull()) {
|
||||
_timerDetails.remove(labelName);
|
||||
scriptManager->scriptErrorMessage("Invalid start time for " + labelName);
|
||||
scriptManager->scriptErrorMessage("Invalid start time for " + labelName, context()->currentFileName(), context()->currentLineNumber());
|
||||
return;
|
||||
}
|
||||
QDateTime _startTime = _timerDetails.value(labelName);
|
||||
|
@ -108,7 +108,7 @@ void ConsoleScriptingInterface::timeEnd(QString labelName) {
|
|||
QString message = QString("%1: %2ms").arg(labelName).arg(QString::number(diffInMS));
|
||||
_timerDetails.remove(labelName);
|
||||
|
||||
scriptManager->scriptPrintedMessage(message);
|
||||
scriptManager->scriptPrintedMessage(message, context()->currentFileName(), context()->currentLineNumber());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ ScriptValue ConsoleScriptingInterface::assertion(ScriptContext* context, ScriptE
|
|||
assertionResult = QString("Assertion failed : %1").arg(message);
|
||||
}
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptErrorMessage(assertionResult);
|
||||
scriptManager->scriptErrorMessage(assertionResult, context->currentFileName(), context->currentLineNumber());
|
||||
}
|
||||
}
|
||||
return engine->nullValue();
|
||||
|
@ -143,7 +143,7 @@ void ConsoleScriptingInterface::trace() {
|
|||
if (ScriptManager* scriptManager = scriptEngine->manager()) {
|
||||
scriptManager->scriptPrintedMessage
|
||||
(QString(STACK_TRACE_FORMAT).arg(LINE_SEPARATOR,
|
||||
scriptEngine->currentContext()->backtrace().join(LINE_SEPARATOR)));
|
||||
scriptEngine->currentContext()->backtrace().join(LINE_SEPARATOR)), context()->currentFileName(), context()->currentLineNumber());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,6 @@ void ConsoleScriptingInterface::logGroupMessage(QString message, ScriptEngine* e
|
|||
}
|
||||
logMessage.append(message);
|
||||
if (ScriptManager* scriptManager = engine->manager()) {
|
||||
scriptManager->scriptPrintedMessage(logMessage);
|
||||
scriptManager->scriptPrintedMessage(logMessage, context()->currentFileName(), context()->currentLineNumber());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,13 @@ public:
|
|||
virtual int argumentCount() const = 0;
|
||||
virtual ScriptValue argument(int index) const = 0;
|
||||
virtual QStringList backtrace() const = 0;
|
||||
|
||||
// Name of the file in which message was generated. Empty string when no file name is available.
|
||||
virtual int currentLineNumber() const = 0;
|
||||
|
||||
// Number of the line on which message was generated. -1 if there line number is not available.
|
||||
virtual QString currentFileName() const = 0;
|
||||
|
||||
virtual ScriptValue callee() const = 0;
|
||||
virtual ScriptEnginePointer engine() const = 0;
|
||||
virtual ScriptFunctionContextPointer functionContext() const = 0;
|
||||
|
|
|
@ -158,8 +158,69 @@ void ScriptEngines::removeScriptEngine(ScriptManagerPointer manager) {
|
|||
QMutexLocker locker(&_allScriptsMutex);
|
||||
_allKnownScriptManagers.remove(manager);
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(_subscriptionsToEntityScriptMessagesMutex);
|
||||
_managersSubscribedToEntityScriptMessages.remove(manager.get());
|
||||
_entitiesSubscribedToEntityScriptMessages.remove(manager.get());
|
||||
}
|
||||
|
||||
void ScriptEngines::requestServerEntityScriptMessages(ScriptManager *manager) {
|
||||
std::lock_guard<std::mutex> lock(_subscriptionsToEntityScriptMessagesMutex);
|
||||
if (!_managersSubscribedToEntityScriptMessages.contains(manager)) {
|
||||
_managersSubscribedToEntityScriptMessages.insert(manager);
|
||||
// Emit a signal to inform EntityScriptServerLogClient about subscription request
|
||||
emit requestingEntityScriptServerLog(true);
|
||||
qDebug() << "ScriptEngines::requestServerEntityScriptMessages";
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngines::requestServerEntityScriptMessages(ScriptManager *manager, const QUuid& entityID) {
|
||||
std::lock_guard<std::mutex> lock(_subscriptionsToEntityScriptMessagesMutex);
|
||||
if (!_entitiesSubscribedToEntityScriptMessages.contains(manager)) {
|
||||
_entitiesSubscribedToEntityScriptMessages.insert(manager,QSet<QUuid>());
|
||||
}
|
||||
if (!_entitiesSubscribedToEntityScriptMessages[manager].contains(entityID)) {
|
||||
_entitiesSubscribedToEntityScriptMessages[manager].insert(entityID);
|
||||
// Emit a signal to inform EntityScriptServerLogClient about subscription request
|
||||
emit requestingEntityScriptServerLog(true);
|
||||
qDebug() << "ScriptEngines::requestServerEntityScriptMessages uuid";
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngines::removeServerEntityScriptMessagesRequest(ScriptManager *manager) {
|
||||
std::lock_guard<std::mutex> lock(_subscriptionsToEntityScriptMessagesMutex);
|
||||
if (_managersSubscribedToEntityScriptMessages.contains(manager)) {
|
||||
_managersSubscribedToEntityScriptMessages.remove(manager);
|
||||
}
|
||||
if (_entitiesSubscribedToEntityScriptMessages.isEmpty()
|
||||
&& _managersSubscribedToEntityScriptMessages.isEmpty()) {
|
||||
// No managers requiring entity script server messages remain, so we inform EntityScriptServerLogClient about this
|
||||
// Emit a signal to inform EntityScriptServerLogClient about subscription request
|
||||
emit requestingEntityScriptServerLog(false);
|
||||
qDebug() << "ScriptEngines::removeServerEntityScriptMessagesRequest";
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngines::removeServerEntityScriptMessagesRequest(ScriptManager *manager, const QUuid& entityID) {
|
||||
std::lock_guard<std::mutex> lock(_subscriptionsToEntityScriptMessagesMutex);
|
||||
if (!_entitiesSubscribedToEntityScriptMessages.contains(manager)) {
|
||||
return;
|
||||
}
|
||||
if (_entitiesSubscribedToEntityScriptMessages[manager].contains(entityID)) {
|
||||
_entitiesSubscribedToEntityScriptMessages[manager].remove(entityID);
|
||||
}
|
||||
if (_entitiesSubscribedToEntityScriptMessages[manager].isEmpty()) {
|
||||
_entitiesSubscribedToEntityScriptMessages.remove(manager);
|
||||
}
|
||||
if (_entitiesSubscribedToEntityScriptMessages.isEmpty()
|
||||
&& _managersSubscribedToEntityScriptMessages.isEmpty()) {
|
||||
// No managers requiring entity script server messages remain, so we inform EntityScriptServerLogClient about this
|
||||
// Emit a signal to inform EntityScriptServerLogClient about subscription request
|
||||
emit requestingEntityScriptServerLog(false);
|
||||
qDebug() << "ScriptEngines::removeServerEntityScriptMessagesRequest uuid";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScriptEngines::shutdownScripting() {
|
||||
_isStopped = true;
|
||||
QMutexLocker locker(&_allScriptsMutex);
|
||||
|
|
|
@ -186,6 +186,13 @@ public:
|
|||
|
||||
void removeScriptEngine(ScriptManagerPointer);
|
||||
|
||||
// Called by ScriptManagerScriptingInterface
|
||||
void requestServerEntityScriptMessages(ScriptManager *manager);
|
||||
void requestServerEntityScriptMessages(ScriptManager *manager, const QUuid& entityID);
|
||||
|
||||
void removeServerEntityScriptMessagesRequest(ScriptManager *manager);
|
||||
void removeServerEntityScriptMessagesRequest(ScriptManager *manager, const QUuid& entityID);
|
||||
|
||||
ScriptGatekeeper scriptGatekeeper;
|
||||
|
||||
signals:
|
||||
|
@ -251,11 +258,62 @@ signals:
|
|||
* Triggered when any script generates an information message or {@link console.info} is called.
|
||||
* @function ScriptDiscoveryService.infoMessage
|
||||
* @param {string} message - The information message.
|
||||
* @param {string} scriptName - The name of the script that generated the informaton message.
|
||||
* @param {string} scriptName - The name of the script that generated the information message.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
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.
|
||||
|
@ -272,6 +330,12 @@ signals:
|
|||
*/
|
||||
void clearDebugWindow();
|
||||
|
||||
/**
|
||||
* @brief Fires when script engines need entity server script messages (areMessagesRequested == true)
|
||||
* and when messages are not needed anymore (areMessagesRequested == false).
|
||||
*/
|
||||
void requestingEntityScriptServerLog(bool areMessagesRequested);
|
||||
|
||||
public slots:
|
||||
|
||||
/*@jsdoc
|
||||
|
@ -355,6 +419,12 @@ protected:
|
|||
bool _defaultScriptsLocationOverridden { false };
|
||||
QString _debugScriptUrl;
|
||||
|
||||
// For subscriptions to server entity script messages
|
||||
std::mutex _subscriptionsToEntityScriptMessagesMutex;
|
||||
QSet<ScriptManager*> _managersSubscribedToEntityScriptMessages;
|
||||
// Since multiple entity scripts run in the same script engine, there's a need to track subscriptions per entity
|
||||
QHash<ScriptManager*, QSet<QUuid>> _entitiesSubscribedToEntityScriptMessages;
|
||||
|
||||
// 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 { };
|
||||
|
|
|
@ -225,7 +225,12 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID)
|
|||
|
||||
QString ScriptManager::logException(const ScriptValue& exception) {
|
||||
auto message = formatException(exception, _enableExtendedJSExceptions.get());
|
||||
scriptErrorMessage(message);
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
scriptErrorMessage(message, context->currentFileName(), context->currentLineNumber());
|
||||
} else {
|
||||
scriptErrorMessage(message, "", -1);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
|
@ -330,6 +335,11 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con
|
|||
});
|
||||
}
|
||||
|
||||
//Gather entity script messages for transmission when running server side.
|
||||
if (_type == Type::ENTITY_SERVER) {
|
||||
;
|
||||
}
|
||||
|
||||
if (!_areMetaTypesInitialized) {
|
||||
initMetaTypes();
|
||||
}
|
||||
|
@ -514,7 +524,7 @@ void ScriptManager::waitTillDoneRunning(bool shutdown) {
|
|||
}
|
||||
#endif
|
||||
|
||||
scriptInfoMessage("Script Engine has stopped:" + getFilename());
|
||||
scriptInfoMessage("Script Engine has stopped:" + getFilename(), "", -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,7 +559,7 @@ void ScriptManager::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
|
||||
// Check that script has a supported file extension
|
||||
if (!hasValidScriptSuffix(_fileNameString)) {
|
||||
scriptErrorMessage("File extension of file: " + _fileNameString + " is not a currently supported script type");
|
||||
scriptErrorMessage("File extension of file: " + _fileNameString + " is not a currently supported script type", _fileNameString, -1);
|
||||
emit errorLoadingScript(_fileNameString);
|
||||
return;
|
||||
}
|
||||
|
@ -559,7 +569,7 @@ void ScriptManager::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
scriptCache->getScriptContents(url.toString(), [this](const QString& url, const QString& scriptContents, bool isURL, bool success, const QString&status) {
|
||||
qCDebug(scriptengine) << "loadURL" << url << status << QThread::currentThread();
|
||||
if (!success) {
|
||||
scriptErrorMessage("ERROR Loading file (" + status + "):" + url);
|
||||
scriptErrorMessage("ERROR Loading file (" + status + "):" + url, url, -1);
|
||||
emit errorLoadingScript(_fileNameString);
|
||||
return;
|
||||
}
|
||||
|
@ -570,24 +580,36 @@ void ScriptManager::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
}, reload, maxRetries);
|
||||
}
|
||||
|
||||
void ScriptManager::scriptErrorMessage(const QString& message) {
|
||||
void ScriptManager::scriptErrorMessage(const QString& message, const QString& fileName, int lineNumber) {
|
||||
qCCritical(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message));
|
||||
emit errorMessage(message, getFilename());
|
||||
if (!currentEntityIdentifier.isInvalidID()) {
|
||||
emit errorEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManager::scriptWarningMessage(const QString& message) {
|
||||
void ScriptManager::scriptWarningMessage(const QString& message, const QString& fileName, int lineNumber) {
|
||||
qCWarning(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message));
|
||||
emit warningMessage(message, getFilename());
|
||||
if (!currentEntityIdentifier.isInvalidID()) {
|
||||
emit warningEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManager::scriptInfoMessage(const QString& message) {
|
||||
void ScriptManager::scriptInfoMessage(const QString& message, const QString& fileName, int lineNumber) {
|
||||
qCInfo(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message));
|
||||
emit infoMessage(message, getFilename());
|
||||
if (!currentEntityIdentifier.isInvalidID()) {
|
||||
emit infoEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManager::scriptPrintedMessage(const QString& message) {
|
||||
void ScriptManager::scriptPrintedMessage(const QString& message, const QString& fileName, int lineNumber) {
|
||||
qCDebug(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message));
|
||||
emit printedMessage(message, getFilename());
|
||||
if (!currentEntityIdentifier.isInvalidID()) {
|
||||
emit printedEntityMessage(message, fileName, lineNumber, currentEntityIdentifier, isEntityServerScript());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManager::clearDebugLogWindow() {
|
||||
|
@ -912,7 +934,7 @@ void ScriptManager::run() {
|
|||
return; // bail early - avoid setting state in init(), as evaluate() will bail too
|
||||
}
|
||||
|
||||
scriptInfoMessage("Script Engine starting:" + getFilename());
|
||||
scriptInfoMessage("Script Engine starting:" + getFilename(), getFilename(), -1);
|
||||
|
||||
if (!_isInitialized) {
|
||||
init();
|
||||
|
@ -1064,7 +1086,7 @@ void ScriptManager::run() {
|
|||
_engine->clearExceptions();
|
||||
}
|
||||
}
|
||||
scriptInfoMessage("Script Engine stopping:" + getFilename());
|
||||
scriptInfoMessage("Script Engine stopping:" + getFilename(), getFilename(), -1);
|
||||
|
||||
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
||||
emit scriptEnding();
|
||||
|
@ -1139,7 +1161,7 @@ void ScriptManager::updateMemoryCost(const qint64& deltaSize) {
|
|||
|
||||
void ScriptManager::timerFired() {
|
||||
if (isStopped()) {
|
||||
scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename());
|
||||
scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename(), getFilename(), -1);
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
|
@ -1206,7 +1228,14 @@ QTimer* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int i
|
|||
|
||||
QTimer* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) {
|
||||
if (isStopped()) {
|
||||
scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename());
|
||||
int lineNumber = -1;
|
||||
QString fileName = getFilename();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename(), fileName, lineNumber);
|
||||
return NULL; // bail early
|
||||
}
|
||||
|
||||
|
@ -1215,7 +1244,14 @@ QTimer* ScriptManager::setInterval(const ScriptValue& function, int intervalMS)
|
|||
|
||||
QTimer* ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) {
|
||||
if (isStopped()) {
|
||||
scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename());
|
||||
int lineNumber = -1;
|
||||
QString fileName = getFilename();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename(), fileName, lineNumber);
|
||||
return NULL; // bail early
|
||||
}
|
||||
|
||||
|
@ -1281,7 +1317,7 @@ QUrl ScriptManager::resourcesPath() const {
|
|||
}
|
||||
|
||||
void ScriptManager::print(const QString& message) {
|
||||
emit printedMessage(message, getFilename());
|
||||
emit scriptPrintedMessage(message, getFilename(), engine()->currentContext()->currentLineNumber());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1651,8 +1687,15 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue&
|
|||
return;
|
||||
}
|
||||
if (isStopped()) {
|
||||
int lineNumber = -1;
|
||||
QString fileName = getFilename();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptWarningMessage("Script.include() while shutting down is ignored... includeFiles:"
|
||||
+ includeFiles.join(",") + "parent script:" + getFilename());
|
||||
+ includeFiles.join(",") + "parent script:" + getFilename(), fileName, lineNumber);
|
||||
return; // bail early
|
||||
}
|
||||
QList<QUrl> urls;
|
||||
|
@ -1665,8 +1708,15 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue&
|
|||
thisURL = expandScriptUrl(QUrl::fromLocalFile(expandScriptPath(file)));
|
||||
QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation();
|
||||
if (!defaultScriptsLoc.isParentOf(thisURL)) {
|
||||
int lineNumber = -1;
|
||||
QString fileName = getFilename();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
//V8TODO this probably needs to be done per context, otherwise file cannot be included again in a module
|
||||
scriptWarningMessage("Script.include() -- skipping" + file + "-- outside of standard libraries");
|
||||
scriptWarningMessage("Script.include() -- skipping" + file + "-- outside of standard libraries", fileName, lineNumber);
|
||||
continue;
|
||||
}
|
||||
isStandardLibrary = true;
|
||||
|
@ -1676,8 +1726,15 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue&
|
|||
|
||||
bool disallowOutsideFiles = thisURL.isLocalFile() && !isStandardLibrary && !currentSandboxURL.isLocalFile();
|
||||
if (disallowOutsideFiles && !PathUtils::isDescendantOf(thisURL, currentSandboxURL)) {
|
||||
int lineNumber = -1;
|
||||
QString fileName = currentSandboxURL.toString();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptWarningMessage("Script.include() ignoring file path" + thisURL.toString()
|
||||
+ "outside of original entity script" + currentSandboxURL.toString());
|
||||
+ "outside of original entity script" + currentSandboxURL.toString(), fileName, lineNumber);
|
||||
} else {
|
||||
// We could also check here for CORS, but we don't yet.
|
||||
// It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here.
|
||||
|
@ -1699,7 +1756,14 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue&
|
|||
for (QUrl url : urls) {
|
||||
QString contents = data[url];
|
||||
if (contents.isNull()) {
|
||||
scriptErrorMessage("Error loading file (" + status[url] +"): " + url.toString());
|
||||
int lineNumber = -1;
|
||||
QString fileName = url.toString();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptErrorMessage("Error loading file (" + status[url] +"): " + url.toString(), fileName, lineNumber);
|
||||
} else {
|
||||
std::lock_guard<std::recursive_mutex> lock(_lock);
|
||||
if (!_includedURLs.contains(url)) {
|
||||
|
@ -1719,7 +1783,14 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue&
|
|||
_engine->clearExceptions();
|
||||
}
|
||||
} else {
|
||||
scriptPrintedMessage("Script.include() skipping evaluation of previously included url:" + url.toString());
|
||||
int lineNumber = -1;
|
||||
QString fileName = url.toString();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptPrintedMessage("Script.include() skipping evaluation of previously included url:" + url.toString(), fileName, lineNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1748,8 +1819,15 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue&
|
|||
|
||||
void ScriptManager::include(const QString& includeFile, const ScriptValue& callback) {
|
||||
if (isStopped()) {
|
||||
int lineNumber = -1;
|
||||
QString fileName = currentSandboxURL.toString();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:"
|
||||
+ includeFile + "parent script:" + getFilename());
|
||||
+ includeFile + "parent script:" + getFilename(), fileName, lineNumber);
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
|
@ -1765,14 +1843,21 @@ void ScriptManager::load(const QString& loadFile) {
|
|||
if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) {
|
||||
return;
|
||||
}
|
||||
int lineNumber = -1;
|
||||
QString fileName = getFilename();
|
||||
auto context = _engine->currentContext();
|
||||
if (context) {
|
||||
lineNumber = context->currentLineNumber();
|
||||
fileName = context->currentFileName();
|
||||
}
|
||||
if (isStopped()) {
|
||||
scriptWarningMessage("Script.load() while shutting down is ignored... loadFile:"
|
||||
+ loadFile + "parent script:" + getFilename());
|
||||
+ loadFile + "parent script:" + getFilename(), fileName, lineNumber);
|
||||
return; // bail early
|
||||
}
|
||||
if (!currentEntityIdentifier.isInvalidID()) {
|
||||
scriptWarningMessage("Script.load() from entity script is ignored... loadFile:"
|
||||
+ loadFile + "parent script:" + getFilename() + "entity: " + currentEntityIdentifier.toString());
|
||||
+ loadFile + "parent script:" + getFilename() + "entity: " + currentEntityIdentifier.toString(), fileName, lineNumber);
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
|
@ -2440,7 +2525,7 @@ void ScriptManager::refreshFileScript(const EntityItemID& entityID) {
|
|||
QString filePath = QUrl(details.scriptText).toLocalFile();
|
||||
auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
|
||||
if (lastModified > details.lastModified) {
|
||||
scriptInfoMessage("Reloading modified script " + details.scriptText);
|
||||
scriptInfoMessage("Reloading modified script " + details.scriptText, filePath, -1);
|
||||
loadEntityScript(entityID, details.scriptText, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1074,8 +1074,10 @@ public:
|
|||
* Emits errorMessage()
|
||||
*
|
||||
* @param message Message to send to the log
|
||||
* @param fileName Name of the file in which message was generated. Empty string when no file name is available.
|
||||
* @param lineNumber Number of the line on which message was generated. -1 if there line number is not available.
|
||||
*/
|
||||
void scriptErrorMessage(const QString& message);
|
||||
void scriptErrorMessage(const QString& message, const QString& fileName, int lineNumber);
|
||||
|
||||
/**
|
||||
* @brief Logs a script warning message and emits an warningMessage event
|
||||
|
@ -1083,8 +1085,10 @@ public:
|
|||
* Emits warningMessage()
|
||||
*
|
||||
* @param message Message to send to the log
|
||||
* @param fileName Name of the file in which message was generated. Empty string when no file name is available.
|
||||
* @param lineNumber Number of the line on which message was generated. -1 if there line number is not available.
|
||||
*/
|
||||
void scriptWarningMessage(const QString& message);
|
||||
void scriptWarningMessage(const QString& message, const QString& fileName, int lineNumber);
|
||||
|
||||
/**
|
||||
* @brief Logs a script info message and emits an infoMessage event
|
||||
|
@ -1092,8 +1096,10 @@ public:
|
|||
* Emits infoMessage()
|
||||
*
|
||||
* @param message Message to send to the log
|
||||
* @param fileName Name of the file in which message was generated. Empty string when no file name is available.
|
||||
* @param lineNumber Number of the line on which message was generated. -1 if there line number is not available.
|
||||
*/
|
||||
void scriptInfoMessage(const QString& message);
|
||||
void scriptInfoMessage(const QString& message, const QString& fileName, int lineNumber);
|
||||
|
||||
/**
|
||||
* @brief Logs a script printed message and emits an printedMessage event
|
||||
|
@ -1102,9 +1108,11 @@ public:
|
|||
* Emits printedMessage()
|
||||
*
|
||||
* @param message Message to send to the log
|
||||
* @param fileName Name of the file in which message was generated. Empty string when no file name is available.
|
||||
* @param lineNumber Number of the line on which message was generated. -1 if there line number is not available.
|
||||
*/
|
||||
|
||||
void scriptPrintedMessage(const QString& message);
|
||||
void scriptPrintedMessage(const QString& message, const QString& fileName, int lineNumber);
|
||||
|
||||
/**
|
||||
* @brief Clears the debug log window
|
||||
|
@ -1321,6 +1329,54 @@ signals:
|
|||
*/
|
||||
void infoMessage(const QString& message, const QString& scriptName);
|
||||
|
||||
/**
|
||||
* @brief Triggered when a client side entity script prints a message to the program log
|
||||
*
|
||||
* @param message
|
||||
* @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, bool isServerScript);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Triggered when a client side entity script generates an error
|
||||
*
|
||||
* @param message
|
||||
* @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, bool isServerScript);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Triggered when a client side entity script generates a warning
|
||||
*
|
||||
* @param message
|
||||
* @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, bool isServerScript);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Triggered when a client side entity script generates an information message
|
||||
*
|
||||
* @param message
|
||||
* @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, bool isServerScript);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Triggered when the running state of the script changes, e.g., from running to stopping.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "ScriptManager.h"
|
||||
#include "ScriptManagerScriptingInterface.h"
|
||||
#include "ScriptEngines.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include <QMetaType>
|
||||
|
||||
|
@ -88,3 +89,39 @@ void ScriptManagerScriptingInterface::startProfiling() {
|
|||
void ScriptManagerScriptingInterface::stopProfilingAndSave() {
|
||||
_manager->engine()->stopProfilingAndSave();
|
||||
}
|
||||
|
||||
void ScriptManagerScriptingInterface::requestServerEntityScriptMessages() {
|
||||
if (_manager->isEntityServerScript() || _manager->isEntityServerScript()) {
|
||||
_manager->engine()->raiseException("Uuid needs to be specified when requestServerEntityScriptMessages is invoked from entity script");
|
||||
} else {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->requestServerEntityScriptMessages(_manager);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManagerScriptingInterface::requestServerEntityScriptMessages(const QUuid& entityID) {
|
||||
if (_manager->isEntityServerScript() || _manager->isEntityServerScript()) {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->requestServerEntityScriptMessages(_manager, entityID);
|
||||
} else {
|
||||
_manager->engine()->raiseException("Uuid must not be specified when requestServerEntityScriptMessages is invoked from entity script");
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManagerScriptingInterface::removeServerEntityScriptMessagesRequest() {
|
||||
if (_manager->isEntityServerScript() || _manager->isEntityServerScript()) {
|
||||
_manager->engine()->raiseException("Uuid needs to be specified when removeServerEntityScriptMessagesRequest is invoked from entity script");
|
||||
} else {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->removeServerEntityScriptMessagesRequest(_manager);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManagerScriptingInterface::removeServerEntityScriptMessagesRequest(const QUuid& entityID) {
|
||||
if (_manager->isEntityServerScript() || _manager->isEntityServerScript()) {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->removeServerEntityScriptMessagesRequest(_manager, entityID);
|
||||
} else {
|
||||
_manager->engine()->raiseException("Uuid must not be specified when removeServerEntityScriptMessagesRequest is invoked from entity script");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -512,7 +512,7 @@ public:
|
|||
|
||||
/*@jsdoc
|
||||
* Start collecting object statistics that can later be reported with Script.dumpHeapObjectStatistics().
|
||||
* @function Script.dumpHeapObjectStatistics
|
||||
* @function Script.startCollectingObjectStatistics
|
||||
*/
|
||||
Q_INVOKABLE void startCollectingObjectStatistics();
|
||||
|
||||
|
@ -557,7 +557,31 @@ 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
|
||||
* @param {Uuid=} entityID - The ID of the entity that requests entity server script messages. Only needs to be specified
|
||||
* for entity scripts, and must not be specified for other types of scripts.
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void requestServerEntityScriptMessages();
|
||||
Q_INVOKABLE void requestServerEntityScriptMessages(const QUuid& entityID);
|
||||
|
||||
/*@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
|
||||
* @param {Uuid=} entityID - The ID of the entity that requests entity server script messages. Only needs to be specified
|
||||
* for entity scripts, and must not be specified for other types of scripts.
|
||||
*/
|
||||
|
||||
Q_INVOKABLE void removeServerEntityScriptMessagesRequest();
|
||||
Q_INVOKABLE void removeServerEntityScriptMessagesRequest(const QUuid& entityID);
|
||||
|
||||
signals:
|
||||
|
||||
/*@jsdoc
|
||||
* @function Script.scriptLoaded
|
||||
|
|
48
libraries/script-engine/src/ScriptMessage.cpp
Normal file
48
libraries/script-engine/src/ScriptMessage.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// ScriptMessage.h
|
||||
// libraries/script-engine/src/v8/FastScriptValueUtils.cpp
|
||||
//
|
||||
// Created by dr Karol Suprynowicz on 2023/09/24.
|
||||
// Copyright 2023 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ScriptMessage.h"
|
||||
|
||||
#include <qhash.h>
|
||||
|
||||
QJsonObject ScriptMessage::toJson() {
|
||||
QJsonObject object;
|
||||
object["message"] = _messageContent;
|
||||
object["lineNumber"] = _lineNumber;
|
||||
object["fileName"] = _fileName;
|
||||
object["entityID"] = _entityID.toString();
|
||||
object["type"] = static_cast<int>(_scriptType);
|
||||
object["severity"] = static_cast<int>(_severity);
|
||||
return object;
|
||||
}
|
||||
|
||||
bool ScriptMessage::fromJson(const QJsonObject &object) {
|
||||
if (object.isEmpty()) {
|
||||
qDebug() << "ScriptMessage::fromJson object is empty";
|
||||
return false;
|
||||
}
|
||||
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";
|
||||
return false;
|
||||
}
|
||||
_messageContent = object["message"].toString();
|
||||
_lineNumber = object["lineNumber"].toInt();
|
||||
_fileName = object["fileName"].toInt();
|
||||
_entityID = QUuid::fromString(object["entityID"].toString());
|
||||
_scriptType = static_cast<ScriptMessage::ScriptType>(object["type"].toInt());
|
||||
_severity = static_cast<ScriptMessage::Severity>(object["severity"].toInt());
|
||||
return true;
|
||||
}
|
61
libraries/script-engine/src/ScriptMessage.h
Normal file
61
libraries/script-engine/src/ScriptMessage.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// ScriptMessage.h
|
||||
// libraries/script-engine/src/v8/FastScriptValueUtils.cpp
|
||||
//
|
||||
// Created by dr Karol Suprynowicz on 2023/09/24.
|
||||
// Copyright 2023 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef OVERTE_SCRIPTMESSAGE_H
|
||||
#define OVERTE_SCRIPTMESSAGE_H
|
||||
|
||||
// Used to store script messages on entity script server before transmitting them to clients who subscribed to them.
|
||||
// EntityServerScriptLog packet type is used.
|
||||
// In the future will also be used for storing assignment client script messages before transmission
|
||||
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
#include "EntityItemID.h"
|
||||
|
||||
class ScriptMessage {
|
||||
public:
|
||||
enum class ScriptType {
|
||||
TYPE_NONE,
|
||||
TYPE_ENTITY_SCRIPT
|
||||
};
|
||||
enum class Severity {
|
||||
SEVERITY_NONE,
|
||||
SEVERITY_PRINT,
|
||||
SEVERITY_INFO,
|
||||
SEVERITY_DEBUG,
|
||||
SEVERITY_WARNING,
|
||||
SEVERITY_ERROR
|
||||
};
|
||||
|
||||
ScriptMessage() {};
|
||||
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};
|
||||
};
|
||||
|
||||
#endif //OVERTE_SCRIPTMESSAGE_H
|
|
@ -111,6 +111,37 @@ QStringList ScriptContextV8Wrapper::backtrace() const {
|
|||
return backTrace;
|
||||
}
|
||||
|
||||
int ScriptContextV8Wrapper::currentLineNumber() const {
|
||||
auto isolate = _engine->getIsolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
v8::Context::Scope contextScope(_context.Get(isolate));
|
||||
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 1);
|
||||
if (stackTrace->GetFrameCount() > 0) {
|
||||
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(isolate, 0);
|
||||
return stackFrame->GetLineNumber();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
QString ScriptContextV8Wrapper::currentFileName() const {
|
||||
auto isolate = _engine->getIsolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
v8::Context::Scope contextScope(_context.Get(isolate));
|
||||
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 1);
|
||||
QStringList backTrace;
|
||||
if (stackTrace->GetFrameCount() > 0) {
|
||||
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(isolate, 0);
|
||||
return *v8::String::Utf8Value(isolate, stackFrame->GetScriptNameOrSourceURL());
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue ScriptContextV8Wrapper::callee() const {
|
||||
Q_ASSERT(false);
|
||||
//V8TODO
|
||||
|
|
|
@ -45,6 +45,13 @@ public: // ScriptContext implementation
|
|||
virtual int argumentCount() const override;
|
||||
virtual ScriptValue argument(int index) const override;
|
||||
virtual QStringList backtrace() const override;
|
||||
|
||||
// Name of the file in which message was generated. Empty string when no file name is available.
|
||||
virtual int currentLineNumber() const override;
|
||||
|
||||
// Number of the line on which message was generated. -1 if there line number is not available.
|
||||
virtual QString currentFileName() const override;
|
||||
|
||||
virtual ScriptValue callee() const override;
|
||||
virtual ScriptEnginePointer engine() const override;
|
||||
virtual ScriptFunctionContextPointer functionContext() const override;
|
||||
|
|
|
@ -77,6 +77,17 @@ bool ScriptEngineV8::IS_THREADSAFE_INVOCATION(const QThread* thread, const QStri
|
|||
return false;
|
||||
}
|
||||
|
||||
QString getFileNameFromTryCatch(v8::TryCatch &tryCatch, v8::Isolate *isolate, v8::Local<v8::Context> &context ) {
|
||||
v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
|
||||
QString errorFileName;
|
||||
auto resource = exceptionMessage->GetScriptResourceName();
|
||||
v8::Local<v8::String> v8resourceString;
|
||||
if (resource->ToString(context).ToLocal(&v8resourceString)) {
|
||||
errorFileName = QString(*v8::String::Utf8Value(isolate, v8resourceString));
|
||||
}
|
||||
return errorFileName;
|
||||
}
|
||||
|
||||
ScriptValue ScriptEngineV8::makeError(const ScriptValue& _other, const QString& type) {
|
||||
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
|
||||
return nullValue();
|
||||
|
@ -726,7 +737,13 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
|
|||
+ "tryCatch details:" + formatErrorMessageFromTryCatch(tryCatch);
|
||||
v8Result = v8::Null(_v8Isolate);
|
||||
if (_manager) {
|
||||
_manager->scriptErrorMessage(errorMessage);
|
||||
v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
|
||||
int errorLineNumber = -1;
|
||||
if (!exceptionMessage.IsEmpty()) {
|
||||
errorLineNumber = exceptionMessage->GetLineNumber(closureContext).FromJust();
|
||||
}
|
||||
_manager->scriptErrorMessage(errorMessage, getFileNameFromTryCatch(tryCatch, _v8Isolate, closureContext),
|
||||
errorLineNumber);
|
||||
} else {
|
||||
qWarning(scriptengine_v8) << errorMessage;
|
||||
}
|
||||
|
@ -781,7 +798,13 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f
|
|||
if (!v8::Script::Compile(context, v8::String::NewFromUtf8(getIsolate(), sourceCode.toStdString().c_str()).ToLocalChecked(), &scriptOrigin).ToLocal(&script)) {
|
||||
QString errorMessage(QString("Error while compiling script: \"") + fileName + QString("\" ") + formatErrorMessageFromTryCatch(tryCatch));
|
||||
if (_manager) {
|
||||
_manager->scriptErrorMessage(errorMessage);
|
||||
v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
|
||||
int errorLineNumber = -1;
|
||||
if (!exceptionMessage.IsEmpty()) {
|
||||
errorLineNumber = exceptionMessage->GetLineNumber(context).FromJust();
|
||||
}
|
||||
_manager->scriptErrorMessage(errorMessage, getFileNameFromTryCatch(tryCatch, _v8Isolate, context),
|
||||
errorLineNumber);
|
||||
} else {
|
||||
qDebug(scriptengine_v8) << errorMessage;
|
||||
}
|
||||
|
@ -799,7 +822,13 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f
|
|||
ScriptValue errorValue(new ScriptValueV8Wrapper(this, V8ScriptValue(this, runError->Get())));
|
||||
QString errorMessage(QString("Running script: \"") + fileName + QString("\" ") + formatErrorMessageFromTryCatch(tryCatchRun));
|
||||
if (_manager) {
|
||||
_manager->scriptErrorMessage(errorMessage);
|
||||
v8::Local<v8::Message> exceptionMessage = tryCatchRun.Message();
|
||||
int errorLineNumber = -1;
|
||||
if (!exceptionMessage.IsEmpty()) {
|
||||
errorLineNumber = exceptionMessage->GetLineNumber(context).FromJust();
|
||||
}
|
||||
_manager->scriptErrorMessage(errorMessage, getFileNameFromTryCatch(tryCatchRun, _v8Isolate, context),
|
||||
errorLineNumber);
|
||||
} else {
|
||||
qDebug(scriptengine_v8) << errorMessage;
|
||||
}
|
||||
|
|
|
@ -309,6 +309,8 @@ private:
|
|||
ScriptEngineV8* _engine;
|
||||
};
|
||||
|
||||
QString getFileNameFromTryCatch(v8::TryCatch &tryCatch, v8::Isolate *isolate, v8::Local<v8::Context> &context );
|
||||
|
||||
#include "V8Types.h"
|
||||
|
||||
#endif // hifi_ScriptEngineV8_h
|
||||
|
|
|
@ -56,6 +56,13 @@ public: // ScriptContext implementation
|
|||
virtual int argumentCount() const override { return _parent->argumentCount(); }
|
||||
virtual ScriptValue argument(int index) const override { return _parent->argument(index); }
|
||||
virtual QStringList backtrace() const override { return _parent->backtrace(); }
|
||||
|
||||
// Name of the file in which message was generated. Empty string when no file name is available.
|
||||
virtual int currentLineNumber() const override { return _parent->currentLineNumber(); }
|
||||
|
||||
// Number of the line on which message was generated. -1 if there line number is not available.
|
||||
virtual QString currentFileName() const override { return _parent->currentFileName(); }
|
||||
|
||||
virtual ScriptValue callee() const override { return _parent->callee(); }
|
||||
virtual ScriptEnginePointer engine() const override { return _parent->engine(); }
|
||||
virtual ScriptFunctionContextPointer functionContext() const override { return _parent->functionContext(); }
|
||||
|
@ -1274,8 +1281,14 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
|
|||
QString errorMessage(QString("Signal proxy ") + fullName() + " connection call failed: \""
|
||||
+ _engine->formatErrorMessageFromTryCatch(tryCatch)
|
||||
+ "\nThis provided: " + QString::number(conn.thisValue.get()->IsObject()));
|
||||
v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
|
||||
int errorLineNumber = -1;
|
||||
if (!exceptionMessage.IsEmpty()) {
|
||||
errorLineNumber = exceptionMessage->GetLineNumber(context).FromJust();
|
||||
}
|
||||
if (_engine->_manager) {
|
||||
_engine->_manager->scriptErrorMessage(errorMessage);
|
||||
_engine->_manager->scriptErrorMessage(errorMessage, getFileNameFromTryCatch(tryCatch, isolate, context),
|
||||
errorLineNumber);
|
||||
} else {
|
||||
qDebug(scriptengine_v8) << errorMessage;
|
||||
}
|
||||
|
|
|
@ -104,7 +104,13 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
|
|||
if (tryCatch.HasCaught()) {
|
||||
QString errorMessage(QString("Function call failed: \"") + _engine->formatErrorMessageFromTryCatch(tryCatch));
|
||||
if (_engine->_manager) {
|
||||
_engine->_manager->scriptErrorMessage(errorMessage);
|
||||
v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
|
||||
int errorLineNumber = -1;
|
||||
if (!exceptionMessage.IsEmpty()) {
|
||||
errorLineNumber = exceptionMessage->GetLineNumber(context).FromJust();
|
||||
}
|
||||
_engine->_manager->scriptErrorMessage(errorMessage, getFileNameFromTryCatch(tryCatch, isolate, context),
|
||||
errorLineNumber);
|
||||
} else {
|
||||
qDebug(scriptengine_v8) << errorMessage;
|
||||
}
|
||||
|
@ -114,9 +120,10 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
|
|||
if (maybeResult.ToLocal(&result)) {
|
||||
return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine, result)));
|
||||
} else {
|
||||
QString errorMessage("JS function call failed: " + _engine->currentContext()->backtrace().join("\n"));
|
||||
auto currentContext = _engine->currentContext();
|
||||
QString errorMessage("JS function call failed: " + currentContext->backtrace().join("\n"));
|
||||
if (_engine->_manager) {
|
||||
_engine->_manager->scriptErrorMessage(errorMessage);
|
||||
_engine->_manager->scriptErrorMessage(errorMessage, currentContext->currentFileName(), currentContext->currentLineNumber());
|
||||
} else {
|
||||
qDebug(scriptengine_v8) << errorMessage;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue