From 4521c1e7ae5371ab9d639adc617d17fb4e8ded0c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Mon, 9 Apr 2018 18:16:07 +0200 Subject: [PATCH] api-v3: First draft MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This commit introduces the bindings v3 API for bindings. The documentation has still to be improved and will come very soon. Change-Id: I8f9007370e29f671fdfd1da87fff7372a17db7af Signed-off-by: José Bollo --- .gitignore | 2 + CMakeLists.txt | 5 +- README.md | 166 +- bindings/intrinsics/afb-dbus-binding.c | 40 +- bindings/samples/AuthLogin.c | 41 +- bindings/samples/CMakeLists.txt | 24 + bindings/samples/DemoContext.c | 83 +- bindings/samples/DemoPost.c | 43 +- bindings/samples/HelloWorld.c | 113 +- bindings/samples/ave.c | 19 +- bindings/samples/hello3.c | 486 ++++ bindings/samples/hi3.c | 485 ++++ bindings/samples/tic-tac-toe.c | 237 +- bindings/tutorial/tuto-1.c | 10 +- bindings/tutorial/tuto-2.c | 40 +- bindings/tutorial/tuto-3.cpp | 28 +- book.json | 4 +- docs/README.md | 32 +- docs/REVISIONS.md | 14 + docs/SUMMARY.md | 9 +- docs/afb-binding-references.md | 283 ++- docs/afb-binding-writing.md | 180 +- docs/afb-daemon-debugging.md | 2 +- docs/afb-daemon-vocabulary.md | 6 +- docs/afb-migration-to-binding-v3.md | 110 + docs/afb-migration-v1-to-v2.md | 7 +- docs/afb-overview.md | 6 +- docs/annexes.md | 5 +- docs/migration-to-binding-v3.sed | 68 + doxyfile.binder | 2435 ++++++++++++++++++++ doxyfile.binding | 2434 +++++++++++++++++++ include/afb/afb-api-x3-itf.h | 262 +++ include/afb/afb-api-x3.h | 884 +++++++ include/afb/afb-arg.h | 33 + include/afb/afb-auth.h | 49 +- include/afb/afb-binding-postdefs.h | 92 + include/afb/afb-binding-predefs.h | 372 +++ include/afb/afb-binding-v1.h | 188 +- include/afb/afb-binding-v2.h | 185 +- include/afb/afb-binding-v3.h | 262 +++ include/afb/afb-binding-vdyn.h | 95 - include/afb/afb-binding.h | 283 +-- include/afb/afb-binding.hpp | 334 ++- include/afb/afb-daemon-itf-x1.h | 91 + include/afb/afb-daemon-itf.h | 59 - include/afb/afb-daemon-v1.h | 101 +- include/afb/afb-daemon-v2.h | 76 +- include/afb/afb-dynapi-itf.h | 166 -- include/afb/afb-dynapi-legacy.h | 191 ++ include/afb/afb-dynapi.h | 302 --- include/afb/afb-event-x1-itf.h | 32 + include/afb/{afb-event.h => afb-event-x1.h} | 55 +- .../afb/{afb-eventid-itf.h => afb-event-x2-itf.h} | 42 +- include/afb/afb-event-x2.h | 113 + include/afb/afb-eventid.h | 83 - include/afb/afb-req-v1.h | 20 +- include/afb/afb-req-v2.h | 10 +- include/afb/{afb-req-itf.h => afb-req-x1-itf.h} | 14 +- include/afb/{afb-req.h => afb-req-x1.h} | 268 ++- include/afb/afb-req-x2-itf.h | 306 +++ include/afb/afb-req-x2.h | 758 ++++++ include/afb/afb-request-itf.h | 205 -- include/afb/afb-request.h | 389 ---- .../{afb-service-itf.h => afb-service-itf-x1.h} | 23 +- include/afb/afb-service-v1.h | 10 +- include/afb/afb-service-v2.h | 6 +- include/afb/afb-session-v1.h | 59 - include/afb/afb-session-v2.h | 38 - include/afb/afb-session-x1.h | 61 + include/afb/afb-session-x2.h | 38 + include/afb/afb-verbosity.h | 43 +- memo-supervisor.txt | 11 + memo-v3.txt | 9 + mkdocs.yml | 2 +- src/CMakeLists.txt | 28 +- src/afb-api-dbus.c | 129 +- src/afb-api-dbus.h | 4 +- src/afb-api-dyn.c | 285 --- src/afb-api-dyn.h | 63 - src/afb-api-so-v1.c | 139 +- src/afb-api-so-v1.h | 10 +- src/afb-api-so-v2.c | 125 +- src/afb-api-so-v2.h | 9 +- src/afb-api-so-v3.c | 128 + src/afb-api-so-v3.h | 23 + src/afb-api-so-vdyn.c | 27 +- src/afb-api-so-vdyn.h | 2 +- src/afb-api-so.c | 86 +- src/afb-api-so.h | 12 +- src/afb-api-v3.c | 358 +++ src/afb-api-v3.h | 81 + src/afb-api-ws.c | 23 +- src/afb-api-ws.h | 8 +- src/afb-api.c | 4 +- src/afb-api.h | 13 +- src/afb-apiset.c | 823 +++++-- src/afb-apiset.h | 47 +- src/afb-auth.c | 60 +- src/afb-autoset.c | 104 + src/afb-autoset.h | 23 + src/afb-calls.c | 818 +++++++ src/afb-calls.h | 235 ++ src/afb-config.c | 236 +- src/afb-config.h | 52 +- src/afb-context.c | 11 +- src/afb-cred.c | 110 + src/afb-cred.h | 7 + src/afb-evt.c | 147 +- src/afb-evt.h | 30 +- src/afb-export.c | 1774 ++++++++------ src/afb-export.h | 115 +- src/afb-hook.c | 928 ++++---- src/afb-hook.h | 375 +-- src/afb-hreq.c | 43 +- src/afb-monitor.c | 96 +- src/afb-monitor.h | 4 +- src/afb-msg-json.c | 21 +- src/afb-msg-json.h | 4 +- src/afb-proto-ws.c | 306 +-- src/afb-proto-ws.h | 23 +- src/afb-session.c | 92 +- src/afb-stub-ws.c | 138 +- src/afb-stub-ws.h | 4 +- src/afb-supervision.c | 39 +- src/afb-trace.c | 591 +++-- src/afb-trace.h | 4 +- src/afb-ws-json1.c | 16 +- src/afb-xreq.c | 977 +++----- src/afb-xreq.h | 89 +- src/afs-config.c | 6 +- src/afs-supervision.h | 2 +- src/afs-supervisor.c | 133 +- src/afs-supervisor.h | 5 +- src/devtools/genskel.c | 108 +- src/devtools/monitor-api.json | 11 +- src/jobs-fake.c | 4 +- src/jobs.c | 2 +- src/{afb-client-demo.c => main-afb-client-demo.c} | 83 +- src/{main.c => main-afb-daemon.c} | 56 +- src/{afs-main.c => main-afs-supervisor.c} | 4 +- src/monitor-api.inc | 39 +- src/pearson.c | 39 + src/pearson.h | 20 + src/tests/CMakeLists.txt | 2 + src/tests/apiset/CMakeLists.txt | 23 + src/tests/apiset/test-apiset.c | 579 +++++ src/tests/apiv3/CMakeLists.txt | 24 + src/tests/apiv3/test-apiv3.c | 198 ++ src/tests/session/test-session.c | 2 +- src/verbose.c | 152 +- src/verbose.h | 50 +- src/wrap-json.c | 432 +++- src/wrap-json.h | 19 + test/monitoring/monitor.js | 4 +- test/tic-tac-toe.html | 87 + 155 files changed, 19209 insertions(+), 6811 deletions(-) create mode 100644 bindings/samples/hello3.c create mode 100644 bindings/samples/hi3.c create mode 100644 docs/REVISIONS.md create mode 100644 docs/afb-migration-to-binding-v3.md create mode 100644 docs/migration-to-binding-v3.sed create mode 100644 doxyfile.binder create mode 100644 doxyfile.binding create mode 100644 include/afb/afb-api-x3-itf.h create mode 100644 include/afb/afb-api-x3.h create mode 100644 include/afb/afb-arg.h create mode 100644 include/afb/afb-binding-postdefs.h create mode 100644 include/afb/afb-binding-predefs.h create mode 100644 include/afb/afb-binding-v3.h delete mode 100644 include/afb/afb-binding-vdyn.h create mode 100644 include/afb/afb-daemon-itf-x1.h delete mode 100644 include/afb/afb-daemon-itf.h delete mode 100644 include/afb/afb-dynapi-itf.h create mode 100644 include/afb/afb-dynapi-legacy.h delete mode 100644 include/afb/afb-dynapi.h create mode 100644 include/afb/afb-event-x1-itf.h rename include/afb/{afb-event.h => afb-event-x1.h} (68%) rename include/afb/{afb-eventid-itf.h => afb-event-x2-itf.h} (50%) create mode 100644 include/afb/afb-event-x2.h delete mode 100644 include/afb/afb-eventid.h rename include/afb/{afb-req-itf.h => afb-req-x1-itf.h} (70%) rename include/afb/{afb-req.h => afb-req-x1.h} (62%) create mode 100644 include/afb/afb-req-x2-itf.h create mode 100644 include/afb/afb-req-x2.h delete mode 100644 include/afb/afb-request-itf.h delete mode 100644 include/afb/afb-request.h rename include/afb/{afb-service-itf.h => afb-service-itf-x1.h} (71%) delete mode 100644 include/afb/afb-session-v1.h delete mode 100644 include/afb/afb-session-v2.h create mode 100644 include/afb/afb-session-x1.h create mode 100644 include/afb/afb-session-x2.h create mode 100644 memo-v3.txt delete mode 100644 src/afb-api-dyn.c delete mode 100644 src/afb-api-dyn.h create mode 100644 src/afb-api-so-v3.c create mode 100644 src/afb-api-so-v3.h create mode 100644 src/afb-api-v3.c create mode 100644 src/afb-api-v3.h create mode 100644 src/afb-autoset.c create mode 100644 src/afb-autoset.h create mode 100644 src/afb-calls.c create mode 100644 src/afb-calls.h rename src/{afb-client-demo.c => main-afb-client-demo.c} (84%) rename src/{main.c => main-afb-daemon.c} (89%) rename src/{afs-main.c => main-afs-supervisor.c} (98%) create mode 100644 src/pearson.c create mode 100644 src/pearson.h create mode 100644 src/tests/apiset/CMakeLists.txt create mode 100644 src/tests/apiset/test-apiset.c create mode 100644 src/tests/apiv3/CMakeLists.txt create mode 100644 src/tests/apiv3/test-apiv3.c create mode 100644 test/tic-tac-toe.html diff --git a/.gitignore b/.gitignore index 6ca8cc56..b65071cc 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ node_modules/ _book/ *.kdev4 nbproject/* +docs/binding +docs/binder diff --git a/CMakeLists.txt b/CMakeLists.txt index cda81908..2213f05d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ PROJECT(afb-daemon C CXX) SET(PROJECT_NAME "AFB Daemon") SET(PROJECT_PRETTY_NAME "Application Framework Binder Daemon") SET(PROJECT_DESCRIPTION "Secured binder of API for clients of the Application framework") -SET(PROJECT_VERSION "5.99-FFRC0") +SET(PROJECT_VERSION "5.99-FFRC1") set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=summary") SET(LIBAFBWSC_VERSION "1.1") @@ -37,10 +37,13 @@ INCLUDE(CTest) ########################################################################### # possible settings + set(AGL_DEVEL OFF CACHE BOOL "Activates developping features") set(INCLUDE_MONITORING OFF CACHE BOOL "Activates installation of monitoring") set(INCLUDE_SUPERVISOR OFF CACHE BOOL "Activates installation of supervisor") set(INCLUDE_DBUS_TRANSPARENCY OFF CACHE BOOL "Allows API transparency over DBUS") +set(INCLUDE_LEGACY_BINDING_V1 OFF CACHE BOOL "Includes the legacy Binding API version 1") +set(INCLUDE_LEGACY_BINDING_VDYN OFF CACHE BOOL "Includes the legacy Binding API version dynamic") set(AFS_SUPERVISION_SOCKET "@urn:AGL:afs:supervision:socket" CACHE STRING "Internal socket for supervision") set(AFS_SUPERVISOR_PORT 1619 CACHE STRING "Port of service for the supervisor") set(AFS_SUPERVISOR_TOKEN HELLO CACHE STRING "Secret token for the supervisor") diff --git a/README.md b/README.md index e548bbb9..e69966e9 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,154 @@ -### Application Framework Binder -This is an undergoing work, publication is only intended for developers to review and provide feedback. +# AGL Framework Binder -### License -Apache 2 +This project provides the binder component of the the microservice architecture +of Automotive Grade Linux (AGL). + +This project is available there https://git.automotivelinux.org/src/app-framework-binder/ + +It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**. + + +## License and copying + +This software is an open source software funded by LinuxFoundation and Renesas. + +This software is delivered under the terms of the open source license Apache 2. + +This license is available in the file LICENSE-2.0.txt or on the worl wide web at the +location https://opensource.org/licenses/Apache-2.0 + + +## Building + +### Requirements + +Building the AGL framework binder has been tested under + **Ubuntu**, **Debian** and **Fedora 26** with gcc 6 and 7. + +It requires the following libraries: -### Building -Building Application Framework Binder has been tested under **Ubuntu 16.04 LTS (Xenial Xerus)** or **Fedora 23**, and requires the following libraries: * libmagic ("libmagic-dev" under Ubuntu, "file-devel" under Fedora); - * libmicrohttpd >= 0.9.48 (fetch and build from "http://ftp.gnu.org/gnu/libmicrohttpd"); + * libmicrohttpd >= 0.9.55 (fetch and build from "http://ftp.gnu.org/gnu/libmicrohttpd"); * json-c ("libjson-c-dev/devel"); * uuid ("uuid-dev/libuuid-devel"); * openssl ("libssl-dev/openssl-devel"); * systemd >= 222 ("libsystemd-dev/systemd-devel"); -Optionally, for plugins : - * alsa ("libasound2-dev/alsa-devel"); - * pulseaudio ("libpulse-dev/libpulse-devel"); - * rtl-sdr >= 0.5.0 ("librtlsdr-dev", or fetch and build from "git://git.osmocom.org/rtl-sdr" under Fedora); - * GUPnP ("libglib2.0-dev libgupnp-av-1.0-dev/glib2-devel libgupnp-av-devel"); +The following library can be used for checking permissions: -Libmicrohttpd : - * version >= 0.9.54 + * cynara (https://github.com/Samsung/cynara) and the following tools: + * gcc; - * make; * pkg-config; - * cmake >= 2.8.8. + * cmake >= 3.0 To install all dependencies under Ubuntu (excepting libmicrohttpd), please type: -``` -$ apt-get install libmagic-dev libjson-c-dev uuid-dev libsystemd-dev libssl-dev libasound2-dev libpulse-dev librtlsdr-dev libglib2.0-dev libgupnp-av-1.0-dev gcc make pkg-config cmake -``` + + $ apt-get install libmagic-dev libjson-c-dev uuid-dev libsystemd-dev libssl-dev gcc make pkg-config cmake + or under Fedora (excepting libmicrohttpd and rtl-sdr): -``` -$ dnf install git passwd iproute openssh-server openssh-client openssh-server # Tools needed on top of Docker Minimal Fedora -$ dnf install file-devel gcc gdb make pkgconfig cmake # install gcc development tool chain + cmake -$ dnf install file-devel json-c-devel libuuid-devel systemd-devel openssl-devel -$ dnf install alsa-lib-devel pulseaudio-libs-devel glib2-devel gupnp-av-devel # optional but require to build audio plugin -``` - To build, move to your HOME directory and type: -``` -$ LIB_MH_VERSION=0.9.54 -$ export LIBMICRODEST=/opt/libmicrohttpd-${LIB_MH_VERSION} -$ wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-${LIB_MH_VERSION}.tar.gz -$ tar -xzf libmicrohttpd-${LIB_MH_VERSION}.tar.gz -$ cd libmicrohttpd-${LIB_MH_VERSION} -$ ./configure --prefix=${LIBMICRODEST} -$ make -$ sudo make install-strip - -$ AFB_DAEMON_DIR=$HOME/app-framework-binder -$ git clone https://gerrit.automotivelinux.org/gerrit/src/app-framework-binder ${AFB_DAEMON_DIR} -$ cd ${AFB_DAEMON_DIR} -$ mkdir -p build; cd build
-$ export PKG_CONFIG_PATH=${LIBMICRODEST}/lib/pkgconfig -$ cmake ..
-$ make; -$ sudo make install
-``` + $ dnf install git passwd iproute openssh-server openssh-client + $ dnf install file-devel gcc gdb make pkgconfig cmake + $ dnf install json-c-devel libuuid-devel systemd-devel openssl-devel + +### Simple compilation + +The following commands will install the binder in your subdirectory +**$HOME/local** (instead of **/usr/local** the default when +*CMAKE_INSTALL_PREFIX* isn't set). + + $ git clone https://git.automotivelinux.org/src/app-framework-binder + $ cd app-framework-binder + $ mkdir build + $ cd build + $ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local .. + $ make install + +### Advanced compilation + +You can tune options when calling cmake. Here are the known options with +their default values. + + $ git clone https://git.automotivelinux.org/src/app-framework-binder + $ cd app-framework-binder + $ mkdir build + $ cd build + $ cmake \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DAGL_DEVEL=OFF \ + -DINCLUDE_MONITORING=OFF \ + -DINCLUDE_SUPERVISOR=OFF \ + -DINCLUDE_DBUS_TRANSPARENCY=OFF \ + -DINCLUDE_LEGACY_BINDING_V1=OFF \ + -DINCLUDE_LEGACY_BINDING_VDYN=OFF \ + -DAFS_SUPERVISOR_PORT=1619  \ + -DAFS_SUPERVISOR_TOKEN="HELLO" \ + -DAFS_SUPERVISION_SOCKET="@urn:AGL:afs:supervision:socket" \ + -DUNITDIR_SYSTEM=${CMAKE_INSTALL_LIBDIR}/systemd/system \ + .. + $ make install + +The configuration options are: + +| Variable | Type | Feature +|:----------------------------|:-------:|:------------------------------ +| AGL_DEVEL | BOOLEAN | Activates development features +| INCLUDE_MONITORING | BOOLEAN | Activates installation of monitoring +| INCLUDE_SUPERVISOR | BOOLEAN | Activates installation of supervisor +| INCLUDE_DBUS_TRANSPARENCY | BOOLEAN | Allows API transparency over DBUS +| INCLUDE_LEGACY_BINDING_V1 | BOOLEAN | Includes the legacy Binding API version 1 +| INCLUDE_LEGACY_BINDING_VDYN | BOOLEAN | Includes the legacy Binding API version dynamic +| AFS_SUPERVISOR_PORT | INTEGER | Port of service for the supervisor +| AFS_SUPERVISOR_TOKEN | STRING | Secret token for the supervisor +| AFS_SUPERVISION_SOCKET | STRING | Internal socket path for supervision (internal if starts with @) +| UNITDIR_SYSTEM | STRING | Path to systemd system unit files for installing supervisor + + + + +***** TO BE COMPLETED ***** + + + + + + + + + + + + +## Simple demo + -### Archive -``` -VERSION=2.0 -GIT_TAG=master -PKG_NAME=app-framework-binder -git archive --format=tar.gz --prefix=agl-${PKG_NAME}-${VERSION}/ ${GIT_TAG} -o agl-${PKG_NAME}_${VERSION}.orig.tar.gz -``` ### Testing/Debug + ``` $ ${AFB_DAEMON_DIR}/build/src/afb-daemon --help $ ${AFB_DAEMON_DIR}/build/src/afb-daemon --port=1234 --token='' --ldpaths=${AFB_DAEMON_DIR}/build --sessiondir=/tmp --rootdir=${AFB_DAEMON_DIR}/test ``` ### Starting + ``` $ afb-daemon --help $ afb-daemon --verbose --port= --token='' --sessiondir= --rootdir= ``` ### Example + ``` $ afb-daemon --verbose --port=1234 --token='' --sessiondir=/tmp --rootdir=/srv/www/htdocs --alias=icons:/usr/share/icons ``` ### Directories & Paths + Default behaviour is to locate ROOTDIR in $HOME/.AFB ### REST API @@ -136,4 +197,3 @@ Only use alias for external support static files. This should not be used for AP ### Ongoing work Javascript plugins. As of today, only C plugins are supported, but JS plugins are on the TODO list. - diff --git a/bindings/intrinsics/afb-dbus-binding.c b/bindings/intrinsics/afb-dbus-binding.c index a5b7d788..51474f6b 100644 --- a/bindings/intrinsics/afb-dbus-binding.c +++ b/bindings/intrinsics/afb-dbus-binding.c @@ -23,14 +23,9 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include -/* - * the interface to afb-daemon - */ -const struct afb_binding_interface *afbitf; - /* * union of possible dbus values */ @@ -497,7 +492,7 @@ error: /* * handle the reply */ -static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error) +static int on_rawcall_reply(sd_bus_message *msg, afb_req_t *req, sd_bus_error *ret_error) { struct json_object *obj = NULL; int rc; @@ -532,7 +527,7 @@ static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_err * "arguments": "ARRAY of arguments" * } */ -static void rawcall(struct afb_req req) +static void rawcall(afb_req_t req) { struct json_object *obj; struct json_object *args; @@ -569,9 +564,9 @@ static void rawcall(struct afb_req req) /* get bus */ busname = strval(obj, "bus"); if (busname != NULL && !strcmp(busname, "system")) - bus = afb_daemon_get_system_bus(afbitf->daemon); + bus = afb_api_get_system_bus(req->api); else - bus = afb_daemon_get_user_bus(afbitf->daemon); + bus = afb_api_get_user_bus(req->api); /* creates the message */ rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member); @@ -601,32 +596,19 @@ cleanup: /* * array of the verbs exported to afb-daemon */ -static const struct afb_verb_desc_v1 binding_verbs[] = { +static const struct afb_verb_v3 binding_verbs[] = { /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ - { .name= "rawcall", .session= AFB_SESSION_NONE, .callback= rawcall, .info= "raw call to dbus method" }, - { .name= NULL } /* marker for end of the array */ + { .verb= "rawcall", .session= AFB_SESSION_NONE, .callback= rawcall, .info= "raw call to dbus method" }, + { .verb= NULL } /* marker for end of the array */ }; /* * description of the binding for afb-daemon */ -static const struct afb_binding binding_description = +const struct afb_binding_v3 afbBindingV3 = { - /* description conforms to VERSION 1 */ - .type= AFB_BINDING_VERSION_1, - .v1= { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */ - .prefix= "dbus", /* the API name (or binding name or prefix) */ - .info= "raw dbus binding", /* short description of of the binding */ + .api = "dbus", /* the API name (or binding name or prefix) */ + .info = "raw dbus binding", /* short description of of the binding */ .verbs = binding_verbs /* the array describing the verbs of the API */ - } }; -/* - * activation function for registering the binding called by afb-daemon - */ -const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) -{ - afbitf = itf; /* records the interface for accessing afb-daemon */ - return &binding_description; /* returns the description of the binding */ -} - diff --git a/bindings/samples/AuthLogin.c b/bindings/samples/AuthLogin.c index a71f7d6e..0f29dd0d 100644 --- a/bindings/samples/AuthLogin.c +++ b/bindings/samples/AuthLogin.c @@ -19,7 +19,7 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include // Dummy sample of Client Application Context @@ -37,7 +37,7 @@ static void clientContextFree(void *context) { } // Request Creation of new context if it does not exist -static void clientContextConnect (struct afb_req request) +static void clientContextConnect (afb_req_t request) { json_object *jresp; @@ -56,7 +56,7 @@ static void clientContextConnect (struct afb_req request) } // Before entering here token will be check and renew -static void clientContextRefresh (struct afb_req request) { +static void clientContextRefresh (afb_req_t request) { json_object *jresp; @@ -68,7 +68,7 @@ static void clientContextRefresh (struct afb_req request) { // Session token will we verified before entering here -static void clientContextCheck (struct afb_req request) { +static void clientContextCheck (afb_req_t request) { json_object *jresp = json_object_new_object(); json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE)); @@ -78,7 +78,7 @@ static void clientContextCheck (struct afb_req request) { // Close and Free context -static void clientContextLogout (struct afb_req request) { +static void clientContextLogout (afb_req_t request) { json_object *jresp; /* after this call token will be reset @@ -95,7 +95,7 @@ static void clientContextLogout (struct afb_req request) { afb_req_session_set_LOA(request, 0); } // Close and Free context -static void clientGetPing (struct afb_req request) { +static void clientGetPing (afb_req_t request) { static int count=0; json_object *jresp; @@ -106,25 +106,18 @@ static void clientGetPing (struct afb_req request) { } -static const struct afb_verb_desc_v1 verbs[]= { - {"ping" , AFB_SESSION_NONE , clientGetPing ,"Ping Rest Test Service"}, - {"connect" , AFB_SESSION_LOA_EQ_0 | AFB_SESSION_RENEW, clientContextConnect,"Connect/Login Client"}, - {"refresh" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_RENEW, clientContextRefresh,"Refresh Client Authentication Token"}, - {"check" , AFB_SESSION_LOA_GE_1 , clientContextCheck ,"Check Client Authentication Token"}, - {"logout" , AFB_SESSION_LOA_GE_1 | AFB_SESSION_CLOSE, clientContextLogout ,"Logout Client and Free resources"}, +static const struct afb_verb_v3 verbs[]= { + {.verb="ping" , .session=AFB_SESSION_NONE , .callback=clientGetPing ,.info="Ping Rest Test Service"}, + {.verb="connect" , .session=AFB_SESSION_LOA_0 | AFB_SESSION_RENEW, .callback=clientContextConnect,.info="Connect/Login Client"}, + {.verb="refresh" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_RENEW, .callback=clientContextRefresh,.info="Refresh Client Authentication Token"}, + {.verb="check" , .session=AFB_SESSION_LOA_1 , .callback=clientContextCheck ,.info="Check Client Authentication Token"}, + {.verb="logout" , .session=AFB_SESSION_LOA_1 | AFB_SESSION_CLOSE, .callback=clientContextLogout ,.info="Logout Client and Free resources"}, {NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Application Framework Binder Authentication sample", - .prefix = "auth", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +const struct afb_binding_v3 afbBindingV3 = { - return &plugin_desc; -} + .api = "auth", /* the API name (or binding name or prefix) */ + .info = "Application Framework Binder Authentication sample", /* short description of of the binding */ + .verbs = verbs /* the array describing the verbs of the API */ +}; diff --git a/bindings/samples/CMakeLists.txt b/bindings/samples/CMakeLists.txt index f596c333..d4e85e30 100644 --- a/bindings/samples/CMakeLists.txt +++ b/bindings/samples/CMakeLists.txt @@ -91,3 +91,27 @@ TARGET_LINK_LIBRARIES(tic-tac-toe ${link_libraries}) INSTALL(TARGETS tic-tac-toe LIBRARY DESTINATION ${binding_install_dir}) +################################################## +# hi3 +################################################## +ADD_LIBRARY(hi3 MODULE hi3.c) +SET_TARGET_PROPERTIES(hi3 PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) +TARGET_LINK_LIBRARIES(hi3 ${link_libraries}) +INSTALL(TARGETS hi3 + LIBRARY DESTINATION ${binding_install_dir}) + +################################################## +# hello3 +################################################## +ADD_LIBRARY(hello3 MODULE hello3.c) +SET_TARGET_PROPERTIES(hello3 PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" +) +TARGET_LINK_LIBRARIES(hello3 ${link_libraries}) +INSTALL(TARGETS hello3 + LIBRARY DESTINATION ${binding_install_dir}) + diff --git a/bindings/samples/DemoContext.c b/bindings/samples/DemoContext.c index bf35ab17..09f1764e 100644 --- a/bindings/samples/DemoContext.c +++ b/bindings/samples/DemoContext.c @@ -19,7 +19,7 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include typedef struct { @@ -48,7 +48,7 @@ typedef struct { // This function is call at session open time. Any client trying to // call it with an already open session will be denied. // Ex: http://localhost:1234/api/context/create?token=123456789 -static void myCreate (struct afb_req request) +static void myCreate (afb_req_t request) { MyClientContextT *ctx = malloc (sizeof (MyClientContextT)); @@ -64,7 +64,7 @@ static void myCreate (struct afb_req request) // session timeout a standard renew api is avaliable at /api/token/renew this API // can be called automatically with HTML5 widget. // ex: http://localhost:1234/api/context/action?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx -static void myAction (struct afb_req request) +static void myAction (afb_req_t request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); @@ -81,7 +81,7 @@ static void myAction (struct afb_req request) // created a context [request->context != NULL] every plugins will be notified // that they should free context resources. // ex: http://localhost:1234/api/context/close?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx -static void myClose (struct afb_req request) +static void myClose (afb_req_t request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); @@ -95,75 +95,44 @@ static void myClose (struct afb_req request) } // Set the LOA -static void setLOA(struct afb_req request, unsigned loa) +static void setLOA(afb_req_t request, unsigned loa) { - if (afb_req_session_set_LOA(request, loa)) + if (afb_req_session_set_LOA(request, loa) >= 0) afb_req_success_f(request, NULL, "loa set to %u", loa); else afb_req_fail_f(request, "failed", "can't set loa to %u", loa); } -static void clientSetLOA0(struct afb_req request) +static void clientSetLOA(afb_req_t request) { - setLOA(request, 0); + setLOA(request, (unsigned)(intptr_t)request->vcbdata); } -static void clientSetLOA1(struct afb_req request) -{ - setLOA(request, 1); -} - -static void clientSetLOA2(struct afb_req request) -{ - setLOA(request, 2); -} - -static void clientSetLOA3(struct afb_req request) -{ - setLOA(request, 3); -} - -static void clientCheckLOA(struct afb_req request) +static void clientCheckLOA(afb_req_t request) { afb_req_success(request, NULL, "LOA checked and okay"); } // 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[]= { - {"create", AFB_SESSION_CREATE, myCreate , "Create a new session"}, - {"action", AFB_SESSION_CHECK , myAction , "Use Session Context"}, - {"close" , AFB_SESSION_CLOSE , myClose , "Free Context"}, - {"set_loa_0", AFB_SESSION_RENEW, clientSetLOA0 ,"Set level of assurance to 0"}, - {"set_loa_1", AFB_SESSION_RENEW, clientSetLOA1 ,"Set level of assurance to 1"}, - {"set_loa_2", AFB_SESSION_RENEW, clientSetLOA2 ,"Set level of assurance to 2"}, - {"set_loa_3", AFB_SESSION_RENEW, clientSetLOA3 ,"Set level of assurance to 3"}, - {"check_loa_ge_0", AFB_SESSION_LOA_GE_0, clientCheckLOA ,"Check whether level of assurance is greater or equal to 0"}, - {"check_loa_ge_1", AFB_SESSION_LOA_GE_1, clientCheckLOA ,"Check whether level of assurance is greater or equal to 1"}, - {"check_loa_ge_2", AFB_SESSION_LOA_GE_2, clientCheckLOA ,"Check whether level of assurance is greater or equal to 2"}, - {"check_loa_ge_3", AFB_SESSION_LOA_GE_3, clientCheckLOA ,"Check whether level of assurance is greater or equal to 3"}, - {"check_loa_le_0", AFB_SESSION_LOA_LE_0, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 0"}, - {"check_loa_le_1", AFB_SESSION_LOA_LE_1, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 1"}, - {"check_loa_le_2", AFB_SESSION_LOA_LE_2, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 2"}, - {"check_loa_le_3", AFB_SESSION_LOA_LE_3, clientCheckLOA ,"Check whether level of assurance is lesser or equal to 3"}, - {"check_loa_eq_0", AFB_SESSION_LOA_EQ_0, clientCheckLOA ,"Check whether level of assurance is equal to 0"}, - {"check_loa_eq_1", AFB_SESSION_LOA_EQ_1, clientCheckLOA ,"Check whether level of assurance is equal to 1"}, - {"check_loa_eq_2", AFB_SESSION_LOA_EQ_2, clientCheckLOA ,"Check whether level of assurance is equal to 2"}, - {"check_loa_eq_3", AFB_SESSION_LOA_EQ_3, clientCheckLOA ,"Check whether level of assurance is equal to 3"}, +static const struct afb_verb_v3 verbs[]= { + {.verb="create", .session=AFB_SESSION_NONE, .callback=myCreate , .info="Create a new session"}, + {.verb="action", .session=AFB_SESSION_CHECK , .callback=myAction , .info="Use Session Context"}, + {.verb="close" , .session=AFB_SESSION_CLOSE , .callback=myClose , .info="Free Context"}, + {.verb="set_loa_0", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Set level of assurance to 0"}, + {.verb="set_loa_1", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Set level of assurance to 1"}, + {.verb="set_loa_2", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Set level of assurance to 2"}, + {.verb="set_loa_3", .session=AFB_SESSION_RENEW, .callback=clientSetLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Set level of assurance to 3"}, + {.verb="check_loa_ge_0", .session=AFB_SESSION_LOA_0, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)0 ,.info="Check whether level of assurance is greater or equal to 0"}, + {.verb="check_loa_ge_1", .session=AFB_SESSION_LOA_1, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)1 ,.info="Check whether level of assurance is greater or equal to 1"}, + {.verb="check_loa_ge_2", .session=AFB_SESSION_LOA_2, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)2 ,.info="Check whether level of assurance is greater or equal to 2"}, + {.verb="check_loa_ge_3", .session=AFB_SESSION_LOA_3, .callback=clientCheckLOA ,.vcbdata=(void*)(intptr_t)3 ,.info="Check whether level of assurance is greater or equal to 3"}, {NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Sample of Client Context Usage", - .prefix = "context", - .verbs = verbs, - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) +const struct afb_binding_v3 afbBindingV3 = { - return &plugin_desc; -} - + .api = "context", /* the API name (or binding name or prefix) */ + .info = "Sample of Client Context Usage", /* short description of of the binding */ + .verbs = verbs /* the array describing the verbs of the API */ +}; diff --git a/bindings/samples/DemoPost.c b/bindings/samples/DemoPost.c index d92d502f..3fd6f983 100644 --- a/bindings/samples/DemoPost.c +++ b/bindings/samples/DemoPost.c @@ -20,12 +20,12 @@ #include #include -#define AFB_BINDING_VERSION 1 +#define AFB_BINDING_VERSION 3 #include // Sample Generic Ping Debug API -static void getPingTest(struct afb_req request) +static void getPingTest(afb_req_t request) { static int pingcount = 0; json_object *query = afb_req_json(request); @@ -34,7 +34,7 @@ static void getPingTest(struct afb_req request) } // With content-type=json data are directly avaliable in request->post->data -static void GetJsonByPost (struct afb_req request) +static void GetJsonByPost (afb_req_t request) { struct afb_arg arg; json_object* jresp; @@ -46,7 +46,7 @@ static void GetJsonByPost (struct afb_req request) } // Upload a file and execute a function when upload is done -static void Uploads (struct afb_req request, const char *destination) +static void Uploads (afb_req_t request, const char *destination) { struct afb_arg a = afb_req_get(request, "file"); if (a.value == NULL || *a.value == 0) @@ -56,20 +56,20 @@ static void Uploads (struct afb_req request, const char *destination) } // Upload a file and execute a function when upload is done -static void UploadAppli (struct afb_req request) +static void UploadAppli (afb_req_t request) { Uploads(request, "applications"); } // Simples Upload case just upload a file -static void UploadMusic (struct afb_req request) +static void UploadMusic (afb_req_t request) { Uploads(request, "musics"); } // PostForm callback is called multiple times (one or each key within form, or once per file buffer) // When file has been fully uploaded call is call with item==NULL -static void UploadImage (struct afb_req request) +static void UploadImage (afb_req_t request) { Uploads(request, "images"); } @@ -77,25 +77,18 @@ static void UploadImage (struct afb_req request) // NOTE: this sample does not use session to keep test a basic as possible // in real application upload-xxx should be protected with AFB_SESSION_CHECK -static const struct afb_verb_desc_v1 verbs[]= { - {"ping" , AFB_SESSION_NONE , getPingTest ,"Ping Rest Test Service"}, - {"upload-json" , AFB_SESSION_NONE , GetJsonByPost ,"Demo for Json Buffer on Post"}, - {"upload-image" , AFB_SESSION_NONE , UploadImage ,"Demo for file upload"}, - {"upload-music" , AFB_SESSION_NONE , UploadMusic ,"Demo for file upload"}, - {"upload-appli" , AFB_SESSION_NONE , UploadAppli ,"Demo for file upload"}, - {NULL} +static const struct afb_verb_v3 verbs[]= { + {.verb="ping" , .session=AFB_SESSION_NONE , .callback=getPingTest ,.info="Ping Rest Test Service"}, + {.verb="upload-json" , .session=AFB_SESSION_NONE , .callback=GetJsonByPost ,.info="Demo for Json Buffer on Post"}, + {.verb="upload-image" , .session=AFB_SESSION_NONE , .callback=UploadImage ,.info="Demo for file upload"}, + {.verb="upload-music" , .session=AFB_SESSION_NONE , .callback=UploadMusic ,.info="Demo for file upload"}, + {.verb="upload-appli" , .session=AFB_SESSION_NONE , .callback=UploadAppli ,.info="Demo for file upload"}, + {.verb=NULL} }; -static const struct afb_binding plugin_desc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Sample with Post Upload Files", - .prefix = "post", - .verbs = verbs - } +const struct afb_binding_v3 afbBindingV3 = { + .info = "Sample with Post Upload Files", + .api = "post", + .verbs = verbs }; -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - return &plugin_desc; -}; diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c index fef87d2d..92d7c4d2 100644 --- a/bindings/samples/HelloWorld.c +++ b/bindings/samples/HelloWorld.c @@ -21,7 +21,7 @@ #include -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -29,7 +29,7 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; struct event { struct event *next; - struct afb_event event; + afb_event_t event; char tag[1]; }; @@ -80,7 +80,7 @@ static int event_add(const char *tag, const char *name) /* make the event */ e->event = afb_daemon_make_event(name); - if (!e->event.closure) { free(e); return -1; } + if (!e->event) { free(e); return -1; } /* link */ e->next = events; @@ -88,14 +88,14 @@ static int event_add(const char *tag, const char *name) return 0; } -static int event_subscribe(afb_req request, const char *tag) +static int event_subscribe(afb_req_t request, const char *tag) { struct event *e; e = event_get(tag); return e ? afb_req_subscribe(request, e->event) : -1; } -static int event_unsubscribe(afb_req request, const char *tag) +static int event_unsubscribe(afb_req_t request, const char *tag) { struct event *e; e = event_get(tag); @@ -117,34 +117,34 @@ static int event_broadcast(struct json_object *args, const char *tag) } // Sample Generic Ping Debug API -static void ping(afb_req request, json_object *jresp, const char *tag) +static void ping(afb_req_t request, json_object *jresp, const char *tag) { static int pingcount = 0; json_object *query = afb_req_json(request); afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); } -static void pingSample (afb_req request) +static void pingSample (afb_req_t request) { ping(request, json_object_new_string ("Some String"), "pingSample"); } -static void pingFail (afb_req request) +static void pingFail (afb_req_t request) { afb_req_fail(request, "failed", "Ping Binder Daemon fails"); } -static void pingNull (afb_req request) +static void pingNull (afb_req_t request) { ping(request, NULL, "pingNull"); } -static void pingBug (afb_req request) +static void pingBug (afb_req_t request) { - ping((afb_req){NULL,NULL}, NULL, "pingBug"); + ping(NULL, NULL, "pingBug"); } -static void pingEvent(afb_req request) +static void pingEvent(afb_req_t request) { json_object *query = afb_req_json(request); afb_daemon_broadcast_event("event", json_object_get(query)); @@ -153,7 +153,7 @@ static void pingEvent(afb_req request) // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ -static void pingJson (afb_req request) { +static void pingJson (afb_req_t request) { json_object *jresp, *embed; jresp = json_object_new_object(); @@ -169,38 +169,12 @@ static void pingJson (afb_req request) { ping(request, jresp, "pingJson"); } -static void subcallcb (void *prequest, int status, json_object *object) +static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request) { - afb_req request = afb_req_unstore(prequest); - if (status < 0) - afb_req_fail(request, "failed", json_object_to_json_string(object)); - else - afb_req_success(request, json_object_get(object), NULL); - afb_req_unref(request); -} - -static void subcall (afb_req request) -{ - const char *api = afb_req_value(request, "api"); - const char *verb = afb_req_value(request, "verb"); - const char *args = afb_req_value(request, "args"); - json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; - - if (object == NULL) - afb_req_fail(request, "failed", "bad arguments"); - else - afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request)); -} - -static void subcallreqcb (void *prequest, int status, json_object *object, afb_req request) -{ - if (status < 0) - afb_req_fail(request, "failed", json_object_to_json_string(object)); - else - afb_req_success(request, json_object_get(object), NULL); + afb_req_reply(request, json_object_get(object), error, info); } -static void subcallreq (afb_req request) +static void subcall (afb_req_t request) { const char *api = afb_req_value(request, "api"); const char *verb = afb_req_value(request, "verb"); @@ -210,10 +184,10 @@ static void subcallreq (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else - afb_req_subcall_req(request, api, verb, object, subcallreqcb, NULL); + afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL); } -static void subcallsync (afb_req request) +static void subcallsync (afb_req_t request) { int rc; const char *api = afb_req_value(request, "api"); @@ -224,7 +198,7 @@ static void subcallsync (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else { - rc = afb_req_subcall_sync(request, api, verb, object, &result); + rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result); if (rc >= 0) afb_req_success(request, result, NULL); else { @@ -234,7 +208,7 @@ static void subcallsync (afb_req request) } } -static void eventadd (afb_req request) +static void eventadd (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *name = afb_req_value(request, "name"); @@ -249,7 +223,7 @@ static void eventadd (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventdel (afb_req request) +static void eventdel (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -263,7 +237,7 @@ static void eventdel (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventsub (afb_req request) +static void eventsub (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -277,7 +251,7 @@ static void eventsub (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventunsub (afb_req request) +static void eventunsub (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); @@ -291,7 +265,7 @@ static void eventunsub (afb_req request) pthread_mutex_unlock(&mutex); } -static void eventpush (afb_req request) +static void eventpush (afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *data = afb_req_value(request, "data"); @@ -308,9 +282,9 @@ static void eventpush (afb_req request) json_object_put(object); } -static void callcb (void *prequest, int status, json_object *object) +static void callcb (void *prequest, int status, json_object *object, afb_api_t api) { - afb_req request = afb_req_unstore(prequest); + afb_req_t request = prequest; if (status < 0) afb_req_fail(request, "failed", json_object_to_json_string(object)); else @@ -318,7 +292,7 @@ static void callcb (void *prequest, int status, json_object *object) afb_req_unref(request); } -static void call (afb_req request) +static void call (afb_req_t request) { const char *api = afb_req_value(request, "api"); const char *verb = afb_req_value(request, "verb"); @@ -328,10 +302,10 @@ static void call (afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); else - afb_service_call(api, verb, object, callcb, afb_req_store(request)); + afb_service_call(api, verb, object, callcb, afb_req_addref(request)); } -static void callsync (afb_req request) +static void callsync (afb_req_t request) { int rc; const char *api = afb_req_value(request, "api"); @@ -352,7 +326,7 @@ static void callsync (afb_req request) } } -static void verbose (afb_req request) +static void verbose (afb_req_t request) { int level = 5; json_object *query = afb_req_json(request), *l; @@ -369,7 +343,7 @@ static void verbose (afb_req request) afb_req_success(request, NULL, NULL); } -static void exitnow (afb_req request) +static void exitnow (afb_req_t request) { int code = 0; json_object *query = afb_req_json(request), *l; @@ -387,7 +361,7 @@ static void exitnow (afb_req request) exit(code); } -static void broadcast(afb_req request) +static void broadcast(afb_req_t request) { const char *tag = afb_req_value(request, "tag"); const char *name = afb_req_value(request, "name"); @@ -412,7 +386,7 @@ static void broadcast(afb_req request) json_object_put(object); } -static void hasperm (afb_req request) +static void hasperm (afb_req_t request) { const char *perm = afb_req_value(request, "perm"); if (afb_req_has_permission(request, perm)) @@ -421,39 +395,39 @@ static void hasperm (afb_req request) afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); } -static void appid (afb_req request) +static void appid (afb_req_t request) { char *aid = afb_req_get_application_id(request); afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); free(aid); } -static void uid (afb_req request) +static void uid (afb_req_t request) { int uid = afb_req_get_uid(request); afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid); } -static int preinit() +static int preinit(afb_api_t api) { - AFB_NOTICE("hello binding comes to live"); + AFB_API_NOTICE(api, "hello binding comes to live"); return 0; } -static int init() +static int init(afb_api_t api) { - AFB_NOTICE("hello binding starting"); + AFB_API_NOTICE(api, "hello binding starting"); return 0; } -static void onevent(const char *event, struct json_object *object) +static void onevent(afb_api_t api, const char *event, struct json_object *object) { - AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object)); + AFB_API_NOTICE(api, "received event %s(%s)", event, json_object_to_json_string(object)); } // 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 afb_verb_v2 verbs[]= { +static const struct afb_verb_v3 verbs[]= { { .verb="ping", .callback=pingSample }, { .verb="pingfail", .callback=pingFail }, { .verb="pingnull", .callback=pingNull }, @@ -461,7 +435,6 @@ static const afb_verb_v2 verbs[]= { { .verb="pingJson", .callback=pingJson }, { .verb="pingevent", .callback=pingEvent }, { .verb="subcall", .callback=subcall }, - { .verb="subcallreq", .callback=subcallreq }, { .verb="subcallsync", .callback=subcallsync }, { .verb="eventadd", .callback=eventadd }, { .verb="eventdel", .callback=eventdel }, @@ -479,7 +452,7 @@ static const afb_verb_v2 verbs[]= { { .verb=NULL} }; -const afb_binding_v2 afbBindingV2 = { +const struct afb_binding_v3 afbBindingV3 = { .api = "hello", .specification = NULL, .verbs = verbs, diff --git a/bindings/samples/ave.c b/bindings/samples/ave.c index 5661e9a5..ce01c6dc 100644 --- a/bindings/samples/ave.c +++ b/bindings/samples/ave.c @@ -21,6 +21,7 @@ #include +#define AFB_BINDING_WANT_DYNAPI #define AFB_BINDING_VERSION 0 #include @@ -147,7 +148,7 @@ static void pingBug (afb_request *request) static void pingEvent(afb_request *request) { json_object *query = afb_request_json(request); - afb_dynapi_broadcast_event(request->dynapi, "event", json_object_get(query)); + afb_dynapi_broadcast_event(request->api, "event", json_object_get(query)); ping(request, json_object_get(query), "event"); } @@ -219,7 +220,7 @@ static void eventadd (afb_request *request) pthread_mutex_lock(&mutex); if (tag == NULL || name == NULL) afb_request_fail(request, "failed", "bad arguments"); - else if (0 != event_add(request->dynapi, tag, name)) + else if (0 != event_add(request->api, tag, name)) afb_request_fail(request, "failed", "creation error"); else afb_request_success(request, NULL, NULL); @@ -305,7 +306,7 @@ static void call (afb_request *request) if (object == NULL) afb_request_fail(request, "failed", "bad arguments"); else - afb_dynapi_call(request->dynapi, api, verb, object, callcb, afb_request_addref(request)); + afb_dynapi_call(request->api, api, verb, object, callcb, afb_request_addref(request)); } static void callsync (afb_request *request) @@ -319,7 +320,7 @@ static void callsync (afb_request *request) if (object == NULL) afb_request_fail(request, "failed", "bad arguments"); else { - rc = afb_dynapi_call_sync(request->dynapi, api, verb, object, &result); + rc = afb_dynapi_call_sync(request->api, api, verb, object, &result); if (rc >= 0) afb_request_success(request, result, NULL); else { @@ -379,7 +380,7 @@ static void broadcast(afb_request *request) afb_request_success(request, NULL, NULL); pthread_mutex_unlock(&mutex); } else if (name != NULL) { - if (0 > afb_dynapi_broadcast_event(request->dynapi, name, object)) + if (0 > afb_dynapi_broadcast_event(request->api, name, object)) afb_request_fail(request, "failed", "broadcast error"); else afb_request_success(request, NULL, NULL); @@ -447,13 +448,13 @@ static const struct { { .verb=NULL} }; -static void pingoo(afb_req req) +static void pingoo(struct afb_req_x1 req) { - json_object *args = afb_req_json(req); - afb_req_success_f(req, json_object_get(args), "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); + json_object *args = afb_req_x1_json(req); + afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); } -static const afb_verb_v2 verbsv2[]= { +static const struct afb_verb_v2 verbsv2[]= { { .verb="pingoo", .callback=pingoo }, { .verb="ping", .callback=pingoo }, { .verb=NULL} diff --git a/bindings/samples/hello3.c b/bindings/samples/hello3.c new file mode 100644 index 00000000..ae70d1e5 --- /dev/null +++ b/bindings/samples/hello3.c @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2015-2018 "IoT.bzh" + * Author "Fulup Ar Foll" + * + * 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. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 3 +#include + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct event +{ + struct event *next; + afb_event_t event; + char tag[1]; +}; + +static struct event *events = 0; + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* deletes the event of tag */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + return 0; +} + +/* creates the event of tag */ +static int event_add(const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_daemon_make_event(name); + if (!e->event) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +static int event_subscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +static int event_unsubscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + +static int event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +static int event_broadcast(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1; +} + +// Sample Generic Ping Debug API +static void ping(afb_req_t request, json_object *jresp, const char *tag) +{ + static int pingcount = 0; + json_object *query = afb_req_json(request); + afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); +} + +static void pingSample (afb_req_t request) +{ + ping(request, json_object_new_string ("Some String"), "pingSample"); +} + +static void pingFail (afb_req_t request) +{ + afb_req_fail(request, "failed", "Ping Binder Daemon fails"); +} + +static void pingNull (afb_req_t request) +{ + ping(request, NULL, "pingNull"); +} + +static void pingBug (afb_req_t request) +{ + ping(NULL, NULL, "pingBug"); +} + +static void pingEvent(afb_req_t request) +{ + json_object *query = afb_req_json(request); + afb_daemon_broadcast_event("event", json_object_get(query)); + ping(request, json_object_get(query), "event"); +} + + +// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ +static void pingJson (afb_req_t request) { + json_object *jresp, *embed; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "myString", json_object_new_string ("Some String")); + json_object_object_add(jresp, "myInt", json_object_new_int (1234)); + + embed = json_object_new_object(); + json_object_object_add(embed, "subObjString", json_object_new_string ("Some String")); + json_object_object_add(embed, "subObjInt", json_object_new_int (5678)); + + json_object_object_add(jresp,"eobj", embed); + + ping(request, jresp, "pingJson"); +} + +static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request) +{ + if (status < 0) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); + afb_req_unref(request); +} + +static void subcall (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL); +} + +static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request) +{ + if (status < 0) + afb_req_fail(request, "failed", json_object_to_json_string(object)); + else + afb_req_success(request, json_object_get(object), NULL); +} + +static void subcallreq (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL); +} + +static void subcallsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result); + if (rc >= 0) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + +static void eventadd (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + pthread_mutex_lock(&mutex); + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventdel (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventunsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventpush (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + json_object_put(object); +} + +static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api) +{ + afb_req_t request = afb_req_unstore(prequest); + afb_req_reply(request, json_object_get(object), error, info); + afb_req_unref(request); +} + +static void call (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_api_call(request->api, api, verb, object, callcb, afb_req_store(request)); +} + +static void callsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_service_call_sync(api, verb, object, &result); + if (rc >= 0) + afb_req_success(request, result, NULL); + else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + } +} + +static void verbose (afb_req_t request) +{ + int level = 5; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + level = json_object_get_int(query); + else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int)) + level = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"message",&l)) + l = query; + + AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l)); + afb_req_success(request, NULL, NULL); +} + +static void exitnow (afb_req_t request) +{ + int code = 0; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + code = json_object_get_int(query); + else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int)) + code = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"reason",&l)) + l = NULL; + + AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown"); + afb_req_success(request, NULL, NULL); + exit(code); +} + +static void broadcast(afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag != NULL) { + pthread_mutex_lock(&mutex); + if (0 > event_broadcast(object, tag)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + } else if (name != NULL) { + if (0 > afb_daemon_broadcast_event(name, object)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + } else { + afb_req_fail(request, "failed", "bad arguments"); + } + json_object_put(object); +} + +static void hasperm (afb_req_t request) +{ + const char *perm = afb_req_value(request, "perm"); + if (afb_req_has_permission(request, perm)) + afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)"); + else + afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); +} + +static void appid (afb_req_t request) +{ + char *aid = afb_req_get_application_id(request); + afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); + free(aid); +} + +static void uid (afb_req_t request) +{ + int uid = afb_req_get_uid(request); + afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid); +} + +static int preinit() +{ + AFB_NOTICE("hello binding comes to live"); + return 0; +} + +static int init() +{ + AFB_NOTICE("hello binding starting"); + return 0; +} + +static void onevent(afb_api_t api, const char *event, struct json_object *object) +{ + AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object)); +} + +// 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_v3 verbs[]= { + { .verb="ping", .callback=pingSample }, + { .verb="pingfail", .callback=pingFail }, + { .verb="pingnull", .callback=pingNull }, + { .verb="pingbug", .callback=pingBug }, + { .verb="pingJson", .callback=pingJson }, + { .verb="pingevent", .callback=pingEvent }, + { .verb="subcall", .callback=subcall }, + { .verb="subcallreq", .callback=subcallreq }, + { .verb="subcallsync", .callback=subcallsync }, + { .verb="eventadd", .callback=eventadd }, + { .verb="eventdel", .callback=eventdel }, + { .verb="eventsub", .callback=eventsub }, + { .verb="eventunsub", .callback=eventunsub }, + { .verb="eventpush", .callback=eventpush }, + { .verb="call", .callback=call }, + { .verb="callsync", .callback=callsync }, + { .verb="verbose", .callback=verbose }, + { .verb="broadcast", .callback=broadcast }, + { .verb="hasperm", .callback=hasperm }, + { .verb="appid", .callback=appid }, + { .verb="uid", .callback=uid }, + { .verb="exit", .callback=exitnow }, + { .verb=NULL} +}; + +const struct afb_binding_v3 afbBindingV3 = { + .api = "hello3", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .onevent = onevent +}; + diff --git a/bindings/samples/hi3.c b/bindings/samples/hi3.c new file mode 100644 index 00000000..5202c46a --- /dev/null +++ b/bindings/samples/hi3.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2015-2018 "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. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 3 +#include + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct event +{ + struct event *next; + afb_event_t event; + char tag[1]; +}; + +static struct event *events = 0; + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* deletes the event of tag */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + return 0; +} + +/* creates the event of tag */ +static int event_add(afb_api_t api, const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_api_make_event(api, name); + if (!e->event) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +static int event_subscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +static int event_unsubscribe(afb_req_t request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + +static int event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +static int event_broadcast(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1; +} + +// Sample Generic Ping Debug API +static void ping(afb_req_t request, json_object *jresp, const char *tag) +{ + static int pingcount = 0; + json_object *query = afb_req_json(request); + afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query)); +} + +static void pingSample (afb_req_t request) +{ + ping(request, json_object_new_string ("Some String"), "pingSample"); +} + +static void pingFail (afb_req_t request) +{ + afb_req_fail(request, "failed", "Ping Binder Daemon fails"); +} + +static void pingNull (afb_req_t request) +{ + ping(request, NULL, "pingNull"); +} + +static void pingBug (afb_req_t request) +{ + ping(NULL, NULL, "pingBug"); +} + +static void pingEvent(afb_req_t request) +{ + json_object *query = afb_req_json(request); + afb_api_broadcast_event(request->api, "event", json_object_get(query)); + ping(request, json_object_get(query), "event"); +} + + +// For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ +static void pingJson (afb_req_t request) { + json_object *jresp, *embed; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "myString", json_object_new_string ("Some String")); + json_object_object_add(jresp, "myInt", json_object_new_int (1234)); + + embed = json_object_new_object(); + json_object_object_add(embed, "subObjString", json_object_new_string ("Some String")); + json_object_object_add(embed, "subObjInt", json_object_new_int (5678)); + + json_object_object_add(jresp,"eobj", embed); + + ping(request, jresp, "pingJson"); +} + +static void subcallcb (void *closure, json_object *object, const char *error, const char *info, afb_req_t request) +{ + afb_req_reply(request, json_object_get(object), error, info); +} + +static void subcall (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_req_subcall(request, api, verb, object, afb_req_subcall_pass_events, subcallcb, NULL); +} + +static void subcallsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL; + json_object *object; + char *error, *info; + + if (oargs == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync(request, api, verb, oargs, afb_req_subcall_pass_events, &object, &error, &info); + afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info?:"NULL"); + free(error); + free(info); + } +} + +static void eventadd (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + pthread_mutex_lock(&mutex); + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(request->api, tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventdel (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventunsub (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); +} + +static void eventpush (afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + pthread_mutex_lock(&mutex); + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + json_object_put(object); +} + +static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api) +{ + afb_req_t request = prequest; + afb_req_reply(request, json_object_get(object), error, info); + afb_req_unref(request); +} + +static void call (afb_req_t request) +{ + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else + afb_api_call(request->api, api, verb, object, callcb, afb_req_addref(request)); +} + +static void callsync (afb_req_t request) +{ + int rc; + const char *api = afb_req_value(request, "api"); + const char *verb = afb_req_value(request, "verb"); + const char *args = afb_req_value(request, "args"); + json_object *oargs = api && verb && args ? json_tokener_parse(args) : NULL; + json_object *object; + char *error, *info; + + if (oargs == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_api_call_sync(request->api, api, verb, oargs, &object, &error, &info); + afb_req_reply_f(request, object, error, "rc=%d, info=%s", rc, info); + free(error); + free(info); + } +} + +static void verbose (afb_req_t request) +{ + int level = 5; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + level = json_object_get_int(query); + else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int)) + level = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"message",&l)) + l = query; + + AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l)); + afb_req_success(request, NULL, NULL); +} + +static void exitnow (afb_req_t request) +{ + int code = 0; + json_object *query = afb_req_json(request), *l; + + if (json_object_is_type(query,json_type_int)) + code = json_object_get_int(query); + else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int)) + code = json_object_get_int(l); + + if (!json_object_object_get_ex(query,"reason",&l)) + l = NULL; + + AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown"); + afb_req_success(request, NULL, NULL); + exit(code); +} + +static void broadcast(afb_req_t request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag != NULL) { + pthread_mutex_lock(&mutex); + if (0 > event_broadcast(object, tag)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + pthread_mutex_unlock(&mutex); + } else if (name != NULL) { + if (0 > afb_api_broadcast_event(request->api, name, object)) + afb_req_fail(request, "failed", "broadcast error"); + else + afb_req_success(request, NULL, NULL); + } else { + afb_req_fail(request, "failed", "bad arguments"); + } + json_object_put(object); +} + +static void hasperm (afb_req_t request) +{ + const char *perm = afb_req_value(request, "perm"); + if (afb_req_has_permission(request, perm)) + afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)"); + else + afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)"); +} + +static void appid (afb_req_t request) +{ + char *aid = afb_req_get_application_id(request); + afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?"); + free(aid); +} + +static int init(afb_api_t api) +{ + AFB_API_NOTICE(api, "dynamic binding AVE(%s) starting", (const char*)api->userdata); + return 0; +} + +static void onevent(afb_api_t api, const char *event, struct json_object *object) +{ + AFB_API_NOTICE(api, "received event %s(%s) by AVE(%s)", + event, json_object_to_json_string(object), + (const char*)afb_api_get_userdata(api)); +} + +// 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 { + const char *verb; + void (*callback)(afb_req_t); } verbs[] = +{ + { .verb="ping", .callback=pingSample }, + { .verb="pingfail", .callback=pingFail }, + { .verb="pingnull", .callback=pingNull }, + { .verb="pingbug", .callback=pingBug }, + { .verb="pingJson", .callback=pingJson }, + { .verb="pingevent", .callback=pingEvent }, + { .verb="subcall", .callback=subcall }, + { .verb="subcallsync", .callback=subcallsync }, + { .verb="eventadd", .callback=eventadd }, + { .verb="eventdel", .callback=eventdel }, + { .verb="eventsub", .callback=eventsub }, + { .verb="eventunsub", .callback=eventunsub }, + { .verb="eventpush", .callback=eventpush }, + { .verb="call", .callback=call }, + { .verb="callsync", .callback=callsync }, + { .verb="verbose", .callback=verbose }, + { .verb="broadcast", .callback=broadcast }, + { .verb="hasperm", .callback=hasperm }, + { .verb="appid", .callback=appid }, + { .verb="exit", .callback=exitnow }, + { .verb=NULL} +}; + +static void pingoo(struct afb_req_x1 req) +{ + json_object *args = afb_req_x1_json(req); + afb_req_x1_reply_f(req, json_object_get(args), NULL, "You reached pingoo \\o/ nice args: %s", json_object_to_json_string(args)); +} + +static const struct afb_verb_v2 verbsv2[]= { + { .verb="pingoo", .callback=pingoo }, + { .verb="ping", .callback=pingoo }, + { .verb=NULL} +}; + +static const char *apis[] = { "ave3", "hi3", "salut3", NULL }; + +static int build_api(void *closure, afb_api_t api) +{ + int i, rc; + + afb_api_set_userdata(api, closure); + AFB_API_NOTICE(api, "dynamic binding AVE(%s) comes to live", (const char*)afb_api_get_userdata(api)); + afb_api_on_init(api, init); + afb_api_on_event(api, onevent); + + rc = afb_api_set_verbs_v2(api, verbsv2); + for (i = rc = 0; verbs[i].verb && rc >= 0 ; i++) { + rc = afb_api_add_verb(api, verbs[i].verb, NULL, verbs[i].callback, (void*)(intptr_t)i, NULL, 0, 0); + } + afb_api_seal(api); + return rc; +} + +int afbBindingV3entry(afb_api_t api) +{ + int i; + afb_api_t napi; + + for (i = 0; apis[i] ; i++) { + napi = afb_api_new_api(api, apis[i], NULL, 0, build_api, (void*)apis[i]); + if (!napi) + AFB_API_ERROR(api, "can't create API %s", apis[i]); + } + return 0; +} + diff --git a/bindings/samples/tic-tac-toe.c b/bindings/samples/tic-tac-toe.c index 6b7022b8..2ee251cb 100644 --- a/bindings/samples/tic-tac-toe.c +++ b/bindings/samples/tic-tac-toe.c @@ -20,17 +20,14 @@ #include #include -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include -/* - * definition of waiters - */ -struct waiter -{ - struct waiter *next; - struct afb_req req; -}; +static const char SPACE = ' '; +static const char CROSS = 'X'; +static const char ROUND = 'O'; +static const char NHERE = '+'; +static const int DEFLVL = 8; /* * definition of a board @@ -44,7 +41,7 @@ struct board int id; int level; char board[9]; - struct waiter *waiters; + afb_event_t event; }; /* @@ -67,19 +64,21 @@ static struct board *search_board(int id) /* * Creates a new board and returns it. */ -static struct board *get_new_board() +static struct board *get_new_board(afb_req_t req) { /* allocation */ struct board *board = calloc(1, sizeof *board); /* initialisation */ - memset(board->board, ' ', sizeof board->board); + memset(board->board, SPACE, sizeof board->board); board->use_count = 1; - board->level = 1; + board->level = DEFLVL; board->moves = 0; do { board->id = (rand() >> 2) % 1000; } while(board->id == 0 || search_board(board->id) != NULL); + board->event = afb_daemon_make_event("board"); + afb_req_subscribe(req, board->event); /* link */ board->next = all_boards; @@ -87,6 +86,12 @@ static struct board *get_new_board() return board; } +static void *get_new_board_cb(void *closure) +{ + afb_req_t req = closure; + return get_new_board(req); +} + /* * Release a board */ @@ -95,6 +100,7 @@ static void release_board(struct board *board) /* decrease the reference count ... */ if (--board->use_count == 0) { /* ... no more use */ + afb_event_unref(board->event); /* unlink from the list of boards */ struct board **prv = &all_boards; while (*prv != NULL && *prv != board) @@ -106,6 +112,24 @@ static void release_board(struct board *board) } } +static void release_board_cb(void *closure) +{ + struct board *board = closure; + return release_board(board); +} + +/* + * Checks who wins + * Returns zero if there is no winner + * Returns the char of the winner if a player won + */ +static char wins(const char b[9], int first, int incr) +{ + char c = b[first]; + + return c != SPACE && b[first + incr] == c && b[first + incr + incr] == c ? c : 0; +} + /* * Checks who wins * Returns zero if there is no winner @@ -113,31 +137,39 @@ static void release_board(struct board *board) */ static char winner(const char b[9]) { - int i; char c; - /* check diagonals */ - c = b[4]; - if (c != ' ') { - if (b[0] == c && b[8] == c) - return c; - if (b[2] == c && b[6] == c) - return c; - } + c = wins(b, 0, 1); + if (c) + return c; - /* check lines */ - for (i = 0 ; i <= 6 ; i += 3) { - c = b[i]; - if (c != ' ' && b[i+1] == c && b[i+2] == c) - return c; - } + c = wins(b, 3, 1); + if (c) + return c; - /* check columns */ - for (i = 0 ; i <= 2 ; i++) { - c = b[i]; - if (c != ' ' && b[i+3] == c && b[i+6] == c) - return c; - } + c = wins(b, 6, 1); + if (c) + return c; + + c = wins(b, 0, 3); + if (c) + return c; + + c = wins(b, 1, 3); + if (c) + return c; + + c = wins(b, 2, 3); + if (c) + return c; + + c = wins(b, 0, 4); + if (c) + return c; + + c = wins(b, 2, 2); + if (c) + return c; return 0; } @@ -145,7 +177,7 @@ static char winner(const char b[9]) /* get the color (X or 0) of the move of index 'move' */ static char color(int move) { - return (move & 1) == 0 ? 'X' : '0'; + return (move & 1) == 0 ? CROSS : ROUND; } /* adds the move to the board */ @@ -160,7 +192,7 @@ static void add_move(struct board *board, int index) static int get_random_move(char b[9]) { int index = rand() % 9; - while (b[index] != ' ') + while (b[index] != SPACE) index = (index + 1) % 9; return index; } @@ -174,40 +206,41 @@ static int get_random_move(char b[9]) */ static int score_position(char b[9], char c, int depth) { - int i, t, r; + int i, s, nc, wc, lc; /* check if winner */ if (winner(b) == c) return 1; /* when depth of analysis is reached return unknown case */ - if (--depth == 0) + if (--depth <= 0) return 0; /* switch to the opponent */ - c = (char)('O' + 'X' - c); + c = (char)(ROUND + CROSS - c); /* inspect opponent moves */ - r = 1; + nc = wc = lc = 0; for (i = 0 ; i < 9 ; i++) { - if (b[i] == ' ') { + if (b[i] == SPACE) { b[i] = c; - t = score_position(b, c, depth); - b[i] = ' '; - if (t > 0) - return -1; /* opponent will win */ - - if (t == 0) - r = 0; /* something not clear */ + s = score_position(b, c, depth); + b[i] = SPACE; + if (s > 0) + lc++; /* opponent's victory, inc loose count */ + else if (s < 0) + wc++; /* current's victory, inc win count */ + else + nc++; /* none wins, increment null count */ } } - return r; + return lc ? -lc : wc; } /* get one move: return the computed index of the move */ static int get_move(struct board *board) { - int index, depth, t, f; + int index, depth, f, s, smax, imax; char c; char b[9]; @@ -222,22 +255,24 @@ static int get_move(struct board *board) /* depth and more */ memcpy(b, board->board, 9); + f = smax = 0; c = color(board->moves); - f = 0; for (index = 0 ; index < 9 ; index++) { - if (board->board[index] == ' ') { + if (board->board[index] == SPACE) { board->board[index] = c; - t = score_position(board->board, c, depth); - board->board[index] = ' '; - if (t > 0) - return index; - if (t < 0) - b[index] = '+'; - else + s = score_position(board->board, c, depth); + board->board[index] = SPACE; + if (s < 0) + b[index] = NHERE; + else if (s <= smax) f = 1; + else { + smax = s; + imax = index; + } } } - return get_random_move(f ? b : board->board); + return smax ? imax : get_random_move(f ? b : board->board); } /* @@ -279,37 +314,21 @@ static struct json_object *describe(struct board *board) */ static void changed(struct board *board, const char *reason) { - struct waiter *waiter, *next; - struct json_object *description; - - /* get the description */ - description = describe(board); - - waiter = board->waiters; - board->waiters = NULL; - while (waiter != NULL) { - next = waiter->next; - afb_req_success(waiter->req, json_object_get(description), reason); - afb_req_unref(waiter->req); - free(waiter); - waiter = next; - } - - afb_daemon_broadcast_event(reason, description); + afb_event_push(board->event, json_object_new_string(reason)); } /* * retrieves the board of the request */ -static inline struct board *board_of_req(struct afb_req req) +static inline struct board *board_of_req(afb_req_t req) { - return afb_req_context(req, (void*)get_new_board, (void*)release_board); + return afb_req_context(req, 0, get_new_board_cb, release_board_cb, req); } /* * start a new game */ -static void new(struct afb_req req) +static void new(afb_req_t req) { struct board *board; @@ -318,7 +337,7 @@ static void new(struct afb_req req) AFB_INFO("method 'new' called for boardid %d", board->id); /* reset the game */ - memset(board->board, ' ', sizeof board->board); + memset(board->board, SPACE, sizeof board->board); board->moves = 0; /* replies */ @@ -331,7 +350,7 @@ static void new(struct afb_req req) /* * get the board */ -static void board(struct afb_req req) +static void board(afb_req_t req) { struct board *board; struct json_object *description; @@ -350,7 +369,7 @@ static void board(struct afb_req req) /* * move a piece */ -static void move(struct afb_req req) +static void move(afb_req_t req) { struct board *board; int i; @@ -379,7 +398,7 @@ static void move(struct afb_req req) } /* checks validity of the move */ - if (board->board[i] != ' ') { + if (board->board[i] != SPACE) { AFB_WARNING("can't move to %s: room occupied", index); afb_req_fail(req, "error", "occupied"); return; @@ -399,7 +418,7 @@ static void move(struct afb_req req) /* * set the level */ -static void level(struct afb_req req) +static void level(afb_req_t req) { struct board *board; int l; @@ -434,7 +453,7 @@ static void level(struct afb_req req) /* * Join a board */ -static void join(struct afb_req req) +static void join(afb_req_t req) { struct board *board, *new_board; const char *id; @@ -450,8 +469,8 @@ static void join(struct afb_req req) /* none is a special id for joining a new session */ if (strcmp(id, "none") == 0) { - new_board = get_new_board(); - goto success; + new_board = get_new_board(req); + goto setctx; } /* searchs the board to join */ @@ -466,13 +485,16 @@ static void join(struct afb_req req) * function 'release_board'. So the use_count MUST not * be incremented. */ - if (new_board != board) - new_board->use_count++; + if (new_board == board) + goto success; -success: + new_board->use_count++; +setctx: /* set the new board (and leaves the previous one) */ - afb_req_context_set(req, new_board, (void*)release_board); + afb_req_context(req, 1, NULL, release_board_cb, new_board); + afb_req_unsubscribe(req, board->event); +success: /* replies */ afb_req_success(req, NULL, NULL); return; @@ -486,7 +508,7 @@ bad_request: /* * Undo the last move */ -static void undo(struct afb_req req) +static void undo(afb_req_t req) { struct board *board; int i; @@ -504,7 +526,7 @@ static void undo(struct afb_req req) /* undo the last move */ i = board->history[--board->moves]; - board->board[i] = ' '; + board->board[i] = SPACE; /* replies */ afb_req_success(req, NULL, NULL); @@ -516,7 +538,7 @@ static void undo(struct afb_req req) /* * computer plays */ -static void play(struct afb_req req) +static void play(afb_req_t req) { struct board *board; int index; @@ -543,27 +565,10 @@ static void play(struct afb_req req) changed(board, "play"); } -static void wait(struct afb_req req) -{ - struct board *board; - struct waiter *waiter; - - /* retrieves the context for the session */ - board = board_of_req(req); - AFB_INFO("method 'wait' called for boardid %d", board->id); - - /* creates the waiter and enqueues it */ - waiter = calloc(1, sizeof *waiter); - waiter->req = req; - waiter->next = board->waiters; - afb_req_addref(req); - board->waiters = waiter; -} - /* * array of the verbs exported to afb-daemon */ -static const struct afb_verb_v2 verbs[] = { +static const afb_verb_t verbs[] = { { .verb="new", .callback=new }, { .verb="play", .callback=play }, { .verb="move", .callback=move }, @@ -571,17 +576,17 @@ static const struct afb_verb_v2 verbs[] = { { .verb="level", .callback=level }, { .verb="join", .callback=join }, { .verb="undo", .callback=undo }, - { .verb="wait", .callback=wait }, { .verb=NULL } }; /* * description of the binding for afb-daemon */ -const afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingV3 = { .api = "tictactoe", .specification = NULL, - .verbs = verbs + .verbs = verbs, + .noconcurrency = 1 }; diff --git a/bindings/tutorial/tuto-1.c b/bindings/tutorial/tuto-1.c index 433a4ebb..1f58be6c 100644 --- a/bindings/tutorial/tuto-1.c +++ b/bindings/tutorial/tuto-1.c @@ -1,18 +1,18 @@ -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include -void hello(afb_req req) +void hello(afb_req_t req) { AFB_REQ_DEBUG(req, "hello world"); - afb_req_success(req, NULL, "hello world"); + afb_req_reply(req, NULL, NULL, "hello world"); } -const afb_verb_v2 verbs[] = { +const afb_verb_t verbs[] = { { .verb="hello", .callback=hello }, { .verb=NULL } }; -const afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingExport = { .api = "tuto-1", .verbs = verbs }; diff --git a/bindings/tutorial/tuto-2.c b/bindings/tutorial/tuto-2.c index dc2d55ab..10797081 100644 --- a/bindings/tutorial/tuto-2.c +++ b/bindings/tutorial/tuto-2.c @@ -1,12 +1,12 @@ #include #include -#define AFB_BINDING_VERSION 2 +#define AFB_BINDING_VERSION 3 #include -afb_event event_login, event_logout; +afb_event_t event_login, event_logout; -void login(afb_req req) +void login(afb_req_t req) { json_object *args, *user, *passwd; char *usr; @@ -15,24 +15,24 @@ void login(afb_req 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); + afb_req_reply(req, NULL, "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); + afb_req_reply(req, NULL, "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); + afb_req_reply(req, NULL, "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_req_reply(req, NULL, NULL, NULL); afb_event_push(event_login, json_object_new_string(usr)); } } -void action(afb_req req) +void action(afb_req_t req) { json_object *args, *val; char *usr; @@ -51,10 +51,10 @@ void action(afb_req req) afb_req_unsubscribe(req, event_logout); } } - afb_req_success(req, json_object_get(args), NULL); + afb_req_reply(req, json_object_get(args), NULL, NULL); } -void logout(afb_req req) +void logout(afb_req_t req) { char *usr; @@ -63,34 +63,34 @@ void logout(afb_req req) 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); + afb_req_reply(req, NULL, NULL, NULL); } -int preinit() +int preinit(afb_api_t api) { - AFB_NOTICE("preinit"); + AFB_API_NOTICE(api, "preinit"); return 0; } -int init() +int init(afb_api_t api) { - AFB_NOTICE("init"); - event_login = afb_daemon_make_event("login"); - event_logout = afb_daemon_make_event("logout"); + AFB_API_NOTICE(api, "init"); + event_login = afb_api_make_event(api, "login"); + event_logout = afb_api_make_event(api, "logout"); if (afb_event_is_valid(event_login) && afb_event_is_valid(event_logout)) return 0; - AFB_ERROR("Can't create events"); + AFB_API_ERROR(api, "Can't create events"); return -1; } -const afb_verb_v2 verbs[] = { +const afb_verb_t 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 = { +const afb_binding_t afbBindingExport = { .api = "tuto-2", .specification = NULL, .verbs = verbs, diff --git a/bindings/tutorial/tuto-3.cpp b/bindings/tutorial/tuto-3.cpp index 7400b986..66f8e83a 100644 --- a/bindings/tutorial/tuto-3.cpp +++ b/bindings/tutorial/tuto-3.cpp @@ -1,11 +1,12 @@ #include #include +#define AFB_BINDING_VERSION 3 #include afb::event event_login, event_logout; -void login(afb_req r) +void login(afb_req_t r) { json_object *args, *user, *passwd; char *usr; @@ -26,20 +27,21 @@ void login(afb_req r) usr = strdup(json_object_get_string(user)); AFB_REQ_NOTICE(req, "login user: %s", usr); req.session_set_LOA(1); - req.context_set(usr, free); +// req.context(1, nullptr, free, usr); req.success(); event_login.push(json_object_new_string(usr)); } } -void action(afb_req r) +void action(afb_req_t r) { json_object *args, *val; char *usr; afb::req req(r); args = req.json(); - usr = (char*)req.context_get(); +// usr = (char*)req.context_get(); +usr = nullptr; 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)) { @@ -55,20 +57,25 @@ void action(afb_req r) req.success(json_object_get(args)); } -void logout(afb_req r) +void logout(afb_req_t r) { char *usr; afb::req req(r); - usr = (char*)req.context_get(); +// usr = (char*)req.context_get(); +usr = nullptr; AFB_REQ_NOTICE(req, "login user %s out", usr); event_logout.push(json_object_new_string(usr)); req.session_set_LOA(0); - req.context_clear(); +// req.context_clear(); req.success(); } -int init() +int init( +#if AFB_BINDING_VERSION >= 3 + afb_api_t api +#endif +) { AFB_NOTICE("init"); event_login = afb_daemon_make_event("login"); @@ -79,12 +86,13 @@ int init() return -1; } -const afb_verb_v2 verbs[] = { +const afb_verb_t verbs[] = { afb::verb("login", login, "log in the system"), afb::verb("action", action, "perform an action", AFB_SESSION_LOA_1), afb::verb("logout", logout, "log out the system", AFB_SESSION_LOA_1), afb::verbend() }; -const afb_binding_v2 afbBindingV2 = afb::binding("tuto-3", verbs, "third tutorial: C++", init); +const afb_binding_t afbBindingExport = afb::binding("tuto-3", verbs, "third tutorial: C++", init); + diff --git a/book.json b/book.json index 41e4cddd..e7127c49 100644 --- a/book.json +++ b/book.json @@ -6,7 +6,7 @@ "author": "IoT.Bzh Team", "website": "http://iot.bzh", "published": "February 2018", - "version": "5.99-FFRC0", + "version": "5.99-FFRC1", "gitbook": "3.2.2", "root": "docs", @@ -89,6 +89,6 @@ "decode": true } ] - } + } } } diff --git a/docs/README.md b/docs/README.md index 94dc16aa..503b8545 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,13 +1,19 @@ -Document revisions -================== - -| Date | Version | Designation  | Author | -|--------------|------------|----------------------------------------------|-------------------------------------------------------| -| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ]
M. Bachmann [ IoT.bzh ] | -| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ]
F. Ar Foll [ IoT.bzh ] | -| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | -| 12 Dec 2016 | 2.1 | Updated for CC Release | S. Desneux [ IoT.bzh ] | -| 14 Dec 2016 | 3.0 | Minor fixes, alignment with CC version | S. Desneux [ IoT.bzh ] | -| 20 Mar 2017 | 3.1 | Systemd integration | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | -| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | -| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | + +# AGL Framework Binder + +This project provides the binder component of the the microservice architecture +of Automotive Grade Linux (AGL). + +This project is available there https://git.automotivelinux.org/src/app-framework-binder/ + +It can be cloned with **git clone https://git.automotivelinux.org/src/app-framework-binder**. + +## License and copying + +This software is an open source software funded by LinuxFoundation and Renesas. + +This software is delivered under the terms of the open source license Apache 2. + +This license is available in the file LICENSE-2.0.txt or on the worl wide web at the +location https://opensource.org/licenses/Apache-2.0 + diff --git a/docs/REVISIONS.md b/docs/REVISIONS.md new file mode 100644 index 00000000..00787b02 --- /dev/null +++ b/docs/REVISIONS.md @@ -0,0 +1,14 @@ +Document revisions +================== + +| Date | Version | Designation  | Author | +|--------------|:----------:|----------------------------------------------|-------------------------------------------------------| +| 23 May 2016 | 0.9 | Initial release | J. Bollo [ IoT.bzh ]
M. Bachmann [ IoT.bzh ] | +| 30 May 2016 | 1.0 | Master document edition, final review | S. Desneux [ IoT.bzh ]
F. Ar Foll [ IoT.bzh ] | +| 21 Sept 2016 | 2.0 | Updated with new sections (events,widgets) | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | +| 12 Dec 2016 | 2.1 | Updated for CC Release | S. Desneux [ IoT.bzh ] | +| 14 Dec 2016 | 3.0 | Minor fixes, alignment with CC version | S. Desneux [ IoT.bzh ] | +| 20 Mar 2017 | 3.1 | Systemd integration | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | +| 21 Jun 2017 | 4.0 | Update for AGL DD | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | +| 21 Sep 2017 | 4.99-EERC1 | Update for AGL EE-RC1 | J. Bollo [ IoT.bzh ]
S. Desneux [ IoT.bzh ] | +| 14 Jun 2018 | 5.99-FFRC1 | Update for AGL FF-RC1 | J. Bollo [ IoT.bzh ] | diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 44b06f8d..580660ea 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,14 +1,15 @@ # Summary -* [Document revisions](README.md) * [Binder Overview](afb-introduction.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) -* [Binder daemon vocabulary](afb-daemon-vocabulary.md) * [Annexes](annexes.md) + * [Migration to binding v3](afb-migration-to-binding-v3.md) * [Installing the binder on a desktop](afb-desktop-package.md) * [Options of afb-daemon](afb-daemon-options.md) - * [Debugging afb-daemon](afb-daemon-debugging.md) + * [Debugging binder and bindings](afb-daemon-debugging.md) + * [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md) +* [Document revisions](REVISIONS.md) diff --git a/docs/afb-binding-references.md b/docs/afb-binding-references.md index 0e30ffe7..4ff0f042 100644 --- a/docs/afb-binding-references.md +++ b/docs/afb-binding-references.md @@ -2,47 +2,98 @@ ## Structure for declaring binding -### struct afb_binding_v2 +### afb_binding_t -The main structure, of type **afb_binding_v2**, for describing the binding -must be exported under the name **afbBindingV2**. +The main structure, of type **afb_binding_t**, for describing the binding +must be exported under the name **afbBindingExport**. This structure is defined as below. ```C -/* - * Description of the bindings of type version 2 +typedef struct afb_binding_v3 afb_binding_t; +``` + +Where: + +```C +/** + * Description of the bindings of type version 3 */ -struct afb_binding_v2 +struct afb_binding_v3 { - const char *api; /* api name for the binding */ - const char *specification; /* textual openAPIv3 specification of the binding */ - const char *info; /* some info about the api, can be NULL */ - 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 */ + /** api name for the binding, can't be NULL */ + const char *api; + + /** textual specification of the binding, can be NULL */ + const char *specification; + + /** some info about the api, can be NULL */ + const char *info; + + /** array of descriptions of verbs terminated by a NULL name, can be NULL */ + const struct afb_verb_v3 *verbs; + + /** callback at load of the binding */ + int (*preinit)(struct afb_api_x3 *api); + + /** callback for starting the service */ + int (*init)(struct afb_api_x3 *api); + + /** callback for handling events */ + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object); + + /** userdata for afb_api_x3 */ + void *userdata; + + /** space separated list of provided class(es) */ + const char *provide_class; + + /** space separated list of required class(es) */ + const char *require_class; + + /** space separated list of required API(es) */ + const char *require_api; + + /** avoids concurrent requests to verbs */ + unsigned noconcurrency: 1; }; ``` -### struct afb_verb_v2 +### struct afb_verb_t -Each verb is described with a structure of type **afb_verb_v2** +Each verb is described with a structure of type **afb_verb_t** defined below: ```C -/* - * Description of one verb of the API provided by the binding - * This enumeration is valid for bindings of type version 2 +typedef struct afb_verb_v3 afb_verb_t; +``` + +```C +/** + * Description of one verb as provided for binding API version 3 */ -struct afb_verb_v2 +struct afb_verb_v3 { - const char *verb; /* name of the verb */ - void (*callback)(struct afb_req req); /* callback function implementing the verb */ - const struct afb_auth *auth; /* required authorization */ - const char *info; /* some info about the verb, can be NULL */ - uint32_t session; /* authorization and session requirements of the verb */ + /** name of the verb, NULL only at end of the array */ + const char *verb; + + /** callback function implementing the verb */ + void (*callback)(afb_req_t_x2 *req); + + /** required authorization, can be NULL */ + const struct afb_auth *auth; + + /** some info about the verb, can be NULL */ + const char *info; + + /**< data for the verb callback */ + void *vcbdata; + + /** authorization and session requirements of the verb */ + uint16_t session; + + /** is the verb glob name */ + uint16_t glob: 1; }; ``` @@ -55,55 +106,91 @@ The **session** flags is one of the constant defined below: - 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 +- AFB_SESSION_CLOSE : Implies closing the session after request processed -The LOA (Level Of Assurance) is set, by binding, using the function **afb_req_session_set_LOA**. +The LOA (Level Of Assurance) is set, by binding api, using the function **afb_req_session_set_LOA**. -### struct afb_auth and enum afb_auth_type +The session can be closed, by binding api, using the function **afb_req_session_close**. -The structure **afb_auth** is used within verb description to +### afb_auth_t and afb_auth_type_t + +The structure **afb_auth_t** is used within verb description to set security requirements. The interpretation of the structure depends on the value of the field **type**. ```C +typedef struct afb_auth afb_auth_t; + +/** + * Definition of an authorization entry + */ 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; + /** type of entry @see afb_auth_type */ + enum afb_auth_type type; + + union { + /** text when @ref type == @ref afb_auth_Permission */ + const char *text; + + /** level of assurancy when @ref type == @ref afb_auth_LOA */ + unsigned loa; + + /** first child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And, @ref afb_auth_Not } */ + const struct afb_auth *first; + }; + + /** second child when @ref type in { @ref afb_auth_Or, @ref afb_auth_And } */ + const struct afb_auth *next; }; + ``` The possible values for **type** is defined here: ```C -/* - * Enum for Session/Token/Assurance middleware. +typedef enum afb_auth_type afb_auth_type_t; + +/** + * Enumeration for authority (Session/Token/Assurance) definitions. + * + * @see afb_auth */ 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 */ + /** never authorized, no data */ + afb_auth_No = 0, + + /** authorized if token valid, no data */ + afb_auth_Token, + + /** authorized if LOA greater than data 'loa' */ + afb_auth_LOA, + + /** authorized if permission 'text' is granted */ + afb_auth_Permission, + + /** authorized if 'first' or 'next' is authorized */ + afb_auth_Or, + + /** authorized if 'first' and 'next' are authorized */ + afb_auth_And, + + /** authorized if 'first' is not authorized */ + afb_auth_Not, + + /** always authorized, no data */ + afb_auth_Yes }; ``` 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] } +static const afb_auth_t myauth[] = { + { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:set" }, + { .type = afb_auth_Permission, .text = "urn:AGL:permission:me:public:get" }, + { .type = afb_auth_Or, .first = &myauth[1], .next = &myauth[0] } }; ``` @@ -115,17 +202,18 @@ to **sd_bus** features. ```C /* - * Retrieves the common systemd's event loop of AFB + * 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 + * Retrieves the common systemd's user/session d-bus of AFB if active */ struct sd_bus *afb_daemon_get_user_bus(); /* - * Retrieves the common systemd's system d-bus of AFB + * Retrieves the common systemd's system d-bus of AFB if active or NULL */ struct sd_bus *afb_daemon_get_system_bus(); ``` @@ -155,7 +243,7 @@ int afb_daemon_broadcast_event(const char *name, struct json_object *object); * * See afb_event_is_valid to check if there is an error. */ -struct afb_event afb_daemon_make_event(const char *name); +afb_event_t afb_daemon_make_event(const char *name); ``` The following function is used by logging macros and should normally @@ -319,7 +407,7 @@ It must be used when creating events. * * Returns 0 if not valid or 1 if valid. */ -int afb_event_is_valid(struct afb_event event); +int afb_event_is_valid(afb_event_t event); ``` The two following functions are used to broadcast or push @@ -336,7 +424,7 @@ event with its data. * * Returns the count of clients that received the event. */ -int afb_event_broadcast(struct afb_event event, struct json_object *object); +int afb_event_broadcast(afb_event_t event, struct json_object *object); /* * Pushes the 'event' with the data 'object' to its observers. @@ -348,18 +436,29 @@ int afb_event_broadcast(struct afb_event event, struct json_object *object); * * Returns the count of clients that received the event. */ -int afb_event_push(struct afb_event event, struct json_object *object); +int afb_event_push(afb_event_t event, struct json_object *object); +``` + +The following function remove one reference to the event. + +```C +/* + * Decrease the reference count of the event. + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_unref(afb_event_t event); ``` -The following function destiys the event. +The following function add one reference to the event. ```C /* - * Drops the data associated to the 'event' + * Decrease the reference count of the event. * After calling this function, the event * MUST NOT BE USED ANYMORE. */ -void afb_event_drop(struct afb_event event); +void afb_event_unref(afb_event_t event); ``` This function allows to retrieve the exact name of the event. @@ -368,7 +467,7 @@ This function allows to retrieve the exact name of the event. /* * Gets the name associated to the 'event'. */ -const char *afb_event_name(struct afb_event event); +const char *afb_event_name(afb_event_t event); ``` ## Functions of class afb_req @@ -381,7 +480,7 @@ This function checks the validity of the **req**. * * Returns 0 if not valid or 1 if valid. */ -int afb_req_is_valid(struct afb_req req); +int afb_req_is_valid(afb_req_t req); ``` The following functions retrieves parameters of the request. @@ -399,7 +498,7 @@ The following functions retrieves parameters of the request. * 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); +afb_arg_t afb_req_get(afb_req_t req, const char *name); /* * Gets from the request 'req' the string value of the argument of 'name'. @@ -408,7 +507,7 @@ struct afb_arg afb_req_get(struct afb_req req, const char *name); * * Shortcut for: afb_req_get(req, name).value */ -const char *afb_req_value(struct afb_req req, const char *name); +const char *afb_req_value(afb_req_t req, const char *name); /* * Gets from the request 'req' the path for file attached to the argument of 'name'. @@ -417,13 +516,13 @@ const char *afb_req_value(struct afb_req req, const char *name); * * Shortcut for: afb_req_get(req, name).path */ -const char *afb_req_path(struct afb_req req, const char *name); +const char *afb_req_path(afb_req_t 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); +struct json_object *afb_req_json(afb_req_t req); ``` The following functions emit the reply to the request. @@ -439,7 +538,7 @@ The following functions emit the reply to the request. * 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); +void afb_req_success(afb_req_t req, struct json_object *obj, const char *info); /* * Same as 'afb_req_success' but the 'info' is a formatting @@ -449,7 +548,7 @@ void afb_req_success(struct afb_req req, struct json_object *obj, const char *in * 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, ...); +void afb_req_success_f(afb_req_t req, struct json_object *obj, const char *info, ...); /* * Same as 'afb_req_success_f' but the arguments to the format 'info' @@ -459,30 +558,30 @@ void afb_req_success_f(struct afb_req req, struct json_object *obj, const char * * 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); +void afb_req_success_v(afb_req_t 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. + * informational 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 recommended to NEVER use "success" for status. */ -void afb_req_fail(struct afb_req req, const char *status, const char *info); +void afb_req_fail(afb_req_t 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, ...); +void afb_req_fail_f(afb_req_t 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); +void afb_req_fail_v(afb_req_t req, const char *status, const char *info, va_list args); ``` The following functions handle the session data. @@ -492,14 +591,14 @@ The following functions handle the session data. * 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); +void *afb_req_context_get(afb_req_t 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*)); +void afb_req_context_set(afb_req_t req, void *context, void (*free_context)(void*)); /* * Gets the pointer stored by the binding for the session of 'req'. @@ -508,7 +607,7 @@ void afb_req_context_set(struct afb_req req, void *context, void (*free_context) * 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*)); +void *afb_req_context(afb_req_t req, void *(*create_context)(), void (*free_context)(void*)); /* * Frees the pointer stored by the binding for the session of 'req' @@ -516,13 +615,13 @@ void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free * * Shortcut for: afb_req_context_set(req, NULL, NULL) */ -void afb_req_context_clear(struct afb_req req); +void afb_req_context_clear(afb_req_t req); /* * Closes the session associated with 'req' * and delete all associated contexts. */ -void afb_req_session_close(struct afb_req req); +void afb_req_session_close(afb_req_t req); /* * Sets the level of assurance of the session of 'req' @@ -530,7 +629,7 @@ void afb_req_session_close(struct afb_req req); * security policies. * Returns 1 on success or 0 if failed. */ -int afb_req_session_set_LOA(struct afb_req req, unsigned level); +int afb_req_session_set_LOA(afb_req_t req, unsigned level); ``` The 4 following functions must be used for asynchronous handling requests. @@ -541,14 +640,14 @@ The 4 following functions must be used for asynchronous handling requests. * 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); +void afb_req_addref(afb_req_t 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); +void afb_req_unref(afb_req_t req); /* * Stores 'req' on heap for asynchronous use. @@ -556,7 +655,7 @@ void afb_req_unref(struct afb_req req); * 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); +struct afb_stored_req *afb_req_store(afb_req_t req); /* * Retrieves the afb_req stored at 'sreq'. @@ -565,7 +664,7 @@ struct afb_stored_req *afb_req_store(struct afb_req req); * 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); +afb_req_t afb_req_unstore(struct afb_stored_req *sreq); ``` The two following functions are used to associate client with events @@ -577,14 +676,14 @@ The two following functions are used to associate client with events * 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); +int afb_req_subscribe(afb_req_t req, afb_event_t 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); +int afb_req_unsubscribe(afb_req_t req, afb_event_t event); ``` The following functions must be used to make request in the name of the @@ -609,7 +708,7 @@ client (with its permissions). * - 'afb_req_subcall_sync' the synchronous version */ void afb_req_subcall( - struct afb_req req, + afb_req_t req, const char *api, const char *verb, struct json_object *args, @@ -634,7 +733,7 @@ void afb_req_subcall( * - 'afb_req_subcall' that doesn't keep request alive automatically. * - 'afb_req_subcall_sync' the synchronous version */ -static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure) +static inline void afb_req_subcall_req(afb_req_t req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, afb_req_t req), void *closure) { req.itf->subcall_req(req.closure, api, verb, args, callback, closure); } @@ -656,7 +755,7 @@ static inline void afb_req_subcall_req(struct afb_req req, const char *api, cons * - 'afb_req_subcall' that doesn't keep request alive automatically. */ int afb_req_subcall_sync( - struct afb_req req, + afb_req_t req, const char *api, const char *verb, struct json_object *args, @@ -691,7 +790,7 @@ Instead, you should use the macros: * 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, ...); +void afb_req_verbose(afb_req_t req, int level, const char *file, int line, const char * func, const char *fmt, ...); ``` The functions below allow a binding involved in the platform security @@ -705,7 +804,7 @@ application identity. * * Returns 1 if the permission is granted or 0 otherwise. */ -int afb_req_has_permission(struct afb_req req, const char *permission); +int afb_req_has_permission(afb_req_t req, const char *permission); /* * Get the application identifier of the client application for the @@ -716,7 +815,7 @@ int afb_req_has_permission(struct afb_req req, const char *permission); * * The returned value if not NULL must be freed by the caller */ -char *afb_req_get_application_id(struct afb_req req); +char *afb_req_get_application_id(afb_req_t req); /* * Get the user identifier (UID) of the client application for the @@ -724,7 +823,7 @@ char *afb_req_get_application_id(struct afb_req req); * * Returns -1 when the application can not be identified. */ -int afb_req_get_uid(struct afb_req req); +int afb_req_get_uid(afb_req_t req); ``` ## Logging macros diff --git a/docs/afb-binding-writing.md b/docs/afb-binding-writing.md index aad422c4..69090e3d 100644 --- a/docs/afb-binding-writing.md +++ b/docs/afb-binding-writing.md @@ -51,14 +51,21 @@ The binder makes 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***. +## Versions of the bindings + +Since introduction of the binder, the way how bindings are written +evolved a little. While changing, attention was made to ensure binary +compatibility between the different versions. + +Actually it exists 3 ways of writing ***bindings***. You can either write: -- a binding version 1 (not recommended); -- a binding version 2 (RECOMMENDED). +- a binding version 1 (not more supported); +- a binding version 2 (not recommended); +- a binding version 3 (RECOMMENDED). A ***binder*** loads and runs any of these version in any combination. -This document explain how to write bindings version 2. +This document explain how to write bindings version 3. @@ -67,21 +74,21 @@ This document explain how to write bindings version 2. This is the code of the binding **tuto-1.c**: ```C - 1 #define AFB_BINDING_VERSION 2 + 1 #define AFB_BINDING_VERSION 3 2 #include 3 - 4 void hello(afb_req req) + 4 void hello(afb_req_t req) 5 { 6 AFB_REQ_DEBUG(req, "hello world"); - 7 afb_req_success(req, NULL, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); 8 } 9 - 10 const afb_verb_v2 verbs[] = { + 10 const afb_verb_t verbs[] = { 11 { .verb="hello", .callback=hello }, 12 { .verb=NULL } 13 }; 14 - 15 const afb_binding_v2 afbBindingV2 = { + 15 const afb_binding_t afbBindingExport = { 16 .api = "tuto-1", 17 .verbs = verbs 18 }; @@ -93,12 +100,18 @@ Compiling: gcc -fPIC -shared tuto-1.c -o tuto-1.so $(pkg-config --cflags-only-I afb-daemon) ``` +> Note: the variable environment variable PKG_CONFIG_PATH might be necessary +> tuned to get **pkg-config** working properly + Running: ```bash afb-daemon --binding tuto-1.so --port 3333 --token '' ``` +At this point, afb-daemon has started, it loaded the binding tuto-1.so and now +listen at localhost on the port 3333. + Testing using **curl**: ```bash @@ -133,18 +146,15 @@ This shows basic things: The lines 1 and 2 show how to get the include file **afb-binding.h**. ```C - 1 #define AFB_BINDING_VERSION 2 + 1 #define AFB_BINDING_VERSION 3 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. +You must define the version of ***binding*** that you are using. +This is done line 1 where we define that this is the version 3 (earlier +versions 1 and 2 are deprecated). -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. +If you don't define it, an error is reported and the compilation aborts. To include **afb-binding.h** successfully, the include search path should be set correctly if needed (not needed only if installed in @@ -156,81 +166,54 @@ Setting the include path is easy using **pkg-config**: 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: +> Note for **C++** developers: +> +> The ***binder*** currently expose a draft version of **C++** api. +> To get it include the file <**afb/afb-binding**> (without **.h**). -```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**. +The ***binder*** knows that this is a ***binding*** because +it finds the exported symbol **afbBindingExport** that is expected to be +a structure of type **afb_binding_t**. ```C - 10 const afb_verb_v2 verbs[] = { + 10 const afb_verb_t verbs[] = { 11 { .verb="hello", .callback=hello }, 12 { .verb=NULL } 13 }; 14 - 15 const afb_binding_v2 afbBindingV2 = { + 15 const afb_binding_t afbBindingExport = { 16 .api = "tuto-1", 17 .verbs = verbs 18 }; ``` -The structure **afbBindingV2** actually tells that: +The structure **afbBindingExport** 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 exported list of verb is specified by an array of structures of +type **afb_verb_t**, 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 explicitly 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) + 4 void hello(afb_req_t req) 5 { 6 AFB_REQ_DEBUG(req, "hello world"); - 7 afb_req_success(req, NULL, "hello world"); + 7 afb_req_reply(req, NULL, NULL, "hello world"); 8 } ``` @@ -241,18 +224,15 @@ 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 -(line 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. +At the line 7, the callback for **tuto-1/hello** replies to the request **req**. +Parameters of the reply are: -Here again, you can explicitly mark the fact that -**afb_req** is a structure by declaring **hello** as below: + 1. The first parameter is the replied request + 2. The second parameter is a json object (here NULL) + 3. The third parameter is the error string indication (here NULL: no error) + 4. The fourth parameter is an informative string (that can be NULL) that can be used to provide meta data. -```C - 4 void hello(struct afb_req req) -``` +The 3 last parameters are sent back to the client as the reply content. @@ -268,43 +248,43 @@ This is the code of the binding **tuto-2.c**: ```C 1 #include 2 #include - 3 - 4 #define AFB_BINDING_VERSION 2 + 3 + 4 #define AFB_BINDING_VERSION 3 5 #include - 6 - 7 afb_event event_login, event_logout; - 8 - 9 void login(afb_req req) + 6 + 7 afb_event_t event_login, event_logout; + 8 + 9 void login(afb_req_t req) 10 { 11 json_object *args, *user, *passwd; 12 char *usr; - 13 + 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); + 18 afb_req_reply(req, NULL, "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); + 21 afb_req_reply(req, NULL, "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); + 24 afb_req_reply(req, NULL, "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); + 30 afb_req_reply(req, NULL, NULL, NULL); 31 afb_event_push(event_login, json_object_new_string(usr)); 32 } 33 } - 34 - 35 void action(afb_req req) + 34 + 35 void action(afb_req_t req) 36 { 37 json_object *args, *val; 38 char *usr; - 39 + 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)); @@ -319,46 +299,46 @@ This is the code of the binding **tuto-2.c**: 51 afb_req_unsubscribe(req, event_logout); 52 } 53 } - 54 afb_req_success(req, json_object_get(args), NULL); + 54 afb_req_reply(req, json_object_get(args), NULL, NULL); 55 } - 56 - 57 void logout(afb_req req) + 56 + 57 void logout(afb_req_t req) 58 { 59 char *usr; - 60 + 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); + 66 afb_req_reply(req, NULL, NULL, NULL); 67 } - 68 - 69 int preinit() + 68 + 69 int preinit(afb_api_t api) 70 { - 71 AFB_NOTICE("preinit"); + 71 AFB_API_NOTICE(api, "preinit"); 72 return 0; 73 } - 74 - 75 int init() + 74 + 75 int init(afb_api_t api) 76 { - 77 AFB_NOTICE("init"); - 78 event_login = afb_daemon_make_event("login"); - 79 event_logout = afb_daemon_make_event("logout"); + 77 AFB_API_NOTICE(api, "init"); + 78 event_login = afb_api_make_event(api, "login"); + 79 event_logout = afb_api_make_event(api, "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"); + 82 AFB_API_ERROR(api, "Can't create events"); 83 return -1; 84 } - 85 - 86 const afb_verb_v2 verbs[] = { + 85 + 86 const afb_verb_t 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 = { + 92 + 93 const afb_binding_t afbBindingExport = { 94 .api = "tuto-2", 95 .specification = NULL, 96 .verbs = verbs, diff --git a/docs/afb-daemon-debugging.md b/docs/afb-daemon-debugging.md index dd5fd64b..4cf62bea 100644 --- a/docs/afb-daemon-debugging.md +++ b/docs/afb-daemon-debugging.md @@ -1,4 +1,4 @@ -# Debugging afb-daemon and its bindings +# Debugging binder and bindings When compiled with the symbol AGL_DEVEL defined, the ***binder*** understand the 2 configuration variables: diff --git a/docs/afb-daemon-vocabulary.md b/docs/afb-daemon-vocabulary.md index 6c51f124..efe53d20 100644 --- a/docs/afb-daemon-vocabulary.md +++ b/docs/afb-daemon-vocabulary.md @@ -24,10 +24,6 @@ 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 @@ -51,7 +47,7 @@ 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. +Using sockets currently but other protocols are considered. ## Session diff --git a/docs/afb-migration-to-binding-v3.md b/docs/afb-migration-to-binding-v3.md new file mode 100644 index 00000000..8f1e678c --- /dev/null +++ b/docs/afb-migration-to-binding-v3.md @@ -0,0 +1,110 @@ +Migration to binding V3 +======================= + +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 obscure features, cleanup + +The ***binder*** can run ***bindings*** v1, v2 and/or v3 in any combination. +Thus moving from v1 or v2 to v3 is not enforced at this time. But ... + +In the face to face meeting of Karlsruhe it was decided to remove support +of bindings v1 and to deprecate the use of bindings v2. + +So at the end, **IT IS HIGHLY NEEDED TO SWITCH TO VERSION 3** + +This guide covers the migration of bindings from version 2 to version 3. + +The migration from version 1 is not treated here because bindings version 1 +are very old and probably does not exist anymore. If needed you can refer +to the old [guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md). + + +Differences between version 2 and version 3 +------------------------------------------- + +### in v3 all is api + +The version 3 introduce the concept of "API" that gather what was called before +the daemon and the service. This is the new concept that predates the 2 others. + +The concept of API is intended to allow the definition of multiple APIs +by a same "binding" (a dynamically loaded library). + +Because there is potentially several "API", the functions that were without +context in bindings version 2 need now to tell what API is consumer. + +To be compatible with version 2, the bindings v3 still have a default hidden +context: the default API named **afbBindingV3root**. + +To summarize, the functions of class **daemon** and **service** use the default +hidden API. + +It is encouraged to avoid use of functions of class **daemon** and **service**. +You should replace these implicit calls to explicit **api** calls that +reference **afbBindingV3root**. + +Same thing for the logging macros: **AFB_ERROR**, **AFB_WARNING**, +**AFB_NOTICE**, **AFB_INFO**, **AFB_DEBUG** that becomes respectively +**AFB_API_ERROR**, **AFB_API_WARNING**, **AFB_API_NOTICE**, **AFB_API_INFO**, +**AFB_API_DEBUG**. + +Example of 2 equivalent writes: + +```C + AFB_NOTICE("send stress event"); + afb_daemon_broadcast_event(stressed_event, NULL); +``` + +or + +```C + AFB_API_NOTICE(afbBindingV3root, "send stress event"); + afb_api_broadcast_event(afbBindingV3root, stressed_event, NULL); +``` + +### the reply mechanism predates success and fail + +### subcall has more power + +Task list for the migration +--------------------------- + +This task list is: + +1. Use the automatic migration procedure described below +2. Adapt the init and preinit functions +3. Consider to change to use the new reply +4. Consider to change to use the new (sub)call + +The remaining chapters explain these task with more details. + +Automatic migration! +-------------------- + +A tiny **sed** script is intended to perform a first pass on the code that +you want to upgrade. It can be down using **curl** and applied using **sed** +as below. + +```bash +BASE=https://git.automotivelinux.org/src/app-framework-binder/tree +SED=migration-to-binding-v3.sed +curl -o $SED $BASE/docs/$SED +sed -i -f $SED file1 file2 file3... +``` + +This automatic action does most of the boring job nut not all the job. +The remaining of this guide explains the missing part. + +Adapt the init and preinit functions +------------------------------------ + +Consider to change to use the new reply +--------------------------------------- + +Consider to change to use the new (sub)call +------------------------------------------- + diff --git a/docs/afb-migration-v1-to-v2.md b/docs/afb-migration-v1-to-v2.md index f3182918..9a43454e 100644 --- a/docs/afb-migration-v1-to-v2.md +++ b/docs/afb-migration-v1-to-v2.md @@ -1,6 +1,11 @@ -Migration from binding V1 to binding V2 +[LEGACY] Migration from binding V1 to binding V2 ======================================= +> LEGACY!!! IT IS NOT EXPECTED THAT YOU STILL NEED THIS GUIDE. +> +> THIS GUIDE WILL BE REMOVED IN A NEAR FUTURE + + The ***binding*** interface evolved from version 1 to version 2 for the following reasons: diff --git a/docs/afb-overview.md b/docs/afb-overview.md index 0cff24cc..2682d8d1 100644 --- a/docs/afb-overview.md +++ b/docs/afb-overview.md @@ -6,14 +6,14 @@ 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 developed for AGL. +- The ***binder*** is developed for AGL (Automotive Grade Linux) but it is not bound to 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). +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. diff --git a/docs/annexes.md b/docs/annexes.md index 2304bfb0..10952e0f 100644 --- a/docs/annexes.md +++ b/docs/annexes.md @@ -1,4 +1,7 @@ # Annexes +* [Migration to binding v3](afb-migration-to-binding-v3.md) +* [Options of afb-daemon](afb-daemon-options.md) * [Installing the binder on a desktop](afb-desktop-package.md) -* [Options of afb-daemon](afb-daemon-options.md) \ No newline at end of file +* [Debugging afb-daemon](afb-daemon-debugging.md) +* [(LEGACY) guide to migrate bindings from v1 to v2](afb-migration-v1-to-v2.md). diff --git a/docs/migration-to-binding-v3.sed b/docs/migration-to-binding-v3.sed new file mode 100644 index 00000000..a6682051 --- /dev/null +++ b/docs/migration-to-binding-v3.sed @@ -0,0 +1,68 @@ +####################################################################################### +# Script sed for migrating from AFB_BINDING_VERSION 2 to AFB_BINDING_VERSION 3 +# See http://docs.automotivelinux.org/docs/apis_services/en/dev/reference/af-binder/afb-migration-to-ibinding-v3.html +####################################################################################### +# update the version +# ------------------ +s:\(\:\13: + +# update common types +# ------------------- +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_req\>:afb_req_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_event\>:afb_event_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_verb_v2\>:afb_verb_t:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_binding_v2\>:afb_binding_t:g + +# update common names +# ------------------- +s:\:afbBindingExport:g + +# very special +# ------------ +s:( *afb_req_t *) *{ *NULL *, *NULL *}:NULL:g + +# special dynapi +# -------------- +s:\(\:\13: +/^[[:blank:]]*# *define *\/d +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_dynapi\>\([[:blank:]]*\)\*:afb_api_t\2:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_request\>\([[:blank:]]*\)\*:afb_req_t\2:g +s:\<\(struct[[:blank:]]\{1,\}\)\{0,1\}afb_eventid\>\([[:blank:]]*\)\*:afb_event_t\2:g +s:\:afbBindingV3entry:g +s:\:api:g +s:\:event:g +s:\:afb_api_make_event:g +s:\:-!&:g +s:\:afb_api_del_verb:g + +# udate legacy calls +# ------------------ +s:\:afb_req_subcall_legacy:g +s:\:afb_req_subcall_sync_legacy:g +s:\:afb_api_call_legacy:g +s:\:afb_api_call_sync_legacy:g +s:\:afb_req_addref:g +s:\ *( *\(.*\) *):\1:g +s:\ *(\):AFB_API_\1afbBindingV3root,:g + +# special app-controller +# ---------------------- +s:\<_\(AFB_SYSLOG_LEVEL_[A-Z]*\)_\>:\1:g + +# UNSAFES (uncomment it if optimistic) +# -------------- +#s:\\( *([^,]*\):afb_req_reply\1\2, NULL:g +#s:\\( *([^,]*,[^,]*\):afb_req_reply\1\2, NULL:g +# +#s:\[^)]*:&, 0:g ;# dynapi +#s:\[^)]*:&, NULL:g ;# dynapi +####################################################################################### diff --git a/doxyfile.binder b/doxyfile.binder new file mode 100644 index 00000000..4aef9a15 --- /dev/null +++ b/doxyfile.binder @@ -0,0 +1,2435 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "AGL micro-service binder" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./docs/binder + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = YES + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ./include \ + ./src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cxx \ + *.cpp \ + *.h \ + *.hxx \ + *.hpp \ + *.md + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = bindings/tutorial + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = NO + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 30 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 150 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 150 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /