annotate utilities/vampipe-convert.cpp @ 51:f4244a2d55ac

Introduce and use output id mappers
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 16 Sep 2016 15:10:57 +0100
parents a98ef4c2616b
children e90fd30990eb
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@51 187 rr.processResponse = VampJson::toVampResponse_Process(j, mapper, serialisation);
c@27 188 break;
c@27 189 case RRType::Finish:
c@51 190 rr.finishResponse = VampJson::toVampResponse_Finish(j, mapper, 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@51 218 mapper,
c@44 219 useBase64 ?
c@44 220 VampJson::BufferSerialisation::Base64 :
c@44 221 VampJson::BufferSerialisation::Text);
c@27 222 break;
c@27 223 case RRType::Finish:
c@44 224 j = VampJson::fromVampResponse_Finish
c@44 225 (rr.finishResponse,
c@51 226 mapper,
c@44 227 useBase64 ?
c@44 228 VampJson::BufferSerialisation::Base64 :
c@44 229 VampJson::BufferSerialisation::Text);
c@27 230 break;
c@27 231 case RRType::NotValid:
c@27 232 break;
c@24 233 }
c@24 234
c@27 235 cout << j.dump() << endl;
c@27 236 }
c@25 237
c@27 238 RequestOrResponse
c@33 239 readRequestCapnp(kj::BufferedInputStreamWrapper &buffered)
c@27 240 {
c@27 241 RequestOrResponse rr;
c@27 242 rr.direction = RequestOrResponse::Request;
c@27 243
c@33 244 ::capnp::InputStreamMessageReader message(buffered);
c@27 245 VampRequest::Reader reader = message.getRoot<VampRequest>();
c@27 246
c@27 247 rr.type = VampnProto::getRequestResponseType(reader);
c@27 248
c@27 249 switch (rr.type) {
c@27 250
c@27 251 case RRType::List:
c@27 252 VampnProto::readVampRequest_List(reader); // type check only
c@27 253 break;
c@27 254 case RRType::Load:
c@27 255 VampnProto::readVampRequest_Load(rr.loadRequest, reader);
c@27 256 break;
c@27 257 case RRType::Configure:
c@32 258 VampnProto::readVampRequest_Configure(rr.configurationRequest,
c@32 259 reader, mapper);
c@27 260 break;
c@27 261 case RRType::Process:
c@32 262 VampnProto::readVampRequest_Process(rr.processRequest, reader, mapper);
c@27 263 break;
c@27 264 case RRType::Finish:
c@32 265 VampnProto::readVampRequest_Finish(rr.finishPlugin, reader, mapper);
c@27 266 break;
c@27 267 case RRType::NotValid:
c@27 268 break;
c@27 269 }
c@27 270
c@27 271 return rr;
c@27 272 }
c@27 273
c@29 274 void
c@29 275 writeRequestCapnp(RequestOrResponse &rr)
c@29 276 {
c@29 277 ::capnp::MallocMessageBuilder message;
c@29 278 VampRequest::Builder builder = message.initRoot<VampRequest>();
c@29 279
c@29 280 switch (rr.type) {
c@29 281
c@29 282 case RRType::List:
c@29 283 VampnProto::buildVampRequest_List(builder);
c@29 284 break;
c@29 285 case RRType::Load:
c@29 286 VampnProto::buildVampRequest_Load(builder, rr.loadRequest);
c@29 287 break;
c@29 288 case RRType::Configure:
c@29 289 VampnProto::buildVampRequest_Configure(builder,
c@32 290 rr.configurationRequest, mapper);
c@29 291 break;
c@29 292 case RRType::Process:
c@32 293 VampnProto::buildVampRequest_Process(builder, rr.processRequest, mapper);
c@29 294 break;
c@29 295 case RRType::Finish:
c@32 296 VampnProto::buildVampRequest_Finish(builder, rr.finishPlugin, mapper);
c@29 297 break;
c@29 298 case RRType::NotValid:
c@29 299 break;
c@29 300 }
c@29 301
c@33 302 writeMessageToFd(1, message);
c@29 303 }
c@29 304
c@27 305 RequestOrResponse
c@33 306 readResponseCapnp(kj::BufferedInputStreamWrapper &buffered)
c@27 307 {
c@27 308 RequestOrResponse rr;
c@27 309 rr.direction = RequestOrResponse::Response;
c@27 310
c@33 311 ::capnp::InputStreamMessageReader message(buffered);
c@27 312 VampResponse::Reader reader = message.getRoot<VampResponse>();
c@27 313
c@27 314 rr.type = VampnProto::getRequestResponseType(reader);
c@27 315
c@27 316 switch (rr.type) {
c@27 317
c@27 318 case RRType::List:
c@27 319 VampnProto::readVampResponse_List(rr.listResponse, reader);
c@27 320 break;
c@27 321 case RRType::Load:
c@32 322 VampnProto::readVampResponse_Load(rr.loadResponse, reader, mapper);
c@27 323 break;
c@27 324 case RRType::Configure:
c@27 325 VampnProto::readVampResponse_Configure(rr.configurationResponse,
c@27 326 reader);
c@27 327 break;
c@27 328 case RRType::Process:
c@51 329 VampnProto::readVampResponse_Process(rr.processResponse, reader, mapper);
c@27 330 break;
c@27 331 case RRType::Finish:
c@51 332 VampnProto::readVampResponse_Finish(rr.finishResponse, reader, mapper);
c@27 333 break;
c@27 334 case RRType::NotValid:
c@27 335 break;
c@27 336 }
c@27 337
c@27 338 return rr;
c@24 339 }
c@24 340
c@29 341 void
c@29 342 writeResponseCapnp(RequestOrResponse &rr)
c@29 343 {
c@29 344 ::capnp::MallocMessageBuilder message;
c@29 345 VampResponse::Builder builder = message.initRoot<VampResponse>();
c@29 346
c@29 347 switch (rr.type) {
c@29 348
c@29 349 case RRType::List:
c@29 350 VampnProto::buildVampResponse_List(builder, "", rr.listResponse);
c@29 351 break;
c@29 352 case RRType::Load:
c@32 353 VampnProto::buildVampResponse_Load(builder, rr.loadResponse, mapper);
c@29 354 break;
c@29 355 case RRType::Configure:
c@29 356 VampnProto::buildVampResponse_Configure(builder, rr.configurationResponse);
c@29 357 break;
c@29 358 case RRType::Process:
c@51 359 VampnProto::buildVampResponse_Process(builder, rr.processResponse, mapper);
c@29 360 break;
c@29 361 case RRType::Finish:
c@51 362 VampnProto::buildVampResponse_Finish(builder, rr.finishResponse, mapper);
c@29 363 break;
c@29 364 case RRType::NotValid:
c@29 365 break;
c@29 366 }
c@29 367
c@33 368 writeMessageToFd(1, message);
c@33 369 }
c@33 370
c@33 371 RequestOrResponse
c@33 372 readInputJson(RequestOrResponse::Direction direction)
c@33 373 {
c@33 374 if (direction == RequestOrResponse::Request) {
c@33 375 return readRequestJson();
c@33 376 } else {
c@33 377 return readResponseJson();
c@33 378 }
c@33 379 }
c@33 380
c@33 381 RequestOrResponse
c@33 382 readInputCapnp(RequestOrResponse::Direction direction)
c@33 383 {
c@33 384 static kj::FdInputStream stream(0); // stdin
c@33 385 static kj::BufferedInputStreamWrapper buffered(stream);
c@33 386
c@33 387 if (buffered.tryGetReadBuffer() == nullptr) {
c@33 388 return {};
c@33 389 }
c@33 390
c@33 391 if (direction == RequestOrResponse::Request) {
c@33 392 return readRequestCapnp(buffered);
c@33 393 } else {
c@33 394 return readResponseCapnp(buffered);
c@33 395 }
c@29 396 }
c@29 397
c@23 398 RequestOrResponse
c@24 399 readInput(string format, RequestOrResponse::Direction direction)
c@23 400 {
c@23 401 if (format == "json") {
c@33 402 return readInputJson(direction);
c@27 403 } else if (format == "capnp") {
c@33 404 return readInputCapnp(direction);
c@23 405 } else {
c@27 406 throw runtime_error("unknown input format \"" + format + "\"");
c@23 407 }
c@23 408 }
c@23 409
c@23 410 void
c@24 411 writeOutput(string format, RequestOrResponse &rr)
c@23 412 {
c@24 413 if (format == "json") {
c@24 414 if (rr.direction == RequestOrResponse::Request) {
c@44 415 writeRequestJson(rr, false);
c@24 416 } else {
c@44 417 writeResponseJson(rr, false);
c@44 418 }
c@44 419 } else if (format == "json-b64") {
c@44 420 if (rr.direction == RequestOrResponse::Request) {
c@44 421 writeRequestJson(rr, true);
c@44 422 } else {
c@44 423 writeResponseJson(rr, true);
c@24 424 }
c@29 425 } else if (format == "capnp") {
c@29 426 if (rr.direction == RequestOrResponse::Request) {
c@29 427 writeRequestCapnp(rr);
c@29 428 } else {
c@29 429 writeResponseCapnp(rr);
c@29 430 }
c@24 431 } else {
c@27 432 throw runtime_error("unknown output format \"" + format + "\"");
c@24 433 }
c@23 434 }
c@23 435
c@23 436 int main(int argc, char **argv)
c@23 437 {
c@24 438 if (argc < 2) {
c@23 439 usage();
c@23 440 }
c@23 441
c@24 442 string informat = "json", outformat = "json";
c@27 443 RequestOrResponse::Direction direction = RequestOrResponse::Request;
c@24 444 bool haveDirection = false;
c@23 445
c@24 446 for (int i = 1; i < argc; ++i) {
c@23 447
c@23 448 string arg = argv[i];
c@24 449 bool final = (i + 1 == argc);
c@23 450
c@23 451 if (arg == "-i") {
c@27 452 if (final) usage();
c@23 453 else informat = argv[++i];
c@23 454
c@23 455 } else if (arg == "-o") {
c@27 456 if (final) usage();
c@23 457 else outformat = argv[++i];
c@23 458
c@24 459 } else if (arg == "request") {
c@24 460 direction = RequestOrResponse::Request;
c@24 461 haveDirection = true;
c@24 462
c@24 463 } else if (arg == "response") {
c@24 464 direction = RequestOrResponse::Response;
c@24 465 haveDirection = true;
c@24 466
c@23 467 } else {
c@23 468 usage();
c@23 469 }
c@23 470 }
c@23 471
c@24 472 if (informat == "" || outformat == "" || !haveDirection) {
c@23 473 usage();
c@23 474 }
c@23 475
c@23 476 while (true) {
c@23 477
c@23 478 try {
c@23 479
c@24 480 RequestOrResponse rr = readInput(informat, direction);
c@29 481
c@29 482 // NotValid without an exception indicates EOF:
c@25 483 if (rr.type == RRType::NotValid) break;
c@29 484
c@23 485 writeOutput(outformat, rr);
c@23 486
c@23 487 } catch (std::exception &e) {
c@23 488 cerr << "Error: " << e.what() << endl;
c@23 489 exit(1);
c@23 490 }
c@23 491 }
c@23 492
c@23 493 exit(0);
c@23 494 }
c@23 495
c@23 496