Mercurial > hg > piper-cpp
changeset 65:2d866edd79d5
Merge from noexcept branch
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Fri, 23 Sep 2016 14:23:10 +0100 |
parents | 85ec33975434 (current diff) 0ea374ea96a2 (diff) |
children | 6f160dee1192 |
files | json/VampJson.h json/json-test.cpp utilities/json-cli.cpp utilities/json-to-capnp.cpp |
diffstat | 12 files changed, 454 insertions(+), 761 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Fri Sep 23 14:20:29 2016 +0100 +++ b/Makefile Fri Sep 23 14:23:10 2016 +0100 @@ -6,7 +6,7 @@ #!!! todo: proper dependencies -all: bin/vamp-json-cli bin/vamp-json-to-capnp bin/vampipe-convert bin/vampipe-server +all: bin/vampipe-convert bin/vampipe-server bin/vampipe-convert: o/vampipe-convert.o o/json11.o o/vamp.capnp.o c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS) @@ -14,12 +14,6 @@ bin/vampipe-server: o/vampipe-server.o o/vamp.capnp.o c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS) -bin/vamp-json-to-capnp: o/json-to-capnp.o o/json11.o - c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS) - -bin/vamp-json-cli: o/json-cli.o o/json11.o - c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS) - capnproto/vamp.capnp.h: capnproto/vamp.capnp capnp compile $< -oc++ @@ -35,15 +29,8 @@ o/vampipe-server.o: utilities/vampipe-server.cpp capnproto/vamp.capnp.h capnproto/VampnProto.h c++ $(CXXFLAGS) $(INCFLAGS) -c $< -o $@ -o/json-to-capnp.o: utilities/json-to-capnp.cpp capnproto/vamp.capnp.h capnproto/VampnProto.h json/VampJson.h - c++ $(CXXFLAGS) $(INCFLAGS) -c $< -o $@ - -o/json-cli.o: utilities/json-cli.cpp json/VampJson.h - c++ $(CXXFLAGS) $(INCFLAGS) -c $< -o $@ - test: all - VAMP_PATH=./vamp-plugin-sdk/examples test/test-json-cli.sh - VAMP_PATH=./vamp-plugin-sdk/examples test/test-json-to-capnp.sh + test/test-vampipe-server.sh clean: rm -f */*.o capnproto/vamp.capnp.h capnproto/vamp.capnp.c++
--- a/bits/CountingPluginHandleMapper.h Fri Sep 23 14:20:29 2016 +0100 +++ b/bits/CountingPluginHandleMapper.h Fri Sep 23 14:23:10 2016 +0100 @@ -44,13 +44,13 @@ namespace vampipe { -//!!! NB not thread-safe at present, should it be? class CountingPluginHandleMapper : public PluginHandleMapper { public: CountingPluginHandleMapper() : m_nextHandle(1) { } void addPlugin(Vamp::Plugin *p) { + if (!p) return; if (m_rplugins.find(p) == m_rplugins.end()) { Handle h = m_nextHandle++; m_plugins[h] = p; @@ -61,9 +61,7 @@ } void removePlugin(Handle h) { - if (m_plugins.find(h) == m_plugins.end()) { - throw NotFound(); - } + if (m_plugins.find(h) == m_plugins.end()) return; Vamp::Plugin *p = m_plugins[h]; m_outputMappers.erase(h); m_plugins.erase(h); @@ -74,54 +72,57 @@ m_rplugins.erase(p); } - Handle pluginToHandle(Vamp::Plugin *p) const { + Handle pluginToHandle(Vamp::Plugin *p) const noexcept { if (m_rplugins.find(p) == m_rplugins.end()) { - throw NotFound(); + return INVALID_HANDLE; } return m_rplugins.at(p); } - Vamp::Plugin *handleToPlugin(Handle h) const { + Vamp::Plugin *handleToPlugin(Handle h) const noexcept { if (m_plugins.find(h) == m_plugins.end()) { - throw NotFound(); + return nullptr; } return m_plugins.at(h); } const std::shared_ptr<PluginOutputIdMapper> pluginToOutputIdMapper - (Vamp::Plugin *p) const { - // pluginToHandle checks the plugin has been registered with us - return m_outputMappers.at(pluginToHandle(p)); + (Vamp::Plugin *p) const noexcept { + return handleToOutputIdMapper(pluginToHandle(p)); } const std::shared_ptr<PluginOutputIdMapper> handleToOutputIdMapper - (Handle h) const { - if (m_plugins.find(h) == m_plugins.end()) { - throw NotFound(); + (Handle h) const noexcept { + if (h != INVALID_HANDLE && + m_outputMappers.find(h) != m_outputMappers.end()) { + return m_outputMappers.at(h); + } else { + return {}; } - return m_outputMappers.at(h); } - bool isConfigured(Handle h) const { + bool isConfigured(Handle h) const noexcept { + if (h == INVALID_HANDLE) return false; return m_configuredPlugins.find(h) != m_configuredPlugins.end(); } void markConfigured(Handle h, int channelCount, int blockSize) { + if (h == INVALID_HANDLE) return; m_configuredPlugins.insert(h); m_channelCounts[h] = channelCount; m_blockSizes[h] = blockSize; } - int getChannelCount(Handle h) const { + int getChannelCount(Handle h) const noexcept { if (m_channelCounts.find(h) == m_channelCounts.end()) { - throw NotFound(); + return 0; } return m_channelCounts.at(h); } - int getBlockSize(Handle h) const { + int getBlockSize(Handle h) const noexcept { if (m_blockSizes.find(h) == m_blockSizes.end()) { - throw NotFound(); + return 0; } return m_blockSizes.at(h); }
--- a/bits/DefaultPluginOutputIdMapper.h Fri Sep 23 14:20:29 2016 +0100 +++ b/bits/DefaultPluginOutputIdMapper.h Fri Sep 23 14:23:10 2016 +0100 @@ -49,19 +49,18 @@ } } - virtual int idToIndex(std::string outputId) const { + virtual int idToIndex(std::string outputId) const noexcept { int n = int(m_ids.size()); for (int i = 0; i < n; ++i) { if (outputId == m_ids[i]) { return i; } } - //!!! todo: this should in fact throw, or otherwise return an error - return 0; + return -1; } - virtual std::string indexToId(int index) const { - //!!! todo: this should in fact throw, or otherwise return an error + virtual std::string indexToId(int index) const noexcept { + if (index < 0 || size_t(index) >= m_ids.size()) return ""; return m_ids[index]; }
--- a/bits/PluginHandleMapper.h Fri Sep 23 14:20:29 2016 +0100 +++ b/bits/PluginHandleMapper.h Fri Sep 23 14:23:10 2016 +0100 @@ -42,28 +42,56 @@ namespace vampipe { +/** + * Convert plugin pointers to handles within some scope defined by the + * individual PluginHandleMapper implementation. + * + * The special handle 0 and the NULL plugin pointer are both used to + * represent "not found" and will be returned in any case where an + * unknown handle or plugin is requested. + * + * Note that the handle type must be representable as a JSON number, + * hence the use of a 32-bit rather than 64-bit int. + * + * This interface also includes methods for obtaining a + * PluginOutputIdMapper, \see PluginOutputIdMapper. + */ + class PluginHandleMapper { - // NB the handle type must fit in a JSON number - public: typedef int32_t Handle; + const Handle INVALID_HANDLE = 0; - virtual ~PluginHandleMapper() { } - - class NotFound : virtual public std::runtime_error { - public: - NotFound() : runtime_error("plugin or handle not found in mapper") { } - }; - - virtual Handle pluginToHandle(Vamp::Plugin *) const = 0; // may throw NotFound - virtual Vamp::Plugin *handleToPlugin(Handle) const = 0; // may throw NotFound + virtual ~PluginHandleMapper() noexcept { } + /** + * Look up and return the handle for a given plugin pointer. + * If the given pointer is null or not known, return INVALID_HANDLE. + */ + virtual Handle pluginToHandle(Vamp::Plugin *) const noexcept = 0; + + /** + * Look up and return the plugin for a given handle. + * If the given handle is INVALID_HANDLE or not known, return nullptr. + */ + virtual Vamp::Plugin *handleToPlugin(Handle) const noexcept = 0; + + /** + * Return a shared pointer to a PluginOutputIdMapper + * implementation for the given plugin pointer. If the given + * pointer is null or not known, return the null shared_ptr. + */ virtual const std::shared_ptr<PluginOutputIdMapper> pluginToOutputIdMapper - (Vamp::Plugin *p) const = 0; // may throw NotFound + (Vamp::Plugin *p) const noexcept = 0; + /** + * Return a shared pointer to a PluginOutputIdMapper + * implementation for the given plugin handle. If the given + * handle is INVALID_HANDLE or not known, return the null shared_ptr. + */ virtual const std::shared_ptr<PluginOutputIdMapper> handleToOutputIdMapper - (Handle h) const = 0; // may throw NotFound + (Handle h) const noexcept = 0; }; }
--- a/bits/PluginOutputIdMapper.h Fri Sep 23 14:20:29 2016 +0100 +++ b/bits/PluginOutputIdMapper.h Fri Sep 23 14:23:10 2016 +0100 @@ -42,14 +42,23 @@ namespace vampipe { -//!!! doc interface class PluginOutputIdMapper { public: virtual ~PluginOutputIdMapper() { } - - virtual int idToIndex(std::string outputId) const = 0; - virtual std::string indexToId(int index) const = 0; + + /** + * Return the index of the given output id in the plugin. The + * first output has index 0. If the given output id is unknown, + * return -1. + */ + virtual int idToIndex(std::string outputId) const noexcept = 0; + + /** + * Return the id of the output with the given index in the + * plugin. If the index is out of range, return the empty string. + */ + virtual std::string indexToId(int index) const noexcept = 0; }; }
--- a/bits/PreservingPluginHandleMapper.h Fri Sep 23 14:20:29 2016 +0100 +++ b/bits/PreservingPluginHandleMapper.h Fri Sep 23 14:23:10 2016 +0100 @@ -54,30 +54,34 @@ m_plugin(0), m_omapper(std::make_shared<PreservingPluginOutputIdMapper>()) { } - virtual Handle pluginToHandle(Vamp::Plugin *p) const { + virtual Handle pluginToHandle(Vamp::Plugin *p) const noexcept { + if (!p) return INVALID_HANDLE; if (p == m_plugin) return m_handle; else { std::cerr << "PreservingPluginHandleMapper: p = " << p << " differs from saved m_plugin " << m_plugin << " (not returning saved handle " << m_handle << ")" << std::endl; - throw NotFound(); + return INVALID_HANDLE; } } - virtual Vamp::Plugin *handleToPlugin(Handle h) const { + virtual Vamp::Plugin *handleToPlugin(Handle h) const noexcept { + if (h == INVALID_HANDLE) return nullptr; m_handle = h; m_plugin = reinterpret_cast<Vamp::Plugin *>(h); return m_plugin; } virtual const std::shared_ptr<PluginOutputIdMapper> pluginToOutputIdMapper - (Vamp::Plugin *) const { + (Vamp::Plugin *p) const noexcept { + if (!p) return {}; return m_omapper; } virtual const std::shared_ptr<PluginOutputIdMapper> handleToOutputIdMapper - (Handle h) const { + (Handle h) const noexcept { + if (h == INVALID_HANDLE) return {}; return m_omapper; }
--- a/bits/PreservingPluginOutputIdMapper.h Fri Sep 23 14:20:29 2016 +0100 +++ b/bits/PreservingPluginOutputIdMapper.h Fri Sep 23 14:23:10 2016 +0100 @@ -49,7 +49,7 @@ public: PreservingPluginOutputIdMapper() { } - virtual int idToIndex(std::string outputId) const { + virtual int idToIndex(std::string outputId) const noexcept { int n = int(m_ids.size()); int i = 0; while (i < n) { @@ -62,8 +62,8 @@ return i; } - virtual std::string indexToId(int index) const { - //!!! todo: this should in fact throw, or otherwise return an error + virtual std::string indexToId(int index) const noexcept { + if (index < 0 || size_t(index) >= m_ids.size()) return ""; return m_ids[index]; }
--- a/json/VampJson.h Fri Sep 23 14:20:29 2016 +0100 +++ b/json/VampJson.h Fri Sep 23 14:23:10 2016 +0100 @@ -38,7 +38,6 @@ #include <vector> #include <string> #include <sstream> -#include <stdexcept> #include <json11/json11.hpp> #include <base-n/include/basen.hpp> @@ -56,7 +55,25 @@ * Convert the structures laid out in the Vamp SDK classes into JSON * (and back again) following the schema in the vamp-json-schema * project repo. + * + * Functions with names starting "from" convert from a Vamp SDK object + * to JSON output. Most of them return a json11::Json object, with a + * few exceptions for low-level utilities that return a string. These + * functions succeed all of the time. + * + * Functions with names starting "to" convert to a Vamp SDK object + * from JSON input. These functions all accept a json11::Json object + * as first argument, with a few exceptions for low-level utilities + * that accept a string. These functions all accept a string reference + * as a final argument and return an error string through it if the + * conversion fails. If conversion fails the return value is + * undefined, and any returned object may be incomplete or + * invalid. Callers should check for an empty error string (indicating + * success) before using the returned value. */ + +//!!! todo: convert pmapper to err style + class VampJson { public: @@ -88,10 +105,9 @@ Base64 }; - class Failure : virtual public std::runtime_error { - public: - Failure(std::string s) : runtime_error(s) { } - }; + static bool failed(const std::string &err) { + return err != ""; + } template <typename T> static json11::Json @@ -105,12 +121,14 @@ template <typename T> static void - toBasicDescriptor(json11::Json j, T &t) { + toBasicDescriptor(json11::Json j, T &t, std::string &err) { if (!j.is_object()) { - throw Failure("object expected for basic descriptor content"); + err = "object expected for basic descriptor content"; + return; } if (!j["identifier"].is_string()) { - throw Failure("string expected for identifier"); + err = "string expected for identifier"; + return; } t.identifier = j["identifier"].string_value(); t.name = j["name"].string_value(); @@ -128,7 +146,7 @@ template <typename T> static bool - toValueExtents(json11::Json j, T &t) { + toValueExtents(json11::Json j, T &t, std::string &err) { if (j["extents"].is_null()) { return false; } else if (j["extents"].is_object()) { @@ -138,10 +156,12 @@ t.maxValue = j["extents"]["max"].number_value(); return true; } else { - throw Failure("numbers expected for min and max"); + err = "numbers expected for min and max"; + return false; } } else { - throw Failure("object expected for extents (if present)"); + err = "object expected for extents (if present)"; + return false; } } @@ -154,11 +174,12 @@ } static Vamp::RealTime - toRealTime(json11::Json j) { + toRealTime(json11::Json j, std::string &err) { json11::Json sec = j["s"]; json11::Json nsec = j["n"]; if (!sec.is_number() || !nsec.is_number()) { - throw Failure("invalid Vamp::RealTime object " + j.dump()); + err = "invalid Vamp::RealTime object " + j.dump(); + return {}; } return Vamp::RealTime(sec.int_value(), nsec.int_value()); } @@ -177,7 +198,7 @@ } static Vamp::Plugin::OutputDescriptor::SampleType - toSampleType(std::string text) { + toSampleType(std::string text, std::string &err) { if (text == "OneSamplePerStep") { return Vamp::Plugin::OutputDescriptor::OneSamplePerStep; } else if (text == "FixedSampleRate") { @@ -185,7 +206,8 @@ } else if (text == "VariableSampleRate") { return Vamp::Plugin::OutputDescriptor::VariableSampleRate; } else { - throw Failure("invalid sample type string: " + text); + err = "invalid sample type string: " + text; + return Vamp::Plugin::OutputDescriptor::OneSamplePerStep; } } @@ -221,19 +243,22 @@ } static Vamp::Plugin::OutputDescriptor - toConfiguredOutputDescriptor(json11::Json j) { + toConfiguredOutputDescriptor(json11::Json j, std::string &err) { Vamp::Plugin::OutputDescriptor od; if (!j.is_object()) { - throw Failure("object expected for output descriptor"); + err = "object expected for output descriptor"; + return {}; } od.unit = j["unit"].string_value(); - od.sampleType = toSampleType(j["sampleType"].string_value()); + od.sampleType = toSampleType(j["sampleType"].string_value(), err); + if (failed(err)) return {}; if (!j["sampleRate"].is_number()) { - throw Failure("number expected for sample rate"); + err = "number expected for sample rate"; + return {}; } od.sampleRate = j["sampleRate"].number_value(); od.hasDuration = j["hasDuration"].bool_value(); @@ -243,7 +268,8 @@ od.binCount = j["binCount"].int_value(); for (auto &n: j["binNames"].array_items()) { if (!n.is_string()) { - throw Failure("string expected for bin name"); + err = "string expected for bin name"; + return {}; } od.binNames.push_back(n.string_value()); } @@ -251,7 +277,9 @@ od.hasFixedBinCount = false; } - bool extentsPresent = toValueExtents(j, od); + bool extentsPresent = toValueExtents(j, od, err); + if (failed(err)) return {}; + od.hasKnownExtents = extentsPresent; if (j["quantizeStep"].is_number()) { @@ -265,16 +293,19 @@ } static Vamp::Plugin::OutputDescriptor - toOutputDescriptor(json11::Json j) { + toOutputDescriptor(json11::Json j, std::string &err) { Vamp::Plugin::OutputDescriptor od; if (!j.is_object()) { - throw Failure("object expected for output descriptor"); + err = "object expected for output descriptor"; + return {}; } - od = toConfiguredOutputDescriptor(j); + od = toConfiguredOutputDescriptor(j, err); + if (failed(err)) return {}; - toBasicDescriptor(j["basic"], od); + toBasicDescriptor(j["basic"], od, err); + if (failed(err)) return {}; return od; } @@ -297,24 +328,29 @@ } static Vamp::PluginBase::ParameterDescriptor - toParameterDescriptor(json11::Json j) { + toParameterDescriptor(json11::Json j, std::string &err) { Vamp::PluginBase::ParameterDescriptor pd; if (!j.is_object()) { - throw Failure("object expected for parameter descriptor"); + err = "object expected for parameter descriptor"; + return {}; } - toBasicDescriptor(j["basic"], pd); + toBasicDescriptor(j["basic"], pd, err); + if (failed(err)) return {}; pd.unit = j["unit"].string_value(); - bool extentsPresent = toValueExtents(j, pd); + bool extentsPresent = toValueExtents(j, pd, err); + if (failed(err)) return {}; if (!extentsPresent) { - throw Failure("extents must be present in parameter descriptor"); + err = "extents must be present in parameter descriptor"; + return {}; } if (!j["defaultValue"].is_number()) { - throw Failure("number expected for default value"); + err = "number expected for default value"; + return {}; } pd.defaultValue = j["defaultValue"].number_value(); @@ -322,7 +358,8 @@ pd.valueNames.clear(); for (auto &n: j["valueNames"].array_items()) { if (!n.is_string()) { - throw Failure("string expected for value name"); + err = "string expected for value name"; + return {}; } pd.valueNames.push_back(n.string_value()); } @@ -349,7 +386,7 @@ } static std::vector<float> - toFloatBuffer(std::string encoded) { + toFloatBuffer(std::string encoded, std::string & /* err */) { std::string decoded; bn::decode_b64(encoded.begin(), encoded.end(), back_inserter(decoded)); const float *buffer = reinterpret_cast<const float *>(decoded.c_str()); @@ -384,23 +421,26 @@ } static Vamp::Plugin::Feature - toFeature(json11::Json j, - BufferSerialisation &serialisation) { + toFeature(json11::Json j, BufferSerialisation &serialisation, std::string &err) { Vamp::Plugin::Feature f; if (!j.is_object()) { - throw Failure("object expected for feature"); + err = "object expected for feature"; + return {}; } if (j["timestamp"].is_object()) { - f.timestamp = toRealTime(j["timestamp"]); + f.timestamp = toRealTime(j["timestamp"], err); + if (failed(err)) return {}; f.hasTimestamp = true; } if (j["duration"].is_object()) { - f.duration = toRealTime(j["duration"]); + f.duration = toRealTime(j["duration"], err); + if (failed(err)) return {}; f.hasDuration = true; } if (j["b64values"].is_string()) { - f.values = toFloatBuffer(j["b64values"].string_value()); + f.values = toFloatBuffer(j["b64values"].string_value(), err); + if (failed(err)) return {}; serialisation = BufferSerialisation::Base64; } else if (j["values"].is_array()) { for (auto v : j["values"].array_items()) { @@ -430,14 +470,16 @@ static Vamp::Plugin::FeatureList toFeatureList(json11::Json j, - BufferSerialisation &serialisation) { + BufferSerialisation &serialisation, std::string &err) { Vamp::Plugin::FeatureList fl; if (!j.is_array()) { - throw Failure("array expected for feature list"); + err = "array expected for feature list"; + return {}; } for (const json11::Json &fj : j.array_items()) { - fl.push_back(toFeature(fj, serialisation)); + fl.push_back(toFeature(fj, serialisation, err)); + if (failed(err)) return {}; } return fl; } @@ -445,18 +487,22 @@ static Vamp::Plugin::FeatureSet toFeatureSet(json11::Json j, const PluginOutputIdMapper &omapper, - BufferSerialisation &serialisation) { + BufferSerialisation &serialisation, + std::string &err) { Vamp::Plugin::FeatureSet fs; if (!j.is_object()) { - throw Failure("object expected for feature set"); + err = "object expected for feature set"; + return {}; } for (auto &entry : j.object_items()) { int n = omapper.idToIndex(entry.first); if (fs.find(n) != fs.end()) { - throw Failure("duplicate numerical index for output"); + err = "duplicate numerical index for output"; + return {}; } - fs[n] = toFeatureList(entry.second, serialisation); + fs[n] = toFeatureList(entry.second, serialisation, err); + if (failed(err)) return {}; } return fs; } @@ -474,14 +520,15 @@ } static Vamp::Plugin::InputDomain - toInputDomain(std::string text) { + toInputDomain(std::string text, std::string &err) { if (text == "TimeDomain") { return Vamp::Plugin::TimeDomain; } else if (text == "FrequencyDomain") { return Vamp::Plugin::FrequencyDomain; } else { - throw Failure("invalid input domain string: " + text); + err = "invalid input domain string: " + text; + return {}; } } @@ -523,98 +570,108 @@ } static Vamp::HostExt::PluginStaticData - toPluginStaticData(json11::Json j) { + toPluginStaticData(json11::Json j, std::string &err) { - std::string err; if (!j.has_shape({ { "pluginKey", json11::Json::STRING }, { "pluginVersion", json11::Json::NUMBER }, { "minChannelCount", json11::Json::NUMBER }, { "maxChannelCount", json11::Json::NUMBER }, { "inputDomain", json11::Json::STRING }}, err)) { - throw Failure("malformed plugin static data: " + err); + + err = "malformed plugin static data: " + err; + + } else if (!j["basicOutputInfo"].is_array()) { + + err = "array expected for basic output info"; + + } else if (!j["maker"].is_null() && + !j["maker"].is_string()) { + + err = "string expected for maker"; + + } else if (!j["copyright"].is_null() && + !j["copyright"].is_string()) { + err = "string expected for copyright"; + + } else if (!j["category"].is_null() && + !j["category"].is_array()) { + + err = "array expected for category"; + + } else if (!j["parameters"].is_null() && + !j["parameters"].is_array()) { + + err = "array expected for parameters"; + + } else if (!j["programs"].is_null() && + !j["programs"].is_array()) { + + err = "array expected for programs"; + + } else if (!j["inputDomain"].is_null() && + !j["inputDomain"].is_string()) { + + err = "string expected for inputDomain"; + + } else if (!j["basicOutputInfo"].is_null() && + !j["basicOutputInfo"].is_array()) { + + err = "array expected for basicOutputInfo"; + + } else { + + Vamp::HostExt::PluginStaticData psd; + + psd.pluginKey = j["pluginKey"].string_value(); + + toBasicDescriptor(j["basic"], psd.basic, err); + if (failed(err)) return {}; + + psd.maker = j["maker"].string_value(); + psd.copyright = j["copyright"].string_value(); + psd.pluginVersion = j["pluginVersion"].int_value(); + + for (const auto &c : j["category"].array_items()) { + if (!c.is_string()) { + err = "strings expected in category array"; + return {}; + } + psd.category.push_back(c.string_value()); + } + + psd.minChannelCount = j["minChannelCount"].int_value(); + psd.maxChannelCount = j["maxChannelCount"].int_value(); + + for (const auto &p : j["parameters"].array_items()) { + auto pd = toParameterDescriptor(p, err); + if (failed(err)) return {}; + psd.parameters.push_back(pd); + } + + for (const auto &p : j["programs"].array_items()) { + if (!p.is_string()) { + err = "strings expected in programs array"; + return {}; + } + psd.programs.push_back(p.string_value()); + } + + psd.inputDomain = toInputDomain(j["inputDomain"].string_value(), err); + if (failed(err)) return {}; + + for (const auto &bo : j["basicOutputInfo"].array_items()) { + Vamp::HostExt::PluginStaticData::Basic b; + toBasicDescriptor(bo, b, err); + if (failed(err)) return {}; + psd.basicOutputInfo.push_back(b); + } + + return psd; } - if (!j["basicOutputInfo"].is_array()) { - throw Failure("array expected for basic output info"); - } - - if (!j["maker"].is_null() && - !j["maker"].is_string()) { - throw Failure("string expected for maker"); - } - - if (!j["copyright"].is_null() && - !j["copyright"].is_string()) { - throw Failure("string expected for copyright"); - } - - if (!j["category"].is_null() && - !j["category"].is_array()) { - throw Failure("array expected for category"); - } - - if (!j["parameters"].is_null() && - !j["parameters"].is_array()) { - throw Failure("array expected for parameters"); - } - - if (!j["programs"].is_null() && - !j["programs"].is_array()) { - throw Failure("array expected for programs"); - } - - if (!j["inputDomain"].is_null() && - !j["inputDomain"].is_string()) { - throw Failure("string expected for inputDomain"); - } - - if (!j["basicOutputInfo"].is_null() && - !j["basicOutputInfo"].is_array()) { - throw Failure("array expected for basicOutputInfo"); - } - - Vamp::HostExt::PluginStaticData psd; - - psd.pluginKey = j["pluginKey"].string_value(); - - toBasicDescriptor(j["basic"], psd.basic); - - psd.maker = j["maker"].string_value(); - psd.copyright = j["copyright"].string_value(); - psd.pluginVersion = j["pluginVersion"].int_value(); - - for (const auto &c : j["category"].array_items()) { - if (!c.is_string()) { - throw Failure("strings expected in category array"); - } - psd.category.push_back(c.string_value()); - } - - psd.minChannelCount = j["minChannelCount"].int_value(); - psd.maxChannelCount = j["maxChannelCount"].int_value(); - - for (const auto &p : j["parameters"].array_items()) { - auto pd = toParameterDescriptor(p); - psd.parameters.push_back(pd); - } - - for (const auto &p : j["programs"].array_items()) { - if (!p.is_string()) { - throw Failure("strings expected in programs array"); - } - psd.programs.push_back(p.string_value()); - } - - psd.inputDomain = toInputDomain(j["inputDomain"].string_value()); - - for (const auto &bo : j["basicOutputInfo"].array_items()) { - Vamp::HostExt::PluginStaticData::Basic b; - toBasicDescriptor(bo, b); - psd.basicOutputInfo.push_back(b); - } - - return psd; + // fallthrough error case + return {}; } static json11::Json @@ -640,30 +697,33 @@ } static Vamp::HostExt::PluginConfiguration - toPluginConfiguration(json11::Json j) { + toPluginConfiguration(json11::Json j, std::string &err) { - std::string err; if (!j.has_shape({ { "channelCount", json11::Json::NUMBER }, { "stepSize", json11::Json::NUMBER }, { "blockSize", json11::Json::NUMBER } }, err)) { - throw Failure("malformed plugin configuration: " + err); + err = "malformed plugin configuration: " + err; + return {}; } if (!j["parameterValues"].is_null() && !j["parameterValues"].is_object()) { - throw Failure("object expected for parameter values"); + err = "object expected for parameter values"; + return {}; } for (auto &pv : j["parameterValues"].object_items()) { if (!pv.second.is_number()) { - throw Failure("number expected for parameter value"); + err = "number expected for parameter value"; + return {}; } } if (!j["currentProgram"].is_null() && !j["currentProgram"].is_string()) { - throw Failure("string expected for program name"); + err = "string expected for program name"; + return {}; } Vamp::HostExt::PluginConfiguration config; @@ -702,30 +762,36 @@ } static Vamp::HostExt::PluginLoader::AdapterFlags - toAdapterFlags(json11::Json j) { + toAdapterFlags(json11::Json j, std::string &err) { + + int flags = 0x0; if (!j.is_array()) { - throw Failure("array expected for adapter flags"); - } - int flags = 0x0; - for (auto &jj: j.array_items()) { - if (!jj.is_string()) { - throw Failure("string expected for adapter flag"); - } - std::string text = jj.string_value(); - if (text == "AdaptInputDomain") { - flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN; - } else if (text == "AdaptChannelCount") { - flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT; - } else if (text == "AdaptBufferSize") { - flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE; - } else if (text == "AdaptAllSafe") { - flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE; - } else if (text == "AdaptAll") { - flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL; - } else { - throw Failure("invalid adapter flag string: " + text); + err = "array expected for adapter flags"; + + } else { + + for (auto &jj: j.array_items()) { + if (!jj.is_string()) { + err = "string expected for adapter flag"; + break; + } + std::string text = jj.string_value(); + if (text == "AdaptInputDomain") { + flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN; + } else if (text == "AdaptChannelCount") { + flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT; + } else if (text == "AdaptBufferSize") { + flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE; + } else if (text == "AdaptAllSafe") { + flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE; + } else if (text == "AdaptAll") { + flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL; + } else { + err = "invalid adapter flag string: " + text; + break; + } } } @@ -743,21 +809,21 @@ } static Vamp::HostExt::LoadRequest - toLoadRequest(json11::Json j) { + toLoadRequest(json11::Json j, std::string &err) { - std::string err; - if (!j.has_shape({ { "pluginKey", json11::Json::STRING }, { "inputSampleRate", json11::Json::NUMBER } }, err)) { - throw Failure("malformed load request: " + err); + err = "malformed load request: " + err; + return {}; } Vamp::HostExt::LoadRequest req; req.pluginKey = j["pluginKey"].string_value(); req.inputSampleRate = j["inputSampleRate"].number_value(); if (!j["adapterFlags"].is_null()) { - req.adapterFlags = toAdapterFlags(j["adapterFlags"]); + req.adapterFlags = toAdapterFlags(j["adapterFlags"], err); + if (failed(err)) return {}; } return req; } @@ -776,21 +842,23 @@ static Vamp::HostExt::LoadResponse toLoadResponse(json11::Json j, - const PluginHandleMapper &pmapper) { - - std::string err; + const PluginHandleMapper &pmapper, std::string &err) { if (!j.has_shape({ { "pluginHandle", json11::Json::NUMBER }, { "staticData", json11::Json::OBJECT }, { "defaultConfiguration", json11::Json::OBJECT } }, err)) { - throw Failure("malformed load response: " + err); + err = "malformed load response: " + err; + return {}; } Vamp::HostExt::LoadResponse resp; resp.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value()); - resp.staticData = toPluginStaticData(j["staticData"]); - resp.defaultConfiguration = toPluginConfiguration(j["defaultConfiguration"]); + resp.staticData = toPluginStaticData(j["staticData"], err); + if (failed(err)) return {}; + resp.defaultConfiguration = toPluginConfiguration(j["defaultConfiguration"], + err); + if (failed(err)) return {}; return resp; } @@ -808,19 +876,19 @@ static Vamp::HostExt::ConfigurationRequest toConfigurationRequest(json11::Json j, - const PluginHandleMapper &pmapper) { - - std::string err; + const PluginHandleMapper &pmapper, std::string &err) { if (!j.has_shape({ { "pluginHandle", json11::Json::NUMBER }, { "configuration", json11::Json::OBJECT } }, err)) { - throw Failure("malformed configuration request: " + err); + err = "malformed configuration request: " + err; + return {}; } Vamp::HostExt::ConfigurationRequest cr; cr.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value()); - cr.configuration = toPluginConfiguration(j["configuration"]); + cr.configuration = toPluginConfiguration(j["configuration"], err); + if (failed(err)) return {}; return cr; } @@ -843,18 +911,20 @@ static Vamp::HostExt::ConfigurationResponse toConfigurationResponse(json11::Json j, - const PluginHandleMapper &pmapper) { + const PluginHandleMapper &pmapper, std::string &err) { Vamp::HostExt::ConfigurationResponse cr; cr.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value()); if (!j["outputList"].is_array()) { - throw Failure("array expected for output list"); + err = "array expected for output list"; + return {}; } for (const auto &o: j["outputList"].array_items()) { - cr.outputs.push_back(toOutputDescriptor(o)); + cr.outputs.push_back(toOutputDescriptor(o, err)); + if (failed(err)) return {}; } return cr; @@ -892,14 +962,13 @@ static Vamp::HostExt::ProcessRequest toProcessRequest(json11::Json j, const PluginHandleMapper &pmapper, - BufferSerialisation &serialisation) { - - std::string err; + BufferSerialisation &serialisation, std::string &err) { if (!j.has_shape({ { "pluginHandle", json11::Json::NUMBER }, { "processInput", json11::Json::OBJECT } }, err)) { - throw Failure("malformed process request: " + err); + err = "malformed process request: " + err; + return {}; } auto input = j["processInput"]; @@ -907,18 +976,22 @@ if (!input.has_shape({ { "timestamp", json11::Json::OBJECT }, { "inputBuffers", json11::Json::ARRAY } }, err)) { - throw Failure("malformed process request: " + err); + err = "malformed process request: " + err; + return {}; } Vamp::HostExt::ProcessRequest r; r.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value()); - r.timestamp = toRealTime(input["timestamp"]); + r.timestamp = toRealTime(input["timestamp"], err); + if (failed(err)) return {}; for (auto a: input["inputBuffers"].array_items()) { if (a["b64values"].is_string()) { - std::vector<float> buf = toFloatBuffer(a["b64values"].string_value()); + std::vector<float> buf = toFloatBuffer(a["b64values"].string_value(), + err); + if (failed(err)) return {}; r.inputBuffers.push_back(buf); serialisation = BufferSerialisation::Base64; @@ -931,7 +1004,8 @@ serialisation = BufferSerialisation::Text; } else { - throw Failure("expected values or b64values in inputBuffers object"); + err = "expected values or b64values in inputBuffers object"; + return {}; } } @@ -1084,39 +1158,37 @@ jo["errorText"] = std::string("error in ") + type + " request: " + errorText; return json11::Json(jo); } - - static json11::Json - fromException(const std::exception &e, RRType responseType) { - - return fromError(e.what(), responseType); - } private: // go private briefly for a couple of helper functions static void - checkTypeField(json11::Json j, std::string expected) { + checkTypeField(json11::Json j, std::string expected, std::string &err) { if (!j["type"].is_string()) { - throw Failure("string expected for type"); + err = "string expected for type"; + return; } if (j["type"].string_value() != expected) { - throw Failure("expected value \"" + expected + "\" for type"); + err = "expected value \"" + expected + "\" for type"; + return; } } static bool - successful(json11::Json j) { + successful(json11::Json j, std::string &err) { if (!j["success"].is_bool()) { - throw Failure("bool expected for success"); + err = "bool expected for success"; + return false; } return j["success"].bool_value(); } public: static RRType - getRequestResponseType(json11::Json j) { + getRequestResponseType(json11::Json j, std::string &err) { if (!j["type"].is_string()) { - throw Failure("string expected for type"); + err = "string expected for type"; + return RRType::NotValid; } std::string type = j["type"].string_value(); @@ -1126,93 +1198,106 @@ else if (type == "configure") return RRType::Configure; else if (type == "process") return RRType::Process; else if (type == "finish") return RRType::Finish; + else if (type == "invalid") return RRType::NotValid; else { - throw Failure("unknown or unexpected request/response type \"" + - type + "\""); + err = "unknown or unexpected request/response type \"" + type + "\""; + return RRType::NotValid; } } static void - toVampRequest_List(json11::Json j) { - - checkTypeField(j, "list"); + toVampRequest_List(json11::Json j, std::string &err) { + checkTypeField(j, "list", err); } static Vamp::HostExt::ListResponse - toVampResponse_List(json11::Json j) { + toVampResponse_List(json11::Json j, std::string &err) { Vamp::HostExt::ListResponse resp; - if (successful(j)) { + if (successful(j, err) && !failed(err)) { for (const auto &a: j["content"]["plugins"].array_items()) { - resp.plugins.push_back(toPluginStaticData(a)); + resp.plugins.push_back(toPluginStaticData(a, err)); + if (failed(err)) return {}; } } + return resp; } static Vamp::HostExt::LoadRequest - toVampRequest_Load(json11::Json j) { + toVampRequest_Load(json11::Json j, std::string &err) { - checkTypeField(j, "load"); - return toLoadRequest(j["content"]); + checkTypeField(j, "load", err); + if (failed(err)) return {}; + return toLoadRequest(j["content"], err); } static Vamp::HostExt::LoadResponse - toVampResponse_Load(json11::Json j, const PluginHandleMapper &pmapper) { + toVampResponse_Load(json11::Json j, + const PluginHandleMapper &pmapper, + std::string &err) { Vamp::HostExt::LoadResponse resp; - if (successful(j)) { - resp = toLoadResponse(j["content"], pmapper); + if (successful(j, err) && !failed(err)) { + resp = toLoadResponse(j["content"], pmapper, err); } return resp; } static Vamp::HostExt::ConfigurationRequest - toVampRequest_Configure(json11::Json j, const PluginHandleMapper &pmapper) { + toVampRequest_Configure(json11::Json j, + const PluginHandleMapper &pmapper, + std::string &err) { - checkTypeField(j, "configure"); - return toConfigurationRequest(j["content"], pmapper); + checkTypeField(j, "configure", err); + if (failed(err)) return {}; + return toConfigurationRequest(j["content"], pmapper, err); } static Vamp::HostExt::ConfigurationResponse - toVampResponse_Configure(json11::Json j, const PluginHandleMapper &pmapper) { + toVampResponse_Configure(json11::Json j, + const PluginHandleMapper &pmapper, + std::string &err) { Vamp::HostExt::ConfigurationResponse resp; - if (successful(j)) { - resp = toConfigurationResponse(j["content"], pmapper); + if (successful(j, err) && !failed(err)) { + resp = toConfigurationResponse(j["content"], pmapper, err); } return resp; } static Vamp::HostExt::ProcessRequest toVampRequest_Process(json11::Json j, const PluginHandleMapper &pmapper, - BufferSerialisation &serialisation) { + BufferSerialisation &serialisation, std::string &err) { - checkTypeField(j, "process"); - return toProcessRequest(j["content"], pmapper, serialisation); + checkTypeField(j, "process", err); + if (failed(err)) return {}; + return toProcessRequest(j["content"], pmapper, serialisation, err); } static Vamp::HostExt::ProcessResponse toVampResponse_Process(json11::Json j, const PluginHandleMapper &pmapper, - BufferSerialisation &serialisation) { + BufferSerialisation &serialisation, std::string &err) { Vamp::HostExt::ProcessResponse resp; - if (successful(j)) { + if (successful(j, err) && !failed(err)) { auto jc = j["content"]; auto h = jc["pluginHandle"].int_value(); resp.plugin = pmapper.handleToPlugin(h); resp.features = toFeatureSet(jc["features"], *pmapper.handleToOutputIdMapper(h), - serialisation); + serialisation, err); } return resp; } static Vamp::HostExt::FinishRequest - toVampRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper) { + toVampRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper, + std::string &err) { - checkTypeField(j, "finish"); + checkTypeField(j, "finish", err); + if (failed(err)) return {}; Vamp::HostExt::FinishRequest req; req.plugin = pmapper.handleToPlugin (j["content"]["pluginHandle"].int_value()); @@ -1222,16 +1307,16 @@ static Vamp::HostExt::ProcessResponse toVampResponse_Finish(json11::Json j, const PluginHandleMapper &pmapper, - BufferSerialisation &serialisation) { + BufferSerialisation &serialisation, std::string &err) { Vamp::HostExt::ProcessResponse resp; - if (successful(j)) { + if (successful(j, err) && !failed(err)) { auto jc = j["content"]; auto h = jc["pluginHandle"].int_value(); resp.plugin = pmapper.handleToPlugin(h); resp.features = toFeatureSet(jc["features"], *pmapper.handleToOutputIdMapper(h), - serialisation); + serialisation, err); } return resp; }
--- a/json/json-test.cpp Fri Sep 23 14:20:29 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ - -#include "VampJson.h" - -using std::cerr; -using std::endl; - -int main(int, char **) -{ - Vamp::PluginBase::ParameterDescriptor d; - d.identifier = "threshold"; - d.name = "Energy rise threshold"; - d.description = "Energy rise within a frequency bin necessary to count toward broadband total"; - d.unit = "dB"; - d.minValue = 0; - d.maxValue = 20.5; - d.defaultValue = 3; - d.isQuantized = false; - cerr << VampJson::fromParameterDescriptor(d).dump() << endl; - - Vamp::Plugin::OutputDescriptor od; - od.identifier = "powerspectrum"; - od.name = "Power Spectrum"; - od.description = "Power values of the frequency spectrum bins calculated from the input signal"; - od.unit = ""; - od.hasFixedBinCount = true; - od.binCount = 513; - od.hasKnownExtents = false; - od.isQuantized = false; - od.sampleType = Vamp::Plugin::OutputDescriptor::OneSamplePerStep; - cerr << VampJson::fromOutputDescriptor(od).dump() << endl; - - cerr << VampJson::fromFeature(Vamp::Plugin::Feature()).dump() << endl; - - Vamp::Plugin::Feature f; - f.hasTimestamp = true; - f.timestamp = Vamp::RealTime::fromSeconds(3.14159); - f.hasDuration = false; - f.values = { 1, 2, 3.000001, 4, 5, 6, 6.5, 7 }; - f.label = "A feature"; - cerr << VampJson::fromFeature(f).dump() << endl; - - Vamp::Plugin::FeatureSet fs; - fs[0].push_back(f); - std::string fs_str = VampJson::fromFeatureSet(fs).dump(); - cerr << fs_str << endl; - - std::string err; - - try { - Vamp::Plugin::ParameterDescriptor d1 = - VampJson::toParameterDescriptor - (json11::Json::parse - (VampJson::fromParameterDescriptor(d).dump(), err)); - if (err != "") { - cerr << "error returned from parser: " << err << endl; - } - cerr << "\nsuccessfully converted parameter descriptor back from json: serialising it again, we get:" << endl; - cerr << VampJson::fromParameterDescriptor(d1).dump() << endl; - } catch (std::runtime_error &e) { - cerr << "caught exception: " << e.what() << endl; - } - - try { - Vamp::Plugin::OutputDescriptor od1 = - VampJson::toOutputDescriptor - (json11::Json::parse - (VampJson::fromOutputDescriptor(od).dump(), err)); - if (err != "") { - cerr << "error returned from parser: " << err << endl; - } - cerr << "\nsuccessfully converted output descriptor back from json: serialising it again, we get:" << endl; - cerr << VampJson::fromOutputDescriptor(od1).dump() << endl; - } catch (std::runtime_error &e) { - cerr << "caught exception: " << e.what() << endl; - } - - try { - Vamp::Plugin::FeatureSet fs1 = - VampJson::toFeatureSet - (json11::Json::parse(fs_str, err)); - if (err != "") { - cerr << "error returned from parser: " << err << endl; - } - cerr << "\nsuccessfully converted feature set back from json: serialising it again, we get:" << endl; - cerr << VampJson::fromFeatureSet(fs1).dump() << endl; - } catch (std::runtime_error &e) { - cerr << "caught exception: " << e.what() << endl; - } - - return 0; -} - - -
--- a/utilities/json-cli.cpp Fri Sep 23 14:20:29 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ - -//!!! This program was an early test -- it should still compile but -//!!! it's incomplete. Remove it and use the server program instead. - -#include "VampJson.h" -#include "bits/CountingPluginHandleMapper.h" - -#include <iostream> -#include <sstream> -#include <stdexcept> - -#include <map> -#include <set> - -using namespace std; -using namespace Vamp; -using namespace Vamp::HostExt; -using namespace json11; -using namespace vampipe; - -static CountingPluginHandleMapper mapper; - -Vamp::HostExt::LoadResponse -loadPlugin(json11::Json j) { - - auto req = VampJson::toLoadRequest(j); - auto loader = Vamp::HostExt::PluginLoader::getInstance(); - auto response = loader->loadPlugin(req); - - if (!response.plugin) { - throw VampJson::Failure("plugin load failed"); - } - - return response; -} - -Vamp::HostExt::ConfigurationResponse -configurePlugin(Vamp::Plugin *plugin, json11::Json j) { - - auto config = VampJson::toPluginConfiguration(j); - Vamp::HostExt::ConfigurationRequest req; - req.plugin = plugin; - req.configuration = config; - auto loader = Vamp::HostExt::PluginLoader::getInstance(); - - auto response = loader->configurePlugin(req); - if (response.outputs.empty()) { - throw VampJson::Failure("plugin initialisation failed (invalid channelCount, stepSize, blockSize?)"); - } - return response; -} - -Json -handle_list(Json content) -{ - if (content != Json()) { - throw VampJson::Failure("no content expected for list request"); - } - - auto loader = PluginLoader::getInstance(); - auto resp = loader->listPluginData(); - - Json::array j; - for (const auto &pd: resp.plugins) { - j.push_back(VampJson::fromPluginStaticData(pd)); - } - return Json(j); -} - -Json -handle_load(Json j) -{ - auto loadResponse = loadPlugin(j); - - if (!loadResponse.plugin) { - throw VampJson::Failure("plugin load failed"); - } - - mapper.addPlugin(loadResponse.plugin); - - return VampJson::fromLoadResponse(loadResponse, mapper); -} - -Json -handle_configure(Json j) -{ - string err; - - if (!j.has_shape({ - { "pluginHandle", Json::NUMBER }, - { "configuration", Json::OBJECT }}, err)) { - throw VampJson::Failure("malformed configuration request: " + err); - } - - int32_t handle = j["pluginHandle"].int_value(); - - if (mapper.isConfigured(handle)) { - throw VampJson::Failure("plugin has already been configured"); - } - - Plugin *plugin = mapper.handleToPlugin(handle); - - Json config = j["configuration"]; - - auto response = configurePlugin(plugin, config); - - mapper.markConfigured(handle, 0, 0); //!!! - - cerr << "Configured and initialised plugin " << handle << endl; - - return VampJson::fromConfigurationResponse(response, mapper); -} - -Json -handle(string input) -{ - string err; - Json j = Json::parse(input, err); - - if (err != "") { - throw VampJson::Failure("invalid request: " + err); - } - - if (!j["type"].is_string()) { - throw VampJson::Failure("type expected in request"); - } - - if (!j["content"].is_null() && - !j["content"].is_object()) { - throw VampJson::Failure("object expected for content"); - } - - string verb = j["type"].string_value(); - Json content = j["content"]; - Json result; - - if (verb == "list") { - result = handle_list(content); - } else if (verb == "load") { - result = handle_load(content); - } else if (verb == "configure") { - result = handle_configure(content); - } else { - throw VampJson::Failure("unknown verb: " + verb + - " (known verbs are: list load configure)"); - } - - return result; -} - -Json -success_response(Json payload) -{ - Json::object obj; - obj["success"] = true; - obj["response"] = payload; - return Json(obj); -} - -Json -error_response(string text) -{ - Json::object obj; - obj["success"] = false; - obj["errorText"] = text; - return Json(obj); -} - -template<typename T> -T &getline(T &in, string prompt, string &out) -{ - cerr << prompt; - return getline(in, out); -} - -int main(int, char **) -{ - string line; - - while (getline(cin, "> ", line)) { - try { - Json result = handle(line); - cout << success_response(result).dump() << endl; - } catch (const VampJson::Failure &e) { - cout << error_response(e.what()).dump() << endl; - } catch (const PluginHandleMapper::NotFound &e) { - cout << error_response(e.what()).dump() << endl; - } - } - - return 0; -} - -
--- a/utilities/json-to-capnp.cpp Fri Sep 23 14:20:29 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ - -#include "VampJson.h" -#include "VampnProto.h" - -#include <iostream> -#include <sstream> -#include <stdexcept> - -#include "bits/PreservingPluginHandleMapper.h" - -using namespace std; -using namespace json11; -using namespace vampipe; - -// Accepting JSON objects with two fields, "type" and "payload". The -// "type" string corresponds to the JSON schema filename -// (e.g. "outputdescriptor") and the "payload" is the JSON object -// encoded with that schema. - -Json -json_input(string input) -{ - string err; - Json j = Json::parse(input, err); - if (err != "") { - throw VampJson::Failure("invalid json: " + err); - } - if (!j.is_object()) { - throw VampJson::Failure("object expected at top level"); - } - if (!j["type"].is_string()) { - throw VampJson::Failure("string expected for type field"); - } - if (!j["payload"].is_object()) { - throw VampJson::Failure("object expected for payload field"); - } - return j; -} - -void -handle_input(::capnp::MallocMessageBuilder &message, string input) -{ - string err; - - Json j = json_input(input); - string type = j["type"].string_value(); - Json payload = j["payload"]; - VampJson::BufferSerialisation serialisation; - - if (type == "configurationrequest") { - auto req = message.initRoot<ConfigurationRequest>(); - PreservingPluginHandleMapper mapper; - VampnProto::buildConfigurationRequest - (req, VampJson::toConfigurationRequest(payload, mapper), mapper); - - } else if (type == "configurationresponse") { - auto resp = message.initRoot<ConfigurationResponse>(); - PreservingPluginHandleMapper mapper; - VampnProto::buildConfigurationResponse - (resp, VampJson::toConfigurationResponse(payload, mapper), mapper); - - } else if (type == "feature") { - auto f = message.initRoot<Feature>(); - VampnProto::buildFeature - (f, VampJson::toFeature(payload, serialisation)); - - } else if (type == "featureset") { - auto fs = message.initRoot<FeatureSet>(); - PreservingPluginOutputIdMapper omapper; - VampnProto::buildFeatureSet - (fs, VampJson::toFeatureSet(payload, omapper, serialisation), omapper); - - } else if (type == "loadrequest") { - auto req = message.initRoot<LoadRequest>(); - VampnProto::buildLoadRequest - (req, VampJson::toLoadRequest(payload)); - - } else if (type == "loadresponse") { - auto resp = message.initRoot<LoadResponse>(); - PreservingPluginHandleMapper mapper; - VampnProto::buildLoadResponse - (resp, VampJson::toLoadResponse(payload, mapper), mapper); - - } else if (type == "outputdescriptor") { - auto od = message.initRoot<OutputDescriptor>(); - VampnProto::buildOutputDescriptor - (od, VampJson::toOutputDescriptor(payload)); - - } else if (type == "parameterdescriptor") { - auto pd = message.initRoot<ParameterDescriptor>(); - VampnProto::buildParameterDescriptor - (pd, VampJson::toParameterDescriptor(payload)); - - } else if (type == "pluginconfiguration") { - auto pc = message.initRoot<PluginConfiguration>(); - auto config = VampJson::toPluginConfiguration(payload); - VampnProto::buildPluginConfiguration(pc, config); - - } else if (type == "pluginstaticdata") { - auto pc = message.initRoot<PluginStaticData>(); - auto sd = VampJson::toPluginStaticData(payload); - VampnProto::buildPluginStaticData(pc, sd); - - } else if (type == "processrequest") { - auto p = message.initRoot<ProcessRequest>(); - PreservingPluginHandleMapper mapper; - VampnProto::buildProcessRequest - (p, VampJson::toProcessRequest(payload, mapper, serialisation), mapper); - - } else if (type == "realtime") { - auto b = message.initRoot<RealTime>(); - VampnProto::buildRealTime - (b, VampJson::toRealTime(payload)); - - } else { - throw VampJson::Failure("unknown or unsupported JSON schema type " + - type); - } -} - -int main(int, char **) -{ - string input; - - while (getline(cin, input)) { - try { - ::capnp::MallocMessageBuilder message; - handle_input(message, input); - writePackedMessageToFd(1, message); // stdout - return 0; - } catch (const VampJson::Failure &e) { - cerr << "Failed to convert JSON to Cap'n Proto message: " - << e.what() << endl; - return 1; - } - } -} - -
--- a/utilities/vampipe-convert.cpp Fri Sep 23 14:20:29 2016 +0100 +++ b/utilities/vampipe-convert.cpp Fri Sep 23 14:23:10 2016 +0100 @@ -37,41 +37,37 @@ } Json -convertRequestJson(string input) +convertRequestJson(string input, string &err) { - string err; Json j = Json::parse(input, err); if (err != "") { - throw VampJson::Failure("invalid json: " + err); + err = "invalid json: " + err; + return {}; } if (!j.is_object()) { - throw VampJson::Failure("object expected at top level"); - } - if (!j["type"].is_string()) { - throw VampJson::Failure("string expected for type field"); - } - if (!j["content"].is_null() && !j["content"].is_object()) { - throw VampJson::Failure("object expected for content field"); + err = "object expected at top level"; + } else if (!j["type"].is_string()) { + err = "string expected for type field"; + } else if (!j["content"].is_null() && !j["content"].is_object()) { + err = "object expected for content field"; } return j; } Json -convertResponseJson(string input) +convertResponseJson(string input, string &err) { - string err; Json j = Json::parse(input, err); if (err != "") { - throw VampJson::Failure("invalid json: " + err); + err = "invalid json: " + err; + return {}; } if (!j.is_object()) { - throw VampJson::Failure("object expected at top level"); - } - if (!j["success"].is_bool()) { - throw VampJson::Failure("bool expected for success field"); - } - if (!j["content"].is_object()) { - throw VampJson::Failure("object expected for content field"); + err = "object expected at top level"; + } else if (!j["success"].is_bool()) { + err = "bool expected for success field"; + } else if (!j["content"].is_object()) { + err = "object expected for content field"; } return j; } @@ -82,38 +78,42 @@ PreservingPluginHandleMapper mapper; RequestOrResponse -readRequestJson() +readRequestJson(string &err) { RequestOrResponse rr; rr.direction = RequestOrResponse::Request; string input; if (!getline(cin, input)) { + // the EOF case, not actually an error rr.type = RRType::NotValid; return rr; } - Json j = convertRequestJson(input); + Json j = convertRequestJson(input, err); + if (err != "") return {}; - rr.type = VampJson::getRequestResponseType(j); + rr.type = VampJson::getRequestResponseType(j, err); + if (err != "") return {}; + VampJson::BufferSerialisation serialisation = VampJson::BufferSerialisation::Text; switch (rr.type) { case RRType::List: - VampJson::toVampRequest_List(j); // type check only + VampJson::toVampRequest_List(j, err); // type check only break; case RRType::Load: - rr.loadRequest = VampJson::toVampRequest_Load(j); + rr.loadRequest = VampJson::toVampRequest_Load(j, err); break; case RRType::Configure: - rr.configurationRequest = VampJson::toVampRequest_Configure(j, mapper); + rr.configurationRequest = VampJson::toVampRequest_Configure(j, mapper, err); break; case RRType::Process: - rr.processRequest = VampJson::toVampRequest_Process(j, mapper, serialisation); + rr.processRequest = VampJson::toVampRequest_Process(j, mapper, serialisation, err); break; case RRType::Finish: - rr.finishRequest = VampJson::toVampRequest_Finish(j, mapper); + rr.finishRequest = VampJson::toVampRequest_Finish(j, mapper, err); break; case RRType::NotValid: break; @@ -158,20 +158,24 @@ } RequestOrResponse -readResponseJson() +readResponseJson(string &err) { RequestOrResponse rr; rr.direction = RequestOrResponse::Response; string input; if (!getline(cin, input)) { + // the EOF case, not actually an error rr.type = RRType::NotValid; return rr; } - Json j = convertResponseJson(input); + Json j = convertResponseJson(input, err); + if (err != "") return {}; - rr.type = VampJson::getRequestResponseType(j); + rr.type = VampJson::getRequestResponseType(j, err); + if (err != "") return {}; + VampJson::BufferSerialisation serialisation = VampJson::BufferSerialisation::Text; rr.success = j["success"].bool_value(); @@ -180,19 +184,19 @@ switch (rr.type) { case RRType::List: - rr.listResponse = VampJson::toVampResponse_List(j); + rr.listResponse = VampJson::toVampResponse_List(j, err); break; case RRType::Load: - rr.loadResponse = VampJson::toVampResponse_Load(j, mapper); + rr.loadResponse = VampJson::toVampResponse_Load(j, mapper, err); break; case RRType::Configure: - rr.configurationResponse = VampJson::toVampResponse_Configure(j, mapper); + rr.configurationResponse = VampJson::toVampResponse_Configure(j, mapper, err); break; case RRType::Process: - rr.processResponse = VampJson::toVampResponse_Process(j, mapper, serialisation); + rr.processResponse = VampJson::toVampResponse_Process(j, mapper, serialisation, err); break; case RRType::Finish: - rr.finishResponse = VampJson::toVampResponse_Finish(j, mapper, serialisation); + rr.finishResponse = VampJson::toVampResponse_Finish(j, mapper, serialisation, err); break; case RRType::NotValid: break; @@ -388,12 +392,12 @@ } RequestOrResponse -readInputJson(RequestOrResponse::Direction direction) +readInputJson(RequestOrResponse::Direction direction, string &err) { if (direction == RequestOrResponse::Request) { - return readRequestJson(); + return readRequestJson(err); } else { - return readResponseJson(); + return readResponseJson(err); } } @@ -418,7 +422,10 @@ readInput(string format, RequestOrResponse::Direction direction) { if (format == "json") { - return readInputJson(direction); + string err; + auto result = readInputJson(direction, err); + if (err != "") throw runtime_error(err); + else return result; } else if (format == "capnp") { return readInputCapnp(direction); } else {