From f6bc48698587758fb764bae66302002fe148e978 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Wed, 7 Jun 2017 18:40:00 +0200 Subject: [PATCH] Refactor of the documentation --- bindings/CMakeLists.txt | 3 +- bindings/tutorial/CMakeLists.txt | 32 ++ bindings/tutorial/export.map | 1 + bindings/tutorial/tuto-1.c | 19 + bindings/tutorial/tuto-2.c | 100 ++++ {doc => docs}/FAQ.md | 0 {doc => docs}/afb-application-writing.md | 0 docs/afb-binding-references.md | 672 ++++++++++++++++++++++ docs/afb-binding-writing.md | 465 +++++++++++++++ docs/afb-daemon-options.md | 200 +++++++ {doc => docs}/afb-daemon-vocabulary.md | 0 docs/afb-desktop-package.md | 40 ++ docs/afb-events-guide.md | 371 ++++++++++++ docs/afb-migration-v1-to-v2.md | 611 ++++++++++++++++++++ docs/afb-overview.md | 98 ++++ {doc => docs}/index.md | 0 {doc => docs}/pictures/AFB_for_services.svg | 0 docs/pictures/basis.odg | Bin 0 -> 15170 bytes docs/pictures/basis.svg | 356 ++++++++++++ docs/pictures/interconnection.odg | Bin 0 -> 20244 bytes docs/pictures/interconnection.svg | 854 ++++++++++++++++++++++++++++ {doc => docs}/pictures/signaling-basis.svg | 0 {doc => docs}/pictures/tic-tac-toe.svg | 0 {doc => docs}/pictures/triskel_iot_bzh.svg | 0 mkdocs.yml | 14 +- old-docs/FAQ.md | 5 + old-docs/afb-application-writing.md | 301 ++++++++++ {doc => old-docs}/afb-bindings-overview.md | 0 {doc => old-docs}/afb-bindings-writing.md | 0 old-docs/afb-daemon-vocabulary.md | 98 ++++ {doc => old-docs}/afb-events-guide.md | 0 {doc => old-docs}/afb-overview.md | 0 {doc => old-docs}/afb-tests-overview.md | 0 old-docs/index.md | 1 + old-docs/pictures/AFB_for_services.svg | 238 ++++++++ {doc => old-docs}/pictures/AFB_overview.svg | 0 old-docs/pictures/signaling-basis.svg | 145 +++++ old-docs/pictures/tic-tac-toe.svg | 289 ++++++++++ old-docs/pictures/triskel_iot_bzh.svg | 110 ++++ 39 files changed, 5017 insertions(+), 6 deletions(-) create mode 100644 bindings/tutorial/CMakeLists.txt create mode 100644 bindings/tutorial/export.map create mode 100644 bindings/tutorial/tuto-1.c create mode 100644 bindings/tutorial/tuto-2.c rename {doc => docs}/FAQ.md (100%) rename {doc => docs}/afb-application-writing.md (100%) create mode 100644 docs/afb-binding-references.md create mode 100644 docs/afb-binding-writing.md create mode 100644 docs/afb-daemon-options.md rename {doc => docs}/afb-daemon-vocabulary.md (100%) create mode 100644 docs/afb-desktop-package.md create mode 100644 docs/afb-events-guide.md create mode 100644 docs/afb-migration-v1-to-v2.md create mode 100644 docs/afb-overview.md rename {doc => docs}/index.md (100%) rename {doc => docs}/pictures/AFB_for_services.svg (100%) create mode 100644 docs/pictures/basis.odg create mode 100644 docs/pictures/basis.svg create mode 100644 docs/pictures/interconnection.odg create mode 100644 docs/pictures/interconnection.svg rename {doc => docs}/pictures/signaling-basis.svg (100%) rename {doc => docs}/pictures/tic-tac-toe.svg (100%) rename {doc => docs}/pictures/triskel_iot_bzh.svg (100%) create mode 100644 old-docs/FAQ.md create mode 100644 old-docs/afb-application-writing.md rename {doc => old-docs}/afb-bindings-overview.md (100%) rename {doc => old-docs}/afb-bindings-writing.md (100%) create mode 100644 old-docs/afb-daemon-vocabulary.md rename {doc => old-docs}/afb-events-guide.md (100%) rename {doc => old-docs}/afb-overview.md (100%) rename {doc => old-docs}/afb-tests-overview.md (100%) create mode 120000 old-docs/index.md create mode 100644 old-docs/pictures/AFB_for_services.svg rename {doc => old-docs}/pictures/AFB_overview.svg (100%) create mode 100644 old-docs/pictures/signaling-basis.svg create mode 100644 old-docs/pictures/tic-tac-toe.svg create mode 100644 old-docs/pictures/triskel_iot_bzh.svg diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 490e29aa..1a1e9016 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -16,5 +16,6 @@ # limitations under the License. ########################################################################### -ADD_SUBDIRECTORY(samples) ADD_SUBDIRECTORY(intrinsics) +ADD_SUBDIRECTORY(samples) +ADD_SUBDIRECTORY(tutorial) diff --git a/bindings/tutorial/CMakeLists.txt b/bindings/tutorial/CMakeLists.txt new file mode 100644 index 00000000..844e2dfb --- /dev/null +++ b/bindings/tutorial/CMakeLists.txt @@ -0,0 +1,32 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: José Bollo +# +# 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. +########################################################################### + + +#INCLUDE_DIRECTORIES(${include_dirs}) + +MACRO(tuto num) + ADD_LIBRARY(tuto-${num} MODULE tuto-${num}.c) + SET_TARGET_PROPERTIES(tuto-${num} PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" + ) + TARGET_LINK_LIBRARIES(tuto-${num} ${link_libraries}) +ENDMACRO(tuto) + +tuto(1) +tuto(2) diff --git a/bindings/tutorial/export.map b/bindings/tutorial/export.map new file mode 100644 index 00000000..ee2f4133 --- /dev/null +++ b/bindings/tutorial/export.map @@ -0,0 +1 @@ +{ global: afbBindingV*; local: *; }; diff --git a/bindings/tutorial/tuto-1.c b/bindings/tutorial/tuto-1.c new file mode 100644 index 00000000..433a4ebb --- /dev/null +++ b/bindings/tutorial/tuto-1.c @@ -0,0 +1,19 @@ +#define AFB_BINDING_VERSION 2 +#include + +void hello(afb_req req) +{ + AFB_REQ_DEBUG(req, "hello world"); + afb_req_success(req, NULL, "hello world"); +} + +const afb_verb_v2 verbs[] = { + { .verb="hello", .callback=hello }, + { .verb=NULL } +}; + +const afb_binding_v2 afbBindingV2 = { + .api = "tuto-1", + .verbs = verbs +}; + diff --git a/bindings/tutorial/tuto-2.c b/bindings/tutorial/tuto-2.c new file mode 100644 index 00000000..dc2d55ab --- /dev/null +++ b/bindings/tutorial/tuto-2.c @@ -0,0 +1,100 @@ +#include +#include + +#define AFB_BINDING_VERSION 2 +#include + +afb_event event_login, event_logout; + +void login(afb_req req) +{ + json_object *args, *user, *passwd; + char *usr; + + args = afb_req_json(req); + if (!json_object_object_get_ex(args, "user", &user) + || !json_object_object_get_ex(args, "password", &passwd)) { + AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args)); + afb_req_fail(req, "bad-request", NULL); + } else if (afb_req_context_get(req)) { + AFB_REQ_ERROR(req, "login, bad state, logout first"); + afb_req_fail(req, "bad-state", NULL); + } else if (strcmp(json_object_get_string(passwd), "please")) { + AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args)); + afb_req_fail(req, "unauthorized", NULL); + } else { + usr = strdup(json_object_get_string(user)); + AFB_REQ_NOTICE(req, "login user: %s", usr); + afb_req_session_set_LOA(req, 1); + afb_req_context_set(req, usr, free); + afb_req_success(req, NULL, NULL); + afb_event_push(event_login, json_object_new_string(usr)); + } +} + +void action(afb_req req) +{ + json_object *args, *val; + char *usr; + + args = afb_req_json(req); + usr = afb_req_context_get(req); + AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args)); + if (json_object_object_get_ex(args, "subscribe", &val)) { + if (json_object_get_boolean(val)) { + AFB_REQ_NOTICE(req, "user %s subscribes to events", usr); + afb_req_subscribe(req, event_login); + afb_req_subscribe(req, event_logout); + } else { + AFB_REQ_NOTICE(req, "user %s unsubscribes to events", usr); + afb_req_unsubscribe(req, event_login); + afb_req_unsubscribe(req, event_logout); + } + } + afb_req_success(req, json_object_get(args), NULL); +} + +void logout(afb_req req) +{ + char *usr; + + usr = afb_req_context_get(req); + AFB_REQ_NOTICE(req, "login user %s out", usr); + afb_event_push(event_logout, json_object_new_string(usr)); + afb_req_session_set_LOA(req, 0); + afb_req_context_clear(req); + afb_req_success(req, NULL, NULL); +} + +int preinit() +{ + AFB_NOTICE("preinit"); + return 0; +} + +int init() +{ + AFB_NOTICE("init"); + event_login = afb_daemon_make_event("login"); + event_logout = afb_daemon_make_event("logout"); + if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout)) + return 0; + AFB_ERROR("Can't create events"); + return -1; +} + +const afb_verb_v2 verbs[] = { + { .verb="login", .callback=login }, + { .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 }, + { .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 }, + { .verb=NULL } +}; + +const afb_binding_v2 afbBindingV2 = { + .api = "tuto-2", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .noconcurrency = 0 +}; \ No newline at end of file diff --git a/doc/FAQ.md b/docs/FAQ.md similarity index 100% rename from doc/FAQ.md rename to docs/FAQ.md diff --git a/doc/afb-application-writing.md b/docs/afb-application-writing.md similarity index 100% rename from doc/afb-application-writing.md rename to docs/afb-application-writing.md diff --git a/docs/afb-binding-references.md b/docs/afb-binding-references.md new file mode 100644 index 00000000..7d6cdd1d --- /dev/null +++ b/docs/afb-binding-references.md @@ -0,0 +1,672 @@ +Binding Reference +================= + +Structure for declaring binding +------------------------------- + +### struct afb_binding_v2 + +The main structure, of type **afb_binding_v2**, for describing the binding +must be exported under the name **afbBindingV2**. + +This structure is defined as below. + +```C +/* + * Description of the bindings of type version 2 + */ +struct afb_binding_v2 +{ + const char *api; /* api name for the binding */ + const char *specification; /* textual openAPIv3 specification of the binding */ + const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */ + int (*preinit)(); /* callback at load of the binding */ + int (*init)(); /* callback for starting the service */ + void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */ + unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */ +}; +``` + +### struct afb_verb_v2 + +Each verb is described with a structure of type **afb_verb_v2** +defined below: + +```C +/* + * Description of one verb of the API provided by the binding + * This enumeration is valid for bindings of type version 2 + */ +struct afb_verb_v2 +{ + const char *verb; /* name of the verb */ + void (*callback)(struct afb_req req); /* callback function implementing the verb */ + const struct afb_auth *auth; /* required authorisation */ + uint32_t session; /* authorisation and session requirements of the verb */ +}; +``` + +The session flags is an or of the constant defined below: + + - AFB_SESSION_NONE : no flag, synonym to 0 + - AFB_SESSION_LOA_0 : Requires the LOA to be 0 or more, synonym to 0 or AFB_SESSION_NONE + - AFB_SESSION_LOA_1 : Requires the LOA to be 1 or more + - AFB_SESSION_LOA_2 : Requires the LOA to be 2 or more + - AFB_SESSION_LOA_3 : Requires the LOA to be 3 or more + - AFB_SESSION_CHECK : Requires the token to be set and valid + - AFB_SESSION_REFRESH : Implies a token refresh + - AFB_SESSION_CLOSE : Implies cloing the session + +The LOA is set binding by binding using the function **afb_req_session_set_LOA**. + +### struct afb_auth and enum afb_auth_type + +The structure **afb_auth** is used within verb description to +set security requirements. The interpretation of the structure +depends on the value of the field **type**. + +```C +struct afb_auth +{ + const enum afb_auth_type type; + union { + const char *text; + const unsigned loa; + const struct afb_auth *first; + }; + const struct afb_auth *next; +}; +``` +The possible values for **type** is defined here: + +```C +/* + * Enum for Session/Token/Assurance middleware. + */ +enum afb_auth_type +{ + afb_auth_No = 0, /** never authorized, no data */ + afb_auth_Token, /** authorized if token valid, no data */ + afb_auth_LOA, /** authorized if LOA greater than data 'loa' */ + afb_auth_Permission, /** authorized if permission 'text' is granted */ + afb_auth_Or, /** authorized if 'first' or 'next' is authorized */ + afb_auth_And, /** authorized if 'first' and 'next' are authorized */ + afb_auth_Not, /** authorized if 'first' is not authorized */ + afb_auth_Yes /** always authorized, no data */ +}; +``` + +Example: + +```C +static const struct afb_auth _afb_auths_v2_monitor[] = { + { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:set" }, + { .type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:get" }, + { .type = afb_auth_Or, .first = &_afb_auths_v2_monitor[1], .next = &_afb_auths_v2_monitor[0] } +}; +``` + +Functions of class afb_daemon... +------------------------- + +The 3 following functions are linked to libsystemd. +They allow use of **sd_event** features and access +to **sd_bus** features. + +```C +/* + * Retrieves the common systemd's event loop of AFB + */ +struct sd_event *afb_daemon_get_event_loop(); + +/* + * Retrieves the common systemd's user/session d-bus of AFB + */ +struct sd_bus *afb_daemon_get_user_bus(); + +/* + * Retrieves the common systemd's system d-bus of AFB + */ +struct sd_bus *afb_daemon_get_system_bus(); +``` + +The 2 following functions are linked to event management. +Broadcasting an event send it to any possible listener. + +```C +/* + * Broadcasts widely the event of 'name' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_daemon_broadcast_event(const char *name, struct json_object *object); + +/* + * Creates an event of 'name' and returns it. + * + * See afb_event_is_valid to check if there is an error. + */ +struct afb_event afb_daemon_make_event(const char *name); +``` + +The following function is used by logging macros and should normally +not be used. Instead, you should use the macros +**AFB\_ERROR**, **AFB\_WARNING**, **AFB\_NOTICE**, +**AFB\_INFO**, **AFB\_DEBUG** + +```C +/* + * Send a message described by 'fmt' and following parameters + * to the journal for the verbosity 'level'. + * + * 'file', 'line' and 'func' are indicators of position of the code in source files + * (see macros __FILE__, __LINE__ and __func__). + * + * 'level' is defined by syslog standard: + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + */ +void afb_daemon_verbose(int level, const char *file, int line, const char * func, const char *fmt, ...); +``` + +The 2 following functions MUST be used to access data of the bindings. + +```C +/* + * Get the root directory file descriptor. This file descriptor can + * be used with functions 'openat', 'fstatat', ... + */ +int afb_daemon_rootdir_get_fd(); + +/* + * Opens 'filename' within the root directory with 'flags' (see function openat) + * using the 'locale' definition (example: "jp,en-US") that can be NULL. + * Returns the file descriptor or -1 in case of error. + */ +int afb_daemon_rootdir_open_locale(const char *filename, int flags, const char *locale); +``` + +The following function is used to queue jobs. + +```C +/* + * Queue the job defined by 'callback' and 'argument' for being executed asynchronously + * in this thread (later) or in an other thread. + * If 'group' is not NUL, the jobs queued with a same value (as the pointer value 'group') + * are executed in sequence in the order of there submission. + * If 'timeout' is not 0, it represent the maximum execution time for the job in seconds. + * At first, the job is called with 0 as signum and the given argument. + * The job is executed with the monitoring of its time and some signals like SIGSEGV and + * SIGFPE. When a such signal is catched, the job is terminated and reexecuted but with + * signum being the signal number (SIGALRM when timeout expired). + * + * Returns 0 in case of success or -1 in case of error. + */ +int afb_daemon_queue_job(void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +``` + +The following function must be used when a binding depends on other +bindings at its initialisation. + +```C +/* + * Tells that it requires the API of "name" to exist + * and if 'initialized' is not null to be initialized. + * Returns 0 in case of success or -1 in case of error. + */ +int afb_daemon_require_api(const char *name, int initialized) +``` + +Functions of class afb_service... +------------------------- + +The following functions allow services to call verbs of other +bindings for themselves. + +```C +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * The result of the call is delivered to the 'callback' function with the 'callback_closure'. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * The 'callback' receives 3 arguments: + * 1. 'closure' the user defined closure pointer 'callback_closure', + * 2. 'iserror' a boolean status being true (not null) when an error occured, + * 2. 'result' the resulting data as a JSON object. + * + * @param api The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param callback The to call on completion + * @param callback_closure The closure to pass to the callback + * + * @see also 'afb_req_subcall' + */ +void afb_service_call( + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*closure, int iserror, struct json_object *result), + void *callback_closure); + +/** + * Calls the 'verb' of the 'api' with the arguments 'args' and 'verb' in the name of the binding. + * 'result' will receive the response. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * @param api The api name of the method to call + * @param verb The verb name of the method to call + * @param args The arguments to pass to the method + * @param result Where to store the result - should call json_object_put on it - + * + * @returns 1 in case of success or 0 in case of error. + * + * @see also 'afb_req_subcall' + */ +int afb_service_call_sync( + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); +``` + +Functions of class afb_event... +------------------------- + +This function checks whether the event is valid. It must be used +when creating events. + +```C +/* + * Checks wether the 'event' is valid or not. + * + * Returns 0 if not valid or 1 if valid. + */ +int afb_event_is_valid(struct afb_event event); +``` + +The two following functions are used to broadcast or push +event with its data. + +```C +/* + * Broadcasts widely the 'event' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_event_broadcast(struct afb_event event, struct json_object *object); + +/* + * Pushes the 'event' with the data 'object' to its observers. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_event_push(struct afb_event event, struct json_object *object); +``` + +The following function destiys the event. + +```C +/* + * Drops the data associated to the 'event' + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_drop(struct afb_event event); +``` + +This function allows to retrieve the exact name of the event. + +```C +/* + * Gets the name associated to the 'event'. + */ +const char *afb_event_name(struct afb_event event); +``` + +Functions of class afb_req... +------------------------- + +This function checks the validity of the **req**. + +```C +/* + * Checks wether the request 'req' is valid or not. + * + * Returns 0 if not valid or 1 if valid. + */ +int afb_req_is_valid(struct afb_req req); +``` + +The following functions retrieves parameters of the request. + +```C +/* + * Gets from the request 'req' the argument of 'name'. + * Returns a PLAIN structure of type 'struct afb_arg'. + * When the argument of 'name' is not found, all fields of result are set to NULL. + * When the argument of 'name' is found, the fields are filled, + * in particular, the field 'result.name' is set to 'name'. + * + * There is a special name value: the empty string. + * The argument of name "" is defined only if the request was made using + * an HTTP POST of Content-Type "application/json". In that case, the + * argument of name "" receives the value of the body of the HTTP request. + */ +struct afb_arg afb_req_get(struct afb_req req, const char *name); + +/* + * Gets from the request 'req' the string value of the argument of 'name'. + * Returns NULL if when there is no argument of 'name'. + * Returns the value of the argument of 'name' otherwise. + * + * Shortcut for: afb_req_get(req, name).value + */ +const char *afb_req_value(struct afb_req req, const char *name); + +/* + * Gets from the request 'req' the path for file attached to the argument of 'name'. + * Returns NULL if when there is no argument of 'name' or when there is no file. + * Returns the path of the argument of 'name' otherwise. + * + * Shortcut for: afb_req_get(req, name).path + */ +const char *afb_req_path(struct afb_req req, const char *name); + +/* + * Gets from the request 'req' the json object hashing the arguments. + * The returned object must not be released using 'json_object_put'. + */ +struct json_object *afb_req_json(struct afb_req req); +``` + +The following functions emit the reply to the request. + +```C +/* + * Sends a reply of kind success to the request 'req'. + * The status of the reply is automatically set to "success". + * Its send the object 'obj' (can be NULL) with an + * informationnal comment 'info (can also be NULL). + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_success(struct afb_req req, struct json_object *obj, const char *info); + +/* + * Same as 'afb_req_success' but the 'info' is a formatting + * string followed by arguments. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...); + +/* + * Same as 'afb_req_success_f' but the arguments to the format 'info' + * are given as a variable argument list instance. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_success_v(struct afb_req req, struct json_object *obj, const char *info, va_list args); + +/* + * Sends a reply of kind failure to the request 'req'. + * The status of the reply is set to 'status' and an + * informationnal comment 'info' (can also be NULL) can be added. + * + * Note that calling afb_req_fail("success", info) is equivalent + * to call afb_req_success(NULL, info). Thus even if possible it + * is strongly recommanded to NEVER use "success" for status. + */ +void afb_req_fail(struct afb_req req, const char *status, const char *info); + +/* + * Same as 'afb_req_fail' but the 'info' is a formatting + * string followed by arguments. + */ +void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...); + +/* + * Same as 'afb_req_fail_f' but the arguments to the format 'info' + * are given as a variable argument list instance. + */ +void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args); +``` + +The following functions handle the session data. + +```C +/* + * Gets the pointer stored by the binding for the session of 'req'. + * When the binding has not yet recorded a pointer, NULL is returned. + */ +void *afb_req_context_get(struct afb_req req); + +/* + * Stores for the binding the pointer 'context' to the session of 'req'. + * The function 'free_context' will be called when the session is closed + * or if binding stores an other pointer. + */ +void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*)); + +/* + * Gets the pointer stored by the binding for the session of 'req'. + * If the stored pointer is NULL, indicating that no pointer was + * already stored, afb_req_context creates a new context by calling + * the function 'create_context' and stores it with the freeing function + * 'free_context'. + */ +void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*)); + +/* + * Frees the pointer stored by the binding for the session of 'req' + * and sets it to NULL. + * + * Shortcut for: afb_req_context_set(req, NULL, NULL) + */ +void afb_req_context_clear(struct afb_req req); + +/* + * Closes the session associated with 'req' + * and delete all associated contexts. + */ +void afb_req_session_close(struct afb_req req); + +/* + * Sets the level of assurance of the session of 'req' + * to 'level'. The effect of this function is subject of + * security policies. + * Returns 1 on success or 0 if failed. + */ +int afb_req_session_set_LOA(struct afb_req req, unsigned level); +``` + + +The 4 following functions must be used for asynchronous handling requests. + +```C +/* + * Adds one to the count of references of 'req'. + * This function MUST be called by asynchronous implementations + * of verbs if no reply was sent before returning. + */ +void afb_req_addref(struct afb_req req); + +/* + * Substracts one to the count of references of 'req'. + * This function MUST be called by asynchronous implementations + * of verbs after sending the asynchronous reply. + */ +void afb_req_unref(struct afb_req req); + +/* + * Stores 'req' on heap for asynchrnous use. + * Returns a handler to the stored 'req' or NULL on memory depletion. + * The count of reference to 'req' is incremented on success + * (see afb_req_addref). + */ +struct afb_stored_req *afb_req_store(struct afb_req req); + +/* + * Retrieves the afb_req stored at 'sreq'. + * Returns the stored request. + * The count of reference is UNCHANGED, thus, the + * function 'afb_req_unref' should be called on the result + * after that the asynchronous reply if sent. + */ +struct afb_req afb_req_unstore(struct afb_stored_req *sreq); +``` + +The two following functions are used to associate client with events +(subscription). + +```C +/* + * Establishes for the client link identified by 'req' a subscription + * to the 'event'. + * Returns 0 in case of successful subscription or -1 in case of error. + */ +int afb_req_subscribe(struct afb_req req, struct afb_event event); + +/* + * Revokes the subscription established to the 'event' for the client + * link identified by 'req'. + * Returns 0 in case of successful subscription or -1 in case of error. + */ +int afb_req_unsubscribe(struct afb_req req, struct afb_event event); +``` + +The following functions must be used to make request in the name of the +client (with its permissions). + +```C +/* + * Makes a call to the method of name 'api' / 'verb' with the object 'args'. + * This call is made in the context of the request 'req'. + * On completion, the function 'callback' is invoked with the + * 'closure' given at call and two other parameters: 'iserror' and 'result'. + * 'iserror' is a boolean that indicates if the reply is an error reply. + * 'result' is the json object of the reply, you must not call json_object_put + * on the result. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_subcall( + struct afb_req req, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void *closure, int iserror, struct json_object *result), + void *closure); + +/* + * Makes a call to the method of name 'api' / 'verb' with the object 'args'. + * This call is made in the context of the request 'req'. + * This call is synchronous, it waits untill completion of the request. + * It returns 0 on an error answer and returns 1 when no error was detected. + * The object pointed by 'result' is filled and must be released by the caller + * after its use by calling 'json_object_put'. + * + * For convenience, the function calls 'json_object_put' for 'args'. + * Thus, in the case where 'args' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +int afb_req_subcall_sync( + struct afb_req req, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); +``` + +The following function is used by logging macros and should normally +not be used. Instead, you should use the macros +**AFB_REQ_ERROR**, **AFB_REQ_WARNING**, **AFB_REQ_NOTICE**, +**AFB_REQ_INFO**, **AFB_REQ_DEBUG** + +```C +/* + * Send associated to 'req' a message described by 'fmt' and following parameters + * to the journal for the verbosity 'level'. + * + * 'file', 'line' and 'func' are indicators of position of the code in source files + * (see macros __FILE__, __LINE__ and __func__). + * + * 'level' is defined by syslog standard: + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + */ +void afb_req_verbose(struct afb_req req, int level, const char *file, int line, const char * func, const char *fmt, ...); +``` + +Logging macros +-------------- + +The following macros must be used for logging: + +```C +AFB_ERROR(fmt,...) +AFB_WARNING(fmt,...) +AFB_NOTICE(fmt,...) +AFB_INFO(fmt,...) +AFB_DEBUG(fmt,...) +``` + +The following macros can be used for logging in the context +of a request **req** of type **afb_req**: + +```C +AFB_REQ_ERROR(req,fmt,...) +AFB_REQ_WARNING(req,fmt,...) +AFB_REQ_NOTICE(req,fmt,...) +AFB_REQ_INFO(req,fmt,...) +AFB_REQ_DEBUG(req,fmt,...) +``` + +By default, the logging macros add file, line and function +indication. + +Some definitions can be used to + + diff --git a/docs/afb-binding-writing.md b/docs/afb-binding-writing.md new file mode 100644 index 00000000..dd9a8b56 --- /dev/null +++ b/docs/afb-binding-writing.md @@ -0,0 +1,465 @@ + +Overview of the bindings +======================== + +The ***binder*** serves files through HTTP protocol and offers to +developers the capability to offer application API methods through HTTP or +WebSocket protocol. + +The ***bindings*** are used to add **API** to ***binders***. +This part describes how to write a ***binding*** for ***binder*** +or in other words how to add a new **API** to the system. + +Excepting this summary, this section target developers. + +This section shortly explain how to write a binding +using the C programming language. + +It is convenient to install the ***binder*** on the +desktop used for writing the binding. It allows easy +debug and test. + +Nature of a binding +------------------- + +A ***binding*** is an independent piece of software compiled as a shared +library and dynamically loaded by a ***binder***. + +It is intended to provide one **API** (**A**pplication **P**rogramming +**I**nterface). + +The **API** is designated and accessed through its name. +It contains several **verbs** that implement the ***binding*** +functionnalities. Each of these **verbs** is a **method** that +processes requests of applications and sends result. + +The ***binding***'s methods is invoqued by HTTP or websocket +requests. + +The **methods** of the ***bindings*** are noted **api/verb** +where **api** is the **API** name of the binding and **verb** is +the **method**'s name within the **API**. +This notation comes from HTTP invocations that rely on URL path terminated +with **api/verb**. + +The name of an **API** can be made of any characters except: + + - the control characters (\u0000 .. \u001f) + - the characters of the set { ' ', '"', '#', '%', '&', + '\'', '/', '?', '`', '\x7f' } + +The names if the **verbs** can be any character. + +The binder mkes no distinctions between upper case and lower case +latin letters. So **API/VERB** matches **Api/Verb** or **api/verb**. + +Actually it exists 2 ways of writing ***bindings***. +You can either write: + + - a binding version 1 (not recommanded); + - a binding version 2 (RECOMMANDED). + +A ***binder*** loads and runs any of these version +in any combination. + +This document explain how to write bindings version 2. + + +Sample binding: tuto-1 +====================== + +This is the code of the binding **tuto-1.c**: + +```C + 1 #define AFB_BINDING_VERSION 2 + 2 #include + 3 + 4 void hello(afb_req req) + 5 { + 6 AFB_REQ_DEBUG(req, "hello world"); + 7 afb_req_success(req, NULL, "hello world"); + 8 } + 9 + 10 const afb_verb_v2 verbs[] = { + 11 { .verb="hello", .callback=hello }, + 12 { .verb=NULL } + 13 }; + 14 + 15 const afb_binding_v2 afbBindingV2 = { + 16 .api = "tuto-1", + 17 .verbs = verbs + 18 }; +``` + +Compiling: + +```bash +$ gcc -fPIC -shared tuto-1.c -o tuto-1.so $(pkg-config --cflags-only-I afb-daemon) +``` + +Running: + +```bash +$ afb-daemon --binding tuto-1.so --port 3333 --token '' +``` + +Testing using **curl**: + +```bash +$ curl http://localhost:3333/api/tuto-1/hello +{"jtype":"afb-reply","request":{"status":"success","info":"hello world","uuid":"1e587b54-900b-49ab-9940-46141bc2e1d6"}} +``` + +Testing using **afb-client-demo** (with option -H for +getting a human readable output): + +```bash +$ afb-client-demo -H ws://localhost:3333/api?token=x tuto-1 hello +ON-REPLY 1:tuto-1/hello: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success", + "info":"hello world", + "uuid":"03a84ad1-458a-4ace-af74-b1da917391b9" + } +} +``` + +This shows basic things: + + - The include to get for creating a binding + - How to declare the API offered by the binding + - How to handle request made to the binding + + +### Getting declarations for the binding + +The lines 1 and 2 show how to get the include file **afb-binding.h**. + +```C + 1 #define AFB_BINDING_VERSION 2 + 2 #include +``` + +You must define the version of ***binding*** that you are using. +This is done line 1 where we define that this is the version 2. + +If you don't define it, a warning message is prompted by the compiler +and the version is switched to version 1. This behaviour is +temporarily and enables to continue to use previously written +***binding*** without change but it will change in some future when +***bindings*** V1 will become obsoletes. + +To include **afb-binding.h** successfuly, the include search path +should be set correctly if needed (not needed only if installed in +/usr/include/afb directory that is the default). + +Setting the include path is easy using **pkg-config**: + +```bash +$ pkg-config --cflags-only-I afb-daemon +``` + +Note for **C++** developers: The ***binder*** currently expose +only **C** language **API**. The file **afb/afb-binding.h** +isn't **C++** ready. You should use the construct **extern "C"** +as below: + +```C + #define AFB_BINDING_VERSION 2 + extern "C" { + #include + } +``` + +Future version of the ***binder*** will include a **C++** +interface. Until it is available, please, use the above +construct. + +### Declaring the API of the binding + +Lines 10 to 18 show the declaration of the ***binding***. + +The ***binder*** knows that this is a ***binding*** version 2 because +it finds the exported symbol **afbBindingV2** that is expected to be +a structure of type **afb_binding_v2**. + +```C + 10 const afb_verb_v2 verbs[] = { + 11 { .verb="hello", .callback=hello }, + 12 { .verb=NULL } + 13 }; + 14 + 15 const afb_binding_v2 afbBindingV2 = { + 16 .api = "tuto-1", + 17 .verbs = verbs + 18 }; +``` + +The structure **afbBindingV2** actually tells that: + + - the exported **API** name is **tuto-1** (line 16) + - the array of verbs is the above defined one + +The exported list of verb is specified by an array of structures, +each describing a verb, ended with a verb NULL (line 12). + +The only defined verb here (line 11) is named **hello** (field **.verb**) +and the function that handle the related request is **hello** +(field **.callback**). + +Note that you can explicitely mark the fact that these are +struct by typing the **struct** as below: + +```C + 10 const struct afb_verb_v2 verbs[] = { + 11 { .verb="hello", .callback=hello }, + 12 { .verb=NULL } + 13 }; + 14 + 15 const struct afb_binding_v2 afbBindingV2 = { + 16 .api = "tuto-1", + 17 .verbs = verbs + 18 }; +``` + +### Handling binder's requests + +As shown above this is by default the common include directory where +the AGL stuff is installed. + +```C + 4 void hello(afb_req req) + 5 { + 6 AFB_REQ_DEBUG(req, "hello world"); + 7 afb_req_success(req, NULL, "hello world"); + 8 } +``` + +When the ***binder*** receives a request for the verb **hello** of +of the api **tuto-1**, it invoque the callback **hello** of the **binding** +with the argument **req** that handles the client request. + +The callback has to treat synchronously or asynchronously the request and +should at the end emit a reply for the request. + +Here, the callback for **tuto-1/hello** replies a successful answer +(ligne 7) to the request **req**. The second parameter (here NULL) +is a json object that is sent to the client with the reply. +The third parameter is also sent with the reply and is a string +called info that can be used as some meta data. + +Here again, you can explicitely mark the fact that +**afb_req** is a structure by declaring **hello** as below: + +```C + 4 void hello(struct afb_req req) +``` + +Sample binding: tuto-2 +====================== + +The second tutorial shows many important feature that can +commonly be used when writting a ***binding***: initialisation, +getting arguments, sending replies, pushing events. + +This is the code of the binding **tuto-2.c**: + +```C + 1 #include + 2 #include + 3 + 4 #define AFB_BINDING_VERSION 2 + 5 #include + 6 + 7 afb_event event_login, event_logout; + 8 + 9 void login(afb_req req) + 10 { + 11 json_object *args, *user, *passwd; + 12 char *usr; + 13 + 14 args = afb_req_json(req); + 15 if (!json_object_object_get_ex(args, "user", &user) + 16 || !json_object_object_get_ex(args, "password", &passwd)) { + 17 AFB_REQ_ERROR(req, "login, bad request: %s", json_object_get_string(args)); + 18 afb_req_fail(req, "bad-request", NULL); + 19 } else if (afb_req_context_get(req)) { + 20 AFB_REQ_ERROR(req, "login, bad state, logout first"); + 21 afb_req_fail(req, "bad-state", NULL); + 22 } else if (strcmp(json_object_get_string(passwd), "please")) { + 23 AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args)); + 24 afb_req_fail(req, "unauthorized", NULL); + 25 } else { + 26 usr = strdup(json_object_get_string(user)); + 27 AFB_REQ_NOTICE(req, "login user: %s", usr); + 28 afb_req_session_set_LOA(req, 1); + 29 afb_req_context_set(req, usr, free); + 30 afb_req_success(req, NULL, NULL); + 31 afb_event_push(event_login, json_object_new_string(usr)); + 32 } + 33 } + 34 + 35 void action(afb_req req) + 36 { + 37 json_object *args, *val; + 38 char *usr; + 39 + 40 args = afb_req_json(req); + 41 usr = afb_req_context_get(req); + 42 AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args)); + 43 if (json_object_object_get_ex(args, "subscribe", &val)) { + 44 if (json_object_get_boolean(val)) { + 45 AFB_REQ_NOTICE(req, "user %s subscribes to events", usr); + 46 afb_req_subscribe(req, event_login); + 47 afb_req_subscribe(req, event_logout); + 48 } else { + 49 AFB_REQ_NOTICE(req, "user %s unsubscribes to events", usr); + 50 afb_req_unsubscribe(req, event_login); + 51 afb_req_unsubscribe(req, event_logout); + 52 } + 53 } + 54 afb_req_success(req, json_object_get(args), NULL); + 55 } + 56 + 57 void logout(afb_req req) + 58 { + 59 char *usr; + 60 + 61 usr = afb_req_context_get(req); + 62 AFB_REQ_NOTICE(req, "login user %s out", usr); + 63 afb_event_push(event_logout, json_object_new_string(usr)); + 64 afb_req_session_set_LOA(req, 0); + 65 afb_req_context_clear(req); + 66 afb_req_success(req, NULL, NULL); + 67 } + 68 + 69 int preinit() + 70 { + 71 AFB_NOTICE("preinit"); + 72 return 0; + 73 } + 74 + 75 int init() + 76 { + 77 AFB_NOTICE("init"); + 78 event_login = afb_daemon_make_event("login"); + 79 event_logout = afb_daemon_make_event("logout"); + 80 if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout)) + 81 return 0; + 82 AFB_ERROR("Can't create events"); + 83 return -1; + 84 } + 85 + 86 const afb_verb_v2 verbs[] = { + 87 { .verb="login", .callback=login }, + 88 { .verb="action", .callback=action, .session=AFB_SESSION_LOA_1 }, + 89 { .verb="logout", .callback=logout, .session=AFB_SESSION_LOA_1 }, + 90 { .verb=NULL } + 91 }; + 92 + 93 const afb_binding_v2 afbBindingV2 = { + 94 .api = "tuto-2", + 95 .specification = NULL, + 96 .verbs = verbs, + 97 .preinit = preinit, + 98 .init = init, + 99 .noconcurrency = 0 + 100 }; +``` + +Compiling: + +```bash +$ gcc -fPIC -shared tuto-2.c -o tuto-2.so $(pkg-config --cflags --libs afb-daemon) +``` + +Running: + +```bash +$ afb-daemon --binding tuto-2.so --port 3333 --token '' +``` + +Testing: + +```bash +$ afb-client-demo -H localhost:3333/api?token=toto +tuto-2 login {"help":true} +ON-REPLY 1:tuto-2/login: ERROR +{ + "jtype":"afb-reply", + "request":{ + "status":"bad-request", + "uuid":"e2b24a13-fc43-487e-a5f4-9266dd1e60a9" + } +} +tuto-2 login {"user":"jose","password":"please"} +ON-REPLY 2:tuto-2/login: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success" + } +} +tuto-2 login {"user":"jobol","password":"please"} +ON-REPLY 3:tuto-2/login: ERROR +{ + "jtype":"afb-reply", + "request":{ + "status":"bad-state" + } +} +tuto-2 action {"subscribe":true} +ON-REPLY 4:tuto-2/action: OK +{ + "response":{ + "subscribe":true + }, + "jtype":"afb-reply", + "request":{ + "status":"success" + } +} +``` + +In an other terminal: + +```bash +$ afb-client-demo -H localhost:3333/api?token=toto +tuto-2 login {"user":"jobol","password":"please"} +ON-REPLY 1:tuto-2/login: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success", + "uuid":"a09f55ff-0e89-4f4e-8415-c6e0e7f439be" + } +} +tuto-2 logout true +ON-REPLY 2:tuto-2/logout: OK +{ + "jtype":"afb-reply", + "request":{ + "status":"success" + } +} +``` + +It produced in the first terminal: + +```bash +ON-EVENT tuto-2/login: +{ + "event":"tuto-2\/login", + "data":"jobol", + "jtype":"afb-event" +} +ON-EVENT tuto-2/logout: +{ + "event":"tuto-2\/logout", + "data":"jobol", + "jtype":"afb-event" +} +``` + diff --git a/docs/afb-daemon-options.md b/docs/afb-daemon-options.md new file mode 100644 index 00000000..39cf0bdb --- /dev/null +++ b/docs/afb-daemon-options.md @@ -0,0 +1,200 @@ + +Launching options of afb-daemon +--------------------- + +The launch options for binder **afb-daemon** are: + + --help + + Prints help with available options + + --version + + Display version and copyright + + --verbose + + Increases the verbosity, can be repeated + + --quiet + + Decreases the verbosity, can be repeated + + --port=xxxx + + HTTP listening TCP port [default 1234] + + --workdir=xxxx + + Directory where the daemon must run [default: $PWD if defined + or the current working directory] + + --uploaddir=xxxx + + Directory where uploaded files are temporarily stored [default: workdir] + + --rootdir=xxxx + + Root directory of the application to serve [default: workdir] + + --roothttp=xxxx + + Directory of HTTP served files. If not set, files are not served + but apis are still accessibles. + + --rootbase=xxxx + + Angular Base Root URL [default /opa] + + This is used for any application of kind OPA (one page application). + When set, any missing document whose url has the form /opa/zzz + is translated to /opa/#!zzz + + --rootapi=xxxx + + HTML Root API URL [default /api] + + The bindings are available within that url. + + --alias=xxxx + + Maps a path located anywhere in the file system to the + a subdirectory. The syntax for mapping a PATH to the + subdirectory NAME is: --alias=/NAME:PATH. + + Example: --alias=/icons:/usr/share/icons maps the + content of /usr/share/icons within the subpath /icons. + + This option can be repeated. + + --apitimeout=xxxx + + binding API timeout in seconds [default 20] + + Defines how many seconds maximum a method is allowed to run. + 0 means no limit. + + --cntxtimeout=xxxx + + Client Session Timeout in seconds [default 3600] + + --cache-eol=xxxx + + Client cache end of live [default 100000 that is 27,7 hours] + + --session-max=xxxx + + Maximum count of simultaneous sessions [default 10] + + --ldpaths=xxxx + + Load bindings from given paths separated by colons + as for dir1:dir2:binding1.so:... [default = $libdir/afb] + + You can mix path to directories and to bindings. + The sub-directories of the given directories are searched + recursively. + + The bindings are the files terminated by '.so' (the extension + so denotes shared object) that contain the public entry symbol. + + --binding=xxxx + + Load the binding of given path. + + --token=xxxx + + Initial Secret token to authenticate. + + If not set, no client can authenticate. + + If set to the empty string, then any initial token is accepted. + + --random-token + + Generate a random starting token. See option --exec. + + --mode=xxxx + + Set the mode: either local, remote or global. + + The mode indicate if the application is run locally on the host + or remotely through network. + + --dbus-client=xxxx + + Transparent binding to a binder afb-daemon service through dbus. + + It creates an API of name xxxx that is implemented remotely + and queried via DBUS. + + --dbus-server=xxxx + + Provides a binder afb-daemon service through dbus. + + The name xxxx must be the name of an API defined by a binding. + This API is exported through DBUS. + + --ws-client=xxxx + + Transparent binding to a binder afb-daemon service through a WebSocket. + + The value of xxxx is either a unix naming socket, of the form "unix:path/api", + or an internet socket, of the form "host:port/api". + + --ws-server=xxxx + + Provides a binder afb-daemon service through WebSocket. + + The value of xxxx is either a unix naming socket, of the form "unix:path/api", + or an internet socket, of the form "host:port/api". + + --foreground + + Get all in foreground mode (default) + + --daemon + + Get all in background mode + + --no-httpd + + Forbids HTTP serve + + --exec + + Must be the last option for afb-daemon. The remaining + arguments define a command that afb-daemon will launch. + The sequences @p, @t and @@ of the arguments are replaced + with the port, the token and @. + + --tracereq=xxxx + + Trace the processing of requests in the log file. + + Valid values are 'no' (default), 'common', 'extra' or 'all'. + + --traceditf=xxxx + + Trace the accesses to functions of class daemon. + + Valid values are 'no' (default), 'common', 'extra' or 'all'. + + --tracesvc=xxxx + + Trace the accesses to functions of class service. + + Valid values are 'no' (default) or 'all'. + + --traceevt=xxxx + + Trace the accesses to functions of class event. + + Valid values are 'no' (default), 'common', 'extra' or 'all'. + + --call=xxx + + Call a binding at start (can be be repeated). + The values are given in the form API/VERB:json-args. + + Example: --call 'monitor/set:{"verbosity":{"api":"debug"}}' diff --git a/doc/afb-daemon-vocabulary.md b/docs/afb-daemon-vocabulary.md similarity index 100% rename from doc/afb-daemon-vocabulary.md rename to docs/afb-daemon-vocabulary.md diff --git a/docs/afb-desktop-package.md b/docs/afb-desktop-package.md new file mode 100644 index 00000000..775f4ee5 --- /dev/null +++ b/docs/afb-desktop-package.md @@ -0,0 +1,40 @@ + +Desktop packages for binder developement +======================================== + +It exists packages of the ***binder*** (afb-daemon) +for common desktop linux distributions. + + - Fedora + - Ubuntu + - Debian + - Suse + +Installing the developement package of the ***binder*** +allows to write ***bindings*** that runs on the destop +computer of the developper. + +It is very convenient to quickly write and debug a binding. + +Retriving compiling option with pkg-config +========================================== + +The ***binder*** afb-daemon provides a configuration +file for **pkg-config**. +Typing the command + + pkg-config --cflags afb-daemon + +Print flags use for compilation: + + $ pkg-config --cflags afb-daemon + -I/opt/local/include -I/usr/include/json-c + +For linking, you should use + + $ pkg-config --libs afb-daemon + -ljson-c + +It automatically includes the dependency to json-c. +This is activated through **Requires** keyword in pkg-config. + diff --git a/docs/afb-events-guide.md b/docs/afb-events-guide.md new file mode 100644 index 00000000..b6e4557c --- /dev/null +++ b/docs/afb-events-guide.md @@ -0,0 +1,371 @@ +Guide for developing with events +================================ + +Signaling agents are services that send events to any clients that +subscribed for receiving it. The sent events carry any data. + +To have a good understanding of how to write a signaling agent, the +actions of subscribing, unsubscribing, producing, sending and receiving +events must be described and explained. + +Overview of events +------------------ + +The basis of a signaling agent is shown in the following figure: + +![scenario of using events](pictures/signaling-basis.svg) + +This figure shows the main role of the signaling framework for the events +propagation. + +For people not familiar with the framework, a signaling agent and +a “binding” are similar. + +### Subscribing and unsubscribing + +Subscribing is the action that makes a client able to receive data from a +signaling agent. Subscription must create resources for generating the data, and +for delivering the data to the client. These two aspects are not handled by the +same piece of software. Generating the data is the responsibility of the +developer of the signaling agent while delivering the data is handled by the +framework. + +When a client subscribes for data, the agent must: + +1. check that the subscription request is correct; +2. establish the computation chain of the required data, if not already + done; +3. create a named event for the computed data, if not already done; +4. ask the framework to establish the subscription to the event for the + request; +5. optionally give indications about the event in the reply to + the client. + +The first two steps are not involving the framework. They are linked to +the business logic of the binding. The request can be any description of +the requested data and the computing stream can be of any nature, this +is specific to the binding. + +As said before, the framework uses and integrates **libsystemd** and its event +loop. Within the framework, **libsystemd** is the standard API/library for +bindings expecting to setup and handle I/O, timer or signal events. + +Steps 3 and 4 are bound to the framework. + +The agent must create an object for handling the propagation of produced +data to its clients. That object is called “event” in the framework. An +event has a name that allows clients to distinguish it from other +events. + +Events are created using the ***afb\_daemon\_make\_event*** function +that takes the name of the event. Example: + +```C + event = afb_daemon_make_event(name); +``` + +Once created, the event can be used either to push data to its +subscribers or to broadcast data to any listener. + +The event must be used to establish the subscription for the requesting +client. This is done using the ***afb\_req\_subscribe*** function +that takes the current request object and event and associates them +together. Example: + +```C + rc = afb_req_subscribe(req, event); +``` + +When successful, this function make the connection between the event and +the client that emitted the request. The client becomes a subscriber of +the event until it unsubscribes or disconnects. The +***afb\_req\_subscribe*** function will fail if the client +connection is weak: if the request comes from a HTTP link. To receive +signals, the client must be connected. The AGL framework allows connections +using WebSocket. + +The name of the event is either a well known name or an ad hoc name +forged for the use case. + +Let's see a basic example: client A expects to receive the speed in km/h +every second while client B expects the speed in mph twice a second. In +that case, there are two different events because it is not the same +unit and it is not the same frequency. Having two different events +allows to associate clients to the correct event. But this doesn't tell +any word about the name of these events. The designer of the signaling +agent has two options for naming: + +1. names can be the same (“speed” for example) with sent data + self describing itself or having a specific tag (requiring from + clients awareness about requesting both kinds of speed isn't safe). +2. names of the event include the variations (by example: + “speed-km/h-1Hz” and “speed-mph-2Hz”) and, in that case, sent data + can self describe itself or not. + +In both cases, the signaling agent might have to send the name of the +event and/or an associated tag to its client in the reply of the +subscription. This is part of the step 5 above. + +The framework only uses the event (not its name) for subscription, +unsubscription and pushing. + +When the requested data is already generated and the event used for +pushing it already exists, the signaling agent must not instantiate a +new processing chain and must not create a new event object for pushing +data. The signaling agent must reuse the existing chain and event. + +Unsubscribing is made by the signaling agent on a request of its client. +The ***afb\_req\_unsubscribe*** function tells the framework to +remove the requesting client from the event's list of subscribers. +Example: + +```C + afb_req_unsubscribe(req, event); +``` + +Subscription count does not matter to the framework: subscribing the +same client several times has the same effect that subscribing only one +time. Thus, when unsubscribing is invoked, it becomes immediately +effective. + +#### More on naming events + +Within the AGL framework, a signaling agent is a binding that has an API +prefix. This prefix is meant to be unique and to identify the binding +API. The names of the events that this signaling agent creates are +automatically prefixed by the framework, using the API prefix of the +binding. + +Thus, if a signaling agent of API prefix ***api*** creates an event +of name ***event*** and pushes data to that event, the subscribers +will receive an event of name ***api/event***. + +### Generating and pushing signals and data + +This of the responsibility of the designer of the signaling agent to +establish the processing chain for generating events. In many cases, +this can be achieved using I/O or timer or signal events inserted in the +main loop. For this case, the AGL framework uses **libsystemd** and +provide a way to integrates to the main loop of this library using +afb\_daemon\_get\_event\_loop. Example: + +```C + sdev = afb_daemon_get_event_loop(); + rc = sd_event_add_io(sdev, &source, fd, EPOLLIN, myfunction, NULL); +``` + +In some other cases, the events are coming from D-Bus. In that case, the +framework also uses **libsystemd** internally to access D-Bus. It provides +two methods to get the available D-Bus objects, already existing and +bound to the main**libsystemd**event loop. Use either +***afb\_daemon\_get\_system\_bus*** or +***afb\_daemon\_get\_user\_bus*** to get the required instance. Then +use functions of **libsystemd** to handle D-Bus. + +In some rare cases, the generation of the data requires to start a new +thread. + +When a data is generated and ready to be pushed, the signaling agent +should call the function ***afb\_event\_push***. Example: + +```C + rc = afb_event_push(event, JSON); + if (rc == 0) { + stop_generating(event); + afb_event_drop(event); + } +``` + +The function ***afb\_event\_push*** pushes json data to all the +subscribers. It then returns the count of subscribers. When the count is +zero, there is no subscriber listening for the event. The example above +shows that in that case, the signaling agent stops to generate data for +the event and delete the event using afb\_event\_drop. This is one +possible option. Other valuable options are: do nothing and continue to +generate and push the event or just stop to generate and push the data +but keep the event existing. + +### Receiving the signals + +Understanding what a client expects when it receives signals, events or +data shall be the most important topic of the designer of a signaling +agent. The good point here is that because JSON[^1] is the exchange +format, structured data can be sent in a flexible way. + +The good design is to allow as much as possible the client to describe +what is needed with the goal to optimize the processing to the +requirements only. + +### The exceptional case of wide broadcast + +Some data or events have so much importance that they can be widely +broadcasted to alert any listening client. Examples of such an alert +are: + +- system is entering/leaving “power safe” mode +- system is shutting down +- the car starts/stops moving +- ... + +An event can be broadcasted using one of the two following methods: +***afb\_daemon\_broadcast\_event*** or +***afb\_event\_broadcast***. + +Example 1: + +```C + afb_daemon_broadcast_event(name, json); +``` + +Example 2: + +```C + event = afb_daemon_make_event(name); + . . . . + afb_event_broadcast(event, json); +``` + +As for other events, the name of events broadcasted using +***afb\_daemon\_broadcast\_event*** are automatically prefixed by +the framework with API prefix of the binding (signaling agent). + +Reference of functions +---------------------- + +### Function afb\_event afb\_daemon\_make\_event + +The function ***afb\_daemon\_make\_event*** that is defined as below: + +```C +/* + * Creates an event of 'name' and returns it. + */ +struct afb_event afb_daemon_make_event(const char *name); +``` + +The correct way to create the event at initialisation is to call the function +***afb\_daemon\_make\_event*** within the initialisation +function referenced by the field ***init*** of the structure ***afbBindingV2***. + +### Function afb\_event\_push + +The function ***afb\_event\_push*** is defined as below: + +```C +/* + * Pushes the 'event' with the data 'object' to its observers. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_event_push(struct afb_event event, struct json_object *object); +``` + +As the function ***afb\_event\_push*** returns 0 when there is no +more subscriber, a binding can remove such unexpected event using the +function ***afb\_event\_drop***. + +### Function afb\_event\_drop + +The function ***afb\_event\_drop*** is defined as below: + +```C +/* + * Drops the data associated to the event + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_drop(struct afb_event event); +``` + +### Function afb\_req\_subscribe + +The function ***afb\_req\_subscribe*** is defined as below: + +```C +/* + * Establishes for the client link identified by 'req' a subscription + * to the 'event'. + * Returns 0 in case of successful subscription or -1 in case of error. + */ +int afb_req_subscribe(struct afb_req req, struct afb_event event); +``` + +The subscription adds the client of the request to the list of subscribers +to the event. + +### Function afb\_req\_unsubscribe + +The function ***afb\_req\_unsubscribe*** is defined as +below: + +```C +/* + * Revokes the subscription established to the 'event' for the client + * link identified by 'req'. + * Returns 0 in case of successful unsubscription or -1 in case of error. + */ +int afb_req_unsubscribe(struct afb_req req, struct afb_event event); +``` + +The unsubscription removes the client of the request of the list of subscribers +to the event. +When the list of subscribers to the event becomes empty, +the function ***afb\_event\_push*** will return zero. + +### Function afb\_event\_broadcast + +The function ***afb\_event\_broadcast*** is defined as below: + +```C +/* + * Broadcasts widely the 'event' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_event_broadcast(struct afb_event event, struct json_object *object); +``` + +This uses an existing event (created with ***afb\_daemon\_make\_event***) +for broadcasting an event having its name. + + +### Function afb\_daemon\_broadcast\_event + +The function ***afb\_daemon\_broadcast\_event*** is defined as below: + +```C +/* + * Broadcasts widely the event of 'name' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_daemon_broadcast_event(const char *name, struct json_object *object); +``` + +The name is given here explicitly. The name is automatically prefixed +with the name of the binding. For example, a binding of prefix "xxx" +would broadcat the event "xxx/name". + +### Function onevent (field of afbBindingV2) + +Binding can designate an event handling function using the field **onevent** +of the structure **afbBindingV2**. This function is called when an event is +broadcasted or when an event the binding subscribed to is pushed. +That allow a service to react to an event and do what it is to do if this is +relevant for it (ie: car back camera detects imminent collision and broadcast +it, then appropriate service enable parking brake.). diff --git a/docs/afb-migration-v1-to-v2.md b/docs/afb-migration-v1-to-v2.md new file mode 100644 index 00000000..487c259d --- /dev/null +++ b/docs/afb-migration-v1-to-v2.md @@ -0,0 +1,611 @@ +Migration from binding V1 to binding V2 +======================================= + +The ***binding*** interface evolved from version 1 to version 2 +for the following reasons: + + - integration of the security requirements within the bindings + - simplification of the API (after developer feedbacks) + - removal of obscur features, cleanup + +The ***binder*** can run ***bindings*** v1 and/or v2 in any combination. +Thus moving from v1 to v2 is not enforced. There is no real need. + +More, it is possible to write a dual ***binding***: a ***binding*** that +implements the version 1 AND the version 2. + +However, IT IS HIGHLY RECOMMANDED TO SWITCH TO ONLY VERSION 2: + + - any new developement SHOULD start using ***binding*** V2 + - existing ***bindings*** SHOULD migrate to the version 2 + +This guide covers the migration of bindings from version 1 to version 2. + +It also explains some of the rationale taken when migrating from version 1 to version 2. + +In the future, if ***binding*** api evolves to fresh versions (3, 4, ...) +it might be necessarily to write bindings implementing more than +just one version. For example, a ***binding*** being v2 AND v3 will resolve +the issue of running on older AND newer version of AGL. This should always +be possible even if more complicated. + +Important things to known when migrating +---------------------------------------- + +One of the most important change when migrating from v1 to v2 is +that many functions use an hidden *common* variable. +This affects the functions of the following classes: + + - functions of class **daemon**: + * functions starting with **afb_daemon_...** + * functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG** + - functions of class **service**: + * functions starting with **afb_service_...** + - callback functions: + * the register function (that is removed) + * the service init function + * the onevent function + +For these functions, the first parameter is now implicit. + +Let takes an example. For ***binding*** v1 you had to write: + +```C + afb_daemon_broadcast_event(afbitf->daemon, reason, description); +``` + +For ***binding*** v2, you simply write: + +```C + afb_daemon_broadcast_event(reason, description); +``` + +This simplification is possible because the header files included for the bindings +now provide a common variable for storing the **daemon** and **service** data. + +As a programmer, you shouldn't care much about that hidden variable. +It simplifies the job, that's all and that is the reason of the change. + +An other important difference is between the version 1 and the version 2 is +on how the ***binding***'s **API** is documented. The version 2 enphasis the +**OpenAPI v3** description of the **API**. For this reason, to avoid +duplication of descriptions, only one description is expected: the **OpenAPI** one. + +Task list for the migration +--------------------------- + +This task list is: + + 1. Enforce use of binding v2 by setting **AFB_BINDING_VERSION** + 2. Rewrite the main structure and the list of exported verbs + 3. Adapt the init and callback functions + 4. Removes the first parameter of functions of classes **daemon** + and **service** + 5. Consider where to emit logs for requests + 6. Take care of store/unstore changes + 7. Consider use of synchronous (sub)call requests + 8. Optionnaly, removes explicit struct + +The remaining chapters explain these task with more details. + +Enforce use of binding v2 by setting AFB_BINDING_VERSION +-------------------------------------------------------- + +By defining **AFB_BINDING_VERSION** to **2** you switch to version 2. +This is done as below. + +```C +#define AFB_BINDING_VERSION 2 +#include +``` + +After that you will get many errors when compiling. + +Rewrite the main structures and the list of exported verbs +--------------------------------------------------------- + +The structures describing the ***binding** changed from version 1 to version 2. + +The structure for describing verbs changed to include security +requirements. In version 1 it was: + +```C +struct afb_verb_desc_v1 +{ + const char *name; /* name of the verb */ + enum afb_session_flags_v1 session; /* authorisation and session requirements of the verb */ + void (*callback)(struct afb_req req); /* callback function implementing the verb */ + const char *info; /* textual description of the verb */ +}; +``` + +In version 2 it becomes: + +```C +struct afb_verb_v2 +{ + const char *verb; /* name of the verb */ + void (*callback)(struct afb_req req); /* callback function implementing the verb */ + const struct afb_auth *auth; /* required authorisation */ + uint32_t session; /* authorisation and session requirements of the verb */ +}; + +``` + +The migration of instances of that structure requires the following actions: + + - rename field **name** to **verb** + - remove field **info** + - adapt field **session** if needed + - set field **auth** to NULL + +Example: + +```C + { .name= "new", .session= AFB_SESSION_NONE, .callback= new, .info= "Starts a new game" } +``` + +Becomes + +```C + { .verb = "new", .session = AFB_SESSION_NONE, .callback = new, .auth = NULL } +``` + +The field **auth** can be set to a value describing the requested +authorisation. + +The main describing structure also changed. In version 1 it was: + +```C +struct afb_binding_desc_v1 +{ + const char *info; /* textual information about the binding */ + const char *prefix; /* required prefix name for the binding */ + const struct afb_verb_desc_v1 *verbs; /* array of descriptions of verbs terminated by a NULL name */ +}; +``` + +In version 2 it becomes: + +```C +struct afb_binding_v2 +{ + const char *api; /* api name for the binding */ + const char *specification; /* textual specification of the binding */ + const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */ + int (*preinit)(); /* callback at load of the binding */ + int (*init)(); /* callback for starting the service */ + void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */ + unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */ +}; +``` + +The migration of instances of that structure requires the following actions: + + - declare, expore, name the structure as ```const struct afb_binding_v2 afbBindingV2``` + - rename the field **prefix** to **api** + - remove the field **info** + - setup the fields **preinit**, **init**, **onevent** accordling to the next section + - set the field **noconcurrency** to the right value: + * to 1 if you want to avoid concurrent calls to verbs. + * to 0 if you allow concurrent calls to verbs. + +Example: + +```C +static const struct afb_binding plugin_desc = { + .type = AFB_BINDING_VERSION_1, + .v1 = { + .info = "Minimal Hello World Sample", + .prefix = "hello", + .verbs = verbs + } +``` +Becomes: + +```C +const struct afb_binding_v2 afbBindingV2 = { + .api = "hello", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init +}; +``` + +The **binder** now relies only on the exported names +to deduce the type of the binding. This make the main +structure more simple. + +Adapt the init and callback functions +------------------------------------- + +The ***bindings*** version 1 defined 3 exported functions: + + - **afbBindingV1Register** + - **afbBindingV1ServiceInit** + - **afbBindingV1ServiceEvent** + +These function should not be exported any more and there definition changed. + +The function **afbBindingV1Register** is no more used to describe the binding. +When a binding has to take actions when it is loaded, it must set the field +**preinit** of the structure **afbBindingV2**. This field, this preinit, might +be used to check features at load. When it returns a negative number, the +***binder*** stops before initializing any ***binding***. + +The function **afbBindingV1ServiceInit** is replaced by the field **init** +of the structure **afbBindingV2**. The init function should return 0 in case +of success or a negative error code in case of problem. It is called during +initialisation of services. + +The function **afbBindingV1ServiceEvent**is replaced by the field **onevent** +of the structure **afbBindingV2**. + +The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**, +were taking as parameter the ***binder*** interface and the service interface respectively. +These interfaces are now managed hiddenly for the **binding** by the **binder**. +So the variable that ***bindings*** version used to store the ***binder*** interface +and the service interface are no more needed and can be removed. + +Example: + +```C +const struct afb_binding_interface *interface; +struct afb_service service; + +static const struct afb_binding plugin_desc = { + .type = AFB_BINDING_VERSION_1, + .v1 = { + .info = "Minimal Hello World Sample", + .prefix = "hello", + .verbs = verbs + } +} + +const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +{ + interface = itf; + NOTICE(interface, "binding register"); + return &plugin_desc; +} + +int afbBindingV1ServiceInit(struct afb_service svc) +{ + service = svc; + NOTICE(interface, "binding init"); + return 0; +} + +void afbBindingV1ServiceEvent(const char *event, struct json_object *object) +{ + NOTICE(interface, "onevent %s", event); +} +``` + +Becomes: + +```C +static int preinit() +{ + AFB_NOTICE("binding preinit (was register)"); + return 0; +} + +static int init() +{ + AFB_NOTICE("binding init"); + return 0; +} + +static void onevent(const char *event, struct json_object *object) +{ + AFB_NOTICE("onevent %s", event); +} + +const struct afb_binding_v2 afbBindingV2 = { + .api = "hello", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .onevent = onevent +}; +``` + +The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**, +were taking as parameter the ***binder*** interface and the service interface respectively. +These interfaces are now managed hiddenly for the **binding** by the **binder**. +So the variable that ***bindings*** version used to store the ***binder*** interface +and the service interface are no more needed and can be removed. + +On the above example the folowing lines were removed: +```C +const struct afb_binding_interface *interface; +struct afb_service service; + + interface = itf; + + service = svc; +``` + + + +Removes the first parameter of functions of classes **daemon** and **service** +------------------------------------------------------------------------------ + +As explained before, many functions loose there first +arguments, this are the functions of the following classes: + + - functions of class **daemon**: + * functions starting with **afb_daemon_...** + * functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG** + - functions of class **service**: + * functions starting with **afb_service_...** + - callback functions: + * the register function (that is removed) + * the service init function + * the onevent function + +For these functions, the first parameter is now implicit. + +Example: + +```C + afb_daemon_broadcast_event(afbitf->daemon, reason, description); +``` + +Becomes: + +```C + afb_daemon_broadcast_event(reason, description); +``` + +Also, to avoid possible conflicts, we introduced prefixed logging functions: +the macros **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG** have now +a prefixed version: **AFB\_ERROR**, **AFB\_WARNING**, **AFB\_NOTICE**, +**AFB\_INFO**, **AFB\_DEBUG**. It is now recommanded to use the prefixed version. + +Example: + +```C + NOTICE(interface, "hello plugin comes to live"); +``` + +Become: + +```C + NOTICE("hello plugin comes to live"); +``` + +or, better: + +```C + AFB_NOTICE("hello plugin comes to live"); +``` + +To remove definition of the unprefixed versions of logging macros **ERROR**, **WARNING**, +**NOTICE**, **INFO**, **DEBUG** and just define **AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX** +before to include **afb/afb-binding.h**. + +```C +#define AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX +#define AFB_BINDING_VERSION 2 +#include +``` + +Consider where to emit logs for requests +---------------------------------------- + +The ***bindings*** v2 now allows to emit log messages associated to ***requests***. +This feature is valuable when debugging because it allows to return +side informations associated to a ***request***. + +The defined macros for logging to requests are: **AFB_REQ_ERROR**, +**AFB_REQ_WARNING**, **AFB_REQ_NOTICE**, **AFB_REQ_INFO**, **AFB_REQ_DEBUG**. + +We encourage the use of these new logging facilities everywhere it makes sense. + +Example: + +```C + INFO(afbitf, "method 'new' called for boardid %d", board->id); +``` + +Might become: + +```C + AFB_REQ_INFO(req, "method 'new' called for boardid %d", board->id); +``` + +Take care of store/unstore change +--------------------------------- + +For efficiency, the version 2 redefined how storing/unstoring of +requests works. Storing request is needed for asynchronous handling +of requests. + +For ***bindings*** version, the signature of the functions were: + +```C +struct afb_req *afb_req_store(struct afb_req req); +struct afb_req afb_req_unstore(struct afb_req *req); +``` + +For version 2 it becomes + +```C +struct afb_stored_req *afb_req_store(struct afb_req req); +struct afb_req afb_req_unstore(struct afb_stored_req *sreq); +``` + +Where the structure ```struct afb_stored_req``` is opaque. + +It should require few code change. + +Also check the following chapter that explain that asynchronous (sub)calls +can be replaced by synchronous one, avoiding the need to store/unstore +requests. + +Consider use of synchronous (sub)call requests +---------------------------------------------- + +***Bindings*** can emit requests for themselves (calls) or for +their clients (subcalls). With ***bindings*** version 2 comes +also synchronous requests for both cases. + +So when migrating to bindings version 2, a developper can consider +to replace the asynchronous requests (with asynchronous call back) +by synchronous ones. + +See functions ***afb_service_call_sync*** and ***afb_req_subcall_sync***. + +Optionnaly, removes explicit struct +----------------------------------- + +The new definitions now includes **typedefs** for common +structures, as shown on below sample: + +```C +typedef struct afb_daemon afb_daemon; +typedef struct afb_event afb_event; +typedef struct afb_arg afb_arg; +typedef struct afb_req afb_req; +typedef struct afb_service afb_service; +``` + +So you can remove the keyword **struct** if it bores you. + +Example: + +```C +static void verb(struct afb_req req) +{ + ... +} +``` + +Might become: + +```C +static void verb(afb_req req) +{ + ... +} +``` + +Example of migration +-------------------- + +The first ***binding*** that migrated from v1 to v2 was +the sample **HelloWorld**. Here is shown the differences between +the version 1 and the version 2. + +```diff +diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c +index c6fa779..505aee3 100644 +--- a/bindings/samples/HelloWorld.c ++++ b/bindings/samples/HelloWorld.c +@@ -21,9 +21,9 @@ + + #include + ++#define AFB_BINDING_VERSION 2 + #include + +-const struct afb_binding_interface *interface; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + struct event +@@ -79,7 +80,7 @@ static int event_add(const char *tag, const char *name) + strcpy(e->tag, tag); + + /* make the event */ +- e->event = afb_daemon_make_event(interface->daemon, name); ++ e->event = afb_daemon_make_event(name); + if (!e->event.closure) { free(e); return -1; } + + /* link */ +@@ -140,7 +141,7 @@ static void pingBug (struct afb_req request) + static void pingEvent(struct afb_req request) + { + json_object *query = afb_req_json(request); +- afb_daemon_broadcast_event(interface->daemon, "event", json_object_get(query)); ++ afb_daemon_broadcast_event("event", json_object_get(query)); + ping(request, json_object_get(query), "event"); + } + +@@ -288,38 +289,43 @@ static void exitnow (struct afb_req request) + exit(0); + } + ++static int preinit() ++{ ++ AFB_NOTICE("hello binding comes to live"); ++ return 0; ++} ++ ++static int init() ++{ ++ AFB_NOTICE("hello binding starting"); ++ return 0; ++} ++ + // NOTE: this sample does not use session to keep test a basic as possible + // in real application most APIs should be protected with AFB_SESSION_CHECK +-static const struct afb_verb_desc_v1 verbs[]= { +- {"ping" , AFB_SESSION_NONE, pingSample , "Ping Application Framework"}, +- {"pingfail" , AFB_SESSION_NONE, pingFail , "Fails"}, +- {"pingnull" , AFB_SESSION_NONE, pingNull , "Return NULL"}, +- {"pingbug" , AFB_SESSION_NONE, pingBug , "Do a Memory Violation"}, +- {"pingJson" , AFB_SESSION_NONE, pingJson , "Return a JSON object"}, +- {"pingevent", AFB_SESSION_NONE, pingEvent , "Send an event"}, +- {"subcall", AFB_SESSION_NONE, subcall , "Call api/verb(args)"}, +- {"subcallsync", AFB_SESSION_NONE, subcallsync , "Call api/verb(args)"}, +- {"eventadd", AFB_SESSION_NONE, eventadd , "adds the event of 'name' for the 'tag'"}, +- {"eventdel", AFB_SESSION_NONE, eventdel , "deletes the event of 'tag'"}, +- {"eventsub", AFB_SESSION_NONE, eventsub , "subscribes to the event of 'tag'"}, +- {"eventunsub",AFB_SESSION_NONE, eventunsub , "unsubscribes to the event of 'tag'"}, +- {"eventpush", AFB_SESSION_NONE, eventpush , "pushs the event of 'tag' with the 'data'"}, +- {"exit", AFB_SESSION_NONE, exitnow , "exits from afb-daemon"}, +- {NULL} ++static const struct afb_verb_v2 verbs[]= { ++ { "ping" , pingSample , NULL, AFB_SESSION_NONE }, ++ { "pingfail" , pingFail , NULL, AFB_SESSION_NONE }, ++ { "pingnull" , pingNull , NULL, AFB_SESSION_NONE }, ++ { "pingbug" , pingBug , NULL, AFB_SESSION_NONE }, ++ { "pingJson" , pingJson , NULL, AFB_SESSION_NONE }, ++ { "pingevent", pingEvent , NULL, AFB_SESSION_NONE }, ++ { "subcall", subcall , NULL, AFB_SESSION_NONE }, ++ { "subcallsync", subcallsync, NULL, AFB_SESSION_NONE }, ++ { "eventadd", eventadd , NULL, AFB_SESSION_NONE }, ++ { "eventdel", eventdel , NULL, AFB_SESSION_NONE }, ++ { "eventsub", eventsub , NULL, AFB_SESSION_NONE }, ++ { "eventunsub", eventunsub , NULL, AFB_SESSION_NONE }, ++ { "eventpush", eventpush , NULL, AFB_SESSION_NONE }, ++ { "exit", exitnow , NULL, AFB_SESSION_NONE }, ++ { NULL} + }; + +-static const struct afb_binding plugin_desc = { +- .type = AFB_BINDING_VERSION_1, +- .v1 = { +- .info = "Minimal Hello World Sample", +- .prefix = "hello", +- .verbs = verbs +- } ++const struct afb_binding_v2 afbBindingV2 = { ++ .api = "hello", ++ .specification = NULL, ++ .verbs = verbs, ++ .preinit = preinit, ++ .init = init + }; + +-const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +-{ +- interface = itf; +- NOTICE(interface, "hello plugin comes to live"); +- return &plugin_desc; +-} +``` \ No newline at end of file diff --git a/docs/afb-overview.md b/docs/afb-overview.md new file mode 100644 index 00000000..67e5b0d1 --- /dev/null +++ b/docs/afb-overview.md @@ -0,0 +1,98 @@ + +Overview of the binder +====================== + +The ***binder*** provides the way to connect applications to +the services that it needs. It provides a fast way +to securely offer APIs to applications written in +any language and running almost anywhere. + +The ***binder*** is developped for AGL. + +The ***binder*** is the usual name. +The binary is named **afb-daemon**. + +The name **afb-daemon** stands for ***Application +Framework Binder Daemon***. The word *daemon*, here, +denote the fact that the ***binder*** makes witchcraft to +connect applications to their expected services (note that usually +the term of daemon denotes background process but not here). + +Each ***binder*** **afb-daemon** is in charge to bind +one instance of an application or service to the rest +of the system, applications and services. +Within AGL, the connexion between services and/or +applications is tuned by the AGL framework and +the AGL system. + +The basis of the binder +======================= + +The following figure shows main concepts linked to the ***binder***. + + +![Figure: binder basis](pictures/basis.svg) + +The shown elements are: + +* The SECURITY CONTEXT + + The primary intend of any ***binder*** is to provide + a secured environment for any application. On AGL, the + **security context** is ensured by [Smack][Smack] a security context, + the security context of the application or service. + +* The BINDER + + This is the central element. It makes possible to run HTML5 + applications and provides the unified access to APIs provided + by the ***bindings***. + + Running a pure HTML5 application doesn't require any ***binding***. + in that case , the ***binder*** acts as a simple HTTP server for + the web runtime. + +* The BINDINGs + + A ***binding*** adds one **API** to the ***binder***. + + An **API** is a set of **verbs** that can be called + using either REST over HTTP or a kind of JSON RPC. + + ***bindings*** are either: + + - dynamically loaded libraries in the ***binder*** process + - remote service running on the same host + - remote service running on other hosts + + When acting as an HTTP server, the binder treats the language + settings of the HTTP resquests to provide internationalized + content as specified by + [widget specifications](https://www.w3.org/TR/widgets/#internationalization-and-localization). + +* The APPLICATION + + An ***application*** connects to the binder to get access to + the **API** that it provides or to get its HTTP services to access + resources. + +Interconnection of binders +========================== + +The AGL framework interprets the **widget/application** manifests +to setup the ***bindings*** configuration of the ***binders***. + +The figure below shows that ***binders*** are interconnected. + + +![Figure: binder interconnection](pictures/interconnection.svg) + +The figure shows 4 several **application/service**: **A**, **B**, +**C** and **D**. + +The application **A** might use an **API** that is shown as a +local ***binbing*** but that in reality runs within the context +of **D**. + +The framework AGL takes care of making the plumbing working. + diff --git a/doc/index.md b/docs/index.md similarity index 100% rename from doc/index.md rename to docs/index.md diff --git a/doc/pictures/AFB_for_services.svg b/docs/pictures/AFB_for_services.svg similarity index 100% rename from doc/pictures/AFB_for_services.svg rename to docs/pictures/AFB_for_services.svg diff --git a/docs/pictures/basis.odg b/docs/pictures/basis.odg new file mode 100644 index 0000000000000000000000000000000000000000..6025fdbf95f958e1a7169573bc75dbbf9aab4bc0 GIT binary patch literal 15170 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 literal 0 HcmV?d00001 diff --git a/docs/pictures/basis.svg b/docs/pictures/basis.svg new file mode 100644 index 00000000..0d42d764 --- /dev/null +++ b/docs/pictures/basis.svg @@ -0,0 +1,356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + SECURITYCONTEXT + + + + + + http + + + + + + ws + + + + + + + + \ No newline at end of file diff --git a/docs/pictures/interconnection.odg b/docs/pictures/interconnection.odg new file mode 100644 index 0000000000000000000000000000000000000000..5e99bfa41b63acfcb62a7b4b92a82a22eb47a02c GIT binary patch literal 20244 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 Rd&7XlLySm<_3Q3k{TETb=DGj? literal 0 HcmV?d00001 diff --git a/docs/pictures/interconnection.svg b/docs/pictures/interconnection.svg new file mode 100644 index 00000000..4a102172 --- /dev/null +++ b/docs/pictures/interconnection.svg @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + APPLICATION + + + + + + + + BINDERafb-daemon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BINDING + + + + + + + + + + + + SECURITYCONTEXT + + + + + + + + + interconnectiondbus, ws,bus1, tls,... + + + + + + + + A + + + + + + + + C + + + + + + + + B + + + + + + + + D + + + + + + + + \ No newline at end of file diff --git a/doc/pictures/signaling-basis.svg b/docs/pictures/signaling-basis.svg similarity index 100% rename from doc/pictures/signaling-basis.svg rename to docs/pictures/signaling-basis.svg diff --git a/doc/pictures/tic-tac-toe.svg b/docs/pictures/tic-tac-toe.svg similarity index 100% rename from doc/pictures/tic-tac-toe.svg rename to docs/pictures/tic-tac-toe.svg diff --git a/doc/pictures/triskel_iot_bzh.svg b/docs/pictures/triskel_iot_bzh.svg similarity index 100% rename from doc/pictures/triskel_iot_bzh.svg rename to docs/pictures/triskel_iot_bzh.svg diff --git a/mkdocs.yml b/mkdocs.yml index 87bd6230..b2f24aca 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,11 +1,15 @@ site_name: AGL Application Framework Binder theme: readthedocs -docs_dir: doc +docs_dir: docs pages: - 'Overview' : 'index.md' - - 'Binder daemon vocabulary' : 'afb-daemon-vocabulary.md' + - 'How to write a binding ?': 'afb-binding-writing.md' + - 'Binding references': 'afb-binding-references.md' + - 'Migration from v1 to v2' : 'afb-migration-v1-to-v2.md' - 'Binder events guide' : 'afb-events-guide.md' - 'Binder Application writing guide' : 'afb-application-writing.md' - - 'Binding writing guide' : 'afb-bindings-writing.md' - - 'Binder tests overview' : 'afb-tests-overview.md' - - 'Bindings samples' : 'afb-bindings-overview.md' + - 'Binder daemon vocabulary' : 'afb-daemon-vocabulary.md' + - 'Annexes': + - 'Installing the binder on a desktop': 'afb-desktop-package.md' + - 'Options of afb-daemon' : 'afb-daemon-options.md' + diff --git a/old-docs/FAQ.md b/old-docs/FAQ.md new file mode 100644 index 00000000..5063ed74 --- /dev/null +++ b/old-docs/FAQ.md @@ -0,0 +1,5 @@ +Frequently Asked Question about AFB-DAEMON +========================================== + + + diff --git a/old-docs/afb-application-writing.md b/old-docs/afb-application-writing.md new file mode 100644 index 00000000..cc513b48 --- /dev/null +++ b/old-docs/afb-application-writing.md @@ -0,0 +1,301 @@ +How to write an application on top of AGL FRAMEWORK +==================================================== + +Programming Languages for Applications +----------------------------------------- + +### Writing an HTML5 application + +Developers of HTML5 applications (client side) can easily create +applications for AGL framework using their preferred +HTML5 framework. + +Developers may also take advantage of powerful server side bindings to improve +application behavior. Server side bindings return an application/json mine-type +and can be accessed though either HTTP or Websockets. + +In a near future, JSON-RPC protocol should be added to complete the current +x-afb-json1 protocol. + +Two examples of HTML5 applications are given: + +- [afb-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afb-client) a simple "hello world" application template + +- [afm-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afm-client) a simple "Home screen" application template + +### Writing a Qt application + +Writing Qt applications is also supported. Qt offers standard API to send +request through HTTP or WebSockets. + +It is also possible to write QML applications. A sample QML application +[token-websock] is available: + +- [token-websock](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=test/token-websock.qml) +a simple "hello world" application in QML + +### Writing a "C" application + +C applications can use afb-daemon binder through a websocket connection. + +The library **libafbwsc** is provided for C clients that need +to connect with an afb-daemon binder. + +The program **afb-client-demo** is the C example that use +**libafbwsc** library. +Source code is available here +[src/afb-client-demo.c](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=src/afb-client-demo.c). + +Current implementation relies on libsystemd and file descriptors. +This model might be review in the future to support secure sockets +and get rid of libsystemd dependency. + +Handling sessions within applications +------------------------------------- + +Applications should understand sessions and token management when interacting +with afb-daemon binder. + +Applications communicate with their private binder(afb-daemon) using +a network connection or potentially any other connection channel. While the +current version does not yet implement Unix socket, this feature might be added +in the near future. Developers need to be warn that HTTP protocol is a none +connected protocol and that using HTTP socket connection to authenticate +clients is not supported. + +For this reason, the binder should authenticate the application +by using a shared secret. The secret is named "token" and the identification +of client is named "session". + +The examples **token-websock.qml** and **afb-client** are demonstrating +how authentication and sessions are managed. + +### Handling sessions + +Bindings and other binder features need to keep track of client +instances. This is especially important for bindings running as services +as they may typically have to keep each client's data separated. + +For HTML5 applications, the web runtime handles the cookie of session +that the binder afb-daemon automatically sets. + +Session identifier can be set using the parameter **uuid** or **x-afb-uuid** in +URI requests. Within current version of the framework session UUID is supported +by both HTTP requests and websocket negotiation. + +### Exchanging tokens + +At application start, AGL framework communicates a shared secret to both binder +and client application. This initial secret is called the "**initial token**". + +For each of its client application, the binder manages a current active +token for session management. This authentication token can be use to restrict +the access to some binding's methods. + +The token must be included in URI request on HTTP or during websockets +connection using parameter **token** or **x-afb-token**. + +To ensure security, tokens must be refreshed periodically. + +### Example of session management + +In following examples, we suppose that **afb-daemon** is launched with something +equivalent to: + + $ afb-daemon --port=1234 --token=123456 [...] + +making the expectation that **AuthLogin** binding is requested as default. + +#### Using curl + +First, connects with the initial token, 123456: + + $ curl http://localhost:1234/api/auth/connect?token=123456 + { + "jtype": "afb-reply", + "request": { + "status": "success", + "token": "0aef6841-2ddd-436d-b961-ae78da3b5c5f", + "uuid": "850c4594-1be1-4e9b-9fcc-38cc3e6ff015" + }, + "response": {"token": "A New Token and Session Context Was Created"} + } + +It returns an answer containing session UUID, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015, +and a refreshed token, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015. + +Check if session and token is valid: + + $ curl http://localhost:1234/api/auth/check?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": {"status":"success"}, + "response": {"isvalid":true} + } + +Refresh the token: + + $ curl http://localhost:1234/api/auth/refresh?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": { + "status":"success", + "token":"b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9" + }, + "response": {"token":"Token was refreshed"} + } + +Close the session: + + curl http://localhost:1234/api/auth/logout?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": {"status": "success"}, + "response": {"info":"Token and all resources are released"} + } + +Checking on closed session for uuid should be refused: + + curl http://localhost:1234/api/auth/check?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": { + "status": "failed", + "info": "invalid token's identity" + } + } + +#### Using afb-client-demo + +> The program is packaged within AGL in the rpm **libafbwsc-dev** + +Here is an example of exchange using **afb-client-demo**: + + $ afb-client-demo ws://localhost:1234/api?token=123456 + auth connect + ON-REPLY 1:auth/connect: {"jtype":"afb-reply","request":{"status":"success", + "token":"63f71a29-8b52-4f9b-829f-b3028ba46b68","uuid":"5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1"}, + "response":{"token":"A New Token and Session Context Was Created"}} + auth check + ON-REPLY 2:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + auth refresh + ON-REPLY 4:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", + "token":"8b8ba8f4-1b0c-48fa-962d-4a00a8c9157e"},"response":{"token":"Token was refreshed"}} + auth check + ON-REPLY 5:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + auth refresh + ON-REPLY 6:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", + "token":"e83b36f8-d945-463d-b983-5d8ed73ba529"},"response":{"token":"Token was refreshed"}} + +After closing connection, reconnect as here after: + + $ afb-client-demo ws://localhost:1234/api?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 auth check + ON-REPLY 1:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + +Same connection check using **curl**: + + $ curl http://localhost:1234/api/auth/check?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 + {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + +Format of replies +----------------- + +Replies use javascript object returned as serialized JSON. + +This object contains at least 2 mandatory fields of name **jtype** and +**request** and one optional field of name **response**. + +### Template + +This is a template of replies: + +```json +{ + "jtype": "afb-reply", + "request": { + "status": "success", + "info": "informationnal text", + "token": "e83b36f8-d945-463d-b983-5d8ed73ba52", + "uuid": "5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1", + "reqid": "application-generated-id-23456" + }, + "response": ....any response object.... +} +``` + +### Field jtype + +The field **jtype** must have a value of type string equal to **"afb-reply"**. + +### Field request + +The field **request** must have a value of type object. This request object +has at least one field named **status** and four optional fields named +**info**, **token**, **uuid**, **reqid**. + +#### Subfield request.status + +**status** must have a value of type string. This string is equal to **"success"** +only in case of success. + +#### Subfield request.info + +**info** is of type string and represent optional information added to the reply. + +#### Subfield request.token + +**token** is of type string. It is sent either at session creation +or when the token is refreshed. + +#### Subfield request.uuid + +**uuid** is of type string. It is sent at session creation. + +#### Subfield request.reqid + +**reqid** is of type string. It is sent in response to HTTP requests +that added a parameter of name **reqid** or **x-afb-reqid** at request time. +Value returns in the reply has the exact same value as the one received in the +request. + +### Field response + +This field response optionally contains an object returned when request +succeeded. + +Format of events +---------------- + +Events are javascript object serialized as JSON. + +This object contains at least 2 mandatory fields of name **jtype** and **event** +and one optional field of name **data**. + +### Template + +Here is a template of event: + +```json +{ + "jtype": "afb-event", + "event": "sample_api_name/sample_event_name", + "data": ...any event data... +} +``` + +### Field jtype + +The field **jtype** must have a value of type string equal to **"afb-event"**. + +### Field event + +The field **event** carries the event's name. + +The name of the event is made of two parts separated by a slash: +the name of the name of the API that generated the event +and the name of event within the API. + +### Field data + +This field data if present holds the data carried by the event. + diff --git a/doc/afb-bindings-overview.md b/old-docs/afb-bindings-overview.md similarity index 100% rename from doc/afb-bindings-overview.md rename to old-docs/afb-bindings-overview.md diff --git a/doc/afb-bindings-writing.md b/old-docs/afb-bindings-writing.md similarity index 100% rename from doc/afb-bindings-writing.md rename to old-docs/afb-bindings-writing.md diff --git a/old-docs/afb-daemon-vocabulary.md b/old-docs/afb-daemon-vocabulary.md new file mode 100644 index 00000000..c3b7c1ea --- /dev/null +++ b/old-docs/afb-daemon-vocabulary.md @@ -0,0 +1,98 @@ + +Vocabulary for AFB-DAEMON +========================= + +## Binding + +A shared library object intended to add a functionality to an afb-daemon +instance. It implements an API and may provide a service. + +Binding made for services can have specific entry point called after +initialisation and before serving. + +## Event + +Message with data propagated from the services to the client and not expecting +any reply. + +The current implementation allows to widely broadcast events to all clients. + +## Level of assurance (LOA) + +This level that can be from 0 to 3 represent the level of +assurance that the services can expect from the session. + +The exact definition of the meaning of these levels and how to use it remains to +be achieved. + +## Plugin + +Old name for binding, see binding. + +## Request + +A request is an invocation by a client to a binding method using a message +transferred through some protocol: HTTP, WebSocket, DBUS... and served by +***afb-daemon*** + +## Reply/Response + +This is a message sent to client as the result of the request. + +## Service + +Service are made of bindings running by their side on their binder. +It can serve many client. Each one attached to one session. + +The framework establishes connection between the services and +the clients. Using DBus currently but other protocols are considered. + +## Session + +A session is meant to be the unique instance context of a client, +which identify that instance across requests. + +Each session has an identifier. Session identifier generated by afb-daemon are +UUIDs. + +Internally, afb-daemon offers a mechanism to attach data to sessions. +When the session is closed or disappears, the data attached to that session +are freed. + +## Token + +The token is an identifier that the client must give to be authenticated. + +At start, afb-daemon get an initial token. This initial token must be presented +by incoming client to be authenticated. + +A token is valid only for a period. + +The token must be renewed periodically. When the token is renewed, afb-daemon +sends the new token to the client. + +Tokens generated by afb-daemon are UUIDs. + +## UUID + +It stand for Universal Unique IDentifier. + +It is designed to create identifier in a way that avoid has much as possible +conflicts. It means that if two different instances create an UUID, the +probability that they create the same UUID is very low, near to zero. + +## x-afb-reqid + +Argument name that can be used with HTTP request. When this argument is given, +it is automatically added to the "request" object of the answer. + +## x-afb-token + +Argument name meant to give the token without ambiguity. +You can also use the name **token** but it may conflicts with others arguments. + +## x-afb-uuid + +Argument name for giving explicitly the session identifier without ambiguity. +You can also use the name **uuid** but it may conflicts with others arguments. + diff --git a/doc/afb-events-guide.md b/old-docs/afb-events-guide.md similarity index 100% rename from doc/afb-events-guide.md rename to old-docs/afb-events-guide.md diff --git a/doc/afb-overview.md b/old-docs/afb-overview.md similarity index 100% rename from doc/afb-overview.md rename to old-docs/afb-overview.md diff --git a/doc/afb-tests-overview.md b/old-docs/afb-tests-overview.md similarity index 100% rename from doc/afb-tests-overview.md rename to old-docs/afb-tests-overview.md diff --git a/old-docs/index.md b/old-docs/index.md new file mode 120000 index 00000000..81c25433 --- /dev/null +++ b/old-docs/index.md @@ -0,0 +1 @@ +afb-overview.md \ No newline at end of file diff --git a/old-docs/pictures/AFB_for_services.svg b/old-docs/pictures/AFB_for_services.svg new file mode 100644 index 00000000..6e536c50 --- /dev/null +++ b/old-docs/pictures/AFB_for_services.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Isolated security context + + + + + + + + APPLICATION + + + + + + + + binderAFB-DAEMON + + + + + + + + BINDINGS + + + + + + + + + + + + + + + + + + + + + D-Bus & CYNARA + + + + + + + + Isolated security context A + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS A + + + + + + + + + + + + + + + Isolated security context B + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS B + + + + + + + + + + + + + + + Isolated security context C + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS C + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/pictures/AFB_overview.svg b/old-docs/pictures/AFB_overview.svg similarity index 100% rename from doc/pictures/AFB_overview.svg rename to old-docs/pictures/AFB_overview.svg diff --git a/old-docs/pictures/signaling-basis.svg b/old-docs/pictures/signaling-basis.svg new file mode 100644 index 00000000..b13fcf17 --- /dev/null +++ b/old-docs/pictures/signaling-basis.svg @@ -0,0 +1,145 @@ + + + + + + + request-data + + + + + + client 1 + + + + + + + + client 2 + + + + + + + + : framework + + + + + + + + signaling agent + + + + + + + + + + + request-data + + + + + + afb_daemon_make_event + + + + + + + + + afb_req_subscribe + + + + + reply of request-data + + + + + + afb_req_subscribe + + + + + reply of request-data + + + + + + device + + + + + + + + + setup + + + + + << wake up >> + + + + + afb_event_push + + + + + << event >> + + + + + << event >> + + + + + reply of afb_event_push + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/old-docs/pictures/tic-tac-toe.svg b/old-docs/pictures/tic-tac-toe.svg new file mode 100644 index 00000000..7a5fb84e --- /dev/null +++ b/old-docs/pictures/tic-tac-toe.svg @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tic-Tac-Toe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + move + + + + + + wait + + + + + + success of move + + + + + + success of wait + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/old-docs/pictures/triskel_iot_bzh.svg b/old-docs/pictures/triskel_iot_bzh.svg new file mode 100644 index 00000000..096f4244 --- /dev/null +++ b/old-docs/pictures/triskel_iot_bzh.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + -- 2.16.6