annotate utilities/vampipe-convert.cpp @ 49:f3f7561233d6

Begin plugin output id / index mapping for use in feature sets
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 16 Sep 2016 14:13:21 +0100
parents a98ef4c2616b
children f4244a2d55ac
rev   line source
c@23 1
c@23 2 #include "VampJson.h"
c@23 3 #include "VampnProto.h"
c@23 4
c@31 5 #include "bits/RequestOrResponse.h"
c@32 6 #include "bits/PreservingPluginHandleMapper.h"
c@31 7
c@23 8 #include <iostream>
c@23 9 #include <sstream>
c@23 10 #include <stdexcept>
c@23 11
c@23 12 using namespace std;
c@23 13 using namespace json11;
c@23 14 using namespace vampipe;
c@23 15
c@23 16 void usage()
c@23 17 {
c@23 18 string myname = "vampipe-convert";
c@23 19 cerr << "\n" << myname <<
c@24 20 ": Validate and convert Vamp request and response messages\n\n"
c@24 21 " Usage: " << myname << " [-i <informat>] [-o <outformat>] request\n"
c@24 22 " " << myname << " [-i <informat>] [-o <outformat>] response\n\n"
c@24 23 " where\n"
c@24 24 " <informat>: the format to read from stdin\n"
c@24 25 " (\"json\" or \"capnp\", default is \"json\")\n"
c@24 26 " <outformat>: the format to convert to and write to stdout\n"
c@44 27 " (\"json\", \"json-b64\" or \"capnp\", default is \"json\")\n"
c@44 28 " request|response: whether messages are Vamp request or response type\n\n"
c@24 29 "If <informat> and <outformat> differ, convert from <informat> to <outformat>.\n"
c@24 30 "If <informat> and <outformat> are the same, just check validity of incoming\n"
c@44 31 "messages and pass them to output.\n\n"
c@44 32 "Specifying \"json-b64\" as output format forces base64 encoding for process and\n"
c@44 33 "feature blocks, unlike the \"json\" output format which uses text encoding.\n"
c@44 34 "The \"json\" input format accepts either.\n\n";
c@24 35
c@23 36 exit(2);
c@23 37 }
c@23 38
c@24 39 Json
c@24 40 convertRequestJson(string input)
c@24 41 {
c@24 42 string err;
c@24 43 Json j = Json::parse(input, err);
c@24 44 if (err != "") {
c@24 45 throw VampJson::Failure("invalid json: " + err);
c@24 46 }
c@24 47 if (!j.is_object()) {
c@24 48 throw VampJson::Failure("object expected at top level");
c@24 49 }
c@24 50 if (!j["type"].is_string()) {
c@24 51 throw VampJson::Failure("string expected for type field");
c@24 52 }
c@42 53 if (!j["content"].is_null() && !j["content"].is_object()) {
c@24 54 throw VampJson::Failure("object expected for content field");
c@24 55 }
c@24 56 return j;
c@24 57 }
c@24 58
c@24 59 Json
c@24 60 convertResponseJson(string input)
c@24 61 {
c@24 62 string err;
c@24 63 Json j = Json::parse(input, err);
c@24 64 if (err != "") {
c@24 65 throw VampJson::Failure("invalid json: " + err);
c@24 66 }
c@24 67 if (!j.is_object()) {
c@24 68 throw VampJson::Failure("object expected at top level");
c@24 69 }
c@24 70 if (!j["success"].is_bool()) {
c@24 71 throw VampJson::Failure("bool expected for success field");
c@24 72 }
c@24 73 if (!j["content"].is_object()) {
c@24 74 throw VampJson::Failure("object expected for content field");
c@24 75 }
c@24 76 return j;
c@24 77 }
c@24 78
c@30 79 //!!! Lots of potential for refactoring the conversion classes based
c@30 80 //!!! on the common matter in the following eight functions...
c@30 81
c@32 82 PreservingPluginHandleMapper mapper;
c@32 83
c@23 84 RequestOrResponse
c@24 85 readRequestJson()
c@23 86 {
c@23 87 RequestOrResponse rr;
c@24 88 rr.direction = RequestOrResponse::Request;
c@24 89
c@24 90 string input;
c@24 91 if (!getline(cin, input)) {
c@25 92 rr.type = RRType::NotValid;
c@24 93 return rr;
c@24 94 }
c@24 95
c@24 96 Json j = convertRequestJson(input);
c@27 97
c@25 98 rr.type = VampJson::getRequestResponseType(j);
c@44 99 VampJson::BufferSerialisation serialisation = VampJson::BufferSerialisation::Text;
c@24 100
c@27 101 switch (rr.type) {
c@27 102
c@27 103 case RRType::List:
c@27 104 VampJson::toVampRequest_List(j); // type check only
c@27 105 break;
c@27 106 case RRType::Load:
c@24 107 rr.loadRequest = VampJson::toVampRequest_Load(j);
c@27 108 break;
c@27 109 case RRType::Configure:
c@32 110 rr.configurationRequest = VampJson::toVampRequest_Configure(j, mapper);
c@27 111 break;
c@27 112 case RRType::Process:
c@44 113 rr.processRequest = VampJson::toVampRequest_Process(j, mapper, serialisation);
c@27 114 break;
c@27 115 case RRType::Finish:
c@32 116 rr.finishPlugin = VampJson::toVampRequest_Finish(j, mapper);
c@27 117 break;
c@27 118 case RRType::NotValid:
c@27 119 break;
c@24 120 }
c@24 121
c@24 122 return rr;
c@24 123 }
c@24 124
c@24 125 void
c@44 126 writeRequestJson(RequestOrResponse &rr, bool useBase64)
c@24 127 {
c@24 128 Json j;
c@24 129
c@27 130 switch (rr.type) {
c@27 131
c@27 132 case RRType::List:
c@24 133 j = VampJson::fromVampRequest_List();
c@27 134 break;
c@27 135 case RRType::Load:
c@24 136 j = VampJson::fromVampRequest_Load(rr.loadRequest);
c@27 137 break;
c@27 138 case RRType::Configure:
c@32 139 j = VampJson::fromVampRequest_Configure(rr.configurationRequest, mapper);
c@27 140 break;
c@27 141 case RRType::Process:
c@44 142 j = VampJson::fromVampRequest_Process
c@44 143 (rr.processRequest, mapper,
c@44 144 useBase64 ?
c@44 145 VampJson::BufferSerialisation::Base64 :
c@44 146 VampJson::BufferSerialisation::Text);
c@27 147 break;
c@27 148 case RRType::Finish:
c@32 149 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, mapper);
c@27 150 break;
c@27 151 case RRType::NotValid:
c@27 152 break;
c@24 153 }
c@24 154
c@24 155 cout << j.dump() << endl;
c@24 156 }
c@24 157
c@24 158 RequestOrResponse
c@24 159 readResponseJson()
c@24 160 {
c@24 161 RequestOrResponse rr;
c@24 162 rr.direction = RequestOrResponse::Response;
c@24 163
c@23 164 string input;
c@23 165 if (!getline(cin, input)) {
c@25 166 rr.type = RRType::NotValid;
c@23 167 return rr;
c@23 168 }
c@23 169
c@24 170 Json j = convertResponseJson(input);
c@27 171
c@25 172 rr.type = VampJson::getRequestResponseType(j);
c@44 173 VampJson::BufferSerialisation serialisation = VampJson::BufferSerialisation::Text;
c@23 174
c@27 175 switch (rr.type) {
c@27 176
c@27 177 case RRType::List:
c@24 178 rr.listResponse = VampJson::toVampResponse_List(j);
c@27 179 break;
c@27 180 case RRType::Load:
c@32 181 rr.loadResponse = VampJson::toVampResponse_Load(j, mapper);
c@27 182 break;
c@27 183 case RRType::Configure:
c@24 184 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
c@27 185 break;
c@27 186 case RRType::Process:
c@44 187 rr.processResponse = VampJson::toVampResponse_Process(j, serialisation);
c@27 188 break;
c@27 189 case RRType::Finish:
c@44 190 rr.finishResponse = VampJson::toVampResponse_Finish(j, serialisation);
c@27 191 break;
c@27 192 case RRType::NotValid:
c@27 193 break;
c@23 194 }
c@23 195
c@23 196 return rr;
c@23 197 }
c@23 198
c@24 199 void
c@44 200 writeResponseJson(RequestOrResponse &rr, bool useBase64)
c@24 201 {
c@24 202 Json j;
c@24 203
c@27 204 switch (rr.type) {
c@27 205
c@27 206 case RRType::List:
c@24 207 j = VampJson::fromVampResponse_List("", rr.listResponse);
c@27 208 break;
c@27 209 case RRType::Load:
c@32 210 j = VampJson::fromVampResponse_Load(rr.loadResponse, mapper);
c@27 211 break;
c@27 212 case RRType::Configure:
c@27 213 j = VampJson::fromVampResponse_Configure(rr.configurationResponse);
c@27 214 break;
c@27 215 case RRType::Process:
c@44 216 j = VampJson::fromVampResponse_Process
c@44 217 (rr.processResponse,
c@44 218 useBase64 ?
c@44 219 VampJson::BufferSerialisation::Base64 :
c@44 220 VampJson::BufferSerialisation::Text);
c@27 221 break;
c@27 222 case RRType::Finish:
c@44 223 j = VampJson::fromVampResponse_Finish
c@44 224 (rr.finishResponse,
c@44 225 useBase64 ?
c@44 226 VampJson::BufferSerialisation::Base64 :
c@44 227 VampJson::BufferSerialisation::Text);
c@27 228 break;
c@27 229 case RRType::NotValid:
c@27 230 break;
c@24 231 }
c@24 232
c@27 233 cout << j.dump() << endl;
c@27 234 }
c@25 235
c@27 236 RequestOrResponse
c@33 237 readRequestCapnp(kj::BufferedInputStreamWrapper &buffered)
c@27 238 {
c@27 239 RequestOrResponse rr;
c@27 240 rr.direction = RequestOrResponse::Request;
c@27 241
c@33 242 ::capnp::InputStreamMessageReader message(buffered);
c@27 243 VampRequest::Reader reader = message.getRoot<VampRequest>();
c@27 244
c@27 245 rr.type = VampnProto::getRequestResponseType(reader);
c@27 246
c@27 247 switch (rr.type) {
c@27 248
c@27 249 case RRType::List:
c@27 250 VampnProto::readVampRequest_List(reader); // type check only
c@27 251 break;
c@27 252 case RRType::Load:
c@27 253 VampnProto::readVampRequest_Load(rr.loadRequest, reader);
c@27 254 break;
c@27 255 case RRType::Configure:
c@32 256 VampnProto::readVampRequest_Configure(rr.configurationRequest,
c@32 257 reader, mapper);
c@27 258 break;
c@27 259 case RRType::Process:
c@32 260 VampnProto::readVampRequest_Process(rr.processRequest, reader, mapper);
c@27 261 break;
c@27 262 case RRType::Finish:
c@32 263 VampnProto::readVampRequest_Finish(rr.finishPlugin, reader, mapper);
c@27 264 break;
c@27 265 case RRType::NotValid:
c@27 266 break;
c@27 267 }
c@27 268
c@27 269 return rr;
c@27 270 }
c@27 271
c@29 272 void
c@29 273 writeRequestCapnp(RequestOrResponse &rr)
c@29 274 {
c@29 275 ::capnp::MallocMessageBuilder message;
c@29 276 VampRequest::Builder builder = message.initRoot<VampRequest>();
c@29 277
c@29 278 switch (rr.type) {
c@29 279
c@29 280 case RRType::List:
c@29 281 VampnProto::buildVampRequest_List(builder);
c@29 282 break;
c@29 283 case RRType::Load:
c@29 284 VampnProto::buildVampRequest_Load(builder, rr.loadRequest);
c@29 285 break;
c@29 286 case RRType::Configure:
c@29 287 VampnProto::buildVampRequest_Configure(builder,
c@32 288 rr.configurationRequest, mapper);
c@29 289 break;
c@29 290 case RRType::Process:
c@32 291 VampnProto::buildVampRequest_Process(builder, rr.processRequest, mapper);
c@29 292 break;
c@29 293 case RRType::Finish:
c@32 294 VampnProto::buildVampRequest_Finish(builder, rr.finishPlugin, mapper);
c@29 295 break;
c@29 296 case RRType::NotValid:
c@29 297 break;
c@29 298 }
c@29 299
c@33 300 writeMessageToFd(1, message);
c@29 301 }
c@29 302
c@27 303 RequestOrResponse
c@33 304 readResponseCapnp(kj::BufferedInputStreamWrapper &buffered)
c@27 305 {
c@27 306 RequestOrResponse rr;
c@27 307 rr.direction = RequestOrResponse::Response;
c@27 308
c@33 309 ::capnp::InputStreamMessageReader message(buffered);
c@27 310 VampResponse::Reader reader = message.getRoot<VampResponse>();
c@27 311
c@27 312 rr.type = VampnProto::getRequestResponseType(reader);
c@27 313
c@27 314 switch (rr.type) {
c@27 315
c@27 316 case RRType::List:
c@27 317 VampnProto::readVampResponse_List(rr.listResponse, reader);
c@27 318 break;
c@27 319 case RRType::Load:
c@32 320 VampnProto::readVampResponse_Load(rr.loadResponse, reader, mapper);
c@27 321 break;
c@27 322 case RRType::Configure:
c@27 323 VampnProto::readVampResponse_Configure(rr.configurationResponse,
c@27 324 reader);
c@27 325 break;
c@27 326 case RRType::Process:
c@27 327 VampnProto::readVampResponse_Process(rr.processResponse, reader);
c@27 328 break;
c@27 329 case RRType::Finish:
c@27 330 VampnProto::readVampResponse_Finish(rr.finishResponse, reader);
c@27 331 break;
c@27 332 case RRType::NotValid:
c@27 333 break;
c@27 334 }
c@27 335
c@27 336 return rr;
c@24 337 }
c@24 338
c@29 339 void
c@29 340 writeResponseCapnp(RequestOrResponse &rr)
c@29 341 {
c@29 342 ::capnp::MallocMessageBuilder message;
c@29 343 VampResponse::Builder builder = message.initRoot<VampResponse>();
c@29 344
c@29 345 switch (rr.type) {
c@29 346
c@29 347 case RRType::List:
c@29 348 VampnProto::buildVampResponse_List(builder, "", rr.listResponse);
c@29 349 break;
c@29 350 case RRType::Load:
c@32 351 VampnProto::buildVampResponse_Load(builder, rr.loadResponse, mapper);
c@29 352 break;
c@29 353 case RRType::Configure:
c@29 354 VampnProto::buildVampResponse_Configure(builder, rr.configurationResponse);
c@29 355 break;
c@29 356 case RRType::Process:
c@29 357 VampnProto::buildVampResponse_Process(builder, rr.processResponse);
c@29 358 break;
c@29 359 case RRType::Finish:
c@29 360 VampnProto::buildVampResponse_Finish(builder, rr.finishResponse);
c@29 361 break;
c@29 362 case RRType::NotValid:
c@29 363 break;
c@29 364 }
c@29 365
c@33 366 writeMessageToFd(1, message);
c@33 367 }
c@33 368
c@33 369 RequestOrResponse
c@33 370 readInputJson(RequestOrResponse::Direction direction)
c@33 371 {
c@33 372 if (direction == RequestOrResponse::Request) {
c@33 373 return readRequestJson();
c@33 374 } else {
c@33 375 return readResponseJson();
c@33 376 }
c@33 377 }
c@33 378
c@33 379 RequestOrResponse
c@33 380 readInputCapnp(RequestOrResponse::Direction direction)
c@33 381 {
c@33 382 static kj::FdInputStream stream(0); // stdin
c@33 383 static kj::BufferedInputStreamWrapper buffered(stream);
c@33 384
c@33 385 if (buffered.tryGetReadBuffer() == nullptr) {
c@33 386 return {};
c@33 387 }
c@33 388
c@33 389 if (direction == RequestOrResponse::Request) {
c@33 390 return readRequestCapnp(buffered);
c@33 391 } else {
c@33 392 return readResponseCapnp(buffered);
c@33 393 }
c@29 394 }
c@29 395
c@23 396 RequestOrResponse
c@24 397 readInput(string format, RequestOrResponse::Direction direction)
c@23 398 {
c@23 399 if (format == "json") {
c@33 400 return readInputJson(direction);
c@27 401 } else if (format == "capnp") {
c@33 402 return readInputCapnp(direction);
c@23 403 } else {
c@27 404 throw runtime_error("unknown input format \"" + format + "\"");
c@23 405 }
c@23 406 }
c@23 407
c@23 408 void
c@24 409 writeOutput(string format, RequestOrResponse &rr)
c@23 410 {
c@24 411 if (format == "json") {
c@24 412 if (rr.direction == RequestOrResponse::Request) {
c@44 413 writeRequestJson(rr, false);
c@24 414 } else {
c@44 415 writeResponseJson(rr, false);
c@44 416 }
c@44 417 } else if (format == "json-b64") {
c@44 418 if (rr.direction == RequestOrResponse::Request) {
c@44 419 writeRequestJson(rr, true);
c@44 420 } else {
c@44 421 writeResponseJson(rr, true);
c@24 422 }
c@29 423 } else if (format == "capnp") {
c@29 424 if (rr.direction == RequestOrResponse::Request) {
c@29 425 writeRequestCapnp(rr);
c@29 426 } else {
c@29 427 writeResponseCapnp(rr);
c@29 428 }
c@24 429 } else {
c@27 430 throw runtime_error("unknown output format \"" + format + "\"");
c@24 431 }
c@23 432 }
c@23 433
c@23 434 int main(int argc, char **argv)
c@23 435 {
c@24 436 if (argc < 2) {
c@23 437 usage();
c@23 438 }
c@23 439
c@24 440 string informat = "json", outformat = "json";
c@27 441 RequestOrResponse::Direction direction = RequestOrResponse::Request;
c@24 442 bool haveDirection = false;
c@23 443
c@24 444 for (int i = 1; i < argc; ++i) {
c@23 445
c@23 446 string arg = argv[i];
c@24 447 bool final = (i + 1 == argc);
c@23 448
c@23 449 if (arg == "-i") {
c@27 450 if (final) usage();
c@23 451 else informat = argv[++i];
c@23 452
c@23 453 } else if (arg == "-o") {
c@27 454 if (final) usage();
c@23 455 else outformat = argv[++i];
c@23 456
c@24 457 } else if (arg == "request") {
c@24 458 direction = RequestOrResponse::Request;
c@24 459 haveDirection = true;
c@24 460
c@24 461 } else if (arg == "response") {
c@24 462 direction = RequestOrResponse::Response;
c@24 463 haveDirection = true;
c@24 464
c@23 465 } else {
c@23 466 usage();
c@23 467 }
c@23 468 }
c@23 469
c@24 470 if (informat == "" || outformat == "" || !haveDirection) {
c@23 471 usage();
c@23 472 }
c@23 473
c@23 474 while (true) {
c@23 475
c@23 476 try {
c@23 477
c@24 478 RequestOrResponse rr = readInput(informat, direction);
c@29 479
c@29 480 // NotValid without an exception indicates EOF:
c@25 481 if (rr.type == RRType::NotValid) break;
c@29 482
c@23 483 writeOutput(outformat, rr);
c@23 484
c@23 485 } catch (std::exception &e) {
c@23 486 cerr << "Error: " << e.what() << endl;
c@23 487 exit(1);
c@23 488 }
c@23 489 }
c@23 490
c@23 491 exit(0);
c@23 492 }
c@23 493
c@23 494