diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2016-05-29 23:41:40 +0200 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2016-05-29 23:41:40 +0200 |
commit | 26bca5f8a8c6f9403a84945a5cd914b6da948efd (patch) | |
tree | 88469dc3eaa063b3d773d5221fe3cb67e9b04cc0 | |
parent | 706bc5c7e0db5f7a782f80ab99fa8fe005289f8d (diff) | |
parent | 2ea7ffb3abc8c62cfd5235ba4dbcd040f0235d69 (diff) |
Merge branch 'master' of https://github.com/iotbzh/afb-daemon
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | doc/afb-plugin-writing.html | 131 | ||||
-rw-r--r-- | doc/afb-plugin-writing.md | 4 | ||||
-rwxr-xr-x | doc/updt.sh | 2 | ||||
-rw-r--r-- | include/afb/afb-event-sender-itf.h | 35 | ||||
-rw-r--r-- | include/afb/afb-plugin.h | 23 | ||||
-rw-r--r-- | libafbwsc.pc.in (renamed from afb-wsc.pc.in) | 0 | ||||
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/afb-api-dbus.c | 4 | ||||
-rw-r--r-- | src/afb-api-so.c | 16 | ||||
-rw-r--r-- | src/afb-context.c | 2 | ||||
-rw-r--r-- | src/afb-hreq.c | 4 | ||||
-rw-r--r-- | src/afb-ws-client.h | 6 | ||||
-rw-r--r-- | src/afb-ws-json1.c | 2 | ||||
-rw-r--r-- | src/afb-wsj1.c | 12 | ||||
-rw-r--r-- | src/afb-wsj1.h | 145 | ||||
-rw-r--r-- | test/AFB.html | 2 | ||||
-rw-r--r-- | test/AFB.js | 8 | ||||
-rw-r--r-- | test/websock.js | 8 |
19 files changed, 260 insertions, 154 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c5094bb8..7a1a0d01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,9 @@ SET(PROJECT_DESCRIPTION "Secured binder of API for clients of the Application fr SET(PROJECT_VERSION "0.5") SET(PROJECT_URL "https://github.com/iotbzh/afb-daemon") +SET(LIBAFBWSC_VERSION "0.5") +SET(LIBAFBWSC_SOVERSION "0") + INCLUDE(FindPkgConfig) INCLUDE(CheckIncludeFiles) INCLUDE(CheckLibraryExists) @@ -69,11 +72,11 @@ ADD_SUBDIRECTORY(plugins) ############################################################ # installs the pkgconfig files CONFIGURE_FILE(afb-daemon.pc.in afb-daemon.pc @ONLY) -CONFIGURE_FILE(afb-wsc.pc.in afb-wsc.pc @ONLY) +CONFIGURE_FILE(libafbwsc.pc.in libafbwsc.pc @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/afb-daemon.pc - ${CMAKE_CURRENT_BINARY_DIR}/afb-wsc.pc + ${CMAKE_CURRENT_BINARY_DIR}/libafbwsc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) diff --git a/doc/afb-plugin-writing.html b/doc/afb-plugin-writing.html index 20e25972..b80006f4 100644 --- a/doc/afb-plugin-writing.html +++ b/doc/afb-plugin-writing.html @@ -8,7 +8,7 @@ <h1>HOWTO WRITE a PLUGIN for AFB-DAEMON</h1> <pre><code>version: 1 -Date: 27 mai 2016 +Date: 29 mai 2016 Author: José Bollo </code></pre> @@ -18,14 +18,14 @@ Author: José Bollo <li><a href="#Summary">Summary</a> <ul> <li><a href="#Nature.of.a.plugin">Nature of a plugin</a></li> - <li><a href="#Kinds.of.plugins">Kinds of plugins</a> + <li><a href="#Class.of.plugins">Class of plugins</a> <ul> - <li><a href="#Application.plugins">Application plugins</a></li> - <li><a href="#Service.plugins">Service plugins</a></li> + <li><a href="#Application-plugins">Application-plugins</a></li> + <li><a href="#Service-plugins">Service-plugins</a></li> </ul> </li> - <li><a href="#Live.cycle.of.a.plugin.within.afb-daemon">Live cycle of a plugin within afb-daemon</a></li> - <li><a href="#Content.of.a.plugin">Content of a plugin</a> + <li><a href="#Live.cycle.of.plugins.within.afb-daemon">Live cycle of plugins within afb-daemon</a></li> + <li><a href="#Plugin.Contend">Plugin Contend</a> <ul> <li><a href="#The.name.of.the.plugin">The name of the plugin</a></li> <li><a href="#Names.of.verbs">Names of verbs</a></li> @@ -85,101 +85,90 @@ Author: José Bollo <a name="Summary"></a> <h2>Summary</h2> -<p>The binder afb-daemon serves files through -the HTTP protocol and offers access to API’s through +<p>The binder afb-daemon serves files through HTTP protocol +and offers to developers the capability to expose application APIs through HTTP or WebSocket protocol.</p> -<p>The plugins are used to add API’s to afb-daemon. +<p>Binder plugins are used to add API to afb-daemon. This part describes how to write a plugin for afb-daemon. Excepting this summary, this part is intended to be read -by developpers.</p> +by developers.</p> -<p>Before going into details, through a tiny example, -a short overview plugins basis is needed.</p> +<p>Before moving further through an example, here after +a short overview of binder plugins fundamentals.</p> <a name="Nature.of.a.plugin"></a> <h3>Nature of a plugin</h3> -<p>A plugin is a separate piece of code made of a shared library. -The plugin is loaded and activated by afb-daemon when afb-daemon -starts.</p> +<p>A plugin is an independent piece of software, self contain and expose as a dynamically loadable library. +A plugin is loaded by afb-daemon that exposes contained API dynamically at runtime.</p> -<p>Technically, a plugin is not linked to any library of afb-daemon.</p> +<p>Technically, a binder plugins does not reference and is not linked with any library from afb-daemon.</p> -<a name="Kinds.of.plugins"></a> -<h3>Kinds of plugins</h3> +<a name="Class.of.plugins"></a> +<h3>Class of plugins</h3> -<p>There is two kinds of plugins: application plugins and service -plugins.</p> +<p>Application binder supports two kinds of plugins: application plugins and service +plugins. Technically both class of plugin are equivalent and coding API is shared. Only sharing mode and security context diverge.</p> -<a name="Application.plugins"></a> -<h4>Application plugins</h4> +<a name="Application-plugins"></a> +<h4>Application-plugins</h4> -<p>Application plugins are intended to be instanciated for each -application: when an application using that plugin is started, -its binder starts a new instance of the plugin.</p> +<p>Application-plugins implements the glue in between application’s UI and services. Every AGL application +has a corresponding binder that typically activates one or many plugins to interface the application logic with lower platform services. +When an application is started by AGL application framework, a dedicate binder is started that loads/activates application plugin(s). +The API expose by application-plugin are executed within corresponding application security context.</p> -<p>It means that the application plugins mainly have only one -context to manage for one client.</p> +<p>Application plugins generally handle a unique context for a unique client. As the application framework start +a dedicated instance of afb_daemon for each AGL application, if a given plugin is used within multiple application each of those +application get a new and private instance of this “shared” plugin.</p> -<a name="Service.plugins"></a> -<h4>Service plugins</h4> +<a name="Service-plugins"></a> +<h4>Service-plugins</h4> -<p>Service plugins are intended to be instanciated only one time -only and connected to many clients.</p> +<p>Service-plugins enable API activation within corresponding service security context and not within calling application context. +Service-plugins are intended to run as a unique instance that is shared in between multiple clients.</p> -<p>So either it does not manage context at all or otherwise, -if it manages context, it should be able to manage one context -per client.</p> +<p>Service-plugins can either be stateless or manage client context. When managing context each client get a private context.</p> -<p>In details, it may be useful to have service plugins at a user -level.</p> +<p>Sharing may either be global to the platform (ie: GPS service) or dedicated to a given user (ie: preference management)</p> -<a name="Live.cycle.of.a.plugin.within.afb-daemon"></a> -<h3>Live cycle of a plugin within afb-daemon</h3> +<a name="Live.cycle.of.plugins.within.afb-daemon"></a> +<h3>Live cycle of plugins within afb-daemon</h3> -<p>The plugins are loaded and activated when afb-daemon starts.</p> +<p>Application and service plugins are loaded and activated each time a new afb-daemon is started.</p> -<p>At start, the plugin initialise itself. -If it fails to initialise then afb-daemon stops.</p> +<p>At launch time, every loaded plugin initialise itself. +If a single plugin initialisation fail corresponding instance of afb-daemon self aborts.</p> -<p>Conversely, if it success to initialize, it must declare -a name, that must be unique, and a list of API’s verbs.</p> +<p>Conversely, when plugin initialisation succeeds, it should register +its unique name and the list of API verbs it exposes.</p> -<p>When initialized, the functions implementing the API’s verbs -of the plugin are activated on call.</p> +<p>When initialised, on request from clients plugin’s function corresponding to expose API verbs +are activated by the afb-daemon instance attached to the application or service.</p> -<p>At the end, nothing special is done by afb-daemon. -Consequently, developpers of plugins should use ‘atexit’ -or ‘on_exit’ during initialisation if they need to -perform specific actions when stopping.</p> +<p>At exit time, no special action is enforced by afb-daemon. When a specific actions is required at afb-daemon stop, +developers should use ‘atexit/on_exit’ during plugin initialisation sequence to register a custom exit function.</p> -<a name="Content.of.a.plugin"></a> -<h3>Content of a plugin</h3> +<a name="Plugin.Contend"></a> +<h3>Plugin Contend</h3> -<p>For afb-daemon, a plugin contains 2 different -things: names and functions.</p> +<p>Afb-daemon’s plugin register two classes of objects: names and functions.</p> -<p>There is two kind of names: - - the name of the plugin, - - the names of the verbs.</p> +<p>Plugins declare categories of names: + - A unique plugin name, + - Multiple API verb’s names.</p> -<p>There is two kind of functions: - - the initialisation function - - functions implementing verbs</p> +<p>Plugins declare two categories of functions: + - initialisation function + - API functions implementing verbs</p> -<p>Afb-daemon translates the name of the method that is -invoked to a pair of API and verb names. For example, -the method named <strong>foo/bar</strong> translated to the API -name <strong>foo</strong> and the verb name <strong>bar</strong>. -To serve it, afb-daemon search the plugin that record -the name <strong>foo</strong> and if it also recorded the verb <strong>bar</strong>, -it calls the implementation function declared for this verb.</p> +<p>Afb-daemon parses URI requests to extract plugin name and API verb. +As an example, URI <strong>foo/bar</strong> translates to API verb named <strong>bar</strong> within plugin named <strong>foo</strong>. +To serve such a request, afb-daemon looks for an active plugin named <strong>foo</strong> and then within this plugin for an API verb named <strong>bar</strong>. +When find afb-daemon calls corresponding function with attached parameter if any.</p> -<p>Afb-daemon make no distinction between lower case -and upper case when searching for a method. -Thus, The names <strong>TicTacToe/Board</strong> and <strong>tictactoe/borad</strong> -are equals.</p> +<p>Afb-daemon ignores letter case when parsing URI. Thus <strong>TicTacToe/Board</strong> and <strong>tictactoe/board</strong> are equivalent.</p> <a name="The.name.of.the.plugin"></a> <h4>The name of the plugin</h4> @@ -370,7 +359,7 @@ and upper case when searching for an API by its name.</p> <p>The names of the verbs are not checked.</p> <p>However, the validity rules for verb’s names are the -same as for API’s names except that the dot (.) character +same as for API names except that the dot (.) character is forbidden.</p> <p>Afb-daemon make no distinction between lower case diff --git a/doc/afb-plugin-writing.md b/doc/afb-plugin-writing.md index 3783abcf..54f153c5 100644 --- a/doc/afb-plugin-writing.md +++ b/doc/afb-plugin-writing.md @@ -1,7 +1,7 @@ HOWTO WRITE a PLUGIN for AFB-DAEMON =================================== version: 1 - Date: 27 mai 2016 + Date: 29 mai 2016 Author: José Bollo TABLE-OF-CONTENT-HERE @@ -86,7 +86,7 @@ As an example, URI **foo/bar** translates to plugin named **foo** and method nam To serve such a request, afb-daemon looks for an active plugin named **foo** and then within this plugin for a method named **bar**. When find afb-daemon calls corresponding method with attached parameter if any. -Afb-daemon ignores letter case when parsing URI. Thus **TicTacToe/Board** and **tictactoe/borad** are equivalent. +Afb-daemon ignores letter case when parsing URI. Thus **TicTacToe/Board** and **tictactoe/board** are equivalent. #### The name of the plugin diff --git a/doc/updt.sh b/doc/updt.sh index af64e31e..1c9d023e 100755 --- a/doc/updt.sh +++ b/doc/updt.sh @@ -29,7 +29,7 @@ updadate() { mkhtml() { local x=$1 local h=${x%%.md}.html - expand -i $x | sed 's: : :' > $h.pre + expand -i $x | sed 's:^ : :' > $h.pre markdown -f toc,autolink $h.pre > $h.toc.no markdown -Tf toc,autolink $h.pre > $h.toc.yes head --bytes=-$(stat -c %s $h.toc.no) $h.toc.yes > $h.toc diff --git a/include/afb/afb-event-sender-itf.h b/include/afb/afb-event-sender-itf.h deleted file mode 100644 index ad354319..00000000 --- a/include/afb/afb-event-sender-itf.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -struct json_object; - -struct afb_event_sender_itf { - void (*push)(void *event_sender, const char *name, struct json_object *object); -}; - -struct afb_event_sender { - const struct afb_event_sender_itf *itf; - void *closure; -}; - -static inline void afb_event_sender_push(struct afb_event_sender mgr, const char *name, struct json_object *object) -{ - return mgr.itf->push(mgr.closure, name, object); -} - diff --git a/include/afb/afb-plugin.h b/include/afb/afb-plugin.h index 2b065b08..1eb3475b 100644 --- a/include/afb/afb-plugin.h +++ b/include/afb/afb-plugin.h @@ -39,7 +39,6 @@ */ #include <afb/afb-req-itf.h> -#include <afb/afb-event-sender-itf.h> /* * Definition of the versions of the plugin. @@ -141,10 +140,10 @@ struct sd_bus; * Definition of the facilities provided by the daemon. */ struct afb_daemon_itf { - struct afb_event_sender (*get_event_sender)(void *closure); /* get the event manager */ - struct sd_event *(*get_event_loop)(void *closure); /* get the common systemd's event loop */ - struct sd_bus *(*get_user_bus)(void *closure); /* get the common systemd's user d-bus */ - struct sd_bus *(*get_system_bus)(void *closure); /* get the common systemd's system d-bus */ + void (*event_broadcast)(void *closure, const char *name, struct json_object *object); /* broadcasts evant 'name' with 'object' */ + struct sd_event *(*get_event_loop)(void *closure); /* gets the common systemd's event loop */ + struct sd_bus *(*get_user_bus)(void *closure); /* gets the common systemd's user d-bus */ + struct sd_bus *(*get_system_bus)(void *closure); /* gets the common systemd's system d-bus */ void (*vverbose)(void*closure, int level, const char *file, int line, const char *fmt, va_list args); }; @@ -173,15 +172,6 @@ struct AFB_interface extern const struct AFB_plugin *pluginAfbV1Register (const struct AFB_interface *interface); /* - * Retrieves the event sender of AFB - * 'daemon' MUST be the daemon given in interface when activating the plugin. - */ -static inline struct afb_event_sender afb_daemon_get_event_sender(struct afb_daemon daemon) -{ - return daemon.itf->get_event_sender(daemon.closure); -} - -/* * Retrieves the common systemd's event loop of AFB * 'daemon' MUST be the daemon given in interface when activating the plugin. */ @@ -219,7 +209,7 @@ static inline struct sd_bus *afb_daemon_get_system_bus(struct afb_daemon daemon) */ static inline void afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object) { - return afb_event_sender_push(afb_daemon_get_event_sender(daemon), name, object); + return daemon.itf->event_broadcast(daemon.closure, name, object); } /* @@ -237,6 +227,9 @@ static inline void afb_daemon_verbose(struct afb_daemon daemon, int level, const va_end(args); } +/* + * Macros for logging messages + */ #if !defined(NO_PLUGIN_VERBOSE_MACRO) # if !defined(NO_PLUGIN_FILE_LINE_INDICATION) # define ERROR(itf,...) do{if(itf->verbosity>=0)afb_daemon_verbose(itf->daemon,3,__FILE__,__LINE__,__VA_ARGS__);}while(0) diff --git a/afb-wsc.pc.in b/libafbwsc.pc.in index a8b29d71..a8b29d71 100644 --- a/afb-wsc.pc.in +++ b/libafbwsc.pc.in diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f41a3a88..ca20665b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,6 +73,9 @@ INSTALL(TARGETS afb-daemon # build and install libafbwsc ########################################### ADD_LIBRARY(afbwsc SHARED afb-ws.c afb-ws-client.c afb-wsj1.c websock.c afb-common.c) +SET_TARGET_PROPERTIES(afbwsc PROPERTIES + VERSION ${LIBAFBWSC_VERSION} + SOVERSION ${LIBAFBWSC_SOVERSION}) TARGET_LINK_LIBRARIES(afbwsc ${libsystemd_LIBRARIES} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export-afbwsc.map diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c index f4fd0eba..c0bc57a8 100644 --- a/src/afb-api-dbus.c +++ b/src/afb-api-dbus.c @@ -423,7 +423,7 @@ static void dbus_req_reply(struct dbus_req *dreq, uint8_t type, const char *firs static void dbus_req_success(struct dbus_req *dreq, struct json_object *obj, const char *info) { - dbus_req_reply(dreq, RETOK, json_object_to_json_string(obj), info); + dbus_req_reply(dreq, RETOK, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN), info); } static void dbus_req_fail(struct dbus_req *dreq, const char *status, const char *info) @@ -516,7 +516,7 @@ static void afb_api_dbus_server_send_event(struct api_dbus *api, const char *eve int rc; rc = sd_bus_emit_signal(api->sdbus, api->path, api->name, - "event", "ss", event, json_object_to_json_string(object)); + "event", "ss", event, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN)); if (rc < 0) ERROR("error while emiting event %s", event); json_object_put(object); diff --git a/src/afb-api-so.c b/src/afb-api-so.c index abe100b0..9756b0e0 100644 --- a/src/afb-api-so.c +++ b/src/afb-api-so.c @@ -30,7 +30,6 @@ #include <afb/afb-plugin.h> #include <afb/afb-req-itf.h> -#include <afb/afb-event-sender-itf.h> #include "session.h" #include "afb-common.h" @@ -54,7 +53,7 @@ static int api_timeout = 15; static const char plugin_register_function_v1[] = "pluginAfbV1Register"; -static void afb_api_so_event_sender_push(struct api_so_desc *desc, const char *name, struct json_object *object) +static int afb_api_so_event_broadcast(struct api_so_desc *desc, const char *name, struct json_object *object) { size_t length; char *event; @@ -65,16 +64,7 @@ static void afb_api_so_event_sender_push(struct api_so_desc *desc, const char *n memcpy(event, desc->plugin->v1.prefix, desc->apilength); event[desc->apilength] = '/'; memcpy(event + desc->apilength + 1, name, length + 1); - ctxClientEventSend(NULL, event, object); -} - -static const struct afb_event_sender_itf event_sender_itf = { - .push = (void*)afb_api_so_event_sender_push -}; - -static struct afb_event_sender afb_api_so_get_event_sender(struct api_so_desc *desc) -{ - return (struct afb_event_sender){ .itf = &event_sender_itf, .closure = desc }; + return ctxClientEventSend(NULL, event, object); } static void afb_api_so_vverbose(struct api_so_desc *desc, int level, const char *file, int line, const char *fmt, va_list args) @@ -90,7 +80,7 @@ static void afb_api_so_vverbose(struct api_so_desc *desc, int level, const char } static const struct afb_daemon_itf daemon_itf = { - .get_event_sender = (void*)afb_api_so_get_event_sender, + .event_broadcast = (void*)afb_api_so_event_broadcast, .get_event_loop = (void*)afb_common_get_event_loop, .get_user_bus = (void*)afb_common_get_user_bus, .get_system_bus = (void*)afb_common_get_system_bus, diff --git a/src/afb-context.c b/src/afb-context.c index 0492ecbf..ba093c37 100644 --- a/src/afb-context.c +++ b/src/afb-context.c @@ -58,7 +58,7 @@ int afb_context_connect(struct afb_context *context, const char *uuid, const cha init_context(context, session, token); if (created) { context->created = 1; - context->refreshing = 1; + /* context->refreshing = 1; */ } return 0; } diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 4239670d..ab174e2f 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -677,7 +677,7 @@ static void req_send(struct afb_hreq *hreq, const char *buffer, size_t size) static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t max) { - ssize_t len = stpncpy(buf, json_object_to_json_string(obj)+pos, max) - buf; + ssize_t len = stpncpy(buf, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN)+pos, max) - buf; return len ? : (ssize_t)MHD_CONTENT_READER_END_OF_STREAM; } @@ -698,7 +698,7 @@ static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *statu if (reqid != NULL && json_object_object_get_ex(reply, "request", &request)) json_object_object_add (request, short_key_for_reqid, json_object_new_string(reqid)); - response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string(reply)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put); + response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string_ext(reply, JSON_C_TO_STRING_PLAIN)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put); afb_hreq_reply(hreq, retcode, response, NULL); } diff --git a/src/afb-ws-client.h b/src/afb-ws-client.h index 125bd6f3..f2aee7d0 100644 --- a/src/afb-ws-client.h +++ b/src/afb-ws-client.h @@ -20,4 +20,10 @@ struct afb_wsj1; struct afb_wsj1_itf; +/* + * Makes the WebSocket handshake at the 'uri' and if successful + * instanciate a wsj1 websocket for this connection using 'itf' and 'closure'. + * (see afb_wsj1_create). + * Returns NULL in case of failure with errno set appriately. + */ extern struct afb_wsj1 *afb_ws_client_connect_wsj1(const char *uri, struct afb_wsj1_itf *itf, void *closure); diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index 9e20e7d9..88f9b358 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -416,7 +416,7 @@ static void aws_emit(struct afb_ws_json1 *aws, int code, const char *id, size_t json_object_array_add(msg, json_object_new_string(token)); /* emits the reply */ - txt = json_object_to_json_string(msg); + txt = json_object_to_json_string_ext(msg, JSON_C_TO_STRING_PLAIN); afb_ws_text(aws->ws, txt, strlen(txt)); json_object_put(msg); } diff --git a/src/afb-wsj1.c b/src/afb-wsj1.c index df4a2344..7f030a0c 100644 --- a/src/afb-wsj1.c +++ b/src/afb-wsj1.c @@ -427,18 +427,18 @@ struct afb_wsj1 *afb_wsj1_msg_wsj1(struct afb_wsj1_msg *msg) static int wsj1_send_isot(struct afb_wsj1 *wsj1, int i1, const char *s1, const char *o1, const char *t1) { char code[2] = { (char)('0' + i1), 0 }; - return afb_ws_texts(wsj1->ws, "[", code, ",\"", s1, "\",", o1, t1 != NULL ? ",\"" : "]", t1, "\"]", NULL); + return afb_ws_texts(wsj1->ws, "[", code, ",\"", s1, "\",", o1 == NULL ? "null" : o1, t1 != NULL ? ",\"" : "]", t1, "\"]", NULL); } static int wsj1_send_issot(struct afb_wsj1 *wsj1, int i1, const char *s1, const char *s2, const char *o1, const char *t1) { char code[2] = { (char)('0' + i1), 0 }; - return afb_ws_texts(wsj1->ws, "[", code, ",\"", s1, "\",\"", s2, "\",", o1, t1 != NULL ? ",\"" : "]", t1, "\"]", NULL); + return afb_ws_texts(wsj1->ws, "[", code, ",\"", s1, "\",\"", s2, "\",", o1 == NULL ? "null" : o1, t1 != NULL ? ",\"" : "]", t1, "\"]", NULL); } int afb_wsj1_send_event_j(struct afb_wsj1 *wsj1, const char *event, struct json_object *object) { - return afb_wsj1_send_event_s(wsj1, event, json_object_to_json_string(object)); + return afb_wsj1_send_event_s(wsj1, event, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN)); } int afb_wsj1_send_event_s(struct afb_wsj1 *wsj1, const char *event, const char *object) @@ -448,7 +448,7 @@ int afb_wsj1_send_event_s(struct afb_wsj1 *wsj1, const char *event, const char * int afb_wsj1_call_j(struct afb_wsj1 *wsj1, const char *api, const char *verb, struct json_object *object, void (*on_reply)(void *closure, struct afb_wsj1_msg *msg), void *closure) { - return afb_wsj1_call_s(wsj1, api, verb, json_object_to_json_string(object), on_reply, closure); + return afb_wsj1_call_s(wsj1, api, verb, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN), on_reply, closure); } int afb_wsj1_call_s(struct afb_wsj1 *wsj1, const char *api, const char *verb, const char *object, void (*on_reply)(void *closure, struct afb_wsj1_msg *msg), void *closure) @@ -480,7 +480,7 @@ int afb_wsj1_call_s(struct afb_wsj1 *wsj1, const char *api, const char *verb, co int afb_wsj1_reply_ok_j(struct afb_wsj1_msg *msg, struct json_object *object, const char *token) { - return afb_wsj1_reply_ok_s(msg, json_object_to_json_string(object), token); + return afb_wsj1_reply_ok_s(msg, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN), token); } int afb_wsj1_reply_ok_s(struct afb_wsj1_msg *msg, const char *object, const char *token) @@ -490,7 +490,7 @@ int afb_wsj1_reply_ok_s(struct afb_wsj1_msg *msg, const char *object, const char int afb_wsj1_reply_error_j(struct afb_wsj1_msg *msg, struct json_object *object, const char *token) { - return afb_wsj1_reply_error_s(msg, json_object_to_json_string(object), token); + return afb_wsj1_reply_error_s(msg, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN), token); } int afb_wsj1_reply_error_s(struct afb_wsj1_msg *msg, const char *object, const char *token) diff --git a/src/afb-wsj1.h b/src/afb-wsj1.h index 08bf67f7..44aa5656 100644 --- a/src/afb-wsj1.h +++ b/src/afb-wsj1.h @@ -22,44 +22,189 @@ struct afb_wsj1_msg; struct json_object; +/* + * Interface for callback functions. + * The received closure is the closure passed when creating the afb_wsj1 + * socket using afb_wsj1_create. + */ struct afb_wsj1_itf { + /* + * This function is called on hangup. + * Receives the 'closure' and the handle 'wsj1' + */ void (*on_hangup)(void *closure, struct afb_wsj1 *wsj1); + + /* + * This function is called on incoming call. + * Receives the 'closure' + */ void (*on_call)(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg); + + /* + * This function is called on incoming event + */ void (*on_event)(void *closure, const char *event, struct afb_wsj1_msg *msg); }; +/* + * Creates the afb_wsj1 socket connected to the file descriptor 'fd' + * and having the callback interface defined by 'itf' for the 'closure'. + * Returns the created wsj1 websocket or NULL in case of error. + */ extern struct afb_wsj1 *afb_wsj1_create(int fd, struct afb_wsj1_itf *itf, void *closure); +/* + * Increases by one the count of reference to 'wsj1' + */ extern void afb_wsj1_addref(struct afb_wsj1 *wsj1); + +/* + * Decreases by one the count of reference to 'wsj1' + * and if it falls to zero releases the used resources + * and free the memory + */ extern void afb_wsj1_unref(struct afb_wsj1 *wsj1); +/* + * Sends on 'wsj1' the event of name 'event' with the + * data 'object'. If not NULL, 'object' should be a valid + * JSON string. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_send_event_s(struct afb_wsj1 *wsj1, const char *event, const char *object); + +/* + * Sends on 'wsj1' the event of name 'event' with the + * data 'object'. 'object' can be NULL. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_send_event_j(struct afb_wsj1 *wsj1, const char *event, struct json_object *object); +/* + * Sends on 'wsj1' a call to the method of 'api'/'verb' with arguments + * given by 'object'. If not NULL, 'object' should be a valid JSON string. + * On receiving the reply, the function 'on_reply' is called with 'closure' + * as its first argument and the message of the reply. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_call_s(struct afb_wsj1 *wsj1, const char *api, const char *verb, const char *object, void (*on_reply)(void *closure, struct afb_wsj1_msg *msg), void *closure); + +/* + * Sends on 'wsj1' a call to the method of 'api'/'verb' with arguments + * given by 'object'. 'object' can be NULL. + * On receiving the reply, the function 'on_reply' is called with 'closure' + * as its first argument and the message of the reply. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_call_j(struct afb_wsj1 *wsj1, const char *api, const char *verb, struct json_object *object, void (*on_reply)(void *closure, struct afb_wsj1_msg *msg), void *closure); +/* + * Sends for message 'msg' the OK reply with the 'object' and, if not NULL, the token. + * If not NULL, 'object' should be a valid JSON string. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_reply_ok_s(struct afb_wsj1_msg *msg, const char *object, const char *token); + +/* + * Sends for message 'msg' the OK reply with the 'object' and, if not NULL, the token. + * 'object' can be NULL. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_reply_ok_j(struct afb_wsj1_msg *msg, struct json_object *object, const char *token); +/* + * Sends for message 'msg' the ERROR reply with the 'object' and, if not NULL, the token. + * If not NULL, 'object' should be a valid JSON string. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_reply_error_s(struct afb_wsj1_msg *msg, const char *object, const char *token); + +/* + * Sends for message 'msg' the ERROR reply with the 'object' and, if not NULL, the token. + * 'object' can be NULL. + * Return 0 in case of success. Otherwise, returns -1 and set errno. + */ extern int afb_wsj1_reply_error_j(struct afb_wsj1_msg *msg, struct json_object *object, const char *token); +/* + * Increases by one the count of reference to 'msg'. + * Should be called if callbacks stores the message. + */ extern void afb_wsj1_msg_addref(struct afb_wsj1_msg *msg); + +/* + * Decreases by one the count of reference to 'msg'. + * and if it falls to zero releases the used resources + * and free the memory. + * Should be called if 'afb_wsj1_msg_addref' was called. + */ extern void afb_wsj1_msg_unref(struct afb_wsj1_msg *msg); +/* + * Returns 1 if 'msg' is for a CALL + * Otherwise returns 0. + */ extern int afb_wsj1_msg_is_call(struct afb_wsj1_msg *msg); + +/* + * Returns 1 if 'msg' is for a REPLY of any kind + * Otherwise returns 0. + */ extern int afb_wsj1_msg_is_reply(struct afb_wsj1_msg *msg); + +/* + * Returns 1 if 'msg' is for a REPLY OK + * Otherwise returns 0. + */ extern int afb_wsj1_msg_is_reply_ok(struct afb_wsj1_msg *msg); + +/* + * Returns 1 if 'msg' is for a REPLY ERROR + * Otherwise returns 0. + */ extern int afb_wsj1_msg_is_reply_error(struct afb_wsj1_msg *msg); + +/* + * Returns 1 if 'msg' is for an EVENT + * Otherwise returns 0. + */ extern int afb_wsj1_msg_is_event(struct afb_wsj1_msg *msg); +/* + * Returns the api of the call for 'msg' + * Returns NULL if 'msg' is not for a CALL + */ extern const char *afb_wsj1_msg_api(struct afb_wsj1_msg *msg); + +/* + * Returns the verb call for 'msg' + * Returns NULL if 'msg' is not for a CALL + */ extern const char *afb_wsj1_msg_verb(struct afb_wsj1_msg *msg); + +/* + * Returns the event name for 'msg' + * Returns NULL if 'msg' is not for an EVENT + */ extern const char *afb_wsj1_msg_event(struct afb_wsj1_msg *msg); + +/* + * Returns the token sent with 'msg' or NULL when no token was sent. + */ extern const char *afb_wsj1_msg_token(struct afb_wsj1_msg *msg); + +/* + * Returns the wsj1 of 'msg' + */ extern struct afb_wsj1 *afb_wsj1_msg_wsj1(struct afb_wsj1_msg *msg); +/* + * Returns the string representation of the object received with 'msg' + */ extern const char *afb_wsj1_msg_object_s(struct afb_wsj1_msg *msg); + +/* + * Returns the object received with 'msg' + */ extern struct json_object *afb_wsj1_msg_object_j(struct afb_wsj1_msg *msg); diff --git a/test/AFB.html b/test/AFB.html index a1a4bf59..b0832d9a 100644 --- a/test/AFB.html +++ b/test/AFB.html @@ -3,7 +3,7 @@ <title>Test of AFB Echo</title> <script type="text/javascript" src="AFB.js"></script> <script type="text/javascript"> - var afb = new AFB("api", "hello-token"); + var afb = new AFB("api", "hello"); var ws; function onopen() { diff --git a/test/AFB.js b/test/AFB.js index ae2fd8b8..c77e5e60 100644 --- a/test/AFB.js +++ b/test/AFB.js @@ -42,7 +42,13 @@ var AFB_websocket; var PROTO1 = "x-afb-ws-json1"; AFB_websocket = function(onopen, onabort) { - this.ws = new WebSocket(urlws, [ PROTO1 ]); + var u = urlws; + if (AFB_context.token) { + u = u + '?x-afb-token=' + AFB_context.token; + if (AFB_context.uuid) + u = u + '&x-afb-uuid=' + AFB_context.uuid; + } + this.ws = new WebSocket(u, [ PROTO1 ]); this.pendings = {}; this.awaitens = {}; this.counter = 0; diff --git a/test/websock.js b/test/websock.js index 84465588..c4295536 100644 --- a/test/websock.js +++ b/test/websock.js @@ -27,12 +27,18 @@ AfbWsItf = (function(){ var RETERR = 4; function AfbWsItf(base, onopen, onabort, ctx) { + ctx = ctx || new AfbCtxItf(); var wl = window.location; var u = "ws://"+wl.host+"/"+base; + if (ctx.token) { + u = u + '?x-afb-token=' + ctx.token; + if (ctx.uuid) + u = u + '&x-afb-uuid=' + ctx.uuid; + } this.ws = new (WebSocket || MozWebSocket)(u, [ "x-afb-ws-json1" ]); this.pendings = {}; this.counter = 0; - this.ctx = ctx || new AfbCtxItf(); + this.ctx = ctx; this.ws.onopen = onopen.bind(this); this.ws.onerror = onerror.bind(this); this.ws.onclose = onclose.bind(this); |