@dusted/anqst 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/app.js +86 -103
- package/dist/src/build-stamp.js +5 -0
- package/dist/src/emit.js +326 -104
- package/dist/src/parser.js +108 -5
- package/dist/src/verify.js +6 -1
- package/package.json +1 -1
- package/spec/AnQst-Spec-DSL.d.ts +50 -18
package/dist/src/emit.js
CHANGED
|
@@ -12,6 +12,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
12
12
|
const node_path_1 = __importDefault(require("node:path"));
|
|
13
13
|
const typescript_1 = __importDefault(require("typescript"));
|
|
14
14
|
const pngjs_1 = require("pngjs");
|
|
15
|
+
const build_stamp_1 = require("./build-stamp");
|
|
15
16
|
const layout_1 = require("./layout");
|
|
16
17
|
function stripAnQstType(typeText) {
|
|
17
18
|
return typeText
|
|
@@ -652,13 +653,24 @@ ${decls}
|
|
|
652
653
|
${metatypes}
|
|
653
654
|
`;
|
|
654
655
|
}
|
|
656
|
+
function renderWidgetUmbrellaHeader(spec) {
|
|
657
|
+
return `#pragma once
|
|
658
|
+
// Built by <AnQst_version>
|
|
659
|
+
#include "${spec.widgetName}Widget.h"
|
|
660
|
+
#include "${spec.widgetName}Types.h"
|
|
661
|
+
`;
|
|
662
|
+
}
|
|
655
663
|
function renderWidgetHeader(spec, cppTypes) {
|
|
664
|
+
const widgetClassName = `${spec.widgetName}Widget`;
|
|
656
665
|
const callbackAliases = [];
|
|
657
666
|
const publicMethods = [];
|
|
667
|
+
const slotMethods = [];
|
|
668
|
+
const handleMethods = [];
|
|
669
|
+
const callSetterMethods = [];
|
|
658
670
|
const signals = [];
|
|
659
671
|
const properties = [];
|
|
660
672
|
const fields = [];
|
|
661
|
-
const
|
|
673
|
+
const publicSlots = [];
|
|
662
674
|
const bindings = [];
|
|
663
675
|
for (const service of spec.services) {
|
|
664
676
|
for (const member of service.members) {
|
|
@@ -666,21 +678,20 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
666
678
|
const memberPascal = pascalCase(member.name);
|
|
667
679
|
if (member.kind === "Call" && member.payloadTypeText) {
|
|
668
680
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
669
|
-
const args = member.parameters.map((p) =>
|
|
681
|
+
const args = member.parameters.map((p) => `const ${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])}& ${p.name}`).join(", ");
|
|
670
682
|
callbackAliases.push(`using ${memberPascal}Handler = std::function<${cppType}(${args})>;`);
|
|
671
|
-
|
|
683
|
+
handleMethods.push(` void ${member.name}(const ${memberPascal}Handler& handler) const;`);
|
|
684
|
+
callSetterMethods.push(`void set${memberPascal}CallHandler(const ${memberPascal}Handler& handler);`);
|
|
672
685
|
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
673
686
|
}
|
|
674
687
|
else if (member.kind === "Emitter") {
|
|
675
|
-
const args = member.parameters.map((p) =>
|
|
676
|
-
|
|
677
|
-
publicMethods.push(`void set${memberPascal}Handler(const ${memberPascal}Handler& handler);`);
|
|
678
|
-
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
688
|
+
const args = member.parameters.map((p) => `const ${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])}& ${p.name}`).join(", ");
|
|
689
|
+
signals.push(`void ${member.name}(${args});`);
|
|
679
690
|
}
|
|
680
691
|
else if (member.kind === "Slot") {
|
|
681
692
|
const ret = member.payloadTypeText ? cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]) : "void";
|
|
682
693
|
const args = member.parameters.map((p) => `${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])} ${p.name}`).join(", ");
|
|
683
|
-
|
|
694
|
+
slotMethods.push(`${ret} slot_${member.name}(${args});`);
|
|
684
695
|
}
|
|
685
696
|
else if ((member.kind === "Input" || member.kind === "Output") && member.payloadTypeText) {
|
|
686
697
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
@@ -696,13 +707,16 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
696
707
|
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
697
708
|
}
|
|
698
709
|
else {
|
|
699
|
-
|
|
710
|
+
publicSlots.push(`void ${member.name}Slot(const ${cppType}& value);`);
|
|
700
711
|
}
|
|
701
712
|
}
|
|
702
713
|
}
|
|
703
714
|
}
|
|
704
715
|
return `#pragma once
|
|
716
|
+
#include <QDateTime>
|
|
705
717
|
#include <QHash>
|
|
718
|
+
#include <QMetaMethod>
|
|
719
|
+
#include <QQueue>
|
|
706
720
|
#include <QVariant>
|
|
707
721
|
#include <QVariantList>
|
|
708
722
|
#include <functional>
|
|
@@ -710,28 +724,54 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
710
724
|
#include "${spec.widgetName}Types.h"
|
|
711
725
|
|
|
712
726
|
namespace ${spec.widgetName} {
|
|
727
|
+
} // namespace ${spec.widgetName}
|
|
728
|
+
|
|
729
|
+
using namespace ${spec.widgetName};
|
|
713
730
|
|
|
714
|
-
class ${
|
|
731
|
+
class ${widgetClassName} : public AnQstWebHostBase {
|
|
715
732
|
Q_OBJECT
|
|
716
733
|
${properties.map((p) => ` ${p}`).join("\n")}
|
|
717
734
|
|
|
718
735
|
public:
|
|
719
|
-
|
|
720
|
-
|
|
736
|
+
${callbackAliases.map((s) => ` ${s}`).join("\n")}
|
|
737
|
+
|
|
738
|
+
class handle {
|
|
739
|
+
public:
|
|
740
|
+
explicit handle(${widgetClassName}* owner) : m_owner(owner) {}
|
|
741
|
+
${handleMethods.join("\n")}
|
|
742
|
+
private:
|
|
743
|
+
${widgetClassName}* m_owner;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
explicit ${widgetClassName}(QWidget* parent = nullptr);
|
|
747
|
+
~${widgetClassName}() override;
|
|
721
748
|
bool enableDebug();
|
|
722
749
|
static constexpr const char* kBootstrapEntryPoint = "index.html";
|
|
723
750
|
static constexpr const char* kBootstrapContentRoot = "qrc:/${spec.widgetName.toLowerCase()}";
|
|
724
751
|
static constexpr const char* kBootstrapBridgeObject = "${spec.widgetName}Bridge";
|
|
752
|
+
static constexpr int kMaxQueuedCallsPerEndpoint = 1024;
|
|
725
753
|
|
|
726
|
-
|
|
754
|
+
handle handle;
|
|
727
755
|
${publicMethods.map((s) => ` ${s}`).join("\n")}
|
|
728
|
-
|
|
756
|
+
|
|
757
|
+
public slots:
|
|
758
|
+
${slotMethods.map((s) => ` ${s}`).join("\n")}
|
|
759
|
+
${publicSlots.map((s) => ` ${s}`).join("\n")}
|
|
729
760
|
|
|
730
761
|
signals:
|
|
731
762
|
${signals.map((s) => ` ${s}`).join("\n")}
|
|
732
763
|
void diagnosticsForwarded(const QVariantMap& payload);
|
|
733
764
|
|
|
765
|
+
protected:
|
|
766
|
+
void connectNotify(const QMetaMethod& signal) override;
|
|
767
|
+
void disconnectNotify(const QMetaMethod& signal) override;
|
|
768
|
+
|
|
734
769
|
private:
|
|
770
|
+
struct PendingCallInvocation {
|
|
771
|
+
QString requestId;
|
|
772
|
+
QVariantList args;
|
|
773
|
+
QDateTime enqueuedAt;
|
|
774
|
+
};
|
|
735
775
|
struct BridgeBindingRow {
|
|
736
776
|
const char* service;
|
|
737
777
|
const char* member;
|
|
@@ -741,21 +781,37 @@ private:
|
|
|
741
781
|
static constexpr int kBridgeBindingsCount = ${bindings.length};
|
|
742
782
|
static QString makeBindingKey(const QString& service, const QString& member);
|
|
743
783
|
void installBridgeBindings();
|
|
784
|
+
bool hasEmitterListeners(const QString& service, const QString& member) const;
|
|
744
785
|
QVariant handleGeneratedCall(const QString& service, const QString& member, const QVariantList& args);
|
|
745
786
|
void handleGeneratedEmitter(const QString& service, const QString& member, const QVariantList& args);
|
|
746
787
|
void handleGeneratedInput(const QString& service, const QString& member, const QVariant& value);
|
|
747
|
-
|
|
788
|
+
QVariant waitForCallHandlerAndInvoke(
|
|
789
|
+
const QString& service,
|
|
790
|
+
const QString& member,
|
|
791
|
+
const QString& requestId,
|
|
792
|
+
int timeoutMs,
|
|
793
|
+
const std::function<QVariant()>& invokeNow);
|
|
794
|
+
void removeQueuedCallById(const QString& queueKey, const QString& requestId);
|
|
795
|
+
${callSetterMethods.map((s) => ` ${s}`).join("\n")}
|
|
796
|
+
|
|
797
|
+
qulonglong m_callRequestCounter{0};
|
|
798
|
+
QHash<QString, QQueue<PendingCallInvocation>> m_queuedCalls;
|
|
748
799
|
${fields.map((f) => ` ${f}`).join("\n")}
|
|
749
800
|
};
|
|
750
|
-
|
|
751
|
-
} // namespace ${spec.widgetName}
|
|
752
801
|
`;
|
|
753
802
|
}
|
|
754
803
|
function renderCppStub(spec, cppTypes) {
|
|
804
|
+
const widgetClassName = `${spec.widgetName}Widget`;
|
|
755
805
|
const lines = [];
|
|
756
|
-
lines.push(`#include "include/${spec.widgetName}.h"`);
|
|
806
|
+
lines.push(`#include "include/${spec.widgetName}Widget.h"`);
|
|
757
807
|
lines.push(`#include <QDebug>`);
|
|
808
|
+
lines.push(`#include <QElapsedTimer>`);
|
|
809
|
+
lines.push(`#include <QEventLoop>`);
|
|
758
810
|
lines.push(`#include <QMetaType>`);
|
|
811
|
+
lines.push(`#include <QTimer>`);
|
|
812
|
+
lines.push(`#include <stdexcept>`);
|
|
813
|
+
lines.push("");
|
|
814
|
+
lines.push(`using namespace ${spec.widgetName};`);
|
|
759
815
|
lines.push("");
|
|
760
816
|
lines.push(`extern int qInitResources_${spec.widgetName}();`);
|
|
761
817
|
lines.push("");
|
|
@@ -772,9 +828,23 @@ function renderCppStub(spec, cppTypes) {
|
|
|
772
828
|
lines.push("}");
|
|
773
829
|
lines.push("}");
|
|
774
830
|
lines.push("");
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
831
|
+
for (const service of spec.services) {
|
|
832
|
+
for (const member of service.members) {
|
|
833
|
+
if (member.kind !== "Call" || !member.payloadTypeText)
|
|
834
|
+
continue;
|
|
835
|
+
const pascal = pascalCase(member.name);
|
|
836
|
+
lines.push(`void ${widgetClassName}::handle::${member.name}(const ${pascal}Handler& handler) const {`);
|
|
837
|
+
lines.push(` if (m_owner == nullptr) return;`);
|
|
838
|
+
lines.push(` m_owner->set${pascal}CallHandler(handler);`);
|
|
839
|
+
lines.push(`}`);
|
|
840
|
+
lines.push("");
|
|
841
|
+
lines.push(`void ${widgetClassName}::set${pascal}CallHandler(const ${pascal}Handler& handler) {`);
|
|
842
|
+
lines.push(` m_${member.name}Handler = handler;`);
|
|
843
|
+
lines.push(`}`);
|
|
844
|
+
lines.push("");
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
lines.push(`const ${widgetClassName}::BridgeBindingRow ${widgetClassName}::kBridgeBindings[] = {`);
|
|
778
848
|
for (const service of spec.services) {
|
|
779
849
|
for (const member of service.members) {
|
|
780
850
|
lines.push(` {"${service.name}", "${member.name}", "${member.kind}"},`);
|
|
@@ -782,7 +852,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
782
852
|
}
|
|
783
853
|
lines.push(`};`);
|
|
784
854
|
lines.push("");
|
|
785
|
-
lines.push(`${
|
|
855
|
+
lines.push(`${widgetClassName}::${widgetClassName}(QWidget* parent) : AnQstWebHostBase(parent), handle(this) {`);
|
|
786
856
|
lines.push(` static const bool kResourcesInitialized = []() {`);
|
|
787
857
|
lines.push(` ::qInitResources_${spec.widgetName}();`);
|
|
788
858
|
lines.push(` return true;`);
|
|
@@ -790,7 +860,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
790
860
|
lines.push(` Q_UNUSED(kResourcesInitialized);`);
|
|
791
861
|
lines.push(` registerGeneratedMetaTypes();`);
|
|
792
862
|
lines.push(` installBridgeBindings();`);
|
|
793
|
-
lines.push(` QObject::connect(this, &AnQstWebHostBase::onHostError, this, &${
|
|
863
|
+
lines.push(` QObject::connect(this, &AnQstWebHostBase::onHostError, this, &${widgetClassName}::diagnosticsForwarded);`);
|
|
794
864
|
lines.push(` const bool rootOk = setContentRoot(QString::fromUtf8(kBootstrapContentRoot));`);
|
|
795
865
|
lines.push(` const bool bridgeOk = setBridgeObject(this, QString::fromUtf8(kBootstrapBridgeObject));`);
|
|
796
866
|
lines.push(` const bool loadOk = rootOk && bridgeOk && loadEntryPoint(QString::fromUtf8(kBootstrapEntryPoint));`);
|
|
@@ -799,17 +869,74 @@ function renderCppStub(spec, cppTypes) {
|
|
|
799
869
|
lines.push(` }`);
|
|
800
870
|
lines.push("}");
|
|
801
871
|
lines.push("");
|
|
802
|
-
lines.push(`${
|
|
872
|
+
lines.push(`${widgetClassName}::~${widgetClassName}() = default;`);
|
|
803
873
|
lines.push("");
|
|
804
|
-
lines.push(`bool ${
|
|
874
|
+
lines.push(`bool ${widgetClassName}::enableDebug() {`);
|
|
805
875
|
lines.push(` return AnQstWebHostBase::enableDebug();`);
|
|
806
876
|
lines.push("}");
|
|
807
877
|
lines.push("");
|
|
808
|
-
lines.push(`QString ${
|
|
878
|
+
lines.push(`QString ${widgetClassName}::makeBindingKey(const QString& service, const QString& member) {`);
|
|
809
879
|
lines.push(` return service + QStringLiteral("::") + member;`);
|
|
810
880
|
lines.push(`}`);
|
|
811
881
|
lines.push("");
|
|
812
|
-
lines.push(`void ${
|
|
882
|
+
lines.push(`void ${widgetClassName}::removeQueuedCallById(const QString& queueKey, const QString& requestId) {`);
|
|
883
|
+
lines.push(` if (!m_queuedCalls.contains(queueKey)) return;`);
|
|
884
|
+
lines.push(` auto& queue = m_queuedCalls[queueKey];`);
|
|
885
|
+
lines.push(` for (int i = 0; i < queue.size(); ++i) {`);
|
|
886
|
+
lines.push(` if (queue[i].requestId == requestId) {`);
|
|
887
|
+
lines.push(` queue.removeAt(i);`);
|
|
888
|
+
lines.push(` break;`);
|
|
889
|
+
lines.push(` }`);
|
|
890
|
+
lines.push(` }`);
|
|
891
|
+
lines.push(`}`);
|
|
892
|
+
lines.push("");
|
|
893
|
+
lines.push(`QVariant ${widgetClassName}::waitForCallHandlerAndInvoke(`);
|
|
894
|
+
lines.push(` const QString& service,`);
|
|
895
|
+
lines.push(` const QString& member,`);
|
|
896
|
+
lines.push(` const QString& requestId,`);
|
|
897
|
+
lines.push(` int timeoutMs,`);
|
|
898
|
+
lines.push(` const std::function<QVariant()>& invokeNow) {`);
|
|
899
|
+
lines.push(` const QString queueKey = makeBindingKey(service, member);`);
|
|
900
|
+
lines.push(` QElapsedTimer timer;`);
|
|
901
|
+
lines.push(` timer.start();`);
|
|
902
|
+
lines.push(` QEventLoop loop;`);
|
|
903
|
+
lines.push(` QTimer tick;`);
|
|
904
|
+
lines.push(` tick.setSingleShot(true);`);
|
|
905
|
+
lines.push(` QObject::connect(&tick, &QTimer::timeout, &loop, &QEventLoop::quit);`);
|
|
906
|
+
lines.push(` while (true) {`);
|
|
907
|
+
lines.push(` if (m_queuedCalls.contains(queueKey) && !m_queuedCalls[queueKey].isEmpty() && m_queuedCalls[queueKey].head().requestId == requestId) {`);
|
|
908
|
+
lines.push(` m_queuedCalls[queueKey].dequeue();`);
|
|
909
|
+
lines.push(` return invokeNow();`);
|
|
910
|
+
lines.push(` }`);
|
|
911
|
+
lines.push(` if (timeoutMs > 0 && timer.elapsed() >= timeoutMs) {`);
|
|
912
|
+
lines.push(` removeQueuedCallById(queueKey, requestId);`);
|
|
913
|
+
lines.push(` return QVariantMap{`);
|
|
914
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("BridgeTimeoutError")},`);
|
|
915
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("Call timed out while waiting for callback registration.")},`);
|
|
916
|
+
lines.push(` {QStringLiteral("service"), service},`);
|
|
917
|
+
lines.push(` {QStringLiteral("member"), member},`);
|
|
918
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
919
|
+
lines.push(` };`);
|
|
920
|
+
lines.push(` }`);
|
|
921
|
+
lines.push(` tick.start(10);`);
|
|
922
|
+
lines.push(` loop.exec();`);
|
|
923
|
+
lines.push(` }`);
|
|
924
|
+
lines.push(`}`);
|
|
925
|
+
lines.push("");
|
|
926
|
+
lines.push(`bool ${widgetClassName}::hasEmitterListeners(const QString& service, const QString& member) const {`);
|
|
927
|
+
for (const service of spec.services) {
|
|
928
|
+
for (const member of service.members) {
|
|
929
|
+
if (member.kind !== "Emitter")
|
|
930
|
+
continue;
|
|
931
|
+
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
932
|
+
lines.push(` return isSignalConnected(QMetaMethod::fromSignal(&${widgetClassName}::${member.name}));`);
|
|
933
|
+
lines.push(` }`);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
lines.push(` return false;`);
|
|
937
|
+
lines.push(`}`);
|
|
938
|
+
lines.push("");
|
|
939
|
+
lines.push(`void ${widgetClassName}::installBridgeBindings() {`);
|
|
813
940
|
lines.push(` setCallHandler([this](const QString& service, const QString& member, const QVariantList& args) -> QVariant {`);
|
|
814
941
|
lines.push(` return handleGeneratedCall(service, member, args);`);
|
|
815
942
|
lines.push(` });`);
|
|
@@ -821,55 +948,97 @@ function renderCppStub(spec, cppTypes) {
|
|
|
821
948
|
lines.push(` });`);
|
|
822
949
|
lines.push(`}`);
|
|
823
950
|
lines.push("");
|
|
824
|
-
lines.push(`QVariant ${
|
|
951
|
+
lines.push(`QVariant ${widgetClassName}::handleGeneratedCall(const QString& service, const QString& member, const QVariantList& args) {`);
|
|
825
952
|
for (const service of spec.services) {
|
|
826
953
|
for (const member of service.members) {
|
|
827
954
|
if (member.kind !== "Call" || !member.payloadTypeText)
|
|
828
955
|
continue;
|
|
956
|
+
const timeoutMs = member.timeoutMs;
|
|
829
957
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
830
|
-
const pascal = pascalCase(member.name);
|
|
831
958
|
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
832
|
-
lines.push(` if (!m_${member.name}Handler) {`);
|
|
833
|
-
lines.push(` if (property("anqstDesignerContext").toBool()) {`);
|
|
834
|
-
lines.push(` return ${cppToVariantExpression(cppType, designerPlaceholderCppExpression(cppType, member.name))};`);
|
|
835
|
-
lines.push(` }`);
|
|
836
|
-
lines.push(` return QVariant();`);
|
|
837
|
-
lines.push(` }`);
|
|
838
959
|
for (let i = 0; i < member.parameters.length; i++) {
|
|
839
960
|
const p = member.parameters[i];
|
|
840
961
|
const pType = cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name]);
|
|
841
962
|
lines.push(` const ${pType} ${p.name} = ${variantToCppExpression(pType, `args.value(${i})`)};`);
|
|
842
963
|
}
|
|
843
|
-
const
|
|
844
|
-
lines.push(` const
|
|
845
|
-
lines.push(`
|
|
964
|
+
lines.push(` const QString requestId = QStringLiteral("call-%1").arg(++m_callRequestCounter);`);
|
|
965
|
+
lines.push(` const QString queueKey = makeBindingKey(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"));`);
|
|
966
|
+
lines.push(` auto invokeNow = [this, requestId${member.parameters.length > 0 ? `, ${member.parameters.map((p) => p.name).join(", ")}` : ""}]() -> QVariant {`);
|
|
967
|
+
lines.push(` if (!m_${member.name}Handler) {`);
|
|
968
|
+
lines.push(` return QVariantMap{`);
|
|
969
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("HandlerNotRegisteredError")},`);
|
|
970
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("No callback registered for Call endpoint.")},`);
|
|
971
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
972
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
973
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
974
|
+
lines.push(` };`);
|
|
975
|
+
lines.push(` }`);
|
|
976
|
+
lines.push(` try {`);
|
|
977
|
+
const callArgs = member.parameters.map((p) => p.name).join(", ");
|
|
978
|
+
lines.push(` const ${cppType} result = m_${member.name}Handler(${callArgs});`);
|
|
979
|
+
lines.push(` return ${cppToVariantExpression(cppType, "result")};`);
|
|
980
|
+
lines.push(` } catch (const std::exception& ex) {`);
|
|
981
|
+
lines.push(` return QVariantMap{`);
|
|
982
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("CallHandlerError")},`);
|
|
983
|
+
lines.push(` {QStringLiteral("message"), QString::fromUtf8(ex.what())},`);
|
|
984
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
985
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
986
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
987
|
+
lines.push(` };`);
|
|
988
|
+
lines.push(` } catch (...) {`);
|
|
989
|
+
lines.push(` return QVariantMap{`);
|
|
990
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("CallHandlerError")},`);
|
|
991
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("Call handler threw unknown exception.")},`);
|
|
992
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
993
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
994
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
995
|
+
lines.push(` };`);
|
|
996
|
+
lines.push(` }`);
|
|
997
|
+
lines.push(` };`);
|
|
998
|
+
lines.push(` if (m_${member.name}Handler) {`);
|
|
999
|
+
lines.push(` return invokeNow();`);
|
|
1000
|
+
lines.push(` }`);
|
|
1001
|
+
lines.push(` auto& queue = m_queuedCalls[queueKey];`);
|
|
1002
|
+
lines.push(` if (queue.size() >= kMaxQueuedCallsPerEndpoint) {`);
|
|
1003
|
+
lines.push(` queue.dequeue();`);
|
|
1004
|
+
lines.push(` }`);
|
|
1005
|
+
lines.push(` queue.enqueue(PendingCallInvocation{requestId, args, QDateTime::currentDateTimeUtc()});`);
|
|
1006
|
+
lines.push(` return waitForCallHandlerAndInvoke(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), requestId, ${timeoutMs}, invokeNow);`);
|
|
846
1007
|
lines.push(` }`);
|
|
847
1008
|
}
|
|
848
1009
|
}
|
|
849
|
-
lines.push(` return
|
|
1010
|
+
lines.push(` return QVariantMap{`);
|
|
1011
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("HandlerNotRegisteredError")},`);
|
|
1012
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("No Call mapping found.")},`);
|
|
1013
|
+
lines.push(` {QStringLiteral("service"), service},`);
|
|
1014
|
+
lines.push(` {QStringLiteral("member"), member},`);
|
|
1015
|
+
lines.push(` {QStringLiteral("requestId"), QString()}`);
|
|
1016
|
+
lines.push(` };`);
|
|
850
1017
|
lines.push(`}`);
|
|
851
1018
|
lines.push("");
|
|
852
|
-
lines.push(`void ${
|
|
1019
|
+
lines.push(`void ${widgetClassName}::handleGeneratedEmitter(const QString& service, const QString& member, const QVariantList& args) {`);
|
|
1020
|
+
lines.push(` if (!hasEmitterListeners(service, member)) {`);
|
|
1021
|
+
lines.push(` return;`);
|
|
1022
|
+
lines.push(` }`);
|
|
853
1023
|
for (const service of spec.services) {
|
|
854
1024
|
for (const member of service.members) {
|
|
855
1025
|
if (member.kind !== "Emitter")
|
|
856
1026
|
continue;
|
|
857
1027
|
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
858
|
-
lines.push(` if (!m_${member.name}Handler) return;`);
|
|
859
1028
|
for (let i = 0; i < member.parameters.length; i++) {
|
|
860
1029
|
const p = member.parameters[i];
|
|
861
1030
|
const pType = cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name]);
|
|
862
1031
|
lines.push(` const ${pType} ${p.name} = ${variantToCppExpression(pType, `args.value(${i})`)};`);
|
|
863
1032
|
}
|
|
864
1033
|
const argNames = member.parameters.map((p) => p.name).join(", ");
|
|
865
|
-
lines.push(`
|
|
1034
|
+
lines.push(` emit ${member.name}(${argNames});`);
|
|
866
1035
|
lines.push(` return;`);
|
|
867
1036
|
lines.push(` }`);
|
|
868
1037
|
}
|
|
869
1038
|
}
|
|
870
1039
|
lines.push(`}`);
|
|
871
1040
|
lines.push("");
|
|
872
|
-
lines.push(`void ${
|
|
1041
|
+
lines.push(`void ${widgetClassName}::handleGeneratedInput(const QString& service, const QString& member, const QVariant& value) {`);
|
|
873
1042
|
for (const service of spec.services) {
|
|
874
1043
|
for (const member of service.members) {
|
|
875
1044
|
if (member.kind !== "Input" || !member.payloadTypeText)
|
|
@@ -888,20 +1057,8 @@ function renderCppStub(spec, cppTypes) {
|
|
|
888
1057
|
for (const service of spec.services) {
|
|
889
1058
|
for (const member of service.members) {
|
|
890
1059
|
const memberPascal = pascalCase(member.name);
|
|
891
|
-
if (
|
|
892
|
-
lines.push(`void ${
|
|
893
|
-
lines.push(` m_${member.name}Handler = handler;`);
|
|
894
|
-
lines.push("}");
|
|
895
|
-
lines.push("");
|
|
896
|
-
}
|
|
897
|
-
else if (member.kind === "Emitter") {
|
|
898
|
-
lines.push(`void ${spec.widgetName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
899
|
-
lines.push(` m_${member.name}Handler = handler;`);
|
|
900
|
-
lines.push("}");
|
|
901
|
-
lines.push("");
|
|
902
|
-
}
|
|
903
|
-
else if (member.kind === "Input" && member.payloadTypeText) {
|
|
904
|
-
lines.push(`void ${spec.widgetName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
1060
|
+
if (member.kind === "Input" && member.payloadTypeText) {
|
|
1061
|
+
lines.push(`void ${widgetClassName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
905
1062
|
lines.push(` m_${member.name}Handler = handler;`);
|
|
906
1063
|
lines.push("}");
|
|
907
1064
|
lines.push("");
|
|
@@ -909,8 +1066,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
909
1066
|
if (member.kind === "Slot") {
|
|
910
1067
|
const ret = member.payloadTypeText ? cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]) : "void";
|
|
911
1068
|
const args = member.parameters.map((p) => `${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])} ${p.name}`).join(", ");
|
|
912
|
-
|
|
913
|
-
lines.push(`${ret} ${spec.widgetName}::${member.name}(${argsWithMeta}) {`);
|
|
1069
|
+
lines.push(`${ret} ${widgetClassName}::slot_${member.name}(${args}) {`);
|
|
914
1070
|
lines.push(` QVariantList invokeArgs;`);
|
|
915
1071
|
for (const p of member.parameters) {
|
|
916
1072
|
const pType = mapTsTypeToCpp(p.typeText);
|
|
@@ -919,14 +1075,18 @@ function renderCppStub(spec, cppTypes) {
|
|
|
919
1075
|
lines.push(` QVariant result;`);
|
|
920
1076
|
lines.push(` QString invokeError;`);
|
|
921
1077
|
lines.push(` const bool success = invokeSlot(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), invokeArgs, &result, &invokeError);`);
|
|
922
|
-
lines.push(` if (
|
|
923
|
-
lines.push(`
|
|
1078
|
+
lines.push(` if (!success) {`);
|
|
1079
|
+
lines.push(` if (invokeError == QStringLiteral("slot invocation timeout")) {`);
|
|
1080
|
+
lines.push(` const QString timeoutMsg = QStringLiteral("[Timeout] ${service.name}.${member.name}: The webapp inside the widget did not anwser within %1 ms.").arg(slotInvocationTimeoutMs());`);
|
|
1081
|
+
lines.push(` throw std::runtime_error(timeoutMsg.toStdString());`);
|
|
1082
|
+
lines.push(` }`);
|
|
1083
|
+
lines.push(` const QString requestFailed = QStringLiteral("[RequestFailed]: %1").arg(invokeError);`);
|
|
1084
|
+
lines.push(` throw std::runtime_error(requestFailed.toStdString());`);
|
|
1085
|
+
lines.push(` }`);
|
|
924
1086
|
if (ret === "void") {
|
|
925
|
-
lines.push(` if (!success) return;`);
|
|
926
1087
|
lines.push(` return;`);
|
|
927
1088
|
}
|
|
928
1089
|
else {
|
|
929
|
-
lines.push(` if (!success) return ${ret}{};`);
|
|
930
1090
|
lines.push(` return ${variantToCppExpression(ret, "result")};`);
|
|
931
1091
|
}
|
|
932
1092
|
lines.push("}");
|
|
@@ -935,11 +1095,11 @@ function renderCppStub(spec, cppTypes) {
|
|
|
935
1095
|
else if ((member.kind === "Input" || member.kind === "Output") && member.payloadTypeText) {
|
|
936
1096
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
937
1097
|
const cap = member.name.charAt(0).toUpperCase() + member.name.slice(1);
|
|
938
|
-
lines.push(`${cppType} ${
|
|
1098
|
+
lines.push(`${cppType} ${widgetClassName}::${member.name}() const {`);
|
|
939
1099
|
lines.push(` return m_${member.name};`);
|
|
940
1100
|
lines.push("}");
|
|
941
1101
|
lines.push("");
|
|
942
|
-
lines.push(`void ${
|
|
1102
|
+
lines.push(`void ${widgetClassName}::set${cap}(const ${cppType}& value) {`);
|
|
943
1103
|
lines.push(` if (m_${member.name} == value) return;`);
|
|
944
1104
|
lines.push(` m_${member.name} = value;`);
|
|
945
1105
|
if (member.kind === "Output") {
|
|
@@ -949,7 +1109,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
949
1109
|
lines.push("}");
|
|
950
1110
|
lines.push("");
|
|
951
1111
|
if (member.kind === "Output") {
|
|
952
|
-
lines.push(`void ${
|
|
1112
|
+
lines.push(`void ${widgetClassName}::${member.name}Slot(const ${cppType}& value) {`);
|
|
953
1113
|
lines.push(` set${cap}(value);`);
|
|
954
1114
|
lines.push(`}`);
|
|
955
1115
|
lines.push("");
|
|
@@ -957,7 +1117,16 @@ function renderCppStub(spec, cppTypes) {
|
|
|
957
1117
|
}
|
|
958
1118
|
}
|
|
959
1119
|
}
|
|
960
|
-
lines.push(`}
|
|
1120
|
+
lines.push(`void ${widgetClassName}::connectNotify(const QMetaMethod& signal) {`);
|
|
1121
|
+
lines.push(` AnQstWebHostBase::connectNotify(signal);`);
|
|
1122
|
+
lines.push(` Q_UNUSED(signal);`);
|
|
1123
|
+
lines.push(`}`);
|
|
1124
|
+
lines.push("");
|
|
1125
|
+
lines.push(`void ${widgetClassName}::disconnectNotify(const QMetaMethod& signal) {`);
|
|
1126
|
+
lines.push(` AnQstWebHostBase::disconnectNotify(signal);`);
|
|
1127
|
+
lines.push(` Q_UNUSED(signal);`);
|
|
1128
|
+
lines.push(`}`);
|
|
1129
|
+
lines.push("");
|
|
961
1130
|
return lines.join("\n");
|
|
962
1131
|
}
|
|
963
1132
|
function renderCMake(spec) {
|
|
@@ -977,6 +1146,7 @@ add_library(${spec.widgetName}Widget
|
|
|
977
1146
|
${spec.widgetName}.cpp
|
|
978
1147
|
${spec.widgetName}.qrc
|
|
979
1148
|
include/${spec.widgetName}.h
|
|
1149
|
+
include/${spec.widgetName}Widget.h
|
|
980
1150
|
include/${spec.widgetName}Types.h
|
|
981
1151
|
)
|
|
982
1152
|
target_include_directories(${spec.widgetName}Widget
|
|
@@ -1002,24 +1172,7 @@ function normalizeSlashes(value) {
|
|
|
1002
1172
|
return value.split(node_path_1.default.sep).join("/");
|
|
1003
1173
|
}
|
|
1004
1174
|
function resolveActiveBuildStamp() {
|
|
1005
|
-
|
|
1006
|
-
if (fromEnv && fromEnv.length > 0) {
|
|
1007
|
-
return fromEnv;
|
|
1008
|
-
}
|
|
1009
|
-
const activePath = node_path_1.default.resolve(__dirname, "..", "..", ".anqstgen-version-active.json");
|
|
1010
|
-
if (!node_fs_1.default.existsSync(activePath)) {
|
|
1011
|
-
return "";
|
|
1012
|
-
}
|
|
1013
|
-
try {
|
|
1014
|
-
const parsed = JSON.parse(node_fs_1.default.readFileSync(activePath, "utf8"));
|
|
1015
|
-
if (typeof parsed.active === "string" && parsed.active.trim().length > 0) {
|
|
1016
|
-
return parsed.active.trim();
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
catch {
|
|
1020
|
-
return "";
|
|
1021
|
-
}
|
|
1022
|
-
return "";
|
|
1175
|
+
return build_stamp_1.ANQST_BUILD_STAMP.trim();
|
|
1023
1176
|
}
|
|
1024
1177
|
function withBuildStamp(relativePath, content) {
|
|
1025
1178
|
const stamp = resolveActiveBuildStamp();
|
|
@@ -1114,6 +1267,12 @@ function renderLocalTypeImports(spec) {
|
|
|
1114
1267
|
return "";
|
|
1115
1268
|
return `import type { ${localTypeNames.join(", ")} } from "./types";`;
|
|
1116
1269
|
}
|
|
1270
|
+
function slotHandlerReturnType(tsRet) {
|
|
1271
|
+
if (tsRet === "void") {
|
|
1272
|
+
return "void | Promise<void> | Error";
|
|
1273
|
+
}
|
|
1274
|
+
return `${tsRet} | Promise<${tsRet}> | Error`;
|
|
1275
|
+
}
|
|
1117
1276
|
function renderTsService(spec, serviceName) {
|
|
1118
1277
|
const members = spec.services.find((s) => s.name === serviceName)?.members ?? [];
|
|
1119
1278
|
const fieldLines = [];
|
|
@@ -1137,7 +1296,7 @@ function renderTsService(spec, serviceName) {
|
|
|
1137
1296
|
}
|
|
1138
1297
|
if (m.kind === "Slot") {
|
|
1139
1298
|
const ret = mapTypeTextToTs(m.payloadTypeText ?? "void");
|
|
1140
|
-
onSlotMembers.push(` ${m.name}: (handler: (${args}) => ${ret}): void => {`);
|
|
1299
|
+
onSlotMembers.push(` ${m.name}: (handler: (${args}) => ${slotHandlerReturnType(ret)}): void => {`);
|
|
1141
1300
|
onSlotMembers.push(` this._bridge.registerSlot("${serviceName}", "${m.name}", handler as (...args: unknown[]) => unknown);`);
|
|
1142
1301
|
onSlotMembers.push(" },");
|
|
1143
1302
|
continue;
|
|
@@ -1197,7 +1356,7 @@ function renderTsServiceDts(spec, serviceName) {
|
|
|
1197
1356
|
}
|
|
1198
1357
|
if (m.kind === "Slot") {
|
|
1199
1358
|
const ret = mapTypeTextToTs(m.payloadTypeText ?? "void");
|
|
1200
|
-
onSlotMembers.push(` ${m.name}(handler: (${args}) => ${ret}): void;`);
|
|
1359
|
+
onSlotMembers.push(` ${m.name}(handler: (${args}) => ${slotHandlerReturnType(ret)}): void;`);
|
|
1201
1360
|
continue;
|
|
1202
1361
|
}
|
|
1203
1362
|
if ((m.kind === "Input" || m.kind === "Output") && m.payloadTypeText) {
|
|
@@ -1267,6 +1426,24 @@ interface BridgeAdapter {
|
|
|
1267
1426
|
onSlotInvocation(handler: SlotInvocationListener): void;
|
|
1268
1427
|
}
|
|
1269
1428
|
|
|
1429
|
+
function isBridgeCallError(value: unknown): value is {
|
|
1430
|
+
code: unknown;
|
|
1431
|
+
message: unknown;
|
|
1432
|
+
service: unknown;
|
|
1433
|
+
member: unknown;
|
|
1434
|
+
requestId: unknown;
|
|
1435
|
+
} {
|
|
1436
|
+
if (value === null || typeof value !== "object") return false;
|
|
1437
|
+
const row = value as Record<string, unknown>;
|
|
1438
|
+
return (
|
|
1439
|
+
Object.prototype.hasOwnProperty.call(row, "code")
|
|
1440
|
+
&& Object.prototype.hasOwnProperty.call(row, "message")
|
|
1441
|
+
&& Object.prototype.hasOwnProperty.call(row, "service")
|
|
1442
|
+
&& Object.prototype.hasOwnProperty.call(row, "member")
|
|
1443
|
+
&& Object.prototype.hasOwnProperty.call(row, "requestId")
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1270
1447
|
class QtWebChannelAdapter implements BridgeAdapter {
|
|
1271
1448
|
private constructor(private readonly host: HostBridgeApi) {}
|
|
1272
1449
|
|
|
@@ -1300,8 +1477,14 @@ class QtWebChannelAdapter implements BridgeAdapter {
|
|
|
1300
1477
|
}
|
|
1301
1478
|
|
|
1302
1479
|
async call<T>(service: string, member: string, args: unknown[]): Promise<T> {
|
|
1303
|
-
return new Promise<T>((resolve) => {
|
|
1304
|
-
this.host.anQstBridge_call(service, member, args, (result) =>
|
|
1480
|
+
return new Promise<T>((resolve, reject) => {
|
|
1481
|
+
this.host.anQstBridge_call(service, member, args, (result) => {
|
|
1482
|
+
if (isBridgeCallError(result)) {
|
|
1483
|
+
reject(result);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
resolve(result as T);
|
|
1487
|
+
});
|
|
1305
1488
|
});
|
|
1306
1489
|
}
|
|
1307
1490
|
|
|
@@ -1331,7 +1514,13 @@ class QtWebChannelAdapter implements BridgeAdapter {
|
|
|
1331
1514
|
}
|
|
1332
1515
|
|
|
1333
1516
|
class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
1334
|
-
private readonly pending = new Map<string,
|
|
1517
|
+
private readonly pending = new Map<string, {
|
|
1518
|
+
service: string;
|
|
1519
|
+
member: string;
|
|
1520
|
+
requestId: string;
|
|
1521
|
+
resolve: (result: unknown) => void;
|
|
1522
|
+
reject: (error: unknown) => void;
|
|
1523
|
+
}>();
|
|
1335
1524
|
private readonly outputListeners: OutputListener[] = [];
|
|
1336
1525
|
private readonly slotListeners: SlotInvocationListener[] = [];
|
|
1337
1526
|
private requestCounter = 0;
|
|
@@ -1343,10 +1532,15 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1343
1532
|
const type = String(message["type"] ?? "");
|
|
1344
1533
|
if (type === "callResult") {
|
|
1345
1534
|
const requestId = String(message["requestId"] ?? "");
|
|
1346
|
-
const
|
|
1347
|
-
if (
|
|
1535
|
+
const pending = this.pending.get(requestId);
|
|
1536
|
+
if (pending) {
|
|
1348
1537
|
this.pending.delete(requestId);
|
|
1349
|
-
|
|
1538
|
+
const result = message["result"];
|
|
1539
|
+
if (isBridgeCallError(result)) {
|
|
1540
|
+
pending.reject(result);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
pending.resolve(result);
|
|
1350
1544
|
}
|
|
1351
1545
|
return;
|
|
1352
1546
|
}
|
|
@@ -1377,6 +1571,18 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1377
1571
|
this.socket.close();
|
|
1378
1572
|
}
|
|
1379
1573
|
});
|
|
1574
|
+
this.socket.addEventListener("close", () => {
|
|
1575
|
+
for (const pending of this.pending.values()) {
|
|
1576
|
+
pending.reject({
|
|
1577
|
+
code: "BridgeDisconnectedError",
|
|
1578
|
+
message: "Bridge disconnected before call completion.",
|
|
1579
|
+
service: pending.service,
|
|
1580
|
+
member: pending.member,
|
|
1581
|
+
requestId: pending.requestId
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
this.pending.clear();
|
|
1585
|
+
});
|
|
1380
1586
|
}
|
|
1381
1587
|
|
|
1382
1588
|
static async create(): Promise<WebSocketBridgeAdapter> {
|
|
@@ -1408,8 +1614,14 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1408
1614
|
async call<T>(service: string, member: string, args: unknown[]): Promise<T> {
|
|
1409
1615
|
const requestId = \`req-\${++this.requestCounter}\`;
|
|
1410
1616
|
const payload = { type: "call", requestId, service, member, args };
|
|
1411
|
-
return await new Promise<T>((resolve) => {
|
|
1412
|
-
this.pending.set(requestId,
|
|
1617
|
+
return await new Promise<T>((resolve, reject) => {
|
|
1618
|
+
this.pending.set(requestId, {
|
|
1619
|
+
service,
|
|
1620
|
+
member,
|
|
1621
|
+
requestId,
|
|
1622
|
+
resolve: (value) => resolve(value as T),
|
|
1623
|
+
reject
|
|
1624
|
+
});
|
|
1413
1625
|
this.socket.send(JSON.stringify(payload));
|
|
1414
1626
|
});
|
|
1415
1627
|
}
|
|
@@ -1520,7 +1732,7 @@ class AnQstBridgeRuntime {
|
|
|
1520
1732
|
outputHandler(value);
|
|
1521
1733
|
}
|
|
1522
1734
|
});
|
|
1523
|
-
this.adapter.onSlotInvocation((requestId, service, member, args) => {
|
|
1735
|
+
this.adapter.onSlotInvocation(async (requestId, service, member, args) => {
|
|
1524
1736
|
const key = this.key(service, member);
|
|
1525
1737
|
const handler = this.slotHandlers.get(key);
|
|
1526
1738
|
if (handler === undefined) {
|
|
@@ -1528,10 +1740,15 @@ class AnQstBridgeRuntime {
|
|
|
1528
1740
|
return;
|
|
1529
1741
|
}
|
|
1530
1742
|
try {
|
|
1531
|
-
const result = handler(...args);
|
|
1743
|
+
const result = await Promise.resolve(handler(...args));
|
|
1744
|
+
if (result instanceof Error) {
|
|
1745
|
+
this.adapter!.resolveSlot(requestId, false, undefined, result.message);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1532
1748
|
this.adapter!.resolveSlot(requestId, true, result, "");
|
|
1533
1749
|
} catch (error) {
|
|
1534
|
-
|
|
1750
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1751
|
+
this.adapter!.resolveSlot(requestId, false, undefined, message);
|
|
1535
1752
|
}
|
|
1536
1753
|
});
|
|
1537
1754
|
for (const key of this.slotHandlers.keys()) {
|
|
@@ -1764,7 +1981,7 @@ function renderNodeExpressWsIndex(spec) {
|
|
|
1764
1981
|
sendJson(session.socket, {
|
|
1765
1982
|
type: "callResult",
|
|
1766
1983
|
requestId,
|
|
1767
|
-
result: {
|
|
1984
|
+
result: { code: "HandlerNotRegisteredError", message: err.message, service, member, requestId }
|
|
1768
1985
|
});
|
|
1769
1986
|
throw err;
|
|
1770
1987
|
}
|
|
@@ -1786,7 +2003,7 @@ function renderNodeExpressWsIndex(spec) {
|
|
|
1786
2003
|
sendJson(session.socket, {
|
|
1787
2004
|
type: "callResult",
|
|
1788
2005
|
requestId,
|
|
1789
|
-
result: {
|
|
2006
|
+
result: { code: "CallHandlerError", message, service, member, requestId }
|
|
1790
2007
|
});
|
|
1791
2008
|
});
|
|
1792
2009
|
return;
|
|
@@ -2138,7 +2355,7 @@ export interface ${spec.widgetName}NodeBridge {
|
|
|
2138
2355
|
export function create${spec.widgetName}NodeExpressWsBridge(options: ${spec.widgetName}NodeBridgeOptions): ${spec.widgetName}NodeBridge {
|
|
2139
2356
|
const wsPath = options.wsPath ?? "/anqst-bridge";
|
|
2140
2357
|
const devConfigPath = options.devConfigPath ?? "/anqst-dev-config.json";
|
|
2141
|
-
const defaultSlotTimeoutMs = options.defaultSlotTimeoutMs ??
|
|
2358
|
+
const defaultSlotTimeoutMs = options.defaultSlotTimeoutMs ?? 1000;
|
|
2142
2359
|
const maxQueuedPerSlot = options.maxQueuedSlotInvocationsPerSlot ?? 1024;
|
|
2143
2360
|
const sessions = new Map<WebSocket, ${spec.widgetName}NodeSession>();
|
|
2144
2361
|
const diagnosticListeners = new Set<(diagnostic: AnQstDiagnostic) => void>();
|
|
@@ -2230,7 +2447,7 @@ ${callDispatch}
|
|
|
2230
2447
|
sendJson(session.socket, {
|
|
2231
2448
|
type: "callResult",
|
|
2232
2449
|
requestId,
|
|
2233
|
-
result: {
|
|
2450
|
+
result: { code: "HandlerNotRegisteredError", message: err.message, service, member, requestId }
|
|
2234
2451
|
});
|
|
2235
2452
|
throw err;
|
|
2236
2453
|
}
|
|
@@ -2363,7 +2580,8 @@ function generateOutputs(spec, options = { emitQWidget: true, emitAngularService
|
|
|
2363
2580
|
const cppTypes = buildCppTypeContext(spec);
|
|
2364
2581
|
outputs[`${cppDir}/CMakeLists.txt`] = renderCMake(spec);
|
|
2365
2582
|
outputs[`${cppDir}/${spec.widgetName}.qrc`] = renderEmbeddedQrc(spec.widgetName, []);
|
|
2366
|
-
outputs[`${cppDir}/include/${spec.widgetName}.h`] =
|
|
2583
|
+
outputs[`${cppDir}/include/${spec.widgetName}.h`] = renderWidgetUmbrellaHeader(spec);
|
|
2584
|
+
outputs[`${cppDir}/include/${spec.widgetName}Widget.h`] = renderWidgetHeader(spec, cppTypes);
|
|
2367
2585
|
outputs[`${cppDir}/include/${spec.widgetName}Types.h`] = renderTypesHeader(spec, cppTypes);
|
|
2368
2586
|
outputs[`${cppDir}/${spec.widgetName}.cpp`] = renderCppStub(spec, cppTypes);
|
|
2369
2587
|
}
|
|
@@ -2579,6 +2797,7 @@ add_custom_command(
|
|
|
2579
2797
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2580
2798
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2581
2799
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2800
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2582
2801
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2583
2802
|
"\${${generatedRootVar}}/webapp/index.html"
|
|
2584
2803
|
COMMAND "\${ANQST_NPM_EXECUTABLE}" install
|
|
@@ -2594,6 +2813,7 @@ add_custom_target(${autogenTarget}
|
|
|
2594
2813
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2595
2814
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2596
2815
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2816
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2597
2817
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2598
2818
|
"\${${generatedRootVar}}/webapp/index.html"
|
|
2599
2819
|
)
|
|
@@ -2602,6 +2822,7 @@ set_source_files_properties(
|
|
|
2602
2822
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2603
2823
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2604
2824
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2825
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2605
2826
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2606
2827
|
PROPERTIES GENERATED TRUE
|
|
2607
2828
|
)
|
|
@@ -2610,6 +2831,7 @@ add_library(${widgetTarget}
|
|
|
2610
2831
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2611
2832
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2612
2833
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2834
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2613
2835
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2614
2836
|
)
|
|
2615
2837
|
add_dependencies(${widgetTarget} ${autogenTarget})
|
|
@@ -2797,7 +3019,7 @@ function installDesignerPluginIconAssets(cwd, pluginDir) {
|
|
|
2797
3019
|
}
|
|
2798
3020
|
function renderQtDesignerPluginCpp(widgetName, widgetCategory, hasIcon) {
|
|
2799
3021
|
const pluginClass = `${widgetName}DesignerPlugin`;
|
|
2800
|
-
const widgetClass = `${widgetName}
|
|
3022
|
+
const widgetClass = `${widgetName}Widget`;
|
|
2801
3023
|
const groupName = escapeCppStringLiteral(widgetCategory);
|
|
2802
3024
|
const iconExpression = hasIcon
|
|
2803
3025
|
? 'QIcon(QStringLiteral(":/anqstdesignerplugin/plugin-icon.png"))'
|