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@31
|
6
|
c@23
|
7 #include <iostream>
|
c@23
|
8 #include <sstream>
|
c@23
|
9 #include <stdexcept>
|
c@23
|
10
|
c@23
|
11 using namespace std;
|
c@23
|
12 using namespace json11;
|
c@23
|
13 using namespace vampipe;
|
c@23
|
14
|
c@23
|
15 void usage()
|
c@23
|
16 {
|
c@23
|
17 string myname = "vampipe-convert";
|
c@23
|
18 cerr << "\n" << myname <<
|
c@24
|
19 ": Validate and convert Vamp request and response messages\n\n"
|
c@24
|
20 " Usage: " << myname << " [-i <informat>] [-o <outformat>] request\n"
|
c@24
|
21 " " << myname << " [-i <informat>] [-o <outformat>] response\n\n"
|
c@24
|
22 " where\n"
|
c@24
|
23 " <informat>: the format to read from stdin\n"
|
c@24
|
24 " (\"json\" or \"capnp\", default is \"json\")\n"
|
c@24
|
25 " <outformat>: the format to convert to and write to stdout\n"
|
c@24
|
26 " (\"json\" or \"capnp\", default is \"json\")\n"
|
c@24
|
27 " request|response: whether to expect Vamp request or response messages\n\n"
|
c@24
|
28 "If <informat> and <outformat> differ, convert from <informat> to <outformat>.\n"
|
c@24
|
29 "If <informat> and <outformat> are the same, just check validity of incoming\n"
|
c@24
|
30 "messages and pass them to output.\n\n";
|
c@24
|
31
|
c@23
|
32 exit(2);
|
c@23
|
33 }
|
c@23
|
34
|
c@24
|
35 Json
|
c@24
|
36 convertRequestJson(string input)
|
c@24
|
37 {
|
c@24
|
38 string err;
|
c@24
|
39 Json j = Json::parse(input, err);
|
c@24
|
40 if (err != "") {
|
c@24
|
41 throw VampJson::Failure("invalid json: " + err);
|
c@24
|
42 }
|
c@24
|
43 if (!j.is_object()) {
|
c@24
|
44 throw VampJson::Failure("object expected at top level");
|
c@24
|
45 }
|
c@24
|
46 if (!j["type"].is_string()) {
|
c@24
|
47 throw VampJson::Failure("string expected for type field");
|
c@24
|
48 }
|
c@24
|
49 if (!j["content"].is_object()) {
|
c@24
|
50 throw VampJson::Failure("object expected for content field");
|
c@24
|
51 }
|
c@24
|
52 return j;
|
c@24
|
53 }
|
c@24
|
54
|
c@24
|
55 Json
|
c@24
|
56 convertResponseJson(string input)
|
c@24
|
57 {
|
c@24
|
58 string err;
|
c@24
|
59 Json j = Json::parse(input, err);
|
c@24
|
60 if (err != "") {
|
c@24
|
61 throw VampJson::Failure("invalid json: " + err);
|
c@24
|
62 }
|
c@24
|
63 if (!j.is_object()) {
|
c@24
|
64 throw VampJson::Failure("object expected at top level");
|
c@24
|
65 }
|
c@24
|
66 if (!j["success"].is_bool()) {
|
c@24
|
67 throw VampJson::Failure("bool expected for success field");
|
c@24
|
68 }
|
c@24
|
69 if (!j["content"].is_object()) {
|
c@24
|
70 throw VampJson::Failure("object expected for content field");
|
c@24
|
71 }
|
c@24
|
72 return j;
|
c@24
|
73 }
|
c@24
|
74
|
c@30
|
75 //!!! Lots of potential for refactoring the conversion classes based
|
c@30
|
76 //!!! on the common matter in the following eight functions...
|
c@30
|
77
|
c@23
|
78 RequestOrResponse
|
c@24
|
79 readRequestJson()
|
c@23
|
80 {
|
c@23
|
81 RequestOrResponse rr;
|
c@24
|
82 rr.direction = RequestOrResponse::Request;
|
c@24
|
83
|
c@24
|
84 string input;
|
c@24
|
85 if (!getline(cin, input)) {
|
c@25
|
86 rr.type = RRType::NotValid;
|
c@24
|
87 return rr;
|
c@24
|
88 }
|
c@24
|
89
|
c@24
|
90 Json j = convertRequestJson(input);
|
c@27
|
91
|
c@25
|
92 rr.type = VampJson::getRequestResponseType(j);
|
c@24
|
93
|
c@27
|
94 switch (rr.type) {
|
c@27
|
95
|
c@27
|
96 case RRType::List:
|
c@27
|
97 VampJson::toVampRequest_List(j); // type check only
|
c@27
|
98 break;
|
c@27
|
99 case RRType::Load:
|
c@24
|
100 rr.loadRequest = VampJson::toVampRequest_Load(j);
|
c@27
|
101 break;
|
c@27
|
102 case RRType::Configure:
|
c@27
|
103 rr.configurationRequest =
|
c@27
|
104 VampJson::toVampRequest_Configure(j, rr.mapper);
|
c@27
|
105 break;
|
c@27
|
106 case RRType::Process:
|
c@24
|
107 rr.processRequest = VampJson::toVampRequest_Process(j, rr.mapper);
|
c@27
|
108 break;
|
c@27
|
109 case RRType::Finish:
|
c@24
|
110 rr.finishPlugin = VampJson::toVampRequest_Finish(j, rr.mapper);
|
c@27
|
111 break;
|
c@27
|
112 case RRType::NotValid:
|
c@27
|
113 break;
|
c@24
|
114 }
|
c@24
|
115
|
c@24
|
116 return rr;
|
c@24
|
117 }
|
c@24
|
118
|
c@24
|
119 void
|
c@24
|
120 writeRequestJson(RequestOrResponse &rr)
|
c@24
|
121 {
|
c@24
|
122 Json j;
|
c@24
|
123
|
c@27
|
124 switch (rr.type) {
|
c@27
|
125
|
c@27
|
126 case RRType::List:
|
c@24
|
127 j = VampJson::fromVampRequest_List();
|
c@27
|
128 break;
|
c@27
|
129 case RRType::Load:
|
c@24
|
130 j = VampJson::fromVampRequest_Load(rr.loadRequest);
|
c@27
|
131 break;
|
c@27
|
132 case RRType::Configure:
|
c@27
|
133 j = VampJson::fromVampRequest_Configure(rr.configurationRequest,
|
c@27
|
134 rr.mapper);
|
c@27
|
135 break;
|
c@27
|
136 case RRType::Process:
|
c@24
|
137 j = VampJson::fromVampRequest_Process(rr.processRequest, rr.mapper);
|
c@27
|
138 break;
|
c@27
|
139 case RRType::Finish:
|
c@24
|
140 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, rr.mapper);
|
c@27
|
141 break;
|
c@27
|
142 case RRType::NotValid:
|
c@27
|
143 break;
|
c@24
|
144 }
|
c@24
|
145
|
c@24
|
146 cout << j.dump() << endl;
|
c@24
|
147 }
|
c@24
|
148
|
c@24
|
149 RequestOrResponse
|
c@24
|
150 readResponseJson()
|
c@24
|
151 {
|
c@24
|
152 RequestOrResponse rr;
|
c@24
|
153 rr.direction = RequestOrResponse::Response;
|
c@24
|
154
|
c@23
|
155 string input;
|
c@23
|
156 if (!getline(cin, input)) {
|
c@25
|
157 rr.type = RRType::NotValid;
|
c@23
|
158 return rr;
|
c@23
|
159 }
|
c@23
|
160
|
c@24
|
161 Json j = convertResponseJson(input);
|
c@27
|
162
|
c@25
|
163 rr.type = VampJson::getRequestResponseType(j);
|
c@23
|
164
|
c@27
|
165 switch (rr.type) {
|
c@27
|
166
|
c@27
|
167 case RRType::List:
|
c@24
|
168 rr.listResponse = VampJson::toVampResponse_List(j);
|
c@27
|
169 break;
|
c@27
|
170 case RRType::Load:
|
c@24
|
171 rr.loadResponse = VampJson::toVampResponse_Load(j, rr.mapper);
|
c@27
|
172 break;
|
c@27
|
173 case RRType::Configure:
|
c@24
|
174 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
|
c@27
|
175 break;
|
c@27
|
176 case RRType::Process:
|
c@24
|
177 rr.processResponse = VampJson::toVampResponse_Process(j);
|
c@27
|
178 break;
|
c@27
|
179 case RRType::Finish:
|
c@24
|
180 rr.finishResponse = VampJson::toVampResponse_Finish(j);
|
c@27
|
181 break;
|
c@27
|
182 case RRType::NotValid:
|
c@27
|
183 break;
|
c@23
|
184 }
|
c@23
|
185
|
c@23
|
186 return rr;
|
c@23
|
187 }
|
c@23
|
188
|
c@24
|
189 void
|
c@24
|
190 writeResponseJson(RequestOrResponse &rr)
|
c@24
|
191 {
|
c@24
|
192 Json j;
|
c@24
|
193
|
c@27
|
194 switch (rr.type) {
|
c@27
|
195
|
c@27
|
196 case RRType::List:
|
c@24
|
197 j = VampJson::fromVampResponse_List("", rr.listResponse);
|
c@27
|
198 break;
|
c@27
|
199 case RRType::Load:
|
c@24
|
200 j = VampJson::fromVampResponse_Load(rr.loadResponse, rr.mapper);
|
c@27
|
201 break;
|
c@27
|
202 case RRType::Configure:
|
c@27
|
203 j = VampJson::fromVampResponse_Configure(rr.configurationResponse);
|
c@27
|
204 break;
|
c@27
|
205 case RRType::Process:
|
c@27
|
206 j = VampJson::fromVampResponse_Process(rr.processResponse);
|
c@27
|
207 break;
|
c@27
|
208 case RRType::Finish:
|
c@27
|
209 j = VampJson::fromVampResponse_Finish(rr.finishResponse);
|
c@27
|
210 break;
|
c@27
|
211 case RRType::NotValid:
|
c@27
|
212 break;
|
c@24
|
213 }
|
c@24
|
214
|
c@27
|
215 cout << j.dump() << endl;
|
c@27
|
216 }
|
c@25
|
217
|
c@27
|
218 RequestOrResponse
|
c@27
|
219 readRequestCapnp()
|
c@27
|
220 {
|
c@27
|
221 RequestOrResponse rr;
|
c@27
|
222 rr.direction = RequestOrResponse::Request;
|
c@27
|
223
|
c@27
|
224 ::capnp::PackedFdMessageReader message(0); // stdin
|
c@27
|
225 VampRequest::Reader reader = message.getRoot<VampRequest>();
|
c@27
|
226
|
c@27
|
227 rr.type = VampnProto::getRequestResponseType(reader);
|
c@27
|
228
|
c@27
|
229 switch (rr.type) {
|
c@27
|
230
|
c@27
|
231 case RRType::List:
|
c@27
|
232 VampnProto::readVampRequest_List(reader); // type check only
|
c@27
|
233 break;
|
c@27
|
234 case RRType::Load:
|
c@27
|
235 VampnProto::readVampRequest_Load(rr.loadRequest, reader);
|
c@27
|
236 break;
|
c@27
|
237 case RRType::Configure:
|
c@27
|
238 VampnProto::readVampRequest_Configure(rr.configurationRequest, reader,
|
c@27
|
239 rr.mapper);
|
c@27
|
240 break;
|
c@27
|
241 case RRType::Process:
|
c@27
|
242 VampnProto::readVampRequest_Process(rr.processRequest, reader,
|
c@27
|
243 rr.mapper);
|
c@27
|
244 break;
|
c@27
|
245 case RRType::Finish:
|
c@27
|
246 VampnProto::readVampRequest_Finish(rr.finishPlugin, reader,
|
c@27
|
247 rr.mapper);
|
c@27
|
248 break;
|
c@27
|
249 case RRType::NotValid:
|
c@27
|
250 break;
|
c@27
|
251 }
|
c@27
|
252
|
c@27
|
253 return rr;
|
c@27
|
254 }
|
c@27
|
255
|
c@29
|
256 void
|
c@29
|
257 writeRequestCapnp(RequestOrResponse &rr)
|
c@29
|
258 {
|
c@29
|
259 ::capnp::MallocMessageBuilder message;
|
c@29
|
260 VampRequest::Builder builder = message.initRoot<VampRequest>();
|
c@29
|
261
|
c@29
|
262 switch (rr.type) {
|
c@29
|
263
|
c@29
|
264 case RRType::List:
|
c@29
|
265 VampnProto::buildVampRequest_List(builder);
|
c@29
|
266 break;
|
c@29
|
267 case RRType::Load:
|
c@29
|
268 VampnProto::buildVampRequest_Load(builder, rr.loadRequest);
|
c@29
|
269 break;
|
c@29
|
270 case RRType::Configure:
|
c@29
|
271 VampnProto::buildVampRequest_Configure(builder,
|
c@29
|
272 rr.configurationRequest,
|
c@29
|
273 rr.mapper);
|
c@29
|
274 break;
|
c@29
|
275 case RRType::Process:
|
c@29
|
276 VampnProto::buildVampRequest_Process(builder,
|
c@29
|
277 rr.processRequest,
|
c@29
|
278 rr.mapper);
|
c@29
|
279 break;
|
c@29
|
280 case RRType::Finish:
|
c@29
|
281 VampnProto::buildVampRequest_Finish(builder,
|
c@29
|
282 rr.finishPlugin,
|
c@29
|
283 rr.mapper);
|
c@29
|
284 break;
|
c@29
|
285 case RRType::NotValid:
|
c@29
|
286 break;
|
c@29
|
287 }
|
c@29
|
288
|
c@29
|
289 writePackedMessageToFd(1, message);
|
c@29
|
290 }
|
c@29
|
291
|
c@27
|
292 RequestOrResponse
|
c@27
|
293 readResponseCapnp()
|
c@27
|
294 {
|
c@27
|
295 RequestOrResponse rr;
|
c@27
|
296 rr.direction = RequestOrResponse::Response;
|
c@27
|
297
|
c@27
|
298 ::capnp::PackedFdMessageReader message(0); // stdin
|
c@27
|
299 VampResponse::Reader reader = message.getRoot<VampResponse>();
|
c@27
|
300
|
c@27
|
301 rr.type = VampnProto::getRequestResponseType(reader);
|
c@27
|
302
|
c@27
|
303 switch (rr.type) {
|
c@27
|
304
|
c@27
|
305 case RRType::List:
|
c@27
|
306 VampnProto::readVampResponse_List(rr.listResponse, reader);
|
c@27
|
307 break;
|
c@27
|
308 case RRType::Load:
|
c@27
|
309 VampnProto::readVampResponse_Load(rr.loadResponse, reader, rr.mapper);
|
c@27
|
310 break;
|
c@27
|
311 case RRType::Configure:
|
c@27
|
312 VampnProto::readVampResponse_Configure(rr.configurationResponse,
|
c@27
|
313 reader);
|
c@27
|
314 break;
|
c@27
|
315 case RRType::Process:
|
c@27
|
316 VampnProto::readVampResponse_Process(rr.processResponse, reader);
|
c@27
|
317 break;
|
c@27
|
318 case RRType::Finish:
|
c@27
|
319 VampnProto::readVampResponse_Finish(rr.finishResponse, reader);
|
c@27
|
320 break;
|
c@27
|
321 case RRType::NotValid:
|
c@27
|
322 break;
|
c@27
|
323 }
|
c@27
|
324
|
c@27
|
325 return rr;
|
c@24
|
326 }
|
c@24
|
327
|
c@29
|
328 void
|
c@29
|
329 writeResponseCapnp(RequestOrResponse &rr)
|
c@29
|
330 {
|
c@29
|
331 ::capnp::MallocMessageBuilder message;
|
c@29
|
332 VampResponse::Builder builder = message.initRoot<VampResponse>();
|
c@29
|
333
|
c@29
|
334 switch (rr.type) {
|
c@29
|
335
|
c@29
|
336 case RRType::List:
|
c@29
|
337 VampnProto::buildVampResponse_List(builder, "", rr.listResponse);
|
c@29
|
338 break;
|
c@29
|
339 case RRType::Load:
|
c@29
|
340 VampnProto::buildVampResponse_Load(builder, rr.loadResponse, rr.mapper);
|
c@29
|
341 break;
|
c@29
|
342 case RRType::Configure:
|
c@29
|
343 VampnProto::buildVampResponse_Configure(builder, rr.configurationResponse);
|
c@29
|
344 break;
|
c@29
|
345 case RRType::Process:
|
c@29
|
346 VampnProto::buildVampResponse_Process(builder, rr.processResponse);
|
c@29
|
347 break;
|
c@29
|
348 case RRType::Finish:
|
c@29
|
349 VampnProto::buildVampResponse_Finish(builder, rr.finishResponse);
|
c@29
|
350 break;
|
c@29
|
351 case RRType::NotValid:
|
c@29
|
352 break;
|
c@29
|
353 }
|
c@29
|
354
|
c@29
|
355 writePackedMessageToFd(1, message);
|
c@29
|
356 }
|
c@29
|
357
|
c@23
|
358 RequestOrResponse
|
c@24
|
359 readInput(string format, RequestOrResponse::Direction direction)
|
c@23
|
360 {
|
c@23
|
361 if (format == "json") {
|
c@24
|
362 if (direction == RequestOrResponse::Request) {
|
c@24
|
363 return readRequestJson();
|
c@24
|
364 } else {
|
c@24
|
365 return readResponseJson();
|
c@24
|
366 }
|
c@27
|
367 } else if (format == "capnp") {
|
c@27
|
368 if (direction == RequestOrResponse::Request) {
|
c@27
|
369 return readRequestCapnp();
|
c@27
|
370 } else {
|
c@27
|
371 return readResponseCapnp();
|
c@27
|
372 }
|
c@23
|
373 } else {
|
c@27
|
374 throw runtime_error("unknown input format \"" + format + "\"");
|
c@23
|
375 }
|
c@23
|
376 }
|
c@23
|
377
|
c@23
|
378 void
|
c@24
|
379 writeOutput(string format, RequestOrResponse &rr)
|
c@23
|
380 {
|
c@24
|
381 if (format == "json") {
|
c@24
|
382 if (rr.direction == RequestOrResponse::Request) {
|
c@24
|
383 writeRequestJson(rr);
|
c@24
|
384 } else {
|
c@24
|
385 writeResponseJson(rr);
|
c@24
|
386 }
|
c@29
|
387 } else if (format == "capnp") {
|
c@29
|
388 if (rr.direction == RequestOrResponse::Request) {
|
c@29
|
389 writeRequestCapnp(rr);
|
c@29
|
390 } else {
|
c@29
|
391 writeResponseCapnp(rr);
|
c@29
|
392 }
|
c@24
|
393 } else {
|
c@27
|
394 throw runtime_error("unknown output format \"" + format + "\"");
|
c@24
|
395 }
|
c@23
|
396 }
|
c@23
|
397
|
c@23
|
398 int main(int argc, char **argv)
|
c@23
|
399 {
|
c@24
|
400 if (argc < 2) {
|
c@23
|
401 usage();
|
c@23
|
402 }
|
c@23
|
403
|
c@24
|
404 string informat = "json", outformat = "json";
|
c@27
|
405 RequestOrResponse::Direction direction = RequestOrResponse::Request;
|
c@24
|
406 bool haveDirection = false;
|
c@23
|
407
|
c@24
|
408 for (int i = 1; i < argc; ++i) {
|
c@23
|
409
|
c@23
|
410 string arg = argv[i];
|
c@24
|
411 bool final = (i + 1 == argc);
|
c@23
|
412
|
c@23
|
413 if (arg == "-i") {
|
c@27
|
414 if (final) usage();
|
c@23
|
415 else informat = argv[++i];
|
c@23
|
416
|
c@23
|
417 } else if (arg == "-o") {
|
c@27
|
418 if (final) usage();
|
c@23
|
419 else outformat = argv[++i];
|
c@23
|
420
|
c@24
|
421 } else if (arg == "request") {
|
c@24
|
422 direction = RequestOrResponse::Request;
|
c@24
|
423 haveDirection = true;
|
c@24
|
424
|
c@24
|
425 } else if (arg == "response") {
|
c@24
|
426 direction = RequestOrResponse::Response;
|
c@24
|
427 haveDirection = true;
|
c@24
|
428
|
c@23
|
429 } else {
|
c@23
|
430 usage();
|
c@23
|
431 }
|
c@23
|
432 }
|
c@23
|
433
|
c@24
|
434 if (informat == "" || outformat == "" || !haveDirection) {
|
c@23
|
435 usage();
|
c@23
|
436 }
|
c@23
|
437
|
c@23
|
438 while (true) {
|
c@23
|
439
|
c@23
|
440 try {
|
c@23
|
441
|
c@24
|
442 RequestOrResponse rr = readInput(informat, direction);
|
c@29
|
443
|
c@29
|
444 // NotValid without an exception indicates EOF:
|
c@25
|
445 if (rr.type == RRType::NotValid) break;
|
c@29
|
446
|
c@23
|
447 writeOutput(outformat, rr);
|
c@23
|
448
|
c@23
|
449 } catch (std::exception &e) {
|
c@23
|
450 cerr << "Error: " << e.what() << endl;
|
c@23
|
451 exit(1);
|
c@23
|
452 }
|
c@23
|
453 }
|
c@23
|
454
|
c@23
|
455 exit(0);
|
c@23
|
456 }
|
c@23
|
457
|
c@23
|
458
|