annotate utilities/vampipe-convert.cpp @ 54:524a6d5ee813

Fix dopy error
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 16 Sep 2016 16:34:00 +0100
parents 9bebe2780cc0
children 38780f15ac8d
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@54 130 VampJson::BufferSerialisation serialisation =
c@54 131 (useBase64 ?
c@54 132 VampJson::BufferSerialisation::Base64 :
c@54 133 VampJson::BufferSerialisation::Text);
c@54 134
c@27 135 switch (rr.type) {
c@27 136
c@27 137 case RRType::List:
c@24 138 j = VampJson::fromVampRequest_List();
c@27 139 break;
c@27 140 case RRType::Load:
c@24 141 j = VampJson::fromVampRequest_Load(rr.loadRequest);
c@27 142 break;
c@27 143 case RRType::Configure:
c@32 144 j = VampJson::fromVampRequest_Configure(rr.configurationRequest, mapper);
c@27 145 break;
c@27 146 case RRType::Process:
c@44 147 j = VampJson::fromVampRequest_Process
c@54 148 (rr.processRequest, mapper, serialisation);
c@27 149 break;
c@27 150 case RRType::Finish:
c@32 151 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, mapper);
c@27 152 break;
c@27 153 case RRType::NotValid:
c@27 154 break;
c@24 155 }
c@24 156
c@24 157 cout << j.dump() << endl;
c@24 158 }
c@24 159
c@24 160 RequestOrResponse
c@24 161 readResponseJson()
c@24 162 {
c@24 163 RequestOrResponse rr;
c@24 164 rr.direction = RequestOrResponse::Response;
c@24 165
c@23 166 string input;
c@23 167 if (!getline(cin, input)) {
c@25 168 rr.type = RRType::NotValid;
c@23 169 return rr;
c@23 170 }
c@23 171
c@24 172 Json j = convertResponseJson(input);
c@27 173
c@25 174 rr.type = VampJson::getRequestResponseType(j);
c@44 175 VampJson::BufferSerialisation serialisation = VampJson::BufferSerialisation::Text;
c@23 176
c@52 177 rr.success = j["success"].bool_value();
c@52 178 rr.errorText = j["errorText"].string_value();
c@52 179
c@27 180 switch (rr.type) {
c@27 181
c@27 182 case RRType::List:
c@24 183 rr.listResponse = VampJson::toVampResponse_List(j);
c@27 184 break;
c@27 185 case RRType::Load:
c@32 186 rr.loadResponse = VampJson::toVampResponse_Load(j, mapper);
c@27 187 break;
c@27 188 case RRType::Configure:
c@24 189 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
c@27 190 break;
c@27 191 case RRType::Process:
c@51 192 rr.processResponse = VampJson::toVampResponse_Process(j, mapper, serialisation);
c@27 193 break;
c@27 194 case RRType::Finish:
c@51 195 rr.finishResponse = VampJson::toVampResponse_Finish(j, mapper, serialisation);
c@27 196 break;
c@27 197 case RRType::NotValid:
c@27 198 break;
c@23 199 }
c@23 200
c@23 201 return rr;
c@23 202 }
c@23 203
c@24 204 void
c@44 205 writeResponseJson(RequestOrResponse &rr, bool useBase64)
c@24 206 {
c@24 207 Json j;
c@24 208
c@53 209 VampJson::BufferSerialisation serialisation =
c@54 210 (useBase64 ?
c@53 211 VampJson::BufferSerialisation::Base64 :
c@53 212 VampJson::BufferSerialisation::Text);
c@53 213
c@52 214 if (!rr.success) {
c@27 215
c@52 216 j = VampJson::fromError(rr.errorText, rr.type);
c@52 217
c@52 218 } else {
c@52 219
c@52 220 switch (rr.type) {
c@52 221
c@52 222 case RRType::List:
c@52 223 j = VampJson::fromVampResponse_List("", rr.listResponse);
c@52 224 break;
c@52 225 case RRType::Load:
c@52 226 j = VampJson::fromVampResponse_Load(rr.loadResponse, mapper);
c@52 227 break;
c@52 228 case RRType::Configure:
c@52 229 j = VampJson::fromVampResponse_Configure(rr.configurationResponse);
c@52 230 break;
c@52 231 case RRType::Process:
c@52 232 j = VampJson::fromVampResponse_Process
c@53 233 (rr.processResponse, mapper, serialisation);
c@52 234 break;
c@52 235 case RRType::Finish:
c@52 236 j = VampJson::fromVampResponse_Finish
c@53 237 (rr.finishResponse, mapper, serialisation);
c@52 238 break;
c@52 239 case RRType::NotValid:
c@52 240 break;
c@52 241 }
c@24 242 }
c@52 243
c@27 244 cout << j.dump() << endl;
c@27 245 }
c@25 246
c@27 247 RequestOrResponse
c@33 248 readRequestCapnp(kj::BufferedInputStreamWrapper &buffered)
c@27 249 {
c@27 250 RequestOrResponse rr;
c@27 251 rr.direction = RequestOrResponse::Request;
c@27 252
c@33 253 ::capnp::InputStreamMessageReader message(buffered);
c@27 254 VampRequest::Reader reader = message.getRoot<VampRequest>();
c@27 255
c@27 256 rr.type = VampnProto::getRequestResponseType(reader);
c@27 257
c@27 258 switch (rr.type) {
c@27 259
c@27 260 case RRType::List:
c@27 261 VampnProto::readVampRequest_List(reader); // type check only
c@27 262 break;
c@27 263 case RRType::Load:
c@27 264 VampnProto::readVampRequest_Load(rr.loadRequest, reader);
c@27 265 break;
c@27 266 case RRType::Configure:
c@32 267 VampnProto::readVampRequest_Configure(rr.configurationRequest,
c@32 268 reader, mapper);
c@27 269 break;
c@27 270 case RRType::Process:
c@32 271 VampnProto::readVampRequest_Process(rr.processRequest, reader, mapper);
c@27 272 break;
c@27 273 case RRType::Finish:
c@32 274 VampnProto::readVampRequest_Finish(rr.finishPlugin, reader, mapper);
c@27 275 break;
c@27 276 case RRType::NotValid:
c@27 277 break;
c@27 278 }
c@27 279
c@27 280 return rr;
c@27 281 }
c@27 282
c@29 283 void
c@29 284 writeRequestCapnp(RequestOrResponse &rr)
c@29 285 {
c@29 286 ::capnp::MallocMessageBuilder message;
c@29 287 VampRequest::Builder builder = message.initRoot<VampRequest>();
c@29 288
c@29 289 switch (rr.type) {
c@29 290
c@29 291 case RRType::List:
c@29 292 VampnProto::buildVampRequest_List(builder);
c@29 293 break;
c@29 294 case RRType::Load:
c@29 295 VampnProto::buildVampRequest_Load(builder, rr.loadRequest);
c@29 296 break;
c@29 297 case RRType::Configure:
c@29 298 VampnProto::buildVampRequest_Configure(builder,
c@32 299 rr.configurationRequest, mapper);
c@29 300 break;
c@29 301 case RRType::Process:
c@32 302 VampnProto::buildVampRequest_Process(builder, rr.processRequest, mapper);
c@29 303 break;
c@29 304 case RRType::Finish:
c@32 305 VampnProto::buildVampRequest_Finish(builder, rr.finishPlugin, mapper);
c@29 306 break;
c@29 307 case RRType::NotValid:
c@29 308 break;
c@29 309 }
c@29 310
c@33 311 writeMessageToFd(1, message);
c@29 312 }
c@29 313
c@27 314 RequestOrResponse
c@33 315 readResponseCapnp(kj::BufferedInputStreamWrapper &buffered)
c@27 316 {
c@27 317 RequestOrResponse rr;
c@27 318 rr.direction = RequestOrResponse::Response;
c@27 319
c@33 320 ::capnp::InputStreamMessageReader message(buffered);
c@27 321 VampResponse::Reader reader = message.getRoot<VampResponse>();
c@27 322
c@27 323 rr.type = VampnProto::getRequestResponseType(reader);
c@52 324 rr.success = reader.getSuccess();
c@52 325 rr.errorText = reader.getErrorText();
c@27 326
c@27 327 switch (rr.type) {
c@27 328
c@27 329 case RRType::List:
c@27 330 VampnProto::readVampResponse_List(rr.listResponse, reader);
c@27 331 break;
c@27 332 case RRType::Load:
c@32 333 VampnProto::readVampResponse_Load(rr.loadResponse, reader, mapper);
c@27 334 break;
c@27 335 case RRType::Configure:
c@27 336 VampnProto::readVampResponse_Configure(rr.configurationResponse,
c@27 337 reader);
c@27 338 break;
c@27 339 case RRType::Process:
c@51 340 VampnProto::readVampResponse_Process(rr.processResponse, reader, mapper);
c@27 341 break;
c@27 342 case RRType::Finish:
c@51 343 VampnProto::readVampResponse_Finish(rr.finishResponse, reader, mapper);
c@27 344 break;
c@27 345 case RRType::NotValid:
c@27 346 break;
c@27 347 }
c@27 348
c@27 349 return rr;
c@24 350 }
c@24 351
c@29 352 void
c@29 353 writeResponseCapnp(RequestOrResponse &rr)
c@29 354 {
c@29 355 ::capnp::MallocMessageBuilder message;
c@29 356 VampResponse::Builder builder = message.initRoot<VampResponse>();
c@29 357
c@52 358 if (!rr.success) {
c@29 359
c@52 360 VampnProto::buildVampResponse_Error(builder, rr.errorText, rr.type);
c@52 361
c@52 362 } else {
c@52 363
c@52 364 switch (rr.type) {
c@52 365
c@52 366 case RRType::List:
c@52 367 VampnProto::buildVampResponse_List(builder, "", rr.listResponse);
c@52 368 break;
c@52 369 case RRType::Load:
c@52 370 VampnProto::buildVampResponse_Load(builder, rr.loadResponse, mapper);
c@52 371 break;
c@52 372 case RRType::Configure:
c@52 373 VampnProto::buildVampResponse_Configure(builder, rr.configurationResponse);
c@52 374 break;
c@52 375 case RRType::Process:
c@52 376 VampnProto::buildVampResponse_Process(builder, rr.processResponse, mapper);
c@52 377 break;
c@52 378 case RRType::Finish:
c@52 379 VampnProto::buildVampResponse_Finish(builder, rr.finishResponse, mapper);
c@52 380 break;
c@52 381 case RRType::NotValid:
c@52 382 break;
c@52 383 }
c@29 384 }
c@52 385
c@33 386 writeMessageToFd(1, message);
c@33 387 }
c@33 388
c@33 389 RequestOrResponse
c@33 390 readInputJson(RequestOrResponse::Direction direction)
c@33 391 {
c@33 392 if (direction == RequestOrResponse::Request) {
c@33 393 return readRequestJson();
c@33 394 } else {
c@33 395 return readResponseJson();
c@33 396 }
c@33 397 }
c@33 398
c@33 399 RequestOrResponse
c@33 400 readInputCapnp(RequestOrResponse::Direction direction)
c@33 401 {
c@33 402 static kj::FdInputStream stream(0); // stdin
c@33 403 static kj::BufferedInputStreamWrapper buffered(stream);
c@33 404
c@33 405 if (buffered.tryGetReadBuffer() == nullptr) {
c@33 406 return {};
c@33 407 }
c@33 408
c@33 409 if (direction == RequestOrResponse::Request) {
c@33 410 return readRequestCapnp(buffered);
c@33 411 } else {
c@33 412 return readResponseCapnp(buffered);
c@33 413 }
c@29 414 }
c@29 415
c@23 416 RequestOrResponse
c@24 417 readInput(string format, RequestOrResponse::Direction direction)
c@23 418 {
c@23 419 if (format == "json") {
c@33 420 return readInputJson(direction);
c@27 421 } else if (format == "capnp") {
c@33 422 return readInputCapnp(direction);
c@23 423 } else {
c@27 424 throw runtime_error("unknown input format \"" + format + "\"");
c@23 425 }
c@23 426 }
c@23 427
c@23 428 void
c@24 429 writeOutput(string format, RequestOrResponse &rr)
c@23 430 {
c@24 431 if (format == "json") {
c@24 432 if (rr.direction == RequestOrResponse::Request) {
c@44 433 writeRequestJson(rr, false);
c@24 434 } else {
c@44 435 writeResponseJson(rr, false);
c@44 436 }
c@44 437 } else if (format == "json-b64") {
c@44 438 if (rr.direction == RequestOrResponse::Request) {
c@44 439 writeRequestJson(rr, true);
c@44 440 } else {
c@44 441 writeResponseJson(rr, true);
c@24 442 }
c@29 443 } else if (format == "capnp") {
c@29 444 if (rr.direction == RequestOrResponse::Request) {
c@29 445 writeRequestCapnp(rr);
c@29 446 } else {
c@29 447 writeResponseCapnp(rr);
c@29 448 }
c@24 449 } else {
c@27 450 throw runtime_error("unknown output format \"" + format + "\"");
c@24 451 }
c@23 452 }
c@23 453
c@23 454 int main(int argc, char **argv)
c@23 455 {
c@24 456 if (argc < 2) {
c@23 457 usage();
c@23 458 }
c@23 459
c@24 460 string informat = "json", outformat = "json";
c@27 461 RequestOrResponse::Direction direction = RequestOrResponse::Request;
c@24 462 bool haveDirection = false;
c@23 463
c@24 464 for (int i = 1; i < argc; ++i) {
c@23 465
c@23 466 string arg = argv[i];
c@24 467 bool final = (i + 1 == argc);
c@23 468
c@23 469 if (arg == "-i") {
c@27 470 if (final) usage();
c@23 471 else informat = argv[++i];
c@23 472
c@23 473 } else if (arg == "-o") {
c@27 474 if (final) usage();
c@23 475 else outformat = argv[++i];
c@23 476
c@24 477 } else if (arg == "request") {
c@24 478 direction = RequestOrResponse::Request;
c@24 479 haveDirection = true;
c@24 480
c@24 481 } else if (arg == "response") {
c@24 482 direction = RequestOrResponse::Response;
c@24 483 haveDirection = true;
c@24 484
c@23 485 } else {
c@23 486 usage();
c@23 487 }
c@23 488 }
c@23 489
c@24 490 if (informat == "" || outformat == "" || !haveDirection) {
c@23 491 usage();
c@23 492 }
c@23 493
c@23 494 while (true) {
c@23 495
c@23 496 try {
c@23 497
c@24 498 RequestOrResponse rr = readInput(informat, direction);
c@29 499
c@29 500 // NotValid without an exception indicates EOF:
c@25 501 if (rr.type == RRType::NotValid) break;
c@29 502
c@23 503 writeOutput(outformat, rr);
c@23 504
c@23 505 } catch (std::exception &e) {
c@52 506
c@23 507 cerr << "Error: " << e.what() << endl;
c@23 508 exit(1);
c@23 509 }
c@23 510 }
c@23 511
c@23 512 exit(0);
c@23 513 }
c@23 514
c@23 515