annotate utilities/vampipe-convert.cpp @ 30:eb679afcd1bb

Comment for the future!
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 24 May 2016 15:38:50 +0100
parents 7062a3bebaa3
children b376ab0ce003
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@24 65
c@23 66 RequestOrResponse() : // nothing by default
c@24 67 direction(Request),
c@25 68 type(RRType::NotValid),
c@23 69 success(false),
c@23 70 finishPlugin(0) { }
c@23 71
c@24 72 Direction direction;
c@25 73 RRType type;
c@23 74 bool success;
c@23 75 string errorText;
c@23 76
c@23 77 PreservingPluginHandleMapper mapper;
c@24 78
c@24 79 vector<Vamp::HostExt::PluginStaticData> listResponse;
c@23 80 Vamp::HostExt::LoadRequest loadRequest;
c@23 81 Vamp::HostExt::LoadResponse loadResponse;
c@23 82 Vamp::HostExt::ConfigurationRequest configurationRequest;
c@23 83 Vamp::HostExt::ConfigurationResponse configurationResponse;
c@23 84 Vamp::HostExt::ProcessRequest processRequest;
c@23 85 Vamp::HostExt::ProcessResponse processResponse;
c@23 86 Vamp::Plugin *finishPlugin;
c@23 87 Vamp::HostExt::ProcessResponse finishResponse;
c@23 88 };
c@23 89
c@24 90 Json
c@24 91 convertRequestJson(string input)
c@24 92 {
c@24 93 string err;
c@24 94 Json j = Json::parse(input, err);
c@24 95 if (err != "") {
c@24 96 throw VampJson::Failure("invalid json: " + err);
c@24 97 }
c@24 98 if (!j.is_object()) {
c@24 99 throw VampJson::Failure("object expected at top level");
c@24 100 }
c@24 101 if (!j["type"].is_string()) {
c@24 102 throw VampJson::Failure("string expected for type field");
c@24 103 }
c@24 104 if (!j["content"].is_object()) {
c@24 105 throw VampJson::Failure("object expected for content field");
c@24 106 }
c@24 107 return j;
c@24 108 }
c@24 109
c@24 110 Json
c@24 111 convertResponseJson(string input)
c@24 112 {
c@24 113 string err;
c@24 114 Json j = Json::parse(input, err);
c@24 115 if (err != "") {
c@24 116 throw VampJson::Failure("invalid json: " + err);
c@24 117 }
c@24 118 if (!j.is_object()) {
c@24 119 throw VampJson::Failure("object expected at top level");
c@24 120 }
c@24 121 if (!j["success"].is_bool()) {
c@24 122 throw VampJson::Failure("bool expected for success field");
c@24 123 }
c@24 124 if (!j["content"].is_object()) {
c@24 125 throw VampJson::Failure("object expected for content field");
c@24 126 }
c@24 127 return j;
c@24 128 }
c@24 129
c@30 130 //!!! Lots of potential for refactoring the conversion classes based
c@30 131 //!!! on the common matter in the following eight functions...
c@30 132
c@23 133 RequestOrResponse
c@24 134 readRequestJson()
c@23 135 {
c@23 136 RequestOrResponse rr;
c@24 137 rr.direction = RequestOrResponse::Request;
c@24 138
c@24 139 string input;
c@24 140 if (!getline(cin, input)) {
c@25 141 rr.type = RRType::NotValid;
c@24 142 return rr;
c@24 143 }
c@24 144
c@24 145 Json j = convertRequestJson(input);
c@27 146
c@25 147 rr.type = VampJson::getRequestResponseType(j);
c@24 148
c@27 149 switch (rr.type) {
c@27 150
c@27 151 case RRType::List:
c@27 152 VampJson::toVampRequest_List(j); // type check only
c@27 153 break;
c@27 154 case RRType::Load:
c@24 155 rr.loadRequest = VampJson::toVampRequest_Load(j);
c@27 156 break;
c@27 157 case RRType::Configure:
c@27 158 rr.configurationRequest =
c@27 159 VampJson::toVampRequest_Configure(j, rr.mapper);
c@27 160 break;
c@27 161 case RRType::Process:
c@24 162 rr.processRequest = VampJson::toVampRequest_Process(j, rr.mapper);
c@27 163 break;
c@27 164 case RRType::Finish:
c@24 165 rr.finishPlugin = VampJson::toVampRequest_Finish(j, rr.mapper);
c@27 166 break;
c@27 167 case RRType::NotValid:
c@27 168 break;
c@24 169 }
c@24 170
c@24 171 return rr;
c@24 172 }
c@24 173
c@24 174 void
c@24 175 writeRequestJson(RequestOrResponse &rr)
c@24 176 {
c@24 177 Json j;
c@24 178
c@27 179 switch (rr.type) {
c@27 180
c@27 181 case RRType::List:
c@24 182 j = VampJson::fromVampRequest_List();
c@27 183 break;
c@27 184 case RRType::Load:
c@24 185 j = VampJson::fromVampRequest_Load(rr.loadRequest);
c@27 186 break;
c@27 187 case RRType::Configure:
c@27 188 j = VampJson::fromVampRequest_Configure(rr.configurationRequest,
c@27 189 rr.mapper);
c@27 190 break;
c@27 191 case RRType::Process:
c@24 192 j = VampJson::fromVampRequest_Process(rr.processRequest, rr.mapper);
c@27 193 break;
c@27 194 case RRType::Finish:
c@24 195 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, rr.mapper);
c@27 196 break;
c@27 197 case RRType::NotValid:
c@27 198 break;
c@24 199 }
c@24 200
c@24 201 cout << j.dump() << endl;
c@24 202 }
c@24 203
c@24 204 RequestOrResponse
c@24 205 readResponseJson()
c@24 206 {
c@24 207 RequestOrResponse rr;
c@24 208 rr.direction = RequestOrResponse::Response;
c@24 209
c@23 210 string input;
c@23 211 if (!getline(cin, input)) {
c@25 212 rr.type = RRType::NotValid;
c@23 213 return rr;
c@23 214 }
c@23 215
c@24 216 Json j = convertResponseJson(input);
c@27 217
c@25 218 rr.type = VampJson::getRequestResponseType(j);
c@23 219
c@27 220 switch (rr.type) {
c@27 221
c@27 222 case RRType::List:
c@24 223 rr.listResponse = VampJson::toVampResponse_List(j);
c@27 224 break;
c@27 225 case RRType::Load:
c@24 226 rr.loadResponse = VampJson::toVampResponse_Load(j, rr.mapper);
c@27 227 break;
c@27 228 case RRType::Configure:
c@24 229 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
c@27 230 break;
c@27 231 case RRType::Process:
c@24 232 rr.processResponse = VampJson::toVampResponse_Process(j);
c@27 233 break;
c@27 234 case RRType::Finish:
c@24 235 rr.finishResponse = VampJson::toVampResponse_Finish(j);
c@27 236 break;
c@27 237 case RRType::NotValid:
c@27 238 break;
c@23 239 }
c@23 240
c@23 241 return rr;
c@23 242 }
c@23 243
c@24 244 void
c@24 245 writeResponseJson(RequestOrResponse &rr)
c@24 246 {
c@24 247 Json j;
c@24 248
c@27 249 switch (rr.type) {
c@27 250
c@27 251 case RRType::List:
c@24 252 j = VampJson::fromVampResponse_List("", rr.listResponse);
c@27 253 break;
c@27 254 case RRType::Load:
c@24 255 j = VampJson::fromVampResponse_Load(rr.loadResponse, rr.mapper);
c@27 256 break;
c@27 257 case RRType::Configure:
c@27 258 j = VampJson::fromVampResponse_Configure(rr.configurationResponse);
c@27 259 break;
c@27 260 case RRType::Process:
c@27 261 j = VampJson::fromVampResponse_Process(rr.processResponse);
c@27 262 break;
c@27 263 case RRType::Finish:
c@27 264 j = VampJson::fromVampResponse_Finish(rr.finishResponse);
c@27 265 break;
c@27 266 case RRType::NotValid:
c@27 267 break;
c@24 268 }
c@24 269
c@27 270 cout << j.dump() << endl;
c@27 271 }
c@25 272
c@27 273 RequestOrResponse
c@27 274 readRequestCapnp()
c@27 275 {
c@27 276 RequestOrResponse rr;
c@27 277 rr.direction = RequestOrResponse::Request;
c@27 278
c@27 279 ::capnp::PackedFdMessageReader message(0); // stdin
c@27 280 VampRequest::Reader reader = message.getRoot<VampRequest>();
c@27 281
c@27 282 rr.type = VampnProto::getRequestResponseType(reader);
c@27 283
c@27 284 switch (rr.type) {
c@27 285
c@27 286 case RRType::List:
c@27 287 VampnProto::readVampRequest_List(reader); // type check only
c@27 288 break;
c@27 289 case RRType::Load:
c@27 290 VampnProto::readVampRequest_Load(rr.loadRequest, reader);
c@27 291 break;
c@27 292 case RRType::Configure:
c@27 293 VampnProto::readVampRequest_Configure(rr.configurationRequest, reader,
c@27 294 rr.mapper);
c@27 295 break;
c@27 296 case RRType::Process:
c@27 297 VampnProto::readVampRequest_Process(rr.processRequest, reader,
c@27 298 rr.mapper);
c@27 299 break;
c@27 300 case RRType::Finish:
c@27 301 VampnProto::readVampRequest_Finish(rr.finishPlugin, reader,
c@27 302 rr.mapper);
c@27 303 break;
c@27 304 case RRType::NotValid:
c@27 305 break;
c@27 306 }
c@27 307
c@27 308 return rr;
c@27 309 }
c@27 310
c@29 311 void
c@29 312 writeRequestCapnp(RequestOrResponse &rr)
c@29 313 {
c@29 314 ::capnp::MallocMessageBuilder message;
c@29 315 VampRequest::Builder builder = message.initRoot<VampRequest>();
c@29 316
c@29 317 switch (rr.type) {
c@29 318
c@29 319 case RRType::List:
c@29 320 VampnProto::buildVampRequest_List(builder);
c@29 321 break;
c@29 322 case RRType::Load:
c@29 323 VampnProto::buildVampRequest_Load(builder, rr.loadRequest);
c@29 324 break;
c@29 325 case RRType::Configure:
c@29 326 VampnProto::buildVampRequest_Configure(builder,
c@29 327 rr.configurationRequest,
c@29 328 rr.mapper);
c@29 329 break;
c@29 330 case RRType::Process:
c@29 331 VampnProto::buildVampRequest_Process(builder,
c@29 332 rr.processRequest,
c@29 333 rr.mapper);
c@29 334 break;
c@29 335 case RRType::Finish:
c@29 336 VampnProto::buildVampRequest_Finish(builder,
c@29 337 rr.finishPlugin,
c@29 338 rr.mapper);
c@29 339 break;
c@29 340 case RRType::NotValid:
c@29 341 break;
c@29 342 }
c@29 343
c@29 344 writePackedMessageToFd(1, message);
c@29 345 }
c@29 346
c@27 347 RequestOrResponse
c@27 348 readResponseCapnp()
c@27 349 {
c@27 350 RequestOrResponse rr;
c@27 351 rr.direction = RequestOrResponse::Response;
c@27 352
c@27 353 ::capnp::PackedFdMessageReader message(0); // stdin
c@27 354 VampResponse::Reader reader = message.getRoot<VampResponse>();
c@27 355
c@27 356 rr.type = VampnProto::getRequestResponseType(reader);
c@27 357
c@27 358 switch (rr.type) {
c@27 359
c@27 360 case RRType::List:
c@27 361 VampnProto::readVampResponse_List(rr.listResponse, reader);
c@27 362 break;
c@27 363 case RRType::Load:
c@27 364 VampnProto::readVampResponse_Load(rr.loadResponse, reader, rr.mapper);
c@27 365 break;
c@27 366 case RRType::Configure:
c@27 367 VampnProto::readVampResponse_Configure(rr.configurationResponse,
c@27 368 reader);
c@27 369 break;
c@27 370 case RRType::Process:
c@27 371 VampnProto::readVampResponse_Process(rr.processResponse, reader);
c@27 372 break;
c@27 373 case RRType::Finish:
c@27 374 VampnProto::readVampResponse_Finish(rr.finishResponse, reader);
c@27 375 break;
c@27 376 case RRType::NotValid:
c@27 377 break;
c@27 378 }
c@27 379
c@27 380 return rr;
c@24 381 }
c@24 382
c@29 383 void
c@29 384 writeResponseCapnp(RequestOrResponse &rr)
c@29 385 {
c@29 386 ::capnp::MallocMessageBuilder message;
c@29 387 VampResponse::Builder builder = message.initRoot<VampResponse>();
c@29 388
c@29 389 switch (rr.type) {
c@29 390
c@29 391 case RRType::List:
c@29 392 VampnProto::buildVampResponse_List(builder, "", rr.listResponse);
c@29 393 break;
c@29 394 case RRType::Load:
c@29 395 VampnProto::buildVampResponse_Load(builder, rr.loadResponse, rr.mapper);
c@29 396 break;
c@29 397 case RRType::Configure:
c@29 398 VampnProto::buildVampResponse_Configure(builder, rr.configurationResponse);
c@29 399 break;
c@29 400 case RRType::Process:
c@29 401 VampnProto::buildVampResponse_Process(builder, rr.processResponse);
c@29 402 break;
c@29 403 case RRType::Finish:
c@29 404 VampnProto::buildVampResponse_Finish(builder, rr.finishResponse);
c@29 405 break;
c@29 406 case RRType::NotValid:
c@29 407 break;
c@29 408 }
c@29 409
c@29 410 writePackedMessageToFd(1, message);
c@29 411 }
c@29 412
c@23 413 RequestOrResponse
c@24 414 readInput(string format, RequestOrResponse::Direction direction)
c@23 415 {
c@23 416 if (format == "json") {
c@24 417 if (direction == RequestOrResponse::Request) {
c@24 418 return readRequestJson();
c@24 419 } else {
c@24 420 return readResponseJson();
c@24 421 }
c@27 422 } else if (format == "capnp") {
c@27 423 if (direction == RequestOrResponse::Request) {
c@27 424 return readRequestCapnp();
c@27 425 } else {
c@27 426 return readResponseCapnp();
c@27 427 }
c@23 428 } else {
c@27 429 throw runtime_error("unknown input format \"" + format + "\"");
c@23 430 }
c@23 431 }
c@23 432
c@23 433 void
c@24 434 writeOutput(string format, RequestOrResponse &rr)
c@23 435 {
c@24 436 if (format == "json") {
c@24 437 if (rr.direction == RequestOrResponse::Request) {
c@24 438 writeRequestJson(rr);
c@24 439 } else {
c@24 440 writeResponseJson(rr);
c@24 441 }
c@29 442 } else if (format == "capnp") {
c@29 443 if (rr.direction == RequestOrResponse::Request) {
c@29 444 writeRequestCapnp(rr);
c@29 445 } else {
c@29 446 writeResponseCapnp(rr);
c@29 447 }
c@24 448 } else {
c@27 449 throw runtime_error("unknown output format \"" + format + "\"");
c@24 450 }
c@23 451 }
c@23 452
c@23 453 int main(int argc, char **argv)
c@23 454 {
c@24 455 if (argc < 2) {
c@23 456 usage();
c@23 457 }
c@23 458
c@24 459 string informat = "json", outformat = "json";
c@27 460 RequestOrResponse::Direction direction = RequestOrResponse::Request;
c@24 461 bool haveDirection = false;
c@23 462
c@24 463 for (int i = 1; i < argc; ++i) {
c@23 464
c@23 465 string arg = argv[i];
c@24 466 bool final = (i + 1 == argc);
c@23 467
c@23 468 if (arg == "-i") {
c@27 469 if (final) usage();
c@23 470 else informat = argv[++i];
c@23 471
c@23 472 } else if (arg == "-o") {
c@27 473 if (final) usage();
c@23 474 else outformat = argv[++i];
c@23 475
c@24 476 } else if (arg == "request") {
c@24 477 direction = RequestOrResponse::Request;
c@24 478 haveDirection = true;
c@24 479
c@24 480 } else if (arg == "response") {
c@24 481 direction = RequestOrResponse::Response;
c@24 482 haveDirection = true;
c@24 483
c@23 484 } else {
c@23 485 usage();
c@23 486 }
c@23 487 }
c@23 488
c@24 489 if (informat == "" || outformat == "" || !haveDirection) {
c@23 490 usage();
c@23 491 }
c@23 492
c@23 493 while (true) {
c@23 494
c@23 495 try {
c@23 496
c@24 497 RequestOrResponse rr = readInput(informat, direction);
c@29 498
c@29 499 // NotValid without an exception indicates EOF:
c@25 500 if (rr.type == RRType::NotValid) break;
c@29 501
c@23 502 writeOutput(outformat, rr);
c@23 503
c@23 504 } catch (std::exception &e) {
c@23 505 cerr << "Error: " << e.what() << endl;
c@23 506 exit(1);
c@23 507 }
c@23 508 }
c@23 509
c@23 510 exit(0);
c@23 511 }
c@23 512
c@23 513