- const char *name;
- uint32_t eventid;
-
- /* get event data from the message */
- if (!api_ws_client_msg_event_read(rb, &eventid, &name)) {
- ERROR("Invalid message");
- return 0;
- }
-
- /* check conflicts */
- *ev = api_ws_client_event_search(api, eventid, name);
- if (*ev == NULL) {
- ERROR("event %s not found", name);
- return 0;
- }
-
- return 1;
-}
-
-/* get event from the message */
-static int api_ws_client_msg_memo_get(struct api_ws *api, struct readbuf *rb, struct api_ws_memo **memo)
-{
- uint32_t msgid;
-
- /* get event data from the message */
- if (!api_ws_read_uint32(rb, &msgid)) {
- ERROR("Invalid message");
- return 0;
- }
-
- /* get the memo */
- *memo = api_ws_client_memo_search(api, msgid);
- if (*memo == NULL) {
- ERROR("message not found");
- return 0;
- }
-
- return 1;
-}
-
-/* read a subscrition message */
-static int api_ws_client_msg_subscription_get(struct api_ws *api, struct readbuf *rb, struct api_ws_event **ev, struct api_ws_memo **memo)
-{
- return api_ws_client_msg_memo_get(api, rb, memo) && api_ws_client_msg_event_get(api, rb, ev);
-}
-
-/* adds an event */
-static void api_ws_client_event_create(struct api_ws *api, struct readbuf *rb)
-{
- size_t offset;
- const char *name;
- uint32_t eventid;
- struct api_ws_event *ev;
-
- /* get event data from the message */
- offset = api_ws_client_msg_event_read(rb, &eventid, &name);
- if (offset == 0) {
- ERROR("Invalid message");
- return;
- }
-
- /* check conflicts */
- ev = api_ws_client_event_search(api, eventid, name);
- if (ev != NULL) {
- ev->refcount++;
- return;
- }
-
- /* no conflict, try to add it */
- ev = malloc(sizeof *ev);
- if (ev != NULL) {
- ev->event = afb_evt_create_event(name);
- if (ev->event.closure == NULL)
- free(ev);
- else {
- ev->refcount = 1;
- ev->eventid = eventid;
- ev->next = api->client.events;
- api->client.events = ev;
- return;
- }
- }
- ERROR("can't create event %s, out of memory", name);
-}
-
-/* removes an event */
-static void api_ws_client_event_drop(struct api_ws *api, struct readbuf *rb)
-{
- struct api_ws_event *ev, **prv;
-
- /* retrieves the event */
- if (!api_ws_client_msg_event_get(api, rb, &ev))
- return;
-
- /* decrease the reference count */
- if (--ev->refcount)
- return;
-
- /* unlinks the event */
- prv = &api->client.events;
- while (*prv != ev)
- prv = &(*prv)->next;
- *prv = ev->next;
-
- /* destroys the event */
- afb_event_drop(ev->event);
- free(ev);
-}
-
-/* subscribes an event */
-static void api_ws_client_event_subscribe(struct api_ws *api, struct readbuf *rb)
-{
- struct api_ws_event *ev;
- struct api_ws_memo *memo;
-
- if (api_ws_client_msg_subscription_get(api, rb, &ev, &memo)) {
- /* subscribe the request from the event */
- if (afb_xreq_subscribe(memo->xreq, ev->event) < 0)
- ERROR("can't subscribe: %m");
- }
-}
-
-/* unsubscribes an event */
-static void api_ws_client_event_unsubscribe(struct api_ws *api, struct readbuf *rb)
-{
- struct api_ws_event *ev;
- struct api_ws_memo *memo;
-
- if (api_ws_client_msg_subscription_get(api, rb, &ev, &memo)) {
- /* unsubscribe the request from the event */
- if (afb_xreq_unsubscribe(memo->xreq, ev->event) < 0)
- ERROR("can't unsubscribe: %m");
- }
-}
-
-/* receives broadcasted events */
-static void api_ws_client_event_broadcast(struct api_ws *api, struct readbuf *rb)
-{
- struct json_object *object;
- const char *event;
-
- if (api_ws_read_string(rb, &event, NULL) && api_ws_read_object(rb, &object))
- afb_evt_broadcast(event, object);
- else
- ERROR("unreadable broadcasted event");
-}
-
-/* pushs an event */
-static void api_ws_client_event_push(struct api_ws *api, struct readbuf *rb)
-{
- struct api_ws_event *ev;
- struct json_object *object;
-
- if (api_ws_client_msg_event_get(api, rb, &ev) && api_ws_read_object(rb, &object))
- afb_event_push(ev->event, object);
- else
- ERROR("unreadable push event");
-}
-
-static void api_ws_client_reply_success(struct api_ws *api, struct readbuf *rb)
-{
- struct api_ws_memo *memo;
- struct json_object *object;
- const char *info;
- uint32_t flags;
-
- /* retrieve the message data */
- if (!api_ws_client_msg_memo_get(api, rb, &memo))
- return;
-
- if (api_ws_read_uint32(rb, &flags)
- && api_ws_read_string(rb, &info, NULL)
- && api_ws_read_object(rb, &object)) {
- memo->xreq->context.flags = (unsigned)flags;
- afb_xreq_success(memo->xreq, object, *info ? info : NULL);
- } else {
- /* failing to have the answer */
- afb_xreq_fail(memo->xreq, "error", "ws error");
- }
- api_ws_client_memo_destroy(memo);
-}
-
-static void api_ws_client_reply_fail(struct api_ws *api, struct readbuf *rb)
-{
- struct api_ws_memo *memo;
- const char *info, *status;
- uint32_t flags;
-
- /* retrieve the message data */
- if (!api_ws_client_msg_memo_get(api, rb, &memo))
- return;
-
- if (api_ws_read_uint32(rb, &flags)
- && api_ws_read_string(rb, &status, NULL)
- && api_ws_read_string(rb, &info, NULL)) {
- memo->xreq->context.flags = (unsigned)flags;
- afb_xreq_fail(memo->xreq, status, *info ? info : NULL);
- } else {
- /* failing to have the answer */
- afb_xreq_fail(memo->xreq, "error", "ws error");
- }
- api_ws_client_memo_destroy(memo);
-}
-
-/* callback when receiving binary data */
-static void api_ws_client_on_binary(void *closure, char *data, size_t size)
-{
- if (size > 0) {
- struct readbuf rb = { .head = data, .end = data + size };
- switch (*rb.head++) {
- case CHAR_FOR_ANSWER_SUCCESS: /* success */
- api_ws_client_reply_success(closure, &rb);
- break;
- case CHAR_FOR_ANSWER_FAIL: /* fail */
- api_ws_client_reply_fail(closure, &rb);
- break;
- case CHAR_FOR_EVT_BROADCAST: /* broadcast */
- api_ws_client_event_broadcast(closure, &rb);
- break;
- case CHAR_FOR_EVT_ADD: /* creates the event */
- api_ws_client_event_create(closure, &rb);
- break;
- case CHAR_FOR_EVT_DEL: /* drops the event */
- api_ws_client_event_drop(closure, &rb);
- break;
- case CHAR_FOR_EVT_PUSH: /* pushs the event */
- api_ws_client_event_push(closure, &rb);
- break;
- case CHAR_FOR_EVT_SUBSCRIBE: /* subscribe event for a request */
- api_ws_client_event_subscribe(closure, &rb);
- break;
- case CHAR_FOR_EVT_UNSUBSCRIBE: /* unsubscribe event for a request */
- api_ws_client_event_unsubscribe(closure, &rb);
- break;
- default: /* unexpected message */
- break;
- }
- }
- free(data);
-}
-
-/* on call, propagate it to the ws service */
-static void api_ws_client_call_cb(void * closure, struct afb_xreq *xreq)
-{
- int rc;
- struct api_ws_memo *memo;
- struct writebuf wb = { .count = 0 };
- const char *raw;
- size_t szraw;
- struct api_ws *api = closure;
-
- /* create the recording data */
- memo = api_ws_client_memo_make(api, xreq);
- if (memo == NULL) {
- afb_xreq_fail_f(xreq, "error", "out of memory");
- return;
- }
-
- /* creates the call message */
- raw = afb_xreq_raw(xreq, &szraw);
- if (raw == NULL)
- goto internal_error;
- if (!api_ws_write_uint32(&wb, memo->msgid)
- || !api_ws_write_uint32(&wb, (uint32_t)xreq->context.flags)
- || !api_ws_write_string(&wb, xreq->verb)
- || !api_ws_write_string(&wb, afb_session_uuid(xreq->context.session))
- || !api_ws_write_string_length(&wb, raw, szraw))
- goto overflow;
-
- /* send */
- rc = afb_ws_binary_v(api->client.ws, wb.iovec, wb.count);
- if (rc < 0)
- goto ws_send_error;
- return;
-
-ws_send_error:
- afb_xreq_fail(xreq, "error", "websocket sending error");
- goto clean_memo;
-
-internal_error:
- afb_xreq_fail(xreq, "error", "internal: raw is NULL!");
- goto clean_memo;
-
-overflow:
- afb_xreq_fail(xreq, "error", "overflow: size doesn't match 32 bits!");
-
-clean_memo:
- api_ws_client_memo_destroy(memo);
-}
-
-static int api_ws_service_start_cb(void *closure, int share_session, int onneed)
-{
- struct api_ws *api = closure;
-
- /* not an error when onneed */
- if (onneed != 0)
- return 0;
-
- /* already started: it is an error */
- ERROR("The WS binding %s is not a startable service", api->path);
- return -1;
-}
-
-/* */
-static void api_ws_client_disconnect(struct api_ws *api)
-{
- if (api->fd >= 0) {
- afb_ws_destroy(api->client.ws);
- api->client.ws = NULL;
- close(api->fd);
- api->fd = -1;
- }
-}
-
-/* */
-static int api_ws_client_connect(struct api_ws *api)
-{
- struct afb_ws *ws;
- int fd;
-
- fd = api_ws_socket(api->path, 0);
- if (fd >= 0) {
- ws = afb_ws_create(afb_common_get_event_loop(), fd, &api_ws_client_ws_itf, api);
- if (ws != NULL) {
- api->client.ws = ws;
- api->fd = fd;
- return 0;
- }
- close(fd);
- }
- return -1;
-}
-
-static struct afb_api_itf ws_api_itf = {
- .call = api_ws_client_call_cb,
- .service_start = api_ws_service_start_cb
-};
-
-/* adds a afb-ws-service client api */
-int afb_api_ws_add_client(const char *path)
-{
- int rc;
- struct api_ws *api;
- struct afb_api afb_api;