JavaScript exceptions during Controller system callbacks are now logged

(cherry picked from commit d3aec12e9e76e4aeb8ecbd449cc76afda1a0e35d)
This commit is contained in:
Anthony J. Thibault 2018-03-27 18:51:44 -07:00
parent 5a7267a844
commit ca3fe28b05
3 changed files with 82 additions and 21 deletions

View file

@ -6,10 +6,43 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
// NOTE: we don't need to include this header unless/until we add additional symbols. #include "JSEndpoint.h"
// By removing this header we prevent these warnings on windows: #include "../../Logging.h"
//
// warning LNK4221: This object file does not define any previously undefined public symbols, using namespace controller;
// so it will not be used by any link operation that consumes this library
// QString formatException(const QJSValue& exception) {
//#include "JSEndpoint.h" QString note { "UncaughtException" };
QString result;
const auto message = exception.toString();
const auto fileName = exception.property("fileName").toString();
const auto lineNumber = exception.property("lineNumber").toString();
const auto stacktrace = exception.property("stack").toString();
const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3";
const QString SCRIPT_BACKTRACE_SEP = "\n ";
result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber);
if (!stacktrace.isEmpty()) {
result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace);
}
return result;
}
float JSEndpoint::peek() const {
QJSValue result = _callable.call();
if (result.isError()) {
qCDebug(controllers).noquote() << formatException(result);
return 0.0f;
} else {
return (float)result.toNumber();
}
}
void JSEndpoint::apply(float newValue, const Pointer& source) {
QJSValue result = _callable.call(QJSValueList({ QJSValue(newValue) }));
if (result.isError()) {
qCDebug(controllers).noquote() << formatException(result);
}
}

View file

@ -24,16 +24,11 @@ public:
: Endpoint(Input::INVALID_INPUT), _callable(callable) { : Endpoint(Input::INVALID_INPUT), _callable(callable) {
} }
virtual float peek() const override { virtual float peek() const override;
return (float)const_cast<JSEndpoint*>(this)->_callable.call().toNumber(); virtual void apply(float newValue, const Pointer& source) override;
}
virtual void apply(float newValue, const Pointer& source) override {
_callable.call(QJSValueList({ QJSValue(newValue) }));
}
private: private:
QJSValue _callable; mutable QJSValue _callable;
}; };
} }

View file

@ -7,6 +7,7 @@
// //
#include "ScriptEndpoint.h" #include "ScriptEndpoint.h"
#include "../../Logging.h"
#include <QtCore/QThread> #include <QtCore/QThread>
@ -14,6 +15,25 @@
using namespace controller; using namespace controller;
QString formatException(const QScriptValue& exception) {
QString note { "UncaughtException" };
QString result;
const auto message = exception.toString();
const auto fileName = exception.property("fileName").toString();
const auto lineNumber = exception.property("lineNumber").toString();
const auto stacktrace = exception.property("stack").toString();
const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3";
const QString SCRIPT_BACKTRACE_SEP = "\n ";
result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber);
if (!stacktrace.isEmpty()) {
result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace);
}
return result;
}
float ScriptEndpoint::peek() const { float ScriptEndpoint::peek() const {
const_cast<ScriptEndpoint*>(this)->updateValue(); const_cast<ScriptEndpoint*>(this)->updateValue();
return _lastValueRead; return _lastValueRead;
@ -26,10 +46,11 @@ void ScriptEndpoint::updateValue() {
} }
QScriptValue result = _callable.call(); QScriptValue result = _callable.call();
if (result.isError()) {
// If the callable ever returns a non-number, we assume it's a pose // print JavaScript exception
// and start reporting ourselves as a pose. qCDebug(controllers).noquote() << formatException(result);
if (result.isNumber()) { _lastValueRead = 0.0f;
} else if (result.isNumber()) {
_lastValueRead = (float)_callable.call().toNumber(); _lastValueRead = (float)_callable.call().toNumber();
} else { } else {
Pose::fromScriptValue(result, _lastPoseRead); Pose::fromScriptValue(result, _lastPoseRead);
@ -52,8 +73,12 @@ void ScriptEndpoint::internalApply(float value, int sourceID) {
Q_ARG(int, sourceID)); Q_ARG(int, sourceID));
return; return;
} }
_callable.call(QScriptValue(), QScriptValue result = _callable.call(QScriptValue(),
QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) })); QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) }));
if (result.isError()) {
// print JavaScript exception
qCDebug(controllers).noquote() << formatException(result);
}
} }
Pose ScriptEndpoint::peekPose() const { Pose ScriptEndpoint::peekPose() const {
@ -67,6 +92,10 @@ void ScriptEndpoint::updatePose() {
return; return;
} }
QScriptValue result = _callable.call(); QScriptValue result = _callable.call();
if (result.isError()) {
// print JavaScript exception
qCDebug(controllers).noquote() << formatException(result);
}
Pose::fromScriptValue(result, _lastPoseRead); Pose::fromScriptValue(result, _lastPoseRead);
} }
@ -85,6 +114,10 @@ void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) {
Q_ARG(int, sourceID)); Q_ARG(int, sourceID));
return; return;
} }
_callable.call(QScriptValue(), QScriptValue result = _callable.call(QScriptValue(),
QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) })); QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) }));
if (result.isError()) {
// print JavaScript exception
qCDebug(controllers).noquote() << formatException(result);
}
} }