annotate utilities/vampipe-convert.cpp @ 53:9bebe2780cc0

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