annotate utilities/vampipe-convert.cpp @ 27:cc85c2851605

Wire up Cap'n Proto reading, plus some build and arg processing fixes
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 24 May 2016 12:00:38 +0100
parents 5b9690d18241
children 7062a3bebaa3
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@23 130 RequestOrResponse
c@24 131 readRequestJson()
c@23 132 {
c@23 133 RequestOrResponse rr;
c@24 134 rr.direction = RequestOrResponse::Request;
c@24 135
c@24 136 string input;
c@24 137 if (!getline(cin, input)) {
c@25 138 rr.type = RRType::NotValid;
c@24 139 return rr;
c@24 140 }
c@24 141
c@24 142 Json j = convertRequestJson(input);
c@27 143
c@25 144 rr.type = VampJson::getRequestResponseType(j);
c@24 145
c@27 146 switch (rr.type) {
c@27 147
c@27 148 case RRType::List:
c@27 149 VampJson::toVampRequest_List(j); // type check only
c@27 150 break;
c@27 151 case RRType::Load:
c@24 152 rr.loadRequest = VampJson::toVampRequest_Load(j);
c@27 153 break;
c@27 154 case RRType::Configure:
c@27 155 rr.configurationRequest =
c@27 156 VampJson::toVampRequest_Configure(j, rr.mapper);
c@27 157 break;
c@27 158 case RRType::Process:
c@24 159 rr.processRequest = VampJson::toVampRequest_Process(j, rr.mapper);
c@27 160 break;
c@27 161 case RRType::Finish:
c@24 162 rr.finishPlugin = VampJson::toVampRequest_Finish(j, rr.mapper);
c@27 163 break;
c@27 164 case RRType::NotValid:
c@27 165 break;
c@24 166 }
c@24 167
c@24 168 return rr;
c@24 169 }
c@24 170
c@24 171 void
c@24 172 writeRequestJson(RequestOrResponse &rr)
c@24 173 {
c@24 174 Json j;
c@24 175
c@27 176 switch (rr.type) {
c@27 177
c@27 178 case RRType::List:
c@24 179 j = VampJson::fromVampRequest_List();
c@27 180 break;
c@27 181 case RRType::Load:
c@24 182 j = VampJson::fromVampRequest_Load(rr.loadRequest);
c@27 183 break;
c@27 184 case RRType::Configure:
c@27 185 j = VampJson::fromVampRequest_Configure(rr.configurationRequest,
c@27 186 rr.mapper);
c@27 187 break;
c@27 188 case RRType::Process:
c@24 189 j = VampJson::fromVampRequest_Process(rr.processRequest, rr.mapper);
c@27 190 break;
c@27 191 case RRType::Finish:
c@24 192 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, rr.mapper);
c@27 193 break;
c@27 194 case RRType::NotValid:
c@27 195 break;
c@24 196 }
c@24 197
c@24 198 cout << j.dump() << endl;
c@24 199 }
c@24 200
c@24 201 RequestOrResponse
c@24 202 readResponseJson()
c@24 203 {
c@24 204 RequestOrResponse rr;
c@24 205 rr.direction = RequestOrResponse::Response;
c@24 206
c@23 207 string input;
c@23 208 if (!getline(cin, input)) {
c@25 209 rr.type = RRType::NotValid;
c@23 210 return rr;
c@23 211 }
c@23 212
c@24 213 Json j = convertResponseJson(input);
c@27 214
c@25 215 rr.type = VampJson::getRequestResponseType(j);
c@23 216
c@27 217 switch (rr.type) {
c@27 218
c@27 219 case RRType::List:
c@24 220 rr.listResponse = VampJson::toVampResponse_List(j);
c@27 221 break;
c@27 222 case RRType::Load:
c@24 223 rr.loadResponse = VampJson::toVampResponse_Load(j, rr.mapper);
c@27 224 break;
c@27 225 case RRType::Configure:
c@24 226 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
c@27 227 break;
c@27 228 case RRType::Process:
c@24 229 rr.processResponse = VampJson::toVampResponse_Process(j);
c@27 230 break;
c@27 231 case RRType::Finish:
c@24 232 rr.finishResponse = VampJson::toVampResponse_Finish(j);
c@27 233 break;
c@27 234 case RRType::NotValid:
c@27 235 break;
c@23 236 }
c@23 237
c@23 238 return rr;
c@23 239 }
c@23 240
c@24 241 void
c@24 242 writeResponseJson(RequestOrResponse &rr)
c@24 243 {
c@24 244 Json j;
c@24 245
c@27 246 switch (rr.type) {
c@27 247
c@27 248 case RRType::List:
c@24 249 j = VampJson::fromVampResponse_List("", rr.listResponse);
c@27 250 break;
c@27 251 case RRType::Load:
c@24 252 j = VampJson::fromVampResponse_Load(rr.loadResponse, rr.mapper);
c@27 253 break;
c@27 254 case RRType::Configure:
c@27 255 j = VampJson::fromVampResponse_Configure(rr.configurationResponse);
c@27 256 break;
c@27 257 case RRType::Process:
c@27 258 j = VampJson::fromVampResponse_Process(rr.processResponse);
c@27 259 break;
c@27 260 case RRType::Finish:
c@27 261 j = VampJson::fromVampResponse_Finish(rr.finishResponse);
c@27 262 break;
c@27 263 case RRType::NotValid:
c@27 264 break;
c@24 265 }
c@24 266
c@27 267 cout << j.dump() << endl;
c@27 268 }
c@25 269
c@27 270 RequestOrResponse
c@27 271 readRequestCapnp()
c@27 272 {
c@27 273 RequestOrResponse rr;
c@27 274 rr.direction = RequestOrResponse::Request;
c@27 275
c@27 276 ::capnp::PackedFdMessageReader message(0); // stdin
c@27 277 VampRequest::Reader reader = message.getRoot<VampRequest>();
c@27 278
c@27 279 rr.type = VampnProto::getRequestResponseType(reader);
c@27 280
c@27 281 switch (rr.type) {
c@27 282
c@27 283 case RRType::List:
c@27 284 VampnProto::readVampRequest_List(reader); // type check only
c@27 285 break;
c@27 286 case RRType::Load:
c@27 287 VampnProto::readVampRequest_Load(rr.loadRequest, reader);
c@27 288 break;
c@27 289 case RRType::Configure:
c@27 290 VampnProto::readVampRequest_Configure(rr.configurationRequest, reader,
c@27 291 rr.mapper);
c@27 292 break;
c@27 293 case RRType::Process:
c@27 294 VampnProto::readVampRequest_Process(rr.processRequest, reader,
c@27 295 rr.mapper);
c@27 296 break;
c@27 297 case RRType::Finish:
c@27 298 VampnProto::readVampRequest_Finish(rr.finishPlugin, reader,
c@27 299 rr.mapper);
c@27 300 break;
c@27 301 case RRType::NotValid:
c@27 302 break;
c@27 303 }
c@27 304
c@27 305 return rr;
c@27 306 }
c@27 307
c@27 308 RequestOrResponse
c@27 309 readResponseCapnp()
c@27 310 {
c@27 311 RequestOrResponse rr;
c@27 312 rr.direction = RequestOrResponse::Response;
c@27 313
c@27 314 ::capnp::PackedFdMessageReader message(0); // stdin
c@27 315 VampResponse::Reader reader = message.getRoot<VampResponse>();
c@27 316
c@27 317 rr.type = VampnProto::getRequestResponseType(reader);
c@27 318
c@27 319 switch (rr.type) {
c@27 320
c@27 321 case RRType::List:
c@27 322 VampnProto::readVampResponse_List(rr.listResponse, reader);
c@27 323 break;
c@27 324 case RRType::Load:
c@27 325 VampnProto::readVampResponse_Load(rr.loadResponse, reader, rr.mapper);
c@27 326 break;
c@27 327 case RRType::Configure:
c@27 328 VampnProto::readVampResponse_Configure(rr.configurationResponse,
c@27 329 reader);
c@27 330 break;
c@27 331 case RRType::Process:
c@27 332 VampnProto::readVampResponse_Process(rr.processResponse, reader);
c@27 333 break;
c@27 334 case RRType::Finish:
c@27 335 VampnProto::readVampResponse_Finish(rr.finishResponse, reader);
c@27 336 break;
c@27 337 case RRType::NotValid:
c@27 338 break;
c@27 339 }
c@27 340
c@27 341 return rr;
c@24 342 }
c@24 343
c@23 344 RequestOrResponse
c@24 345 readInput(string format, RequestOrResponse::Direction direction)
c@23 346 {
c@23 347 if (format == "json") {
c@24 348 if (direction == RequestOrResponse::Request) {
c@24 349 return readRequestJson();
c@24 350 } else {
c@24 351 return readResponseJson();
c@24 352 }
c@27 353 } else if (format == "capnp") {
c@27 354 if (direction == RequestOrResponse::Request) {
c@27 355 return readRequestCapnp();
c@27 356 } else {
c@27 357 return readResponseCapnp();
c@27 358 }
c@23 359 } else {
c@27 360 throw runtime_error("unknown input format \"" + format + "\"");
c@23 361 }
c@23 362 }
c@23 363
c@23 364 void
c@24 365 writeOutput(string format, RequestOrResponse &rr)
c@23 366 {
c@24 367 if (format == "json") {
c@24 368 if (rr.direction == RequestOrResponse::Request) {
c@24 369 writeRequestJson(rr);
c@24 370 } else {
c@24 371 writeResponseJson(rr);
c@24 372 }
c@24 373 } else {
c@27 374 throw runtime_error("unknown output format \"" + format + "\"");
c@24 375 }
c@23 376 }
c@23 377
c@23 378 int main(int argc, char **argv)
c@23 379 {
c@24 380 if (argc < 2) {
c@23 381 usage();
c@23 382 }
c@23 383
c@24 384 string informat = "json", outformat = "json";
c@27 385 RequestOrResponse::Direction direction = RequestOrResponse::Request;
c@24 386 bool haveDirection = false;
c@23 387
c@24 388 for (int i = 1; i < argc; ++i) {
c@23 389
c@23 390 string arg = argv[i];
c@24 391 bool final = (i + 1 == argc);
c@23 392
c@23 393 if (arg == "-i") {
c@27 394 if (final) usage();
c@23 395 else informat = argv[++i];
c@23 396
c@23 397 } else if (arg == "-o") {
c@27 398 if (final) usage();
c@23 399 else outformat = argv[++i];
c@23 400
c@24 401 } else if (arg == "request") {
c@24 402 direction = RequestOrResponse::Request;
c@24 403 haveDirection = true;
c@24 404
c@24 405 } else if (arg == "response") {
c@24 406 direction = RequestOrResponse::Response;
c@24 407 haveDirection = true;
c@24 408
c@23 409 } else {
c@23 410 usage();
c@23 411 }
c@23 412 }
c@23 413
c@24 414 if (informat == "" || outformat == "" || !haveDirection) {
c@23 415 usage();
c@23 416 }
c@23 417
c@23 418 while (true) {
c@23 419
c@23 420 try {
c@23 421
c@24 422 RequestOrResponse rr = readInput(informat, direction);
c@25 423 if (rr.type == RRType::NotValid) break;
c@23 424 writeOutput(outformat, rr);
c@23 425
c@23 426 } catch (std::exception &e) {
c@23 427 cerr << "Error: " << e.what() << endl;
c@23 428 exit(1);
c@23 429 }
c@23 430 }
c@23 431
c@23 432 exit(0);
c@23 433 }
c@23 434
c@23 435