annotate utilities/vampipe-convert.cpp @ 24:533ca5ca3404

More on reading and writing json messages
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 23 May 2016 16:09:25 +0100
parents d678cd00e593
children 5b9690d18241
rev   line source
c@23 1
c@23 2 #include "VampJson.h"
c@23 3 #include "VampnProto.h"
c@23 4
c@23 5 #include <iostream>
c@23 6 #include <sstream>
c@23 7 #include <stdexcept>
c@23 8
c@23 9 using namespace std;
c@23 10 using namespace json11;
c@23 11 using namespace vampipe;
c@23 12
c@24 13 // Accepting JSON objects with two fields, "type" and "content". The
c@23 14 // "type" string corresponds to the JSON schema filename
c@24 15 // (e.g. "outputdescriptor") and the "content" is the JSON object
c@23 16 // encoded with that schema.
c@23 17
c@23 18 class PreservingPluginHandleMapper : public PluginHandleMapper
c@23 19 {
c@23 20 public:
c@23 21 PreservingPluginHandleMapper() : m_handle(0), m_plugin(0) { }
c@23 22
c@23 23 virtual int32_t pluginToHandle(Vamp::Plugin *p) {
c@23 24 if (p == m_plugin) return m_handle;
c@23 25 else throw NotFound();
c@23 26 }
c@23 27
c@23 28 virtual Vamp::Plugin *handleToPlugin(int32_t h) {
c@23 29 m_handle = h;
c@23 30 m_plugin = reinterpret_cast<Vamp::Plugin *>(h);
c@23 31 return m_plugin;
c@23 32 }
c@23 33
c@23 34 private:
c@23 35 int32_t m_handle;
c@23 36 Vamp::Plugin *m_plugin;
c@23 37 };
c@23 38
c@23 39 void usage()
c@23 40 {
c@23 41 string myname = "vampipe-convert";
c@23 42 cerr << "\n" << myname <<
c@24 43 ": Validate and convert Vamp request and response messages\n\n"
c@24 44 " Usage: " << myname << " [-i <informat>] [-o <outformat>] request\n"
c@24 45 " " << myname << " [-i <informat>] [-o <outformat>] response\n\n"
c@24 46 " where\n"
c@24 47 " <informat>: the format to read from stdin\n"
c@24 48 " (\"json\" or \"capnp\", default is \"json\")\n"
c@24 49 " <outformat>: the format to convert to and write to stdout\n"
c@24 50 " (\"json\" or \"capnp\", default is \"json\")\n"
c@24 51 " request|response: whether to expect Vamp request or response messages\n\n"
c@24 52 "If <informat> and <outformat> differ, convert from <informat> to <outformat>.\n"
c@24 53 "If <informat> and <outformat> are the same, just check validity of incoming\n"
c@24 54 "messages and pass them to output.\n\n";
c@24 55
c@23 56 exit(2);
c@23 57 }
c@23 58
c@23 59 class RequestOrResponse
c@23 60 {
c@23 61 public:
c@24 62 enum Direction {
c@24 63 Request, Response
c@24 64 };
c@23 65 enum Type {
c@23 66 List, Load, Configure, Process, Finish, Eof
c@23 67 };
c@24 68
c@24 69 static Type typeForName(string name) {
c@24 70 if (name == "list") return List;
c@24 71 else if (name == "load") return Load;
c@24 72 else if (name == "configure") return Configure;
c@24 73 else if (name == "process") return Process;
c@24 74 else if (name == "finish") return Finish;
c@24 75 else if (name == "eof") return Eof;
c@24 76 else {
c@24 77 throw runtime_error("unknown or unexpected request/response type \"" +
c@24 78 name + "\"");
c@24 79 }
c@24 80 }
c@24 81
c@23 82 RequestOrResponse() : // nothing by default
c@24 83 direction(Request),
c@23 84 type(Eof),
c@23 85 success(false),
c@23 86 finishPlugin(0) { }
c@23 87
c@24 88 Direction direction;
c@23 89 Type type;
c@23 90 bool success;
c@23 91 string errorText;
c@23 92
c@23 93 PreservingPluginHandleMapper mapper;
c@24 94
c@24 95 vector<Vamp::HostExt::PluginStaticData> listResponse;
c@23 96 Vamp::HostExt::LoadRequest loadRequest;
c@23 97 Vamp::HostExt::LoadResponse loadResponse;
c@23 98 Vamp::HostExt::ConfigurationRequest configurationRequest;
c@23 99 Vamp::HostExt::ConfigurationResponse configurationResponse;
c@23 100 Vamp::HostExt::ProcessRequest processRequest;
c@23 101 Vamp::HostExt::ProcessResponse processResponse;
c@23 102 Vamp::Plugin *finishPlugin;
c@23 103 Vamp::HostExt::ProcessResponse finishResponse;
c@23 104 };
c@23 105
c@24 106 Json
c@24 107 convertRequestJson(string input)
c@24 108 {
c@24 109 string err;
c@24 110 Json j = Json::parse(input, err);
c@24 111 if (err != "") {
c@24 112 throw VampJson::Failure("invalid json: " + err);
c@24 113 }
c@24 114 if (!j.is_object()) {
c@24 115 throw VampJson::Failure("object expected at top level");
c@24 116 }
c@24 117 if (!j["type"].is_string()) {
c@24 118 throw VampJson::Failure("string expected for type field");
c@24 119 }
c@24 120 if (!j["content"].is_object()) {
c@24 121 throw VampJson::Failure("object expected for content field");
c@24 122 }
c@24 123 return j;
c@24 124 }
c@24 125
c@24 126 Json
c@24 127 convertResponseJson(string input)
c@24 128 {
c@24 129 string err;
c@24 130 Json j = Json::parse(input, err);
c@24 131 if (err != "") {
c@24 132 throw VampJson::Failure("invalid json: " + err);
c@24 133 }
c@24 134 if (!j.is_object()) {
c@24 135 throw VampJson::Failure("object expected at top level");
c@24 136 }
c@24 137 if (!j["success"].is_bool()) {
c@24 138 throw VampJson::Failure("bool expected for success field");
c@24 139 }
c@24 140 if (!j["content"].is_object()) {
c@24 141 throw VampJson::Failure("object expected for content field");
c@24 142 }
c@24 143 return j;
c@24 144 }
c@24 145
c@23 146 RequestOrResponse
c@24 147 readRequestJson()
c@23 148 {
c@23 149 RequestOrResponse rr;
c@24 150 rr.direction = RequestOrResponse::Request;
c@24 151
c@24 152 string input;
c@24 153 if (!getline(cin, input)) {
c@24 154 rr.type = RequestOrResponse::Eof;
c@24 155 return rr;
c@24 156 }
c@24 157
c@24 158 Json j = convertRequestJson(input);
c@24 159 string type = j["type"].string_value();
c@24 160 rr.type = RequestOrResponse::typeForName(type);
c@24 161
c@24 162 if (rr.type == RequestOrResponse::Load) {
c@24 163 rr.loadRequest = VampJson::toVampRequest_Load(j);
c@24 164
c@24 165 } else if (rr.type == RequestOrResponse::Configure) {
c@24 166 rr.configurationRequest = VampJson::toVampRequest_Configure(j, rr.mapper);
c@24 167
c@24 168 } else if (rr.type == RequestOrResponse::Process) {
c@24 169 rr.processRequest = VampJson::toVampRequest_Process(j, rr.mapper);
c@24 170
c@24 171 } else if (rr.type == RequestOrResponse::Finish) {
c@24 172 rr.finishPlugin = VampJson::toVampRequest_Finish(j, rr.mapper);
c@24 173 }
c@24 174
c@24 175 return rr;
c@24 176 }
c@24 177
c@24 178 void
c@24 179 writeRequestJson(RequestOrResponse &rr)
c@24 180 {
c@24 181 Json j;
c@24 182
c@24 183 if (rr.type == RequestOrResponse::List) {
c@24 184 j = VampJson::fromVampRequest_List();
c@24 185
c@24 186 } else if (rr.type == RequestOrResponse::Load) {
c@24 187 j = VampJson::fromVampRequest_Load(rr.loadRequest);
c@24 188
c@24 189 } else if (rr.type == RequestOrResponse::Configure) {
c@24 190 j = VampJson::fromVampRequest_Configure(rr.configurationRequest, rr.mapper);
c@24 191
c@24 192 } else if (rr.type == RequestOrResponse::Process) {
c@24 193 j = VampJson::fromVampRequest_Process(rr.processRequest, rr.mapper);
c@24 194
c@24 195 } else if (rr.type == RequestOrResponse::Finish) {
c@24 196 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, rr.mapper);
c@24 197 }
c@24 198
c@24 199 cout << j.dump() << endl;
c@24 200 }
c@24 201
c@24 202 RequestOrResponse
c@24 203 readResponseJson()
c@24 204 {
c@24 205 RequestOrResponse rr;
c@24 206 rr.direction = RequestOrResponse::Response;
c@24 207
c@23 208 string input;
c@23 209 if (!getline(cin, input)) {
c@23 210 rr.type = RequestOrResponse::Eof;
c@23 211 return rr;
c@23 212 }
c@23 213
c@24 214 Json j = convertResponseJson(input);
c@23 215 string type = j["type"].string_value();
c@24 216 rr.type = RequestOrResponse::typeForName(type);
c@23 217
c@24 218 if (rr.type == RequestOrResponse::List) {
c@24 219 rr.listResponse = VampJson::toVampResponse_List(j);
c@24 220
c@24 221 } else if (rr.type == RequestOrResponse::Load) {
c@24 222 rr.loadResponse = VampJson::toVampResponse_Load(j, rr.mapper);
c@23 223
c@24 224 } else if (rr.type == RequestOrResponse::Configure) {
c@24 225 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
c@23 226
c@24 227 } else if (rr.type == RequestOrResponse::Process) {
c@24 228 rr.processResponse = VampJson::toVampResponse_Process(j);
c@23 229
c@24 230 } else if (rr.type == RequestOrResponse::Finish) {
c@24 231 rr.finishResponse = VampJson::toVampResponse_Finish(j);
c@23 232 }
c@23 233
c@23 234 return rr;
c@23 235 }
c@23 236
c@24 237 void
c@24 238 writeResponseJson(RequestOrResponse &rr)
c@24 239 {
c@24 240 Json j;
c@24 241
c@24 242 if (rr.type == RequestOrResponse::List) {
c@24 243 j = VampJson::fromVampResponse_List("", rr.listResponse);
c@24 244
c@24 245 } else if (rr.type == RequestOrResponse::Load) {
c@24 246 j = VampJson::fromVampResponse_Load(rr.loadResponse, rr.mapper);
c@24 247 }
c@24 248
c@24 249 cout << j.dump() << endl;
c@24 250 }
c@24 251
c@23 252 RequestOrResponse
c@24 253 readInput(string format, RequestOrResponse::Direction direction)
c@23 254 {
c@23 255 if (format == "json") {
c@24 256 if (direction == RequestOrResponse::Request) {
c@24 257 return readRequestJson();
c@24 258 } else {
c@24 259 return readResponseJson();
c@24 260 }
c@23 261 } else {
c@23 262 throw runtime_error("unknown or unimplemented format \"" + format + "\"");
c@23 263 }
c@23 264 }
c@23 265
c@23 266 void
c@24 267 writeOutput(string format, RequestOrResponse &rr)
c@23 268 {
c@24 269 if (format == "json") {
c@24 270 if (rr.direction == RequestOrResponse::Request) {
c@24 271 writeRequestJson(rr);
c@24 272 } else {
c@24 273 writeResponseJson(rr);
c@24 274 }
c@24 275 } else {
c@24 276 throw runtime_error("unknown or unimplemented format \"" + format + "\"");
c@24 277 }
c@23 278 }
c@23 279
c@23 280 int main(int argc, char **argv)
c@23 281 {
c@24 282 if (argc < 2) {
c@23 283 usage();
c@23 284 }
c@23 285
c@24 286 string informat = "json", outformat = "json";
c@24 287 RequestOrResponse::Direction direction;
c@24 288 bool haveDirection = false;
c@23 289
c@24 290 for (int i = 1; i < argc; ++i) {
c@23 291
c@23 292 string arg = argv[i];
c@24 293 bool final = (i + 1 == argc);
c@23 294
c@23 295 if (arg == "-i") {
c@24 296 if (informat != "" || final) usage();
c@23 297 else informat = argv[++i];
c@23 298
c@23 299 } else if (arg == "-o") {
c@24 300 if (outformat != "" || final) usage();
c@23 301 else outformat = argv[++i];
c@23 302
c@24 303 } else if (arg == "request") {
c@24 304 direction = RequestOrResponse::Request;
c@24 305 haveDirection = true;
c@24 306
c@24 307 } else if (arg == "response") {
c@24 308 direction = RequestOrResponse::Response;
c@24 309 haveDirection = true;
c@24 310
c@23 311 } else {
c@23 312 usage();
c@23 313 }
c@23 314 }
c@23 315
c@24 316 if (informat == "" || outformat == "" || !haveDirection) {
c@23 317 usage();
c@23 318 }
c@23 319
c@23 320 while (true) {
c@23 321
c@23 322 try {
c@23 323
c@24 324 RequestOrResponse rr = readInput(informat, direction);
c@23 325 if (rr.type == RequestOrResponse::Eof) break;
c@23 326 writeOutput(outformat, rr);
c@23 327
c@23 328 } catch (std::exception &e) {
c@23 329 cerr << "Error: " << e.what() << endl;
c@23 330 exit(1);
c@23 331 }
c@23 332 }
c@23 333
c@23 334 exit(0);
c@23 335 }
c@23 336
c@23 337