mirror of
https://github.com/corda/corda.git
synced 2025-06-14 21:28:14 +00:00
NOTICK: Add BlobWriter and Schema Dumper
The Blob Writer is a small kotlin app that allows arbitrary things to be serialized and then those bytes written to a file, quite useful for working on non JVM parsing of such things. Along a similar vein, add a schema dumper alongside the blob-inspector to highlight the contents of the header
This commit is contained in:
27
experimental/blobwriter/build.gradle
Normal file
27
experimental/blobwriter/build.gradle
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
apply plugin : 'kotlin'
|
||||||
|
apply plugin : 'application'
|
||||||
|
|
||||||
|
mainClassName = "net.corda.blobwriter.BlobWriter.kt"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':tools:cliutils')
|
||||||
|
compile project(":common-logging")
|
||||||
|
compile project(':serialization')
|
||||||
|
|
||||||
|
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
|
||||||
|
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from (configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {
|
||||||
|
exclude "META-INF/*.SF"
|
||||||
|
exclude "META-INF/*.DSA"
|
||||||
|
exclude "META-INF/*.RSA"
|
||||||
|
}
|
||||||
|
baseName = "blobwriter"
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
'Main-Class': 'net.corda.blobwriter.BlobWriterKt'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package net.corda.blobwriter
|
||||||
|
|
||||||
|
import net.corda.core.serialization.SerializationContext
|
||||||
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
|
import net.corda.core.serialization.internal.SerializationEnvironment
|
||||||
|
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||||
|
import net.corda.core.serialization.serialize
|
||||||
|
import net.corda.serialization.internal.*
|
||||||
|
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
|
||||||
|
import net.corda.serialization.internal.amqp.amqpMagic
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object AMQPInspectorSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) {
|
||||||
|
override fun canDeserializeVersion (
|
||||||
|
magic: CordaSerializationMagic,
|
||||||
|
target: SerializationContext.UseCase
|
||||||
|
): Boolean {
|
||||||
|
return magic == amqpMagic
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
|
||||||
|
override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
val BLOB_WRITER_CONTEXT = SerializationContextImpl(
|
||||||
|
amqpMagic,
|
||||||
|
SerializationDefaults.javaClass.classLoader,
|
||||||
|
AllWhitelist,
|
||||||
|
emptyMap(),
|
||||||
|
true,
|
||||||
|
SerializationContext.UseCase.P2P,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
fun initialiseSerialization() {
|
||||||
|
_contextSerializationEnv.set (
|
||||||
|
SerializationEnvironment.with (
|
||||||
|
SerializationFactoryImpl().apply {
|
||||||
|
registerScheme (AMQPInspectorSerializationScheme)
|
||||||
|
},
|
||||||
|
p2pContext = BLOB_WRITER_CONTEXT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class _i_ (val a: Int)
|
||||||
|
data class _is_ (val a: Int, val b: String)
|
||||||
|
data class _i_is__ (val a: Int, val b: _is_)
|
||||||
|
data class _Li_ (val a: List<Int>)
|
||||||
|
data class _Mis_ (val a: Map<Int, String>)
|
||||||
|
|
||||||
|
fun main (args: Array<String>) {
|
||||||
|
initialiseSerialization()
|
||||||
|
|
||||||
|
File("../cpp-serializer/bin/blob-inspector/test/_i_is__").writeBytes(_i_is__(1, _is_ (2, "three")).serialize().bytes)
|
||||||
|
File("../cpp-serializer/bin/blob-inspector/test/_Li_").writeBytes(_Li_(listOf (1, 2, 3, 4, 5, 6)).serialize().bytes)
|
||||||
|
File("../cpp-serializer/bin/blob-inspector/test/_Mis_").writeBytes(_Mis_(
|
||||||
|
mapOf (1 to "two", 3 to "four", 5 to "six")).serialize().bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,2 @@
|
|||||||
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src)
|
ADD_SUBDIRECTORY (blob-inspector)
|
||||||
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src/amqp)
|
ADD_SUBDIRECTORY (schema-dumper)
|
||||||
|
|
||||||
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
|
|
||||||
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/proton)
|
|
||||||
|
|
||||||
add_executable (blob-inspector main)
|
|
||||||
|
|
||||||
target_link_libraries (blob-inspector amqp proton qpid-proton)
|
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src)
|
||||||
|
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src/amqp)
|
||||||
|
|
||||||
|
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
|
||||||
|
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/proton)
|
||||||
|
|
||||||
|
add_executable (blob-inspector main)
|
||||||
|
|
||||||
|
target_link_libraries (blob-inspector amqp proton qpid-proton)
|
@ -75,7 +75,6 @@ data_and_stop(std::ifstream & f_, ssize_t sz) {
|
|||||||
<< reader->dump ("{ Parsed", d, envelope->schema())->dump()
|
<< reader->dump ("{ Parsed", d, envelope->schema())->dump()
|
||||||
<< " }" << std::endl;
|
<< " }" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +103,9 @@ main (int argc, char **argv) {
|
|||||||
if (encoding == amqp::DATA_AND_STOP) {
|
if (encoding == amqp::DATA_AND_STOP) {
|
||||||
data_and_stop(f, results.st_size - 8);
|
data_and_stop(f, results.st_size - 8);
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "BAD ENCODING " << encoding << " != " << amqp::DATA_AND_STOP << std::endl;
|
std::cerr << "BAD ENCODING " << encoding << " != "
|
||||||
|
<< amqp::DATA_AND_STOP << std::endl;
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
1
experimental/cpp-serializer/bin/schema-dumper/.gitignore
vendored
Normal file
1
experimental/cpp-serializer/bin/schema-dumper/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
schema-dumper
|
@ -0,0 +1,9 @@
|
|||||||
|
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src)
|
||||||
|
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src/amqp)
|
||||||
|
|
||||||
|
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
|
||||||
|
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/proton)
|
||||||
|
|
||||||
|
add_executable (schema-dumper main)
|
||||||
|
|
||||||
|
target_link_libraries (schema-dumper proton amqp qpid-proton)
|
92
experimental/cpp-serializer/bin/schema-dumper/main.cxx
Normal file
92
experimental/cpp-serializer/bin/schema-dumper/main.cxx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <proton/types.h>
|
||||||
|
#include <proton/codec.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#import "debug.h"
|
||||||
|
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
|
||||||
|
#include "amqp/AMQPHeader.h"
|
||||||
|
#include "amqp/AMQPSectionId.h"
|
||||||
|
#include "amqp/descriptors/AMQPDescriptorRegistory.h"
|
||||||
|
|
||||||
|
#include "amqp/schema/Envelope.h"
|
||||||
|
#include "amqp/CompositeFactory.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
printNode (pn_data_t * d_) {
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
if (pn_data_is_described (d_)) {
|
||||||
|
amqp::AMQPDescriptorRegistory[22UL]->read (d_, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << ss.str() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
data_and_stop(std::ifstream & f_, ssize_t sz) {
|
||||||
|
char * blob = new char[sz];
|
||||||
|
memset (blob, 0, sz);
|
||||||
|
f_.read(blob, sz);
|
||||||
|
|
||||||
|
pn_data_t * d = pn_data(sz);
|
||||||
|
|
||||||
|
// returns how many bytes we processed which right now we don't care
|
||||||
|
// about but I assume there is a case where it doesn't process the
|
||||||
|
// entire file
|
||||||
|
auto rtn = pn_data_decode (d, blob, sz);
|
||||||
|
assert (rtn == sz);
|
||||||
|
|
||||||
|
printNode (d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv) {
|
||||||
|
struct stat results { };
|
||||||
|
|
||||||
|
if (stat(argv[1], &results) != 0) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream f (argv[1], std::ios::in | std::ios::binary);
|
||||||
|
std::array<char, 7> header { };
|
||||||
|
f.read(header.data(), 7);
|
||||||
|
|
||||||
|
if (header != amqp::AMQP_HEADER) {
|
||||||
|
std::cerr << "Bad Header in blob" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
amqp::amqp_section_id_t encoding;
|
||||||
|
f.read((char *)&encoding, 1);
|
||||||
|
|
||||||
|
if (encoding == amqp::DATA_AND_STOP) {
|
||||||
|
data_and_stop(f, results.st_size - 8);
|
||||||
|
} else {
|
||||||
|
std::cerr << "BAD ENCODING " << encoding << " != "
|
||||||
|
<< amqp::DATA_AND_STOP << std::endl;
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -12,7 +12,7 @@ namespace amqp {
|
|||||||
* The 8th byte is used to store weather the stream is compressed or
|
* The 8th byte is used to store weather the stream is compressed or
|
||||||
* not
|
* not
|
||||||
*/
|
*/
|
||||||
std::array<char, 7> AMQP_HEADER = { { 'c', 'o', 'r', 'd', 'a', 1, 0 } };
|
std::array<char, 7> AMQP_HEADER { { 'c', 'o', 'r', 'd', 'a', 1, 0 } };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,15 @@ include_directories (.)
|
|||||||
|
|
||||||
set (amqp_sources
|
set (amqp_sources
|
||||||
CompositeFactory.cxx
|
CompositeFactory.cxx
|
||||||
|
descriptors/AMQPDescriptor.cxx
|
||||||
descriptors/AMQPDescriptors.cxx
|
descriptors/AMQPDescriptors.cxx
|
||||||
descriptors/AMQPDescriptorRegistory.cxx
|
descriptors/AMQPDescriptorRegistory.cxx
|
||||||
|
descriptors/corda-descriptors/FieldDescriptor.cxx
|
||||||
|
descriptors/corda-descriptors/SchemaDescriptor.cxx
|
||||||
|
descriptors/corda-descriptors/ObjectDescriptor.cxx
|
||||||
|
descriptors/corda-descriptors/EnvelopeDescriptor.cxx
|
||||||
|
descriptors/corda-descriptors/CompositeDescriptor.cxx
|
||||||
|
descriptors/corda-descriptors/RestrictedDescriptor.cxx
|
||||||
schema/Schema.cxx
|
schema/Schema.cxx
|
||||||
schema/Field.cxx
|
schema/Field.cxx
|
||||||
schema/Envelope.cxx
|
schema/Envelope.cxx
|
||||||
@ -16,14 +23,14 @@ set (amqp_sources
|
|||||||
schema/restricted-types/List.cxx
|
schema/restricted-types/List.cxx
|
||||||
schema/AMQPTypeNotation.cxx
|
schema/AMQPTypeNotation.cxx
|
||||||
reader/Reader.cxx
|
reader/Reader.cxx
|
||||||
reader/RestrictedReader.cxx
|
|
||||||
reader/CompositeReader.cxx
|
|
||||||
reader/PropertyReader.cxx
|
reader/PropertyReader.cxx
|
||||||
reader/property-readers/StringPropertyReader.cxx
|
reader/CompositeReader.cxx
|
||||||
|
reader/RestrictedReader.cxx
|
||||||
reader/property-readers/IntPropertyReader.cxx
|
reader/property-readers/IntPropertyReader.cxx
|
||||||
reader/property-readers/DoublePropertyReader.cxx
|
|
||||||
reader/property-readers/LongPropertyReader.cxx
|
reader/property-readers/LongPropertyReader.cxx
|
||||||
reader/property-readers/BoolPropertyReader.cxx
|
reader/property-readers/BoolPropertyReader.cxx
|
||||||
|
reader/property-readers/DoublePropertyReader.cxx
|
||||||
|
reader/property-readers/StringPropertyReader.cxx
|
||||||
reader/restricted-readers/ListReader.cxx
|
reader/restricted-readers/ListReader.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
#include "AMQPDescriptor.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <amqp/descriptors/corda-descriptors/EnvelopeDescriptor.h>
|
||||||
|
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
#include "AMQPDescriptorRegistory.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
std::ostream &
|
||||||
|
operator<<(std::ostream &stream_, const amqp::internal::AutoIndent &ai_) {
|
||||||
|
stream_ << ai_.indent;
|
||||||
|
return stream_;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const std::string &
|
||||||
|
amqp::internal::
|
||||||
|
AMQPDescriptor::symbol() const {
|
||||||
|
return m_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
std::unique_ptr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
AMQPDescriptor::build (pn_data_t *) const {
|
||||||
|
throw std::runtime_error ("Should never be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
inline void
|
||||||
|
amqp::internal::
|
||||||
|
AMQPDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_
|
||||||
|
) const {
|
||||||
|
return read (data_, ss_, AutoIndent());
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
AMQPDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_,
|
||||||
|
const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
switch (pn_data_type (data_)) {
|
||||||
|
case PN_DESCRIBED : {
|
||||||
|
ss_ << ai_ << "DESCRIBED: " << std::endl;
|
||||||
|
{
|
||||||
|
AutoIndent ai { ai_ } ; // NOLINT
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
|
||||||
|
switch (pn_data_type (data_)) {
|
||||||
|
case PN_ULONG : {
|
||||||
|
auto key = proton::readAndNext<u_long>(data_);
|
||||||
|
|
||||||
|
ss_ << ai << "key : "
|
||||||
|
<< key << " :: " << amqp::stripCorda(key)
|
||||||
|
<< " -> "
|
||||||
|
<< amqp::describedToString ((uint64_t )key)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
proton::is_list (data_);
|
||||||
|
ss_ << ai << "list : entries: "
|
||||||
|
<< pn_data_get_list(data_)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
AMQPDescriptorRegistory[key]->read (data_, ss_, ai);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PN_SYMBOL : {
|
||||||
|
ss_ << ai << "blob: bytes: "
|
||||||
|
<< pn_data_get_symbol(data_).size
|
||||||
|
<< std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default : {
|
||||||
|
throw std::runtime_error (
|
||||||
|
"Described type should only contain long or blob");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default : {
|
||||||
|
throw std::runtime_error ("Can only dispatch described objects");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -16,6 +16,30 @@
|
|||||||
|
|
||||||
struct pn_data_t;
|
struct pn_data_t;
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* amqp::internal::AMQPDescribed
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class AutoIndent {
|
||||||
|
private :
|
||||||
|
std::string indent;
|
||||||
|
public :
|
||||||
|
AutoIndent() : indent { "" } { }
|
||||||
|
|
||||||
|
AutoIndent (const AutoIndent & ai_)
|
||||||
|
: indent { ai_.indent + " "}
|
||||||
|
{ }
|
||||||
|
|
||||||
|
friend std::ostream &
|
||||||
|
operator << (std::ostream & stream_, const AutoIndent & ai_);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* amqp::internal::AMQPDescriptor
|
* amqp::internal::AMQPDescriptor
|
||||||
@ -35,18 +59,27 @@ namespace amqp::internal {
|
|||||||
, m_val (-1)
|
, m_val (-1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
AMQPDescriptor(std::string symbol_, int val_)
|
AMQPDescriptor (std::string symbol_, int val_)
|
||||||
: m_symbol (std::move (symbol_))
|
: m_symbol (std::move (symbol_))
|
||||||
, m_val (val_)
|
, m_val (val_)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual ~AMQPDescriptor() = default;
|
virtual ~AMQPDescriptor() = default;
|
||||||
|
|
||||||
const std::string & symbol() const { return m_symbol; }
|
const std::string & symbol() const;
|
||||||
|
|
||||||
void validateAndNext (pn_data_t *) const;
|
void validateAndNext (pn_data_t *) const;
|
||||||
|
|
||||||
virtual std::unique_ptr<AMQPDescribed> build (pn_data_t * data_) const = 0;
|
virtual std::unique_ptr<AMQPDescribed> build (pn_data_t * data_) const;
|
||||||
|
|
||||||
|
virtual void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &) const;
|
||||||
|
|
||||||
|
virtual void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,13 @@
|
|||||||
#include "AMQPDescriptorRegistory.h"
|
#include "AMQPDescriptorRegistory.h"
|
||||||
#include "AMQPDescriptors.h"
|
#include "AMQPDescriptors.h"
|
||||||
|
|
||||||
|
#include "corda-descriptors/FieldDescriptor.h"
|
||||||
|
#include "corda-descriptors/SchemaDescriptor.h"
|
||||||
|
#include "corda-descriptors/ObjectDescriptor.h"
|
||||||
|
#include "corda-descriptors/EnvelopeDescriptor.h"
|
||||||
|
#include "corda-descriptors/CompositeDescriptor.h"
|
||||||
|
#include "corda-descriptors/RestrictedDescriptor.h"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
@ -8,8 +15,7 @@
|
|||||||
|
|
||||||
namespace amqp::internal {
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
constexpr uint64_t DESCRIPTOR_TOP_32BITS = 0xc562UL << (unsigned int)(32 + 16);
|
||||||
const uint64_t DESCRIPTOR_TOP_32BITS = 0xc562L << (32 + 16);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,77 +47,83 @@ namespace amqp {
|
|||||||
std::map<uint64_t, std::shared_ptr<internal::AMQPDescriptor>>
|
std::map<uint64_t, std::shared_ptr<internal::AMQPDescriptor>>
|
||||||
AMQPDescriptorRegistory = {
|
AMQPDescriptorRegistory = {
|
||||||
{
|
{
|
||||||
1L | internal::DESCRIPTOR_TOP_32BITS,
|
22UL,
|
||||||
|
std::make_shared<internal::AMQPDescriptor> (
|
||||||
|
"DESCRIBED",
|
||||||
|
-1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
1UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::EnvelopeDescriptor> (
|
std::make_shared<internal::EnvelopeDescriptor> (
|
||||||
internal::EnvelopeDescriptor (
|
internal::EnvelopeDescriptor (
|
||||||
"ENVELOPE",
|
"ENVELOPE",
|
||||||
internal::ENVELOPE))
|
internal::ENVELOPE))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
2L | internal::DESCRIPTOR_TOP_32BITS,
|
2UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::SchemaDescriptor> (
|
std::make_shared<internal::SchemaDescriptor> (
|
||||||
internal::SchemaDescriptor (
|
internal::SchemaDescriptor (
|
||||||
"SCHEMA",
|
"SCHEMA",
|
||||||
internal::SCHEMA))
|
internal::SCHEMA))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
3L | internal::DESCRIPTOR_TOP_32BITS,
|
3UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::ObjectDescriptor> (
|
std::make_shared<internal::ObjectDescriptor> (
|
||||||
internal::ObjectDescriptor (
|
internal::ObjectDescriptor (
|
||||||
"OBJECT_DESCRIPTOR",
|
"OBJECT_DESCRIPTOR",
|
||||||
internal::OBJECT))
|
internal::OBJECT))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
4L | internal::DESCRIPTOR_TOP_32BITS,
|
4UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::FieldDescriptor> (
|
std::make_shared<internal::FieldDescriptor> (
|
||||||
internal::FieldDescriptor (
|
internal::FieldDescriptor (
|
||||||
"FIELD",
|
"FIELD",
|
||||||
internal::FIELD))
|
internal::FIELD))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
5L | internal::DESCRIPTOR_TOP_32BITS,
|
5UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::CompositeDescriptor> (
|
std::make_shared<internal::CompositeDescriptor> (
|
||||||
internal::CompositeDescriptor (
|
internal::CompositeDescriptor (
|
||||||
"COMPOSITE_TYPE",
|
"COMPOSITE_TYPE",
|
||||||
internal::COMPOSITE_TYPE))
|
internal::COMPOSITE_TYPE))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
6L | internal::DESCRIPTOR_TOP_32BITS,
|
6UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::RestrictedDescriptor> (
|
std::make_shared<internal::RestrictedDescriptor> (
|
||||||
internal::RestrictedDescriptor (
|
internal::RestrictedDescriptor (
|
||||||
"RESTRICTED_TYPE",
|
"RESTRICTED_TYPE",
|
||||||
internal::RESTRICTED_TYPE))
|
internal::RESTRICTED_TYPE))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
7L | internal::DESCRIPTOR_TOP_32BITS,
|
7UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::ChoiceDescriptor> (
|
std::make_shared<internal::ChoiceDescriptor> (
|
||||||
internal::ChoiceDescriptor (
|
internal::ChoiceDescriptor (
|
||||||
"CHOICE",
|
"CHOICE",
|
||||||
internal::CHOICE))
|
internal::CHOICE))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
8L | internal::DESCRIPTOR_TOP_32BITS,
|
8UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::ReferencedObjectDescriptor> (
|
std::make_shared<internal::ReferencedObjectDescriptor> (
|
||||||
internal::ReferencedObjectDescriptor (
|
internal::ReferencedObjectDescriptor (
|
||||||
"REFERENCED_OBJECT",
|
"REFERENCED_OBJECT",
|
||||||
internal::REFERENCED_OBJECT))
|
internal::REFERENCED_OBJECT))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
9L | internal::DESCRIPTOR_TOP_32BITS,
|
9UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::TransformSchemaDescriptor> (
|
std::make_shared<internal::TransformSchemaDescriptor> (
|
||||||
internal::TransformSchemaDescriptor (
|
internal::TransformSchemaDescriptor (
|
||||||
"TRANSFORM_SCHEMA",
|
"TRANSFORM_SCHEMA",
|
||||||
internal::TRANSFORM_SCHEMA))
|
internal::TRANSFORM_SCHEMA))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
10L | internal::DESCRIPTOR_TOP_32BITS,
|
10UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::TransformElementDescriptor> (
|
std::make_shared<internal::TransformElementDescriptor> (
|
||||||
internal::TransformElementDescriptor (
|
internal::TransformElementDescriptor (
|
||||||
"TRANSFORM_ELEMENT",
|
"TRANSFORM_ELEMENT",
|
||||||
internal::TRANSFORM_ELEMENT))
|
internal::TRANSFORM_ELEMENT))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
11L | internal::DESCRIPTOR_TOP_32BITS,
|
11UL | internal::DESCRIPTOR_TOP_32BITS,
|
||||||
std::make_shared<internal::TransformElementKeyDescriptor> (
|
std::make_shared<internal::TransformElementKeyDescriptor> (
|
||||||
internal::TransformElementKeyDescriptor (
|
internal::TransformElementKeyDescriptor (
|
||||||
"TRANSFORM_ELEMENT_KEY",
|
"TRANSFORM_ELEMENT_KEY",
|
||||||
@ -132,19 +144,19 @@ amqp::stripCorda (uint64_t id) {
|
|||||||
std::string
|
std::string
|
||||||
amqp::describedToString (uint64_t val_) {
|
amqp::describedToString (uint64_t val_) {
|
||||||
switch (val_) {
|
switch (val_) {
|
||||||
case (1L | internal::DESCRIPTOR_TOP_32BITS) : return "ENVELOPE";
|
case (1UL | internal::DESCRIPTOR_TOP_32BITS) : return "ENVELOPE";
|
||||||
case (2L | internal::DESCRIPTOR_TOP_32BITS) : return "SCHEMA";
|
case (2UL | internal::DESCRIPTOR_TOP_32BITS) : return "SCHEMA";
|
||||||
case (3L | internal::DESCRIPTOR_TOP_32BITS) : return "OBJECT_DESCRIPTOR";
|
case (3UL | internal::DESCRIPTOR_TOP_32BITS) : return "OBJECT_DESCRIPTOR";
|
||||||
case (4L | internal::DESCRIPTOR_TOP_32BITS) : return "FIELD";
|
case (4UL | internal::DESCRIPTOR_TOP_32BITS) : return "FIELD";
|
||||||
case (5L | internal::DESCRIPTOR_TOP_32BITS) : return "COMPOSITE_TYPE";
|
case (5UL | internal::DESCRIPTOR_TOP_32BITS) : return "COMPOSITE_TYPE";
|
||||||
case (6L | internal::DESCRIPTOR_TOP_32BITS) : return "RESTRICTED_TYPE";
|
case (6UL | internal::DESCRIPTOR_TOP_32BITS) : return "RESTRICTED_TYPE";
|
||||||
case (7L | internal::DESCRIPTOR_TOP_32BITS) : return "CHOICE";
|
case (7UL | internal::DESCRIPTOR_TOP_32BITS) : return "CHOICE";
|
||||||
case (8L | internal::DESCRIPTOR_TOP_32BITS) : return "REFERENCED_OBJECT";
|
case (8UL | internal::DESCRIPTOR_TOP_32BITS) : return "REFERENCED_OBJECT";
|
||||||
case (9L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_SCHEMA";
|
case (9UL | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_SCHEMA";
|
||||||
case (10L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT";
|
case (10UL | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT";
|
||||||
case (11L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT_KEY";
|
case (11UL | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT_KEY";
|
||||||
default : return "UNKNOWN";
|
default : return "UNKNOWN";
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
#include "amqp/AMQPDescriptor.h"
|
#include "AMQPDescriptor.h"
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -25,31 +25,6 @@
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up a described type by its ID in the AMQPDescriptorRegistry and
|
|
||||||
* return the corresponding schema type. Specialised below to avoid
|
|
||||||
* the cast and re-owning of the unigue pointer when we're happy
|
|
||||||
* with a simple uPtr<AMQPDescribed>
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
uPtr<T>
|
|
||||||
dispatchDescribed (pn_data_t * data_) {
|
|
||||||
proton::is_described(data_);
|
|
||||||
proton::auto_enter p (data_);
|
|
||||||
proton::is_ulong(data_);
|
|
||||||
|
|
||||||
auto id = pn_data_get_ulong(data_);
|
|
||||||
|
|
||||||
return uPtr<T> (
|
|
||||||
static_cast<T *>(amqp::AMQPDescriptorRegistory[id]->build(data_).release()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
void
|
void
|
||||||
amqp::internal::
|
amqp::internal::
|
||||||
AMQPDescriptor::validateAndNext (pn_data_t * const data_) const {
|
AMQPDescriptor::validateAndNext (pn_data_t * const data_) const {
|
||||||
@ -63,272 +38,7 @@ AMQPDescriptor::validateAndNext (pn_data_t * const data_) const {
|
|||||||
throw std::runtime_error ("Invalid Type");
|
throw std::runtime_error ("Invalid Type");
|
||||||
}
|
}
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
const std::string
|
|
||||||
consumeBlob (pn_data_t * data_) {
|
|
||||||
proton::is_described (data_);
|
|
||||||
proton::auto_enter p (data_);
|
|
||||||
return proton::get_symbol<std::string> (data_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* amqp::internal::EnvelopeDescriptor
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
uPtr<amqp::AMQPDescribed>
|
|
||||||
amqp::internal::
|
|
||||||
EnvelopeDescriptor::build(pn_data_t * data_) const {
|
|
||||||
DBG ("ENVELOPE" << std::endl); // NOLINT
|
|
||||||
|
|
||||||
validateAndNext(data_);
|
|
||||||
|
|
||||||
proton::auto_enter p (data_);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The actual blob... if this was java we would use the type symbols
|
|
||||||
* in the blob to look up serialisers in the cache... but we don't
|
|
||||||
* have any so we are actually going to need to use the schema
|
|
||||||
* which we parse *after* this to be able to read any data!
|
|
||||||
*/
|
|
||||||
std::string outerType = consumeBlob(data_);
|
|
||||||
|
|
||||||
pn_data_next (data_);
|
pn_data_next (data_);
|
||||||
|
|
||||||
/*
|
|
||||||
* The schema
|
|
||||||
*/
|
|
||||||
auto schema = dispatchDescribed<schema::Schema> (data_);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The transforms schema
|
|
||||||
*/
|
|
||||||
// Skip for now
|
|
||||||
// dispatchDescribed (data_);
|
|
||||||
|
|
||||||
return std::make_unique<schema::Envelope> (schema::Envelope (schema, outerType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
uPtr<amqp::AMQPDescribed>
|
|
||||||
amqp::internal::
|
|
||||||
SchemaDescriptor::build(pn_data_t * data_) const {
|
|
||||||
DBG ("SCHEMA" << std::endl); // NOLINT
|
|
||||||
|
|
||||||
validateAndNext(data_);
|
|
||||||
|
|
||||||
schema::OrderedTypeNotations<schema::AMQPTypeNotation> schemas;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The Schema is stored as a list of lists of described objects
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
proton::auto_list_enter ale (data_);
|
|
||||||
|
|
||||||
for (int i { 1 } ; pn_data_next(data_) ; ++i) {
|
|
||||||
DBG (" " << i << "/" << ale.elements() << std::endl); // NOLINT
|
|
||||||
proton::auto_list_enter ale2 (data_);
|
|
||||||
while (pn_data_next(data_)) {
|
|
||||||
schemas.insert (dispatchDescribed<schema::AMQPTypeNotation>(data_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_unique<schema::Schema> (std::move (schemas));
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* amqp::internal::ObjectDescriptor
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
uPtr<amqp::AMQPDescribed>
|
|
||||||
amqp::internal::
|
|
||||||
ObjectDescriptor::build(pn_data_t * data_) const {
|
|
||||||
DBG ("DESCRIPTOR" << std::endl); // NOLINT
|
|
||||||
|
|
||||||
validateAndNext(data_);
|
|
||||||
|
|
||||||
proton::auto_enter p (data_);
|
|
||||||
|
|
||||||
auto symbol = proton::get_symbol<std::string> (data_);
|
|
||||||
|
|
||||||
return std::make_unique<schema::Descriptor> (symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* amqp::internal::FieldDescriptor
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
uPtr<amqp::AMQPDescribed>
|
|
||||||
amqp::internal::
|
|
||||||
FieldDescriptor::build(pn_data_t * data_) const {
|
|
||||||
DBG ("FIELD" << std::endl); // NOLINT
|
|
||||||
|
|
||||||
validateAndNext(data_);
|
|
||||||
|
|
||||||
proton::auto_enter ae (data_);
|
|
||||||
|
|
||||||
/* name: String */
|
|
||||||
auto name = proton::get_string (data_);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* type: String */
|
|
||||||
auto type = proton::get_string (data_);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* requires: List<String> */
|
|
||||||
std::list<std::string> requires;
|
|
||||||
{
|
|
||||||
proton::auto_list_enter ale (data_);
|
|
||||||
while (pn_data_next(data_)) {
|
|
||||||
requires.push_back (proton::get_string(data_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* default: String? */
|
|
||||||
auto def = proton::get_string (data_, true);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* label: String? */
|
|
||||||
auto label = proton::get_string (data_, true);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* mandatory: Boolean - copes with the Kotlin concept of nullability.
|
|
||||||
If something is mandatory then it cannot be null */
|
|
||||||
auto mandatory = proton::get_boolean (data_);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* multiple: Boolean */
|
|
||||||
auto multiple = proton::get_boolean(data_);
|
|
||||||
|
|
||||||
return std::make_unique<schema::Field> (name, type, requires, def, label,
|
|
||||||
mandatory, multiple);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* amqp::internal::CompositeDescriptor
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
uPtr<amqp::AMQPDescribed>
|
|
||||||
amqp::internal::
|
|
||||||
CompositeDescriptor::build (pn_data_t * data_) const {
|
|
||||||
DBG ("COMPOSITE" << std::endl); // NOLINT
|
|
||||||
|
|
||||||
validateAndNext(data_);
|
|
||||||
|
|
||||||
proton::auto_enter p (data_);
|
|
||||||
|
|
||||||
/* Class Name - String */
|
|
||||||
auto name = proton::get_string(data_);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* Label Name - Nullable String */
|
|
||||||
auto label = proton::get_string (data_, true);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* provides: List<String> */
|
|
||||||
std::list<std::string> provides;
|
|
||||||
{
|
|
||||||
proton::auto_list_enter p2 (data_);
|
|
||||||
while (pn_data_next(data_)) {
|
|
||||||
provides.push_back (proton::get_string (data_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* descriptor: Descriptor */
|
|
||||||
auto descriptor = dispatchDescribed<schema::Descriptor>(data_);
|
|
||||||
|
|
||||||
pn_data_next(data_);
|
|
||||||
|
|
||||||
/* fields: List<Described>*/
|
|
||||||
std::vector<uPtr<schema::Field>> fields;
|
|
||||||
fields.reserve (pn_data_get_list (data_));
|
|
||||||
{
|
|
||||||
proton::auto_list_enter p2 (data_);
|
|
||||||
while (pn_data_next (data_)) {
|
|
||||||
fields.emplace_back (dispatchDescribed<schema::Field>(data_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_unique<schema::Composite> (
|
|
||||||
schema::Composite (name, label, provides, descriptor, fields));
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Restricted types represent lists and maps
|
|
||||||
*
|
|
||||||
* NOTE: The Corda serialization scheme doesn't support all container classes
|
|
||||||
* as it has the requiremnt that iteration order be deterministic for purposes
|
|
||||||
* of signing over data.
|
|
||||||
*
|
|
||||||
* name : String
|
|
||||||
* label : String?
|
|
||||||
* provides : List<String>
|
|
||||||
* source : String
|
|
||||||
* descriptor : Descriptor
|
|
||||||
* choices : List<Choice>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
uPtr<amqp::AMQPDescribed>
|
|
||||||
amqp::internal::
|
|
||||||
RestrictedDescriptor::build (pn_data_t * data_) const {
|
|
||||||
DBG ("RESTRICTED" << std::endl); // NOLINT
|
|
||||||
validateAndNext(data_);
|
|
||||||
|
|
||||||
proton::auto_enter ae (data_);
|
|
||||||
|
|
||||||
auto name = proton::readAndNext<std::string>(data_);
|
|
||||||
auto label = proton::readAndNext<std::string>(data_, true);
|
|
||||||
|
|
||||||
std::vector<std::string> provides;
|
|
||||||
{
|
|
||||||
proton::auto_list_enter ae2 (data_);
|
|
||||||
while (pn_data_next(data_)) {
|
|
||||||
provides.push_back (proton::get_string (data_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pn_data_next (data_);
|
|
||||||
|
|
||||||
auto source = proton::readAndNext<std::string> (data_);
|
|
||||||
auto descriptor = dispatchDescribed<schema::Descriptor> (data_);
|
|
||||||
|
|
||||||
// SKIP the choices section **FOR NOW**
|
|
||||||
|
|
||||||
return schema::Restricted::make (descriptor, name,
|
|
||||||
label, provides, source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@ -396,3 +106,4 @@ TransformElementKeyDescriptor::build (pn_data_t * data_) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -8,9 +8,12 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
#include "amqp/AMQPDescribed.h"
|
#include "amqp/AMQPDescribed.h"
|
||||||
#include "amqp/AMQPDescriptor.h"
|
#include "AMQPDescriptor.h"
|
||||||
#include "amqp/schema/Descriptor.h"
|
#include "amqp/schema/Descriptor.h"
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
#include "AMQPDescriptorRegistory.h"
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -18,116 +21,26 @@ struct pn_data_t;
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
namespace amqp::internal {
|
namespace amqp::internal::descriptors {
|
||||||
|
|
||||||
class EnvelopeDescriptor : public AMQPDescriptor {
|
/**
|
||||||
public :
|
* Look up a described type by its ID in the AMQPDescriptorRegistry and
|
||||||
EnvelopeDescriptor() : AMQPDescriptor() { }
|
* return the corresponding schema type. Specialised below to avoid
|
||||||
|
* the cast and re-owning of the unigue pointer when we're happy
|
||||||
|
* with a simple uPtr<AMQPDescribed>
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
uPtr <T>
|
||||||
|
dispatchDescribed(pn_data_t *data_) {
|
||||||
|
proton::is_described(data_);
|
||||||
|
proton::auto_enter p(data_);
|
||||||
|
proton::is_ulong(data_);
|
||||||
|
|
||||||
EnvelopeDescriptor(const std::string & symbol_, int val_)
|
auto id = pn_data_get_ulong(data_);
|
||||||
: AMQPDescriptor(symbol_, val_)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~EnvelopeDescriptor() final = default;
|
|
||||||
|
|
||||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
namespace amqp::internal {
|
|
||||||
|
|
||||||
class SchemaDescriptor : public AMQPDescriptor {
|
|
||||||
public :
|
|
||||||
SchemaDescriptor() : AMQPDescriptor() { }
|
|
||||||
|
|
||||||
SchemaDescriptor(const std::string & symbol_, int val_)
|
|
||||||
: AMQPDescriptor(symbol_, val_)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~SchemaDescriptor() final = default;
|
|
||||||
|
|
||||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
namespace amqp::internal {
|
|
||||||
|
|
||||||
class ObjectDescriptor : public AMQPDescriptor {
|
|
||||||
public :
|
|
||||||
ObjectDescriptor() : AMQPDescriptor() { }
|
|
||||||
|
|
||||||
ObjectDescriptor(const std::string & symbol_, int val_)
|
|
||||||
: AMQPDescriptor(symbol_, val_)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~ObjectDescriptor() final = default;
|
|
||||||
|
|
||||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
namespace amqp::internal {
|
|
||||||
|
|
||||||
class FieldDescriptor : public AMQPDescriptor {
|
|
||||||
public :
|
|
||||||
FieldDescriptor() : AMQPDescriptor() { }
|
|
||||||
|
|
||||||
FieldDescriptor(const std::string & symbol_, int val_)
|
|
||||||
: AMQPDescriptor(symbol_, val_)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~FieldDescriptor() final = default;
|
|
||||||
|
|
||||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
namespace amqp::internal {
|
|
||||||
|
|
||||||
class CompositeDescriptor : public AMQPDescriptor {
|
|
||||||
public :
|
|
||||||
CompositeDescriptor() : AMQPDescriptor() { }
|
|
||||||
|
|
||||||
CompositeDescriptor(const std::string & symbol_, int val_)
|
|
||||||
: AMQPDescriptor(symbol_, val_)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~CompositeDescriptor() final = default;
|
|
||||||
|
|
||||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
namespace amqp::internal {
|
|
||||||
|
|
||||||
class RestrictedDescriptor : public AMQPDescriptor {
|
|
||||||
public :
|
|
||||||
RestrictedDescriptor() : AMQPDescriptor() { }
|
|
||||||
|
|
||||||
RestrictedDescriptor(const std::string & symbol_, int val_)
|
|
||||||
: AMQPDescriptor(symbol_, val_)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~RestrictedDescriptor() final = default;
|
|
||||||
|
|
||||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
return uPtr<T>(
|
||||||
|
static_cast<T *>(amqp::AMQPDescriptorRegistory[id]->build(data_).release()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
#include "CompositeDescriptor.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
|
||||||
|
#include "amqp/descriptors/AMQPDescriptors.h"
|
||||||
|
|
||||||
|
#include "amqp/schema/Field.h"
|
||||||
|
#include "amqp/schema/Composite.h"
|
||||||
|
#include "amqp/schema/Descriptor.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* amqp::internal::CompositeDescriptor
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
amqp::internal::
|
||||||
|
CompositeDescriptor::CompositeDescriptor (
|
||||||
|
const std::string & symbol_,
|
||||||
|
int val_
|
||||||
|
) : AMQPDescriptor (symbol_, val_) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
uPtr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
CompositeDescriptor::build (pn_data_t * data_) const {
|
||||||
|
DBG ("COMPOSITE" << std::endl); // NOLINT
|
||||||
|
|
||||||
|
validateAndNext(data_);
|
||||||
|
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
|
||||||
|
/* Class Name - String */
|
||||||
|
auto name = proton::get_string(data_);
|
||||||
|
|
||||||
|
pn_data_next(data_);
|
||||||
|
|
||||||
|
/* Label Name - Nullable String */
|
||||||
|
auto label = proton::get_string (data_, true);
|
||||||
|
|
||||||
|
pn_data_next(data_);
|
||||||
|
|
||||||
|
/* provides: List<String> */
|
||||||
|
std::list<std::string> provides;
|
||||||
|
{
|
||||||
|
proton::auto_list_enter p2 (data_);
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
provides.push_back (proton::get_string (data_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* descriptor: Descriptor */
|
||||||
|
auto descriptor = descriptors::dispatchDescribed<schema::Descriptor>(data_);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* fields: List<Described>*/
|
||||||
|
std::vector<uPtr<schema::Field>> fields;
|
||||||
|
fields.reserve (pn_data_get_list (data_));
|
||||||
|
{
|
||||||
|
proton::auto_list_enter p2 (data_);
|
||||||
|
while (pn_data_next (data_)) {
|
||||||
|
fields.emplace_back (descriptors::dispatchDescribed<schema::Field>(data_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<schema::Composite> (
|
||||||
|
schema::Composite (name, label, provides, descriptor, fields));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
CompositeDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_,
|
||||||
|
const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
proton::is_list(data_);
|
||||||
|
|
||||||
|
{
|
||||||
|
AutoIndent ai { ai_ };
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
|
||||||
|
proton::is_string (data_);
|
||||||
|
ss_ << ai
|
||||||
|
<< "1] String: ClassName: "
|
||||||
|
<< proton::readAndNext<std::string>(data_)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
proton::is_string (data_);
|
||||||
|
ss_ << ai
|
||||||
|
<< "2] String: Label: \""
|
||||||
|
<< proton::readAndNext<std::string>(data_, true)
|
||||||
|
<< "\"" << std::endl;
|
||||||
|
|
||||||
|
proton::is_list (data_);
|
||||||
|
|
||||||
|
ss_ << ai << "3] List: Provides: [ ";
|
||||||
|
{
|
||||||
|
proton::auto_list_enter ale (data_);
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
ss_ << ai << (proton::get_string (data_)) << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss_ << "]" << std::endl;
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
proton::is_described (data_);
|
||||||
|
|
||||||
|
ss_ << ai << "4] Descriptor:" << std::endl;
|
||||||
|
|
||||||
|
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
|
||||||
|
(pn_data_t *)proton::auto_next(data_), ss_, AutoIndent { ai });
|
||||||
|
|
||||||
|
ss_ << ai << "5] List: Fields: " << std::endl;
|
||||||
|
{
|
||||||
|
AutoIndent ai2 { ai };
|
||||||
|
|
||||||
|
proton::auto_list_enter ale (data_);
|
||||||
|
for (int i { 1 } ; pn_data_next (data_) ; ++i) {
|
||||||
|
ss_ << ai2 << i << "/"
|
||||||
|
<< ale.elements() << "]"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
|
||||||
|
data_, ss_, AutoIndent { ai2 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "amqp/descriptors/AMQPDescriptor.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class CompositeDescriptor : public AMQPDescriptor {
|
||||||
|
public :
|
||||||
|
CompositeDescriptor() : AMQPDescriptor() { }
|
||||||
|
CompositeDescriptor (const std::string &, int);
|
||||||
|
|
||||||
|
~CompositeDescriptor() final = default;
|
||||||
|
|
||||||
|
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||||
|
|
||||||
|
void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,114 @@
|
|||||||
|
#include "EnvelopeDescriptor.h"
|
||||||
|
|
||||||
|
#include "amqp/schema/Schema.h"
|
||||||
|
#include "amqp/schema/Envelope.h"
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
consumeBlob (pn_data_t * data_) {
|
||||||
|
proton::is_described (data_);
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
return proton::get_symbol<std::string> (data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* amqp::internal::EnvelopeDescriptor
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described types are a pair of a key and a list of elements. Having
|
||||||
|
* parsed this as such a type we should be in the stack at the point
|
||||||
|
* where we found the list and don't expect to have entered it before
|
||||||
|
* calling this
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
EnvelopeDescriptor::read (
|
||||||
|
pn_data_t * data_, std::stringstream & ss_, const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
// lets just make sure we haven't entered this already
|
||||||
|
proton::is_list (data_);
|
||||||
|
|
||||||
|
{
|
||||||
|
AutoIndent ai { ai_ };
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
|
||||||
|
ss_ << ai << "1]" << std::endl;
|
||||||
|
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
|
||||||
|
(pn_data_t *)proton::auto_next (data_), ss_, AutoIndent { ai });
|
||||||
|
|
||||||
|
|
||||||
|
ss_ << ai << "2]" << std::endl;
|
||||||
|
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
|
||||||
|
(pn_data_t *)proton::auto_next(data_), ss_, AutoIndent { ai });
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
amqp::internal::
|
||||||
|
EnvelopeDescriptor::EnvelopeDescriptor() : AMQPDescriptor() { }
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
amqp::internal::
|
||||||
|
EnvelopeDescriptor::EnvelopeDescriptor (
|
||||||
|
const std::string & symbol_,
|
||||||
|
int val_
|
||||||
|
) : AMQPDescriptor (symbol_, val_) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
uPtr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
EnvelopeDescriptor::build (pn_data_t * data_) const {
|
||||||
|
DBG ("ENVELOPE" << std::endl); // NOLINT
|
||||||
|
|
||||||
|
validateAndNext(data_);
|
||||||
|
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The actual blob... if this was java we would use the type symbols
|
||||||
|
* in the blob to look up serialisers in the cache... but we don't
|
||||||
|
* have any so we are actually going to need to use the schema
|
||||||
|
* which we parse *after* this to be able to read any data!
|
||||||
|
*/
|
||||||
|
std::string outerType = consumeBlob(data_);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The schema
|
||||||
|
*/
|
||||||
|
auto schema = descriptors::dispatchDescribed<schema::Schema> (data_);
|
||||||
|
|
||||||
|
pn_data_next(data_);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The transforms schema
|
||||||
|
*/
|
||||||
|
// Skip for now
|
||||||
|
// dispatchDescribed (data_);
|
||||||
|
|
||||||
|
return std::make_unique<schema::Envelope> (schema::Envelope (schema, outerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "AMQPDescriptors.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Forward Class Declarations
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
struct pn_data_t;
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* class amqp::internal::EnvelopeDescriptor
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class EnvelopeDescriptor : public AMQPDescriptor {
|
||||||
|
public :
|
||||||
|
EnvelopeDescriptor();
|
||||||
|
EnvelopeDescriptor (const std::string &, int);
|
||||||
|
|
||||||
|
~EnvelopeDescriptor() final = default;
|
||||||
|
|
||||||
|
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||||
|
|
||||||
|
void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,138 @@
|
|||||||
|
#include "FieldDescriptor.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
|
||||||
|
#include "amqp/schema/Field.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* amqp::internal::FieldDescriptor
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
amqp::internal::
|
||||||
|
FieldDescriptor::FieldDescriptor() : AMQPDescriptor() { }
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
amqp::internal::
|
||||||
|
FieldDescriptor::FieldDescriptor (
|
||||||
|
const std::string & symbol_,
|
||||||
|
int val_
|
||||||
|
) : AMQPDescriptor(symbol_, val_) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
uPtr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
FieldDescriptor::build(pn_data_t * data_) const {
|
||||||
|
DBG ("FIELD" << std::endl); // NOLINT
|
||||||
|
|
||||||
|
validateAndNext(data_);
|
||||||
|
|
||||||
|
proton::auto_enter ae (data_);
|
||||||
|
|
||||||
|
/* name: String */
|
||||||
|
auto name = proton::get_string (data_);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* type: String */
|
||||||
|
auto type = proton::get_string (data_);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* requires: List<String> */
|
||||||
|
std::list<std::string> requires;
|
||||||
|
{
|
||||||
|
proton::auto_list_enter ale (data_);
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
requires.push_back (proton::get_string(data_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* default: String? */
|
||||||
|
auto def = proton::get_string (data_, true);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* label: String? */
|
||||||
|
auto label = proton::get_string (data_, true);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* mandatory: Boolean - copes with the Kotlin concept of nullability.
|
||||||
|
If something is mandatory then it cannot be null */
|
||||||
|
auto mandatory = proton::get_boolean (data_);
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
/* multiple: Boolean */
|
||||||
|
auto multiple = proton::get_boolean(data_);
|
||||||
|
|
||||||
|
return std::make_unique<schema::Field> (
|
||||||
|
name, type, requires, def, label, mandatory, multiple);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
FieldDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_,
|
||||||
|
const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
proton::is_list (data_);
|
||||||
|
|
||||||
|
proton::auto_list_enter ale (data_, true);
|
||||||
|
AutoIndent ai { ai_ };
|
||||||
|
|
||||||
|
ss_ << ai << "1/7] String: Name: "
|
||||||
|
<< proton::get_string ((pn_data_t *)proton::auto_next (data_))
|
||||||
|
<< std::endl;
|
||||||
|
ss_ << ai << "2/7] String: Type: "
|
||||||
|
<< proton::get_string ((pn_data_t *)proton::auto_next (data_))
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
proton::auto_list_enter ale2 (data_);
|
||||||
|
|
||||||
|
ss_ << ai << "3/7] List: Requires: elements " << ale2.elements()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
AutoIndent ai2 { ai };
|
||||||
|
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
ss_ << ai2 << proton::get_string (data_) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
proton::is_string (data_, true);
|
||||||
|
|
||||||
|
ss_ << ai << "4/7] String: Default: "
|
||||||
|
<< proton::get_string ((pn_data_t *)proton::auto_next (data_), true)
|
||||||
|
<< std::endl;
|
||||||
|
ss_ << ai << "5/7] String: Label: "
|
||||||
|
<< proton::get_string ((pn_data_t *)proton::auto_next (data_), true)
|
||||||
|
<< std::endl;
|
||||||
|
ss_ << ai << "6/7] Boolean: Mandatory: "
|
||||||
|
<< proton::get_boolean ((pn_data_t *)proton::auto_next (data_))
|
||||||
|
<< std::endl;
|
||||||
|
ss_ << ai << "7/7] Boolean: Multiple: "
|
||||||
|
<< proton::get_boolean ((pn_data_t *)proton::auto_next (data_))
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include "proton/codec.h"
|
||||||
|
#include "amqp/AMQPDescribed.h"
|
||||||
|
#include "amqp/descriptors/AMQPDescriptor.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class FieldDescriptor : public AMQPDescriptor {
|
||||||
|
public :
|
||||||
|
FieldDescriptor();
|
||||||
|
FieldDescriptor (const std::string &, int);
|
||||||
|
|
||||||
|
~FieldDescriptor() final = default;
|
||||||
|
|
||||||
|
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||||
|
|
||||||
|
void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,59 @@
|
|||||||
|
#include "ObjectDescriptor.h"
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
#include "amqp/schema/Descriptor.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* amqp::internal::ObjectDescriptor
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uPtr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
ObjectDescriptor::build(pn_data_t * data_) const {
|
||||||
|
DBG ("DESCRIPTOR" << std::endl); // NOLINT
|
||||||
|
|
||||||
|
validateAndNext (data_);
|
||||||
|
|
||||||
|
proton::auto_enter p (data_);
|
||||||
|
|
||||||
|
auto symbol = proton::get_symbol<std::string> (data_);
|
||||||
|
|
||||||
|
return std::make_unique<schema::Descriptor> (symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
ObjectDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_,
|
||||||
|
const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
proton::is_list (data_);
|
||||||
|
|
||||||
|
{
|
||||||
|
AutoIndent ai { ai_ };
|
||||||
|
proton::auto_list_enter ale (data_);
|
||||||
|
pn_data_next(data_);
|
||||||
|
|
||||||
|
ss_ << ai << "1/2] "
|
||||||
|
<< proton::get_symbol<std::string>(
|
||||||
|
(pn_data_t *)proton::auto_next (data_))
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
ss_ << ai << "2/2] " << data_ << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include "amqp/descriptors/AMQPDescriptor.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
struct pn_data_t;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class ObjectDescriptor : public AMQPDescriptor {
|
||||||
|
public :
|
||||||
|
ObjectDescriptor() : AMQPDescriptor() { }
|
||||||
|
|
||||||
|
ObjectDescriptor(const std::string & symbol_, int val_)
|
||||||
|
: AMQPDescriptor(symbol_, val_)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~ObjectDescriptor() final = default;
|
||||||
|
|
||||||
|
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||||
|
|
||||||
|
void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,98 @@
|
|||||||
|
#include "RestrictedDescriptor.h"
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "amqp/schema/restricted-types/Restricted.h"
|
||||||
|
#include "amqp/descriptors/AMQPDescriptors.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Restricted types represent lists and maps
|
||||||
|
*
|
||||||
|
* NOTE: The Corda serialization scheme doesn't support all container classes
|
||||||
|
* as it has the requiremnt that iteration order be deterministic for purposes
|
||||||
|
* of signing over data.
|
||||||
|
*
|
||||||
|
* name : String
|
||||||
|
* label : String?
|
||||||
|
* provides : List<String>
|
||||||
|
* source : String
|
||||||
|
* descriptor : Descriptor
|
||||||
|
* choices : List<Choice>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
uPtr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
RestrictedDescriptor::build (pn_data_t * data_) const {
|
||||||
|
DBG ("RESTRICTED" << std::endl); // NOLINT
|
||||||
|
validateAndNext(data_);
|
||||||
|
|
||||||
|
proton::auto_enter ae (data_);
|
||||||
|
|
||||||
|
auto name = proton::readAndNext<std::string>(data_);
|
||||||
|
auto label = proton::readAndNext<std::string>(data_, true);
|
||||||
|
|
||||||
|
std::vector<std::string> provides;
|
||||||
|
{
|
||||||
|
proton::auto_list_enter ae2 (data_);
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
provides.push_back (proton::get_string (data_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
|
||||||
|
auto source = proton::readAndNext<std::string> (data_);
|
||||||
|
auto descriptor = descriptors::dispatchDescribed<schema::Descriptor> (data_);
|
||||||
|
|
||||||
|
// SKIP the choices section **FOR NOW**
|
||||||
|
|
||||||
|
return schema::Restricted::make (descriptor, name,
|
||||||
|
label, provides, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
RestrictedDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_,
|
||||||
|
const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
proton::is_list (data_);
|
||||||
|
proton::auto_enter ae (data_);
|
||||||
|
AutoIndent ai { ai_ };
|
||||||
|
|
||||||
|
ss_ << ai << "1] String: Name: "
|
||||||
|
<< proton::readAndNext<std::string> (data_)
|
||||||
|
<< std::endl;
|
||||||
|
ss_ << ai << "2] String: Label: "
|
||||||
|
<< proton::readAndNext<std::string> (data_, true)
|
||||||
|
<< std::endl;
|
||||||
|
ss_ << ai << "3] List: Provides: [ ";
|
||||||
|
|
||||||
|
{
|
||||||
|
proton::auto_list_enter ae2 (data_);
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
ss_ << proton::get_string (data_) << " ";
|
||||||
|
}
|
||||||
|
ss_ << "]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn_data_next (data_);
|
||||||
|
ss_ << ai << "4] String: Source: "
|
||||||
|
<< proton::readAndNext<std::string> (data_)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
ss_ << ai << "5] Descriptor:" << std::endl;
|
||||||
|
|
||||||
|
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
|
||||||
|
(pn_data_t *)proton::auto_next(data_), ss_, AutoIndent { ai });
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "amqp/descriptors/AMQPDescriptor.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class RestrictedDescriptor : public AMQPDescriptor {
|
||||||
|
public :
|
||||||
|
RestrictedDescriptor() : AMQPDescriptor() { }
|
||||||
|
|
||||||
|
RestrictedDescriptor(const std::string & symbol_, int val_)
|
||||||
|
: AMQPDescriptor(symbol_, val_)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~RestrictedDescriptor() final = default;
|
||||||
|
|
||||||
|
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||||
|
|
||||||
|
void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
@ -0,0 +1,93 @@
|
|||||||
|
#include "SchemaDescriptor.h"
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "AMQPDescriptor.h"
|
||||||
|
|
||||||
|
#include "proton/codec.h"
|
||||||
|
#include "proton/proton_wrapper.h"
|
||||||
|
#include "amqp/AMQPDescribed.h"
|
||||||
|
#include "amqp/descriptors/AMQPDescriptors.h"
|
||||||
|
#include "amqp/schema/Schema.h"
|
||||||
|
#include "amqp/schema/OrderedTypeNotations.h"
|
||||||
|
#include "amqp/schema/AMQPTypeNotation.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
amqp::internal::
|
||||||
|
SchemaDescriptor::SchemaDescriptor (
|
||||||
|
const std::string & symbol_,
|
||||||
|
int val_
|
||||||
|
) : AMQPDescriptor(symbol_, val_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
uPtr<amqp::AMQPDescribed>
|
||||||
|
amqp::internal::
|
||||||
|
SchemaDescriptor::build (pn_data_t * data_) const {
|
||||||
|
DBG ("SCHEMA" << std::endl); // NOLINT
|
||||||
|
|
||||||
|
validateAndNext(data_);
|
||||||
|
|
||||||
|
schema::OrderedTypeNotations<schema::AMQPTypeNotation> schemas;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Schema is stored as a list of lists of described objects
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
proton::auto_list_enter ale (data_);
|
||||||
|
|
||||||
|
for (int i { 1 } ; pn_data_next(data_) ; ++i) {
|
||||||
|
DBG (" " << i << "/" << ale.elements() << std::endl); // NOLINT
|
||||||
|
proton::auto_list_enter ale2 (data_);
|
||||||
|
while (pn_data_next(data_)) {
|
||||||
|
schemas.insert (
|
||||||
|
descriptors::dispatchDescribed<schema::AMQPTypeNotation>(data_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<schema::Schema> (std::move (schemas));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
amqp::internal::
|
||||||
|
SchemaDescriptor::read (
|
||||||
|
pn_data_t * data_,
|
||||||
|
std::stringstream & ss_,
|
||||||
|
const AutoIndent & ai_
|
||||||
|
) const {
|
||||||
|
proton::is_list (data_);
|
||||||
|
|
||||||
|
{
|
||||||
|
AutoIndent ai { ai_ };
|
||||||
|
proton::auto_list_enter ale (data_);
|
||||||
|
|
||||||
|
for (int i { 1 } ; pn_data_next (data_) ; ++i) {
|
||||||
|
proton::is_list (data_);
|
||||||
|
ss_ << ai << i << "/" << ale.elements() <<"]";
|
||||||
|
|
||||||
|
AutoIndent ai2 { ai };
|
||||||
|
|
||||||
|
proton::auto_list_enter ale2 (data_);
|
||||||
|
ss_ << " list: entries: " << ale2.elements() << std::endl;
|
||||||
|
|
||||||
|
for (int j { 1 } ; pn_data_next (data_) ; ++j) {
|
||||||
|
ss_ << ai2 << i << ":" << j << "/" << ale2.elements()
|
||||||
|
<< "] " << std::endl;
|
||||||
|
|
||||||
|
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
|
||||||
|
data_, ss_,
|
||||||
|
AutoIndent { ai2 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "amqp/descriptors/AMQPDescriptor.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
struct pn_data_t;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
namespace amqp::internal {
|
||||||
|
|
||||||
|
class SchemaDescriptor : public AMQPDescriptor {
|
||||||
|
public :
|
||||||
|
SchemaDescriptor() = default;
|
||||||
|
SchemaDescriptor (const std::string &, int);
|
||||||
|
~SchemaDescriptor() final = default;
|
||||||
|
|
||||||
|
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||||
|
|
||||||
|
void read (
|
||||||
|
pn_data_t *,
|
||||||
|
std::stringstream &,
|
||||||
|
const AutoIndent &) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -31,7 +31,7 @@ namespace amqp::internal::reader {
|
|||||||
|
|
||||||
std::any read (pn_data_t *) const override;
|
std::any read (pn_data_t *) const override;
|
||||||
|
|
||||||
std::string readString(pn_data_t *) const override;
|
std::string readString (pn_data_t *) const override;
|
||||||
|
|
||||||
std::unique_ptr<amqp::reader::IValue> dump(
|
std::unique_ptr<amqp::reader::IValue> dump(
|
||||||
const std::string &,
|
const std::string &,
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator << (std::ostream& stream, pn_data_t * data_) {
|
operator << (std::ostream& stream, pn_data_t * data_) {
|
||||||
auto type = pn_data_type(data_);
|
auto type = pn_data_type (data_);
|
||||||
stream << std::setw (2) << type << " " << pn_type_name (type);
|
stream << std::setw (2) << type << " " << pn_type_name (type);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -89,14 +89,14 @@ proton::is_ulong (pn_data_t * data_) {
|
|||||||
auto t = pn_data_type(data_);
|
auto t = pn_data_type(data_);
|
||||||
if (t != PN_ULONG) {
|
if (t != PN_ULONG) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Expected an unsigned long but recieved " << pn_type_name (t);
|
ss << "Expected an unsigned long but received " << pn_type_name (t);
|
||||||
throw std::runtime_error (ss.str());
|
throw std::runtime_error (ss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
inline void
|
void
|
||||||
proton::is_symbol (pn_data_t * data_) {
|
proton::is_symbol (pn_data_t * data_) {
|
||||||
if (pn_data_type(data_) != PN_SYMBOL) {
|
if (pn_data_type(data_) != PN_SYMBOL) {
|
||||||
throw std::runtime_error ("Expected an unsigned long");
|
throw std::runtime_error ("Expected an unsigned long");
|
||||||
@ -114,7 +114,7 @@ proton::is_list (pn_data_t * data_) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
inline void
|
void
|
||||||
proton::is_string (pn_data_t * data_, bool allowNull) {
|
proton::is_string (pn_data_t * data_, bool allowNull) {
|
||||||
if (pn_data_type(data_) != PN_STRING) {
|
if (pn_data_type(data_) != PN_STRING) {
|
||||||
if (allowNull && pn_data_type(data_) != PN_NULL) {
|
if (allowNull && pn_data_type(data_) != PN_NULL) {
|
||||||
@ -141,9 +141,9 @@ proton::get_string (pn_data_t * data_, bool allowNull) {
|
|||||||
template<>
|
template<>
|
||||||
std::string
|
std::string
|
||||||
proton::get_symbol<std::string> (pn_data_t * data_) {
|
proton::get_symbol<std::string> (pn_data_t * data_) {
|
||||||
is_symbol (data_);
|
is_symbol (data_);
|
||||||
auto symbol = pn_data_get_symbol(data_);
|
auto symbol = pn_data_get_symbol(data_);
|
||||||
return std::string (symbol.start, symbol.size);
|
return std::string (symbol.start, symbol.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -173,8 +173,8 @@ proton::
|
|||||||
auto_enter::auto_enter (pn_data_t * data_, bool next_)
|
auto_enter::auto_enter (pn_data_t * data_, bool next_)
|
||||||
: m_data (data_)
|
: m_data (data_)
|
||||||
{
|
{
|
||||||
proton::pn_data_enter(m_data);
|
proton::pn_data_enter (m_data);
|
||||||
if (next_) pn_data_next(m_data);
|
if (next_) pn_data_next (m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -224,7 +224,7 @@ auto_list_enter::auto_list_enter (pn_data_t * data_, bool next_)
|
|||||||
|
|
||||||
proton::
|
proton::
|
||||||
auto_list_enter::~auto_list_enter() {
|
auto_list_enter::~auto_list_enter() {
|
||||||
pn_data_exit(m_data);
|
pn_data_exit (m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -321,3 +321,16 @@ readAndNext<long> (
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
template<>
|
||||||
|
u_long
|
||||||
|
proton::
|
||||||
|
readAndNext<u_long > (
|
||||||
|
pn_data_t * data_,
|
||||||
|
bool tolerateDeviance_
|
||||||
|
) {
|
||||||
|
long rtn = pn_data_get_ulong (data_);
|
||||||
|
pn_data_next(data_);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
@ -46,7 +46,7 @@ namespace proton {
|
|||||||
pn_data_t * m_data;
|
pn_data_t * m_data;
|
||||||
|
|
||||||
public :
|
public :
|
||||||
auto_enter (pn_data_t *, bool next_ = false);
|
explicit auto_enter (pn_data_t *, bool next_ = false);
|
||||||
~auto_enter();
|
~auto_enter();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,9 +55,13 @@ namespace proton {
|
|||||||
pn_data_t * m_data;
|
pn_data_t * m_data;
|
||||||
|
|
||||||
public :
|
public :
|
||||||
auto_next (pn_data_t *);
|
explicit auto_next (pn_data_t *);
|
||||||
auto_next (const auto_next &) = delete;
|
auto_next (const auto_next &) = delete;
|
||||||
|
|
||||||
|
explicit operator pn_data_t *() {
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
~auto_next();
|
~auto_next();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +71,7 @@ namespace proton {
|
|||||||
pn_data_t * m_data;
|
pn_data_t * m_data;
|
||||||
|
|
||||||
public :
|
public :
|
||||||
auto_list_enter (pn_data_t *, bool next_ = false);
|
explicit auto_list_enter (pn_data_t *, bool next_ = false);
|
||||||
~auto_list_enter();
|
~auto_list_enter();
|
||||||
|
|
||||||
size_t elements() const;
|
size_t elements() const;
|
||||||
@ -81,7 +85,7 @@ namespace proton {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T
|
T
|
||||||
readAndNext (pn_data_t * data_, bool tolerateDeviance_ = false) {
|
readAndNext (pn_data_t *, bool tolerateDeviance_ = false) {
|
||||||
return T{};
|
return T{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ include 'webserver'
|
|||||||
include 'webserver:webcapsule'
|
include 'webserver:webcapsule'
|
||||||
include 'experimental'
|
include 'experimental'
|
||||||
include 'experimental:avalanche'
|
include 'experimental:avalanche'
|
||||||
|
include 'experimental:blobwriter'
|
||||||
include 'experimental:quasar-hook'
|
include 'experimental:quasar-hook'
|
||||||
include 'experimental:corda-utils'
|
include 'experimental:corda-utils'
|
||||||
include 'experimental:nodeinfo'
|
include 'experimental:nodeinfo'
|
||||||
|
Reference in New Issue
Block a user