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
|