2 * Copyright (c) 2020 Collabora Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <systemd/sd-event.h>
21 #include <json-c/json.h>
25 #if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
26 #define JSON_C_TO_STRING_NOSLASHESCAPE 0
32 idle(struct pws_data_source *pws_d_source)
34 struct sd_event *loop = pws_d_source->loop;
37 if (!pws_d_source->callcount)
40 sd_event_run(loop, TIMEOUT_SD_LOOP);
45 dec_callcount(struct pws_data_source *pws_d_source)
50 pws_d_source->callcount--;
54 inc_callcount(struct pws_data_source *pws_d_source)
59 pws_d_source->callcount++;
63 on_pws_reply(void *closure, void *request, struct json_object *result,
64 const char *error, const char *info)
66 struct pws_data_source *pws_d_source =
67 static_cast<struct pws_data_source *>(closure);
69 assert(pws_d_source != NULL);
72 fprintf(stdout, "ON-REPLY %s: %s %s\n%s\n", (char*) request, error,
74 json_object_to_json_string_ext(result,
75 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
80 /* in case of an error do not set the reply */
81 if (!info && !error) {
82 /* should be cleaned-up after a proper request */
83 assert(pws_d_source->reply_valid == false);
85 pws_d_source->reply = result;
86 pws_d_source->reply_valid = true;
88 fprintf(stdout, "ON-REPLY: err: %s, request: %s, info %s\n",
89 error, (char *) request, info);
92 /* necessary when getting the reply to exit idle() */
93 dec_callcount(pws_d_source);
97 on_pws_event_create(void *closure, uint16_t event_id, const char *event_name)
99 struct pws_data_source *pws_d_source =
100 static_cast<struct pws_data_source *>(closure);
104 fprintf(stdout, "ON-EVENT-CREATE: [%d:%s]\n", event_id, event_name);
110 on_pws_event_remove(void *closure, uint16_t event_id)
112 struct pws_data_source *pws_d_source =
113 static_cast<struct pws_data_source *>(closure);
117 fprintf(stdout, "ON-EVENT-REMOVE: [%d]\n", event_id);
123 on_pws_event_subscribe(void *closure, void *request, uint16_t event_id)
125 struct pws_data_source *pws_d_source =
126 static_cast<struct pws_data_source *>(closure);
130 fprintf(stdout, "ON-EVENT-SUBSCRIBE %s: [%d]\n", (char*)request, event_id);
136 on_pws_event_unsubscribe(void *closure, void *request, uint16_t event_id)
138 struct pws_data_source *pws_d_source =
139 static_cast<struct pws_data_source *>(closure);
143 fprintf(stdout, "ON-EVENT-UNSUBSCRIBE %s: [%d]\n", (char*)request, event_id);
149 on_pws_event_push(void *closure, uint16_t event_id, struct json_object *data)
151 struct pws_data_source *pws_d_source =
152 static_cast<struct pws_data_source *>(closure);
156 fprintf(stdout, "ON-EVENT-PUSH: [%d]\n%s\n",
158 json_object_to_json_string_ext(data, JSON_C_TO_STRING_NOSLASHESCAPE));
159 fprintf(stdout, "ON-EVENT-PUSH: [%d]\n%s\n",
161 json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY |
162 JSON_C_TO_STRING_NOSLASHESCAPE));
169 on_pws_event_broadcast(void *closure, const char *event_name,
170 struct json_object *data,
171 const afb_proto_ws_uuid_t uuid, uint8_t hop)
173 struct pws_data_source *pws_d_source =
174 static_cast<struct pws_data_source *>(closure);
181 fprintf(stdout, "ON-EVENT-BROADCAST: [%s]\n%s\n",
183 json_object_to_json_string_ext(data, JSON_C_TO_STRING_NOSLASHESCAPE));
184 fprintf(stdout, "ON-EVENT-BROADCAST: [%s]\n%s\n",
186 json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY |
187 JSON_C_TO_STRING_NOSLASHESCAPE));
192 /* called when pws hangsup */
194 on_pws_hangup(void *closure)
196 struct pws_data_source *pws_d_source =
197 static_cast<struct pws_data_source *>(closure);
201 printf("ON-HANGUP\n");
210 pws_call(const char *verb, const char *object,
211 struct pws_data_source *pws_d_source)
214 struct json_object *o;
215 enum json_tokener_error jerr;
217 struct afb_proto_ws *pws = pws_d_source->pws;
222 /* allocates an id for the request */
223 rc = asprintf(&key, "%d:%s", ++pws_d_source->num_id, verb);
227 /* echo the command if asked */
228 fprintf(stdout, "SEND-CALL: %s %s\n", verb, object?:"null");
230 inc_callcount(pws_d_source);
232 if (object == NULL || object[0] == 0) {
235 o = json_tokener_parse_verbose(object, &jerr);
236 if (jerr != json_tokener_success)
237 o = json_object_new_string(object);
240 /* send the request */
241 rc = afb_proto_ws_client_call(pws, verb, o, 0, 0, key, NULL);
244 fprintf(stderr, "calling %s(%s) failed: %m\n", verb, object ?: "");
245 dec_callcount(pws_d_source);
254 /* the callback interface for pws */
255 static struct afb_proto_ws_client_itf pws_itf = {
256 .on_reply = on_pws_reply,
257 .on_event_create = on_pws_event_create,
258 .on_event_remove = on_pws_event_remove,
259 .on_event_subscribe = on_pws_event_subscribe,
260 .on_event_unsubscribe = on_pws_event_unsubscribe,
261 .on_event_push = on_pws_event_push,
262 .on_event_broadcast = on_pws_event_broadcast,
265 struct pws_data_source *
266 pws_data_source_init(const char *connect_to)
268 struct afb_proto_ws *pws;
269 struct sd_event *sd_loop;
270 struct pws_data_source *pws_d_source = nullptr;
273 fprintf(stderr, "Failed to get a connect_to\n");
277 if (sd_event_default(&sd_loop) < 0) {
278 fprintf(stderr, "Failed to get a default event\n");
283 static_cast<struct pws_data_source *>(calloc(1, sizeof(struct pws_data_source)));
286 fprintf(stderr, "Failed to allocate memory\n");
290 pws = afb_ws_client_connect_api(sd_loop, connect_to,
291 &pws_itf, pws_d_source);
293 fprintf(stderr, "Failed to create a afb_proto_ws\n");
297 afb_proto_ws_on_hangup(pws, on_pws_hangup);
299 pws_d_source->pws = pws;
300 pws_d_source->loop = sd_loop;
301 pws_d_source->callcount = 0;
302 pws_d_source->num_id = 0;
304 pws_d_source->reply = nullptr;
305 pws_d_source->reply_valid = false;
311 pws_do_call(struct pws_data_source *pws_d_source,
312 const char *verb, const char *object)
314 if (!verb || !object || !pws_d_source)
317 if (pws_call(verb, object, pws_d_source) < 0)
326 pws_data_source_destroy(struct pws_data_source *pws_d_source)
328 assert(pws_d_source != nullptr);
330 sd_event_unref(pws_d_source->loop);
335 pws_data_source_reply_destroy(struct pws_data_source *pws)
337 assert(pws->reply_valid == true);
338 pws->reply_valid = false;
344 pws_start_process(struct pws_data_source *pws, const char *afm_name)
347 if (pws_do_call(pws, "start", afm_name) < 0)
350 if (pws->reply_valid) {
351 struct json_object *result = pws->reply;
353 rid = json_object_get_int(result);
354 fprintf(stdout, "ON-REPLY %s\n",
355 json_object_to_json_string_ext(result,
356 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
358 pws_data_source_reply_destroy(pws);
365 pws_stop_process(struct pws_data_source *pws, const char *afm_name)
368 if (pws_do_call(pws, "terminate", afm_name) < 0)
371 if (pws->reply_valid) {
372 struct json_object *result = pws->reply;
374 term = json_object_get_boolean(result);
376 fprintf(stdout, "ON-REPLY %s\n",
377 json_object_to_json_string_ext(result,
378 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
380 pws_data_source_reply_destroy(pws);
388 pws_check_process_is_running(struct pws_data_source *pws, const char *afm_name)
392 if (pws_do_call(pws, "state", afm_name) < 0)
395 if (pws->reply_valid) {
396 struct json_object *result = pws->reply;
397 struct json_object *obj;
399 json_object_object_get_ex(result, "runid", &obj);
401 rid = json_object_get_int(obj);
402 fprintf(stdout, "Found rid %d\n", rid);
405 fprintf(stdout, "ON-REPLY: %s\n",
406 json_object_to_json_string_ext(result,
407 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
409 pws_data_source_reply_destroy(pws);
416 pws_list_runners(struct pws_data_source *pws)
419 if (pws_do_call(pws, "runners", "true") < 0)
422 if (pws->reply_valid) {
423 struct json_object *result = pws->reply;
425 /* at least one is running */
426 items = json_object_array_length(result);
429 fprintf(stdout, "found %ld items\n", items);
430 fprintf(stdout, "ON-REPLY: %s\n",
431 json_object_to_json_string_ext(result,
432 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
434 pws_data_source_reply_destroy(pws);
441 pws_list_runnables(struct pws_data_source *pws)
444 if (pws_do_call(pws, "runnables", "true") < 0)
447 if (pws->reply_valid) {
448 struct json_object *result = pws->reply;
450 items = json_object_array_length(result);
452 fprintf(stdout, "found %ld items\n", items);
453 fprintf(stdout, "ON-REPLY: %s\n",
454 json_object_to_json_string_ext(result,
455 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
457 pws_data_source_reply_destroy(pws);
464 * need to free(json_string) once you're done with it
466 * call pws_data_source_reply_destroy(pws) once you're done with it.
469 pws_get_list_runnables(struct pws_data_source *pws, struct json_object **json)
472 if (pws_do_call(pws, "runnables", "true") < 0)
475 fprintf(stdout, "pws_get_list_runnables()\n");
477 if (pws->reply_valid) {
478 struct json_object *result = pws->reply;
480 items = json_object_array_length(result);
482 fprintf(stdout, "found %ld items\n", items);
483 fprintf(stdout, "ON-REPLY: %s\n",
484 json_object_to_json_string_ext(result,
485 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
488 fprintf(stdout, "pws_get_list_runnables() turn items %d, bails sooner\n", items);
493 fprintf(stdout, "pws_get_list_runnables() json reply is set\n");
497 fprintf(stdout, "pws_get_list_runnables() turn items %d\n", items);