comparison utilities/vampipe-convert.cpp @ 24:533ca5ca3404

More on reading and writing json messages
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 23 May 2016 16:09:25 +0100
parents d678cd00e593
children 5b9690d18241
comparison
equal deleted inserted replaced
23:d678cd00e593 24:533ca5ca3404
8 8
9 using namespace std; 9 using namespace std;
10 using namespace json11; 10 using namespace json11;
11 using namespace vampipe; 11 using namespace vampipe;
12 12
13 // Accepting JSON objects with two fields, "type" and "payload". The 13 // Accepting JSON objects with two fields, "type" and "content". The
14 // "type" string corresponds to the JSON schema filename 14 // "type" string corresponds to the JSON schema filename
15 // (e.g. "outputdescriptor") and the "payload" is the JSON object 15 // (e.g. "outputdescriptor") and the "content" is the JSON object
16 // encoded with that schema. 16 // encoded with that schema.
17
18 Json
19 json_input(string input)
20 {
21 string err;
22 Json j = Json::parse(input, err);
23 if (err != "") {
24 throw VampJson::Failure("invalid json: " + err);
25 }
26 if (!j.is_object()) {
27 throw VampJson::Failure("object expected at top level");
28 }
29 if (!j["type"].is_string()) {
30 throw VampJson::Failure("string expected for type field");
31 }
32 if (!j["payload"].is_object()) {
33 throw VampJson::Failure("object expected for payload field");
34 }
35 return j;
36 }
37 17
38 class PreservingPluginHandleMapper : public PluginHandleMapper 18 class PreservingPluginHandleMapper : public PluginHandleMapper
39 { 19 {
40 public: 20 public:
41 PreservingPluginHandleMapper() : m_handle(0), m_plugin(0) { } 21 PreservingPluginHandleMapper() : m_handle(0), m_plugin(0) { }
54 private: 34 private:
55 int32_t m_handle; 35 int32_t m_handle;
56 Vamp::Plugin *m_plugin; 36 Vamp::Plugin *m_plugin;
57 }; 37 };
58 38
59 void
60 handle_input(::capnp::MallocMessageBuilder &message, string input)
61 {
62 string err;
63
64 Json j = json_input(input);
65 string type = j["type"].string_value();
66 Json payload = j["payload"];
67
68 if (type == "configurationrequest") {
69 auto req = message.initRoot<ConfigurationRequest>();
70 PreservingPluginHandleMapper mapper;
71 VampnProto::buildConfigurationRequest
72 (req, VampJson::toConfigurationRequest(payload, mapper), mapper);
73
74 } else if (type == "configurationresponse") {
75 auto resp = message.initRoot<ConfigurationResponse>();
76 VampnProto::buildConfigurationResponse
77 (resp, VampJson::toConfigurationResponse(payload));
78
79 } else if (type == "feature") {
80 auto f = message.initRoot<Feature>();
81 VampnProto::buildFeature
82 (f, VampJson::toFeature(payload));
83
84 } else if (type == "featureset") {
85 auto fs = message.initRoot<FeatureSet>();
86 VampnProto::buildFeatureSet
87 (fs, VampJson::toFeatureSet(payload));
88
89 } else if (type == "loadrequest") {
90 auto req = message.initRoot<LoadRequest>();
91 VampnProto::buildLoadRequest
92 (req, VampJson::toLoadRequest(payload));
93
94 } else if (type == "loadresponse") {
95 auto resp = message.initRoot<LoadResponse>();
96 PreservingPluginHandleMapper mapper;
97 VampnProto::buildLoadResponse
98 (resp, VampJson::toLoadResponse(payload, mapper), mapper);
99
100 } else if (type == "outputdescriptor") {
101 auto od = message.initRoot<OutputDescriptor>();
102 VampnProto::buildOutputDescriptor
103 (od, VampJson::toOutputDescriptor(payload));
104
105 } else if (type == "parameterdescriptor") {
106 auto pd = message.initRoot<ParameterDescriptor>();
107 VampnProto::buildParameterDescriptor
108 (pd, VampJson::toParameterDescriptor(payload));
109
110 } else if (type == "pluginconfiguration") {
111 auto pc = message.initRoot<PluginConfiguration>();
112 auto config = VampJson::toPluginConfiguration(payload);
113 VampnProto::buildPluginConfiguration(pc, config);
114
115 } else if (type == "pluginstaticdata") {
116 auto pc = message.initRoot<PluginStaticData>();
117 auto sd = VampJson::toPluginStaticData(payload);
118 VampnProto::buildPluginStaticData(pc, sd);
119
120 } else if (type == "processrequest") {
121 auto p = message.initRoot<ProcessRequest>();
122 PreservingPluginHandleMapper mapper;
123 VampnProto::buildProcessRequest
124 (p, VampJson::toProcessRequest(payload, mapper), mapper);
125
126 } else if (type == "realtime") {
127 auto b = message.initRoot<RealTime>();
128 VampnProto::buildRealTime
129 (b, VampJson::toRealTime(payload));
130
131 } else {
132 throw VampJson::Failure("unknown or unsupported JSON schema type " +
133 type);
134 }
135 }
136
137 void usage() 39 void usage()
138 { 40 {
139 string myname = "vampipe-convert"; 41 string myname = "vampipe-convert";
140 cerr << "\n" << myname << 42 cerr << "\n" << myname <<
141 ": Convert Vamp request and response messages between formats\n\n" 43 ": Validate and convert Vamp request and response messages\n\n"
142 " Usage: " << myname << " -i <informat> -o <outformat>\n\n" 44 " Usage: " << myname << " [-i <informat>] [-o <outformat>] request\n"
143 "Where <informat> and <outformat> may be \"json\" or \"capnp\".\n" 45 " " << myname << " [-i <informat>] [-o <outformat>] response\n\n"
144 "Messages are read from stdin and written to stdout.\n" << endl; 46 " where\n"
47 " <informat>: the format to read from stdin\n"
48 " (\"json\" or \"capnp\", default is \"json\")\n"
49 " <outformat>: the format to convert to and write to stdout\n"
50 " (\"json\" or \"capnp\", default is \"json\")\n"
51 " request|response: whether to expect Vamp request or response messages\n\n"
52 "If <informat> and <outformat> differ, convert from <informat> to <outformat>.\n"
53 "If <informat> and <outformat> are the same, just check validity of incoming\n"
54 "messages and pass them to output.\n\n";
55
145 exit(2); 56 exit(2);
146 } 57 }
147 58
148 class RequestOrResponse 59 class RequestOrResponse
149 { 60 {
150 public: 61 public:
62 enum Direction {
63 Request, Response
64 };
151 enum Type { 65 enum Type {
152 List, Load, Configure, Process, Finish, Eof 66 List, Load, Configure, Process, Finish, Eof
153 }; 67 };
68
69 static Type typeForName(string name) {
70 if (name == "list") return List;
71 else if (name == "load") return Load;
72 else if (name == "configure") return Configure;
73 else if (name == "process") return Process;
74 else if (name == "finish") return Finish;
75 else if (name == "eof") return Eof;
76 else {
77 throw runtime_error("unknown or unexpected request/response type \"" +
78 name + "\"");
79 }
80 }
81
154 RequestOrResponse() : // nothing by default 82 RequestOrResponse() : // nothing by default
83 direction(Request),
155 type(Eof), 84 type(Eof),
156 success(false), 85 success(false),
157 finishPlugin(0) { } 86 finishPlugin(0) { }
158 87
88 Direction direction;
159 Type type; 89 Type type;
160 bool success; 90 bool success;
161 string errorText; 91 string errorText;
162 92
163 PreservingPluginHandleMapper mapper; 93 PreservingPluginHandleMapper mapper;
164 94
95 vector<Vamp::HostExt::PluginStaticData> listResponse;
165 Vamp::HostExt::LoadRequest loadRequest; 96 Vamp::HostExt::LoadRequest loadRequest;
166 Vamp::HostExt::LoadResponse loadResponse; 97 Vamp::HostExt::LoadResponse loadResponse;
167 Vamp::HostExt::ConfigurationRequest configurationRequest; 98 Vamp::HostExt::ConfigurationRequest configurationRequest;
168 Vamp::HostExt::ConfigurationResponse configurationResponse; 99 Vamp::HostExt::ConfigurationResponse configurationResponse;
169 Vamp::HostExt::ProcessRequest processRequest; 100 Vamp::HostExt::ProcessRequest processRequest;
170 Vamp::HostExt::ProcessResponse processResponse; 101 Vamp::HostExt::ProcessResponse processResponse;
171 Vamp::Plugin *finishPlugin; 102 Vamp::Plugin *finishPlugin;
172 Vamp::HostExt::ProcessResponse finishResponse; 103 Vamp::HostExt::ProcessResponse finishResponse;
173
174 }; 104 };
175 105
106 Json
107 convertRequestJson(string input)
108 {
109 string err;
110 Json j = Json::parse(input, err);
111 if (err != "") {
112 throw VampJson::Failure("invalid json: " + err);
113 }
114 if (!j.is_object()) {
115 throw VampJson::Failure("object expected at top level");
116 }
117 if (!j["type"].is_string()) {
118 throw VampJson::Failure("string expected for type field");
119 }
120 if (!j["content"].is_object()) {
121 throw VampJson::Failure("object expected for content field");
122 }
123 return j;
124 }
125
126 Json
127 convertResponseJson(string input)
128 {
129 string err;
130 Json j = Json::parse(input, err);
131 if (err != "") {
132 throw VampJson::Failure("invalid json: " + err);
133 }
134 if (!j.is_object()) {
135 throw VampJson::Failure("object expected at top level");
136 }
137 if (!j["success"].is_bool()) {
138 throw VampJson::Failure("bool expected for success field");
139 }
140 if (!j["content"].is_object()) {
141 throw VampJson::Failure("object expected for content field");
142 }
143 return j;
144 }
145
176 RequestOrResponse 146 RequestOrResponse
177 readInputJson() 147 readRequestJson()
178 { 148 {
179 RequestOrResponse rr; 149 RequestOrResponse rr;
150 rr.direction = RequestOrResponse::Request;
151
180 string input; 152 string input;
181 if (!getline(cin, input)) { 153 if (!getline(cin, input)) {
182 rr.type = RequestOrResponse::Eof; 154 rr.type = RequestOrResponse::Eof;
183 return rr; 155 return rr;
184 } 156 }
185 157
186 Json j = json_input(input); 158 Json j = convertRequestJson(input);
187 string type = j["type"].string_value(); 159 string type = j["type"].string_value();
188 160 rr.type = RequestOrResponse::typeForName(type);
189 if (type == "list") { 161
190 rr.type = RequestOrResponse::List; 162 if (rr.type == RequestOrResponse::Load) {
191 163 rr.loadRequest = VampJson::toVampRequest_Load(j);
192 } else if (type == "load") { 164
193 //!!! ah, we need a way to know whether we're dealing with a request or response here 165 } else if (rr.type == RequestOrResponse::Configure) {
194 rr.type = RequestOrResponse::Load; 166 rr.configurationRequest = VampJson::toVampRequest_Configure(j, rr.mapper);
195 rr.loadRequest = VampJson::toLoadRequest(j["content"]); 167
196 168 } else if (rr.type == RequestOrResponse::Process) {
197 } else if (type == "configure") { 169 rr.processRequest = VampJson::toVampRequest_Process(j, rr.mapper);
198 rr.type = RequestOrResponse::Configure; 170
199 rr.configurationRequest = 171 } else if (rr.type == RequestOrResponse::Finish) {
200 VampJson::toConfigurationRequest(j["content"], rr.mapper); 172 rr.finishPlugin = VampJson::toVampRequest_Finish(j, rr.mapper);
201
202 } else if (type == "process") {
203 rr.type = RequestOrResponse::Process;
204 rr.processRequest =
205 VampJson::toProcessRequest(j["content"], rr.mapper);
206
207 } else if (type == "finish") {
208 rr.type = RequestOrResponse::Finish;
209 //!!! VampJsonify
210 rr.finishPlugin = rr.mapper.handleToPlugin(j["content"]["pluginHandle"].int_value());
211
212 } else {
213 throw runtime_error("unknown or unexpected request/response type \"" +
214 type + "\"");
215 } 173 }
216 174
217 return rr; 175 return rr;
218 } 176 }
219 177
178 void
179 writeRequestJson(RequestOrResponse &rr)
180 {
181 Json j;
182
183 if (rr.type == RequestOrResponse::List) {
184 j = VampJson::fromVampRequest_List();
185
186 } else if (rr.type == RequestOrResponse::Load) {
187 j = VampJson::fromVampRequest_Load(rr.loadRequest);
188
189 } else if (rr.type == RequestOrResponse::Configure) {
190 j = VampJson::fromVampRequest_Configure(rr.configurationRequest, rr.mapper);
191
192 } else if (rr.type == RequestOrResponse::Process) {
193 j = VampJson::fromVampRequest_Process(rr.processRequest, rr.mapper);
194
195 } else if (rr.type == RequestOrResponse::Finish) {
196 j = VampJson::fromVampRequest_Finish(rr.finishPlugin, rr.mapper);
197 }
198
199 cout << j.dump() << endl;
200 }
201
220 RequestOrResponse 202 RequestOrResponse
221 readInput(string format) 203 readResponseJson()
204 {
205 RequestOrResponse rr;
206 rr.direction = RequestOrResponse::Response;
207
208 string input;
209 if (!getline(cin, input)) {
210 rr.type = RequestOrResponse::Eof;
211 return rr;
212 }
213
214 Json j = convertResponseJson(input);
215 string type = j["type"].string_value();
216 rr.type = RequestOrResponse::typeForName(type);
217
218 if (rr.type == RequestOrResponse::List) {
219 rr.listResponse = VampJson::toVampResponse_List(j);
220
221 } else if (rr.type == RequestOrResponse::Load) {
222 rr.loadResponse = VampJson::toVampResponse_Load(j, rr.mapper);
223
224 } else if (rr.type == RequestOrResponse::Configure) {
225 rr.configurationResponse = VampJson::toVampResponse_Configure(j);
226
227 } else if (rr.type == RequestOrResponse::Process) {
228 rr.processResponse = VampJson::toVampResponse_Process(j);
229
230 } else if (rr.type == RequestOrResponse::Finish) {
231 rr.finishResponse = VampJson::toVampResponse_Finish(j);
232 }
233
234 return rr;
235 }
236
237 void
238 writeResponseJson(RequestOrResponse &rr)
239 {
240 Json j;
241
242 if (rr.type == RequestOrResponse::List) {
243 j = VampJson::fromVampResponse_List("", rr.listResponse);
244
245 } else if (rr.type == RequestOrResponse::Load) {
246 j = VampJson::fromVampResponse_Load(rr.loadResponse, rr.mapper);
247 }
248
249 cout << j.dump() << endl;
250 }
251
252 RequestOrResponse
253 readInput(string format, RequestOrResponse::Direction direction)
222 { 254 {
223 if (format == "json") { 255 if (format == "json") {
224 return readInputJson(); 256 if (direction == RequestOrResponse::Request) {
257 return readRequestJson();
258 } else {
259 return readResponseJson();
260 }
225 } else { 261 } else {
226 throw runtime_error("unknown or unimplemented format \"" + format + "\""); 262 throw runtime_error("unknown or unimplemented format \"" + format + "\"");
227 } 263 }
228 } 264 }
229 265
230 void 266 void
231 writeOutput(string format, const RequestOrResponse &rr) 267 writeOutput(string format, RequestOrResponse &rr)
232 { 268 {
233 throw runtime_error("writeOutput not implemented yet"); 269 if (format == "json") {
270 if (rr.direction == RequestOrResponse::Request) {
271 writeRequestJson(rr);
272 } else {
273 writeResponseJson(rr);
274 }
275 } else {
276 throw runtime_error("unknown or unimplemented format \"" + format + "\"");
277 }
278 }
279
280 int main(int argc, char **argv)
281 {
282 if (argc < 2) {
283 usage();
284 }
285
286 string informat = "json", outformat = "json";
287 RequestOrResponse::Direction direction;
288 bool haveDirection = false;
234 289
235 } 290 for (int i = 1; i < argc; ++i) {
236
237 int main(int argc, char **argv)
238 {
239 if (argc != 5) {
240 usage();
241 }
242
243 string informat, outformat;
244
245 for (int i = 1; i + 1 < argc; ++i) {
246 291
247 string arg = argv[i]; 292 string arg = argv[i];
293 bool final = (i + 1 == argc);
248 294
249 if (arg == "-i") { 295 if (arg == "-i") {
250 if (informat != "") usage(); 296 if (informat != "" || final) usage();
251 else informat = argv[++i]; 297 else informat = argv[++i];
252 298
253 } else if (arg == "-o") { 299 } else if (arg == "-o") {
254 if (outformat != "") usage(); 300 if (outformat != "" || final) usage();
255 else outformat = argv[++i]; 301 else outformat = argv[++i];
256 302
303 } else if (arg == "request") {
304 direction = RequestOrResponse::Request;
305 haveDirection = true;
306
307 } else if (arg == "response") {
308 direction = RequestOrResponse::Response;
309 haveDirection = true;
310
257 } else { 311 } else {
258 usage(); 312 usage();
259 } 313 }
260 } 314 }
261 315
262 if (informat == "" || outformat == "") { 316 if (informat == "" || outformat == "" || !haveDirection) {
263 usage(); 317 usage();
264 } 318 }
265 319
266 while (true) { 320 while (true) {
267 321
268 try { 322 try {
269 323
270 RequestOrResponse rr = readInput(informat); 324 RequestOrResponse rr = readInput(informat, direction);
271 if (rr.type == RequestOrResponse::Eof) break; 325 if (rr.type == RequestOrResponse::Eof) break;
272 writeOutput(outformat, rr); 326 writeOutput(outformat, rr);
273 327
274 } catch (std::exception &e) { 328 } catch (std::exception &e) {
275 cerr << "Error: " << e.what() << endl; 329 cerr << "Error: " << e.what() << endl;