Argument for BrowserBridge methods is stringified JSON array of stringified JSON parameters - updated to facilitate import:

- Classes potentially used as JS argument templates can define this state by subclassing JSArgumentBase
- JSBridgeArgumentWrap now unpacks and deserialises each stringified parameter
- Argument template state automatically applied as argument types are defined
This commit is contained in:
Ralph Wessel
2024-08-27 23:47:30 +01:00
parent 2ca1713766
commit 550e9caa9c
11 changed files with 99 additions and 18 deletions
@@ -1,7 +1,6 @@
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.h"
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
using namespace active::container;
@@ -1,7 +1,6 @@
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h"
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Connector/Database/Model/Card/ModelCardDatabase.h"
using namespace active::container;
@@ -1,6 +1,7 @@
#include "Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/PackageWrap.h"
#include <array>
@@ -11,11 +12,13 @@ namespace {
///Serialisation fields
enum FieldIndex {
arg0,
darkTheme,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"0"},
Identity{"DarkTheme"},
};
@@ -30,6 +33,9 @@ namespace {
--------------------------------------------------------------------*/
bool ConnectorConfig::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
//When used as an argument template, this wrapper is expected to be first in the list
if (isArgumentTemplate())
inventory.merge({ fieldID[arg0], arg0, element });
inventory.merge(Inventory{
{
{ fieldID[darkTheme], darkTheme, element },
@@ -51,6 +57,9 @@ Cargo::Unique ConnectorConfig::getCargo(const Inventory::Item& item) const {
return nullptr;
using namespace active::serialise;
switch (item.index) {
case arg0:
//This structure is the first argument
return std::make_unique<PackageWrap>(*this);
case darkTheme:
return std::make_unique<ValueWrap<bool>>(isDarkTheme);
default:
@@ -2,13 +2,14 @@
#define CONNECTOR_INTERFACE_BRIDGE_CONNECTOR_CONFIG
#include "Active/Serialise/Package/Package.h"
#include "Speckle/Interface/Browser/Bridge/JSArgumentBase.h"
namespace connector::interfac::browser::bridge {
/*!
Configuration settings class
*/
class ConnectorConfig : public active::serialise::Package {
class ConnectorConfig : public active::serialise::Package, virtual public speckle::interfac::browser::bridge::JSArgumentBase {
public:
// MARK: - Types
@@ -29,11 +29,7 @@ namespace connector::interfac::browser::bridge {
speckle::utility::String ID;
int32_t count = 0;
bool testBool = false;
/* Id = GetHashCode() + " - I am a string",
count = GetHashCode(),
thisIsABoolean = false
*/
// MARK: - Serialisation
/*!
@@ -17,11 +17,11 @@ namespace {
isHelloID,
};
///Serialisation field IDs
///Serialisation field IDs. NB: This structure is never exported, so we only define the incoming argument indices
static std::array fieldID = {
Identity{"name"},
Identity{"count"},
Identity{"sayHelloNotHi"},
Identity{"0"},
Identity{"1"},
Identity{"2"},
};
}
@@ -0,0 +1,44 @@
#ifndef SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT_BASE
#define SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT_BASE
#include "Active/Serialise/Package/Package.h"
#include "Speckle/Utility/String.h"
namespace speckle::interfac::browser::bridge {
/*!
Interface for objects used as arguments for JS bridge arguments
Enables deserialisation to recognise individual parameters in the serialised JS method aergument, e.g. "0", "1", etc
*/
class JSArgumentBase {
public:
/*!
Destructor
*/
virtual ~JSArgumentBase() {}
// MARK: - Functions (const)
/*!
Determine if the object is used as an argument template
@return True if the object is used as an argument template
*/
bool isArgumentTemplate() const { return m_isArgumentTemplate; }
// MARK: - Functions (mutating)
/*!
Set whether the object is used as an argument template
@param state True if the object is used as an argument template
*/
void setArgumentTemplate(bool state) { m_isArgumentTemplate = state; }
private:
///True if the object is used as an argument template
bool m_isArgumentTemplate = false;
};
}
#endif //SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT_BASE
@@ -2,6 +2,7 @@
#define SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT
#include "Active/Serialise/Package/Package.h"
#include "Speckle/Interface/Browser/Bridge/JSArgumentBase.h"
#include "Speckle/Utility/String.h"
namespace speckle::interfac::browser::bridge {
@@ -95,13 +96,18 @@ namespace speckle::interfac::browser::bridge {
class JSArgType : public JSBridgeArgument {
public:
using JSBridgeArgument::JSBridgeArgument;
JSArgType() {
//Tag the argument object as a template where possible
if (auto arg = dynamic_cast<JSArgumentBase*>(&value); arg != nullptr)
arg->setArgumentTemplate(true);
}
/*!
Copy constructor
@param source The object to copy
*/
JSArgType(const JSArgType& source) : JSBridgeArgument{ source }, value{ source.value } {}
JSArgType(const JSArgType& source) : JSBridgeArgument{source}, value{source.value} {}
T value;
};
@@ -2,11 +2,13 @@
#include "Active/Serialise/Inventory/Inventory.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/ValueSettingWrap.h"
#include "Active/Serialise/JSON/JSONTransport.h"
#include "Active/Utility/BufferIn.h"
using namespace active::serialise;
using namespace active::serialise::json;
using namespace active::setting;
using namespace speckle::interfac::browser::bridge;
using namespace speckle::utility;
@@ -41,7 +43,7 @@ namespace {
{ {"arg"}, args, 0, std::nullopt, true }, //The JS arguments are expressed as a flat array - use the array indices to map to expected vars
},
}.withType(&typeid(JSBridgeArgumentWrap));;
}
/*--------------------------------------------------------------------
@@ -131,7 +133,24 @@ std::unique_ptr<JSBridgeArgument> JSBridgeArgumentWrap::makeArgument(const Strin
if (auto maker = m_argumentFactory.find(methodID); (maker != m_argumentFactory.end())) {
if (auto result = reinterpret_cast<JSBridgeArgument*>(maker->second(methodID, requestID)); result != nullptr) {
try {
JSONTransport().receive(std::forward<Cargo&&>(*result), Identity{}, argument);
//The argument is passed as an array of stringified JSON - first unpack the array
JSONTransport transport;
ValueSetting args;
transport.receive(ValueSettingWrap{args}, Identity{}, argument);
//Then unify the argument strings into a single JSON argument
String unifiedArgument{"{"};
int32_t argIndex = 0;
bool isFirst = false;
for (auto& arg : args.operator std::vector<active::utility::String>()) {
if (isFirst)
isFirst = false;
else
unifiedArgument += ",";
unifiedArgument += "\"" + String{argIndex++} + "\":" + JSONTransport::convertFromJSONString(arg);
}
unifiedArgument += "}";
//And receive the unified argument into the methiod argument
transport.receive(std::forward<Cargo&&>(*result), Identity{}, unifiedArgument);
return std::unique_ptr<JSBridgeArgument>{result};
} catch(std::runtime_error e) {
//Populating the error cancels the method
@@ -19,7 +19,11 @@ namespace speckle::interfac::browser::bridge {
template<typename T>
void* constructArgument(const speckle::utility::String& method, const speckle::utility::String& request) {
try {
return new T(method, request);
auto result = new T(method, request);
//Tag the argument object as a template where possible
if (auto arg = dynamic_cast<JSArgumentBase*>(result); arg != nullptr)
arg->setArgumentTemplate(true);
return result;
} catch(...) {
return nullptr; //Object constructors should throw an exception if incoming data isn't viable (NB: only use for unrecoverable problems)
}
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
210CC86F2C7E879700610F58 /* JSArgumentBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 210CC86D2C7E879700610F58 /* JSArgumentBase.h */; };
212A88132AE48821001EAFE7 /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; platformFilters = (macos, ); };
2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351782C624FC100E5A69C /* MenuSubscriber.cpp */; };
2193518C2C62655700E5A69C /* MenuEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 219351892C62655700E5A69C /* MenuEvent.h */; };
@@ -69,6 +70,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
210CC86D2C7E879700610F58 /* JSArgumentBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSArgumentBase.h; sourceTree = "<group>"; };
212A87EF2AE4868C001EAFE7 /* SpeckleLib-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SpeckleLib-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
21329F472BFA611C00B5C7AF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
21329F632BFD452C00B5C7AF /* Environment.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Environment.md; sourceTree = "<group>"; };
@@ -312,6 +314,7 @@
21F69F4A2C6CCC25008B6A06 /* BrowserBridge.cpp */,
21F69F4B2C6CCC25008B6A06 /* BrowserBridge.h */,
21F69F582C6CDAEE008B6A06 /* Functions */,
210CC86D2C7E879700610F58 /* JSArgumentBase.h */,
21F69FA52C733EDA008B6A06 /* JSBridgeArgument.cpp */,
21F69F4D2C6CCC25008B6A06 /* JSBridgeArgument.h */,
21F69F802C6FF3B0008B6A06 /* JSBridgeArgumentWrap.cpp */,
@@ -385,6 +388,7 @@
buildActionMask = 2147483647;
files = (
21F69F5A2C6CDB67008B6A06 /* FunctionBinding.h in Headers */,
210CC86F2C7E879700610F58 /* JSArgumentBase.h in Headers */,
21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */,
21B67D002C7CE15100FD64FC /* Exception.h in Headers */,
2193518C2C62655700E5A69C /* MenuEvent.h in Headers */,