From f6bc48698587758fb764bae66302002fe148e978 Mon Sep 17 00:00:00 2001 From: José Bollo Date: Wed, 7 Jun 2017 18:40:00 +0200 Subject: Refactor of the documentation --- old-docs/FAQ.md | 5 + old-docs/afb-application-writing.md | 301 +++++++ old-docs/afb-bindings-overview.md | 180 ++++ old-docs/afb-bindings-writing.md | 1407 ++++++++++++++++++++++++++++++++ old-docs/afb-daemon-vocabulary.md | 98 +++ old-docs/afb-events-guide.md | 475 +++++++++++ old-docs/afb-overview.md | 315 +++++++ old-docs/afb-tests-overview.md | 89 ++ old-docs/index.md | 1 + old-docs/pictures/AFB_for_services.svg | 238 ++++++ old-docs/pictures/AFB_overview.svg | 140 ++++ old-docs/pictures/signaling-basis.svg | 145 ++++ old-docs/pictures/tic-tac-toe.svg | 289 +++++++ old-docs/pictures/triskel_iot_bzh.svg | 110 +++ 14 files changed, 3793 insertions(+) create mode 100644 old-docs/FAQ.md create mode 100644 old-docs/afb-application-writing.md create mode 100644 old-docs/afb-bindings-overview.md create mode 100644 old-docs/afb-bindings-writing.md create mode 100644 old-docs/afb-daemon-vocabulary.md create mode 100644 old-docs/afb-events-guide.md create mode 100644 old-docs/afb-overview.md create mode 100644 old-docs/afb-tests-overview.md create mode 120000 old-docs/index.md create mode 100644 old-docs/pictures/AFB_for_services.svg create mode 100644 old-docs/pictures/AFB_overview.svg create mode 100644 old-docs/pictures/signaling-basis.svg create mode 100644 old-docs/pictures/tic-tac-toe.svg create mode 100644 old-docs/pictures/triskel_iot_bzh.svg (limited to 'old-docs') diff --git a/old-docs/FAQ.md b/old-docs/FAQ.md new file mode 100644 index 00000000..5063ed74 --- /dev/null +++ b/old-docs/FAQ.md @@ -0,0 +1,5 @@ +Frequently Asked Question about AFB-DAEMON +========================================== + + + diff --git a/old-docs/afb-application-writing.md b/old-docs/afb-application-writing.md new file mode 100644 index 00000000..cc513b48 --- /dev/null +++ b/old-docs/afb-application-writing.md @@ -0,0 +1,301 @@ +How to write an application on top of AGL FRAMEWORK +==================================================== + +Programming Languages for Applications +----------------------------------------- + +### Writing an HTML5 application + +Developers of HTML5 applications (client side) can easily create +applications for AGL framework using their preferred +HTML5 framework. + +Developers may also take advantage of powerful server side bindings to improve +application behavior. Server side bindings return an application/json mine-type +and can be accessed though either HTTP or Websockets. + +In a near future, JSON-RPC protocol should be added to complete the current +x-afb-json1 protocol. + +Two examples of HTML5 applications are given: + +- [afb-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afb-client) a simple "hello world" application template + +- [afm-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afm-client) a simple "Home screen" application template + +### Writing a Qt application + +Writing Qt applications is also supported. Qt offers standard API to send +request through HTTP or WebSockets. + +It is also possible to write QML applications. A sample QML application +[token-websock] is available: + +- [token-websock](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=test/token-websock.qml) +a simple "hello world" application in QML + +### Writing a "C" application + +C applications can use afb-daemon binder through a websocket connection. + +The library **libafbwsc** is provided for C clients that need +to connect with an afb-daemon binder. + +The program **afb-client-demo** is the C example that use +**libafbwsc** library. +Source code is available here +[src/afb-client-demo.c](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=src/afb-client-demo.c). + +Current implementation relies on libsystemd and file descriptors. +This model might be review in the future to support secure sockets +and get rid of libsystemd dependency. + +Handling sessions within applications +------------------------------------- + +Applications should understand sessions and token management when interacting +with afb-daemon binder. + +Applications communicate with their private binder(afb-daemon) using +a network connection or potentially any other connection channel. While the +current version does not yet implement Unix socket, this feature might be added +in the near future. Developers need to be warn that HTTP protocol is a none +connected protocol and that using HTTP socket connection to authenticate +clients is not supported. + +For this reason, the binder should authenticate the application +by using a shared secret. The secret is named "token" and the identification +of client is named "session". + +The examples **token-websock.qml** and **afb-client** are demonstrating +how authentication and sessions are managed. + +### Handling sessions + +Bindings and other binder features need to keep track of client +instances. This is especially important for bindings running as services +as they may typically have to keep each client's data separated. + +For HTML5 applications, the web runtime handles the cookie of session +that the binder afb-daemon automatically sets. + +Session identifier can be set using the parameter **uuid** or **x-afb-uuid** in +URI requests. Within current version of the framework session UUID is supported +by both HTTP requests and websocket negotiation. + +### Exchanging tokens + +At application start, AGL framework communicates a shared secret to both binder +and client application. This initial secret is called the "**initial token**". + +For each of its client application, the binder manages a current active +token for session management. This authentication token can be use to restrict +the access to some binding's methods. + +The token must be included in URI request on HTTP or during websockets +connection using parameter **token** or **x-afb-token**. + +To ensure security, tokens must be refreshed periodically. + +### Example of session management + +In following examples, we suppose that **afb-daemon** is launched with something +equivalent to: + + $ afb-daemon --port=1234 --token=123456 [...] + +making the expectation that **AuthLogin** binding is requested as default. + +#### Using curl + +First, connects with the initial token, 123456: + + $ curl http://localhost:1234/api/auth/connect?token=123456 + { + "jtype": "afb-reply", + "request": { + "status": "success", + "token": "0aef6841-2ddd-436d-b961-ae78da3b5c5f", + "uuid": "850c4594-1be1-4e9b-9fcc-38cc3e6ff015" + }, + "response": {"token": "A New Token and Session Context Was Created"} + } + +It returns an answer containing session UUID, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015, +and a refreshed token, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015. + +Check if session and token is valid: + + $ curl http://localhost:1234/api/auth/check?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": {"status":"success"}, + "response": {"isvalid":true} + } + +Refresh the token: + + $ curl http://localhost:1234/api/auth/refresh?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": { + "status":"success", + "token":"b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9" + }, + "response": {"token":"Token was refreshed"} + } + +Close the session: + + curl http://localhost:1234/api/auth/logout?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": {"status": "success"}, + "response": {"info":"Token and all resources are released"} + } + +Checking on closed session for uuid should be refused: + + curl http://localhost:1234/api/auth/check?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 + { + "jtype": "afb-reply", + "request": { + "status": "failed", + "info": "invalid token's identity" + } + } + +#### Using afb-client-demo + +> The program is packaged within AGL in the rpm **libafbwsc-dev** + +Here is an example of exchange using **afb-client-demo**: + + $ afb-client-demo ws://localhost:1234/api?token=123456 + auth connect + ON-REPLY 1:auth/connect: {"jtype":"afb-reply","request":{"status":"success", + "token":"63f71a29-8b52-4f9b-829f-b3028ba46b68","uuid":"5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1"}, + "response":{"token":"A New Token and Session Context Was Created"}} + auth check + ON-REPLY 2:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + auth refresh + ON-REPLY 4:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", + "token":"8b8ba8f4-1b0c-48fa-962d-4a00a8c9157e"},"response":{"token":"Token was refreshed"}} + auth check + ON-REPLY 5:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + auth refresh + ON-REPLY 6:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", + "token":"e83b36f8-d945-463d-b983-5d8ed73ba529"},"response":{"token":"Token was refreshed"}} + +After closing connection, reconnect as here after: + + $ afb-client-demo ws://localhost:1234/api?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 auth check + ON-REPLY 1:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + +Same connection check using **curl**: + + $ curl http://localhost:1234/api/auth/check?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 + {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} + +Format of replies +----------------- + +Replies use javascript object returned as serialized JSON. + +This object contains at least 2 mandatory fields of name **jtype** and +**request** and one optional field of name **response**. + +### Template + +This is a template of replies: + +```json +{ + "jtype": "afb-reply", + "request": { + "status": "success", + "info": "informationnal text", + "token": "e83b36f8-d945-463d-b983-5d8ed73ba52", + "uuid": "5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1", + "reqid": "application-generated-id-23456" + }, + "response": ....any response object.... +} +``` + +### Field jtype + +The field **jtype** must have a value of type string equal to **"afb-reply"**. + +### Field request + +The field **request** must have a value of type object. This request object +has at least one field named **status** and four optional fields named +**info**, **token**, **uuid**, **reqid**. + +#### Subfield request.status + +**status** must have a value of type string. This string is equal to **"success"** +only in case of success. + +#### Subfield request.info + +**info** is of type string and represent optional information added to the reply. + +#### Subfield request.token + +**token** is of type string. It is sent either at session creation +or when the token is refreshed. + +#### Subfield request.uuid + +**uuid** is of type string. It is sent at session creation. + +#### Subfield request.reqid + +**reqid** is of type string. It is sent in response to HTTP requests +that added a parameter of name **reqid** or **x-afb-reqid** at request time. +Value returns in the reply has the exact same value as the one received in the +request. + +### Field response + +This field response optionally contains an object returned when request +succeeded. + +Format of events +---------------- + +Events are javascript object serialized as JSON. + +This object contains at least 2 mandatory fields of name **jtype** and **event** +and one optional field of name **data**. + +### Template + +Here is a template of event: + +```json +{ + "jtype": "afb-event", + "event": "sample_api_name/sample_event_name", + "data": ...any event data... +} +``` + +### Field jtype + +The field **jtype** must have a value of type string equal to **"afb-event"**. + +### Field event + +The field **event** carries the event's name. + +The name of the event is made of two parts separated by a slash: +the name of the name of the API that generated the event +and the name of event within the API. + +### Field data + +This field data if present holds the data carried by the event. + diff --git a/old-docs/afb-bindings-overview.md b/old-docs/afb-bindings-overview.md new file mode 100644 index 00000000..c79e17f4 --- /dev/null +++ b/old-docs/afb-bindings-overview.md @@ -0,0 +1,180 @@ + +Overview of bindings shipped with AFB-Daemon +=========================================== + +List of bindings +--------------- + +Here are the bindings shipped in the source tree: + +* Hello World +* Authentication +* Tic Tac Toe +* Audio _(2 backends: ALSA/PulseAudio)_ +* Radio _(1 backend: RTLSDR RTL2832U)_ +* Media _(1 backend: Rygel UPnP)_ + +All bindings may not be built, depending on the development libraries present on +the system at build time. + + +Detail of bindings +----------------- + +### Hello World + +A sample Hello World binding for demonstration and learning purposes. + +This binding provides a few unauthenticated requests, all beginning with +"ping", to demonstrate basic binder capabilities. + +**Verbs**: + +* _ping:_ returns a success response +* _pingfail:_ returns a failure response +* _pingnull:_ returns a success response, with an empty JSON response field +* _pingbug:_ does a memory violation (intercepted by the binder) +* _pingJson:_ returns a success response, with a complex JSON response field +* _pingevent:_ broadcasts a global event + +
+ + +### Authentication + +A sample Authentication binding for demonstration purposes. + +This binding provides a few requests to demonstrate the binder's token-based +security mechanism. + +Calling "_connect_" with a security token will initiate a session, calling +"_refresh_" will issue a new token and invalidate the previous one, calling +"_logout_" will invalidate all tokens and close the session. + +**Verbs**: + +* _ping:_ returns a success response +* _connect:_ creates a session and returns a new token +* _refresh:_ returns a new token +* _check:_ verifies the passed token is valid +* _logout:_ closes the session + +
+ + +### Tic Tac Toe + +A sample Tic Tac Toe game binding. + +This binding provides an interactive Tic Tac Toe game where the binder returns +the grid as a JSON response. + +**Verbs**: + +* _new:_ starts a new game +* _play:_ asks the server to play +* _move:_ gives a client move +* _board:_ gets the current board state, as a JSON structure +* _level_: sets the server level +* _join_: joins an existing board +* _undo_: undo the last move +* _wait_: wait for a move + +
+ + +### Audio + +A sample Audio binding with 2 backends: + +* ALSA (mandatory) +* PulseAudio (optional) + +This binding is able to initialize a specific soundcard, define volume levels, +channels (mono/stereo...), mute sound, and play a 22,050 Hz PCM stream. + +**Verbs**: + +* _ping:_ returns a success response +* _init:_ initializes backend, on the "default" sound card +* _volume:_ gets or sets volume, in % (0-100) +* _channels:_ gets or sets channels count (1-8) +* _mute:_ gets or sets the mute status (on-off) +* _play_: gets or sets the playing status (on-off) + +_(if PulseAudio development libraries are not found at build time, only ALSA +will be available)_ + +_(if a PulseAudio server is not found at runtime, the binding will dynamically +fall back to ALSA)_ + +_(a specifc backend can be forced by using this syntax before running afb-daemon +: **$ export AFB_AUDIO_OUTPUT=Alsa**)_ + +
+ + +### Radio + +A sample AM/FM Radio binding with 1 backend: + +* RTLSDR - Realtek RTL2832U dongles (mandatory) + +This binding is able to initialize specific RTL2832U dongles, switch between +AM/FM modes, define frequency, mute sound, and play sound (if combining with +the **audio** binding). + +**Verbs**: + +* _ping:_ returns a success response +* _init:_ initializes backend, looking for plugged-in devices +* _power:_ sets device power status (on-off) +* _mode:_ sets device reception mode (AM-FM) +* _freq:_ sets device frequency (in Hz) +* _mute_: sets device mute status (on-off) +* _play_: sets device playing status (on-off) + +_(if rtlsdr development libraries are not found at build time, this binding will +not be built)_ + +
+ +### Media + +A sample Media Server binding with 1 backend: + + * Rygel + +This binding is able to detect a local Rygel UPnP media server, list audio +files, select an audio file for playback, play/pause/seek in this file, upload +an audio file to the server. + +**Verbs**: + +* _ping:_ returns a success response +* _init:_ initializes backend, looking for an active local UPnP server +* _list:_ returns list of audio files, as a JSON structure +* _select:_ select an audio files, by index number (001-...) +* _play:_ plays the currently selected audio file +* _stop:_ stops the currently selected audio file +* _pause:_ pauses the currently selected audio file +* _seek:_ seeks in the currently selected audio file, in seconds +* _upload:_ uploads an audio file, with a POST request + +_(if GUPnP/GSSDP development libraries are not found at build time, this binding +will not be built)_ + +
+ + +--- +
+ +Sample command-line applications: _afb-client-demo_ (built by default) + +Sample HTML5 applications: +**test/*.html**, +**[afb-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree)**, +**[afb-radio](https://github.com/iotbzh/afb-radio)** + +Sample Qt/QML applications: *test/token-websock.qml* diff --git a/old-docs/afb-bindings-writing.md b/old-docs/afb-bindings-writing.md new file mode 100644 index 00000000..d8335086 --- /dev/null +++ b/old-docs/afb-bindings-writing.md @@ -0,0 +1,1407 @@ + +How to write a binding for AFB-DAEMON +=================================== + +Summary +------- + +The afb-daemon binders serve files through HTTP protocol and offers to +developers the capability to offer application API methods through HTTP or +WebSocket protocol. + +The bindings are used to add API to ***afb-daemon***. +This part describes how to write a binding for***afb-daemon***. + +Excepting this summary, this document target developers. + +Before moving further through an example, here after +a short overview of binder bindings fundamentals. + +### Nature of a binding + +A binding is an independent piece of software. A binding is self contain and +exposes application logic as sharable library. A binding is intended to be +dynamically loaded by ***afb-daemon*** to expose application API. + +Technically, a binder binding does not reference and is not linked with any +***afb-daemon*** library. + +### Class of bindings + +Application binder supports two kinds of bindings: application bindings and +service bindings. Technically both class of binding are equivalent and use the +same coding convention. Only sharing mode and security context diverge. + +#### Application-bindings + +Application-bindings implements the glue in between application's UI and +services. Every AGL application has a corresponding binder that typically +activates one or many bindings to interface the application logic with lower +platform services. When an application is started by the AGL application +framework, a dedicate binder is started that loads/activates application +binding(s). API expose by application-binding are executed within corresponding +application security context. + +Application bindings generally handle a unique context for a unique client. As +the application framework start a dedicated instance of afb_daemon for each AGL +application, if a given binding is used within multiple application each of +those application get a new and private instance of eventually "shared" binding. + +#### Service-bindings + +Service-bindings enable API activation within corresponding service security +context and not within calling application context. Service-bindings are +intended to run as a unique instance. Service-bindings can be shared in between +multiple clients. + +Service-bindings can either be stateless or manage client context. When managing +context each client get a private context. Sharing may either be global to the +platform (ie: GPS service) or dedicated to a given user (ie: user preferences) + +### Live cycle of bindings within ***afb-daemon*** + +Application and service bindings are loaded and activated each time a new +***afb-daemon*** is started. + +At launch time, every loaded binding initialise itself. If a single binding +initialisation fails the corresponding instance of ***afb-daemon*** aborts. + +Conversely, when a binding initialisation succeeds, it should register its +unique name as well as the list of verbs (methods name from binder point of +view) attached to the methods it exposes. + +When initialised, on request from application clients to the right API/verbs +binding methods are activated by the ***afb-daemon*** attached to the +application or service. + +At exit time, no special action is enforced by ***afb-daemon***. When a specific +actions is required at afb-daemon stop, developers should use 'atexit/on_exit' +during binding initialisation sequence to register a custom exit function. + +### Binding Content + +Afb-daemon's bindings register two classes of objects: names and functions. + +Bindings declare categories of names: + - A unique binding name to access all API exposed by this binding, + - One name for each methods/verbs provided by this binding. + +Bindings declare two categories of functions: + - function used for initialisation + - functions implementing the exposed API methods + +Afb-daemon parses URI requests to extract the API(binding name) and the +VERB(method to activate). As an example, URI **foo/bar** translates to binding +named **foo** and method named **bar**. To serve such a request, +***afb-daemon*** looks for an active binding named **foo** and then within this +binding for a method named **bar**. When found ***afb-daemon*** calls +the corresponding method with an attached parameter if any. + +Afb-daemon is case-insensitive when parsing URI. Thus **TicTacToe/Board** and +**tictactoe/board** are equivalent. + +#### The name of the binding + +The name of a given binding is also known as the name +of the API prefix that defines the binding. + +The name of a binding SHOULD be unique within a given ***afb-daemon*** instance. + +For example, when a client of ***afb-daemon*** calls a URI named **foo/bar**. +Afb-daemon extracts the prefix **foo** and the suffix **bar**. **foo** must +match a binding name and **bar** has to match a VERB attached to some method. + +#### Names of methods + +Each binding exposes a set of methods that can be called by the clients of a +given ***afb-daemon***. + +VERB's name attached to a given binding (API) MUST be unique within a binding. + +Bindings static declaration link VERBS to the corresponding methods. +When clients emit requests on a given API/VERB corresponding method is called +by ***afb-daemon***. + +#### Initialisation function + +Binding's initialisation function serves several purposes. + +1. It allows ***afb-daemon*** to control the binding version depending on +the initialisation of function name. As today, the only supported initialisation +function is **afbBindingV1Register**. This identifies version "one" of bindings. + +2. It allows bindings to initialise itself. + +3. It enables names declarations: descriptions, requirements and implementations +of exposed API/VERB. + +#### Functions instantiation of API/VERBs + +When an API/VERB is called, ***afb-daemon*** constructs a request object. Then +it passes this request object to the implementation function corresponding to +requested method, this within attached API binding. + +An implementation function receives a request object used to: get +the arguments of the request, send an answer, store session data. + +A binding MUST set an answer to every received requests. + +Nevertheless, there are two implementations, *synchronous* and *asynchronous*. +API/VERB implementation that set an answer before returning are called +*synchronous implementations*. Those that do not systematically set an answer +before returning are called *asynchronous implementations*. + +Asynchronous implementations typically launch asynchronous actions. They record +some context at request time and provide an answer to the request only at +completion of asynchronous actions. + +The Tic-Tac-Toe example +----------------------- + +This part explains how to write an afb-binding. For the sake of being practical +it uses many examples based on tic-tac-toe. This binding example is in +*bindings/samples/tic-tac-toe.c*. + +This binding is named ***tictactoe***. + +Dependencies when compiling +--------------------------- + +Afb-daemon provides a configuration file for *pkg-config*. +Typing the command + + pkg-config --cflags afb-daemon + +Print flags use for compilation: + + $ pkg-config --cflags afb-daemon + -I/opt/local/include -I/usr/include/json-c + +For linking, you should use + + $ pkg-config --libs afb-daemon + -ljson-c + +Afb-daemon automatically includes the dependency to json-c. +This is activated through **Requires** keyword in pkg-config. +While almost every binding replies on **json-c** this is not a must have +dependency. + +Internally, ***afb-daemon*** relies on **libsystemd** for its event loop, as +well as for its binding to D-Bus. Bindings developers are encouraged to leverage +**libsystemd** when possible. Nevertheless there is no hard dependency to +**libsystemd** if you do not want to use it, feel free to do so. + +> Afb-daemon bindings are fully self contained. They do not enforce dependency +on any libraries from the application framework. +> Afb-daemon dependencies requirer to run AGL bindings are given at runtime +through pointers leveraging read-only +> memory feature. + +Header files to include +----------------------- + +Binding *tictactoe* has following includes: + +```C +#define _GNU_SOURCE +#include +#include +#include +#include +``` + +Header *afb/afb-binding.h* is the only hard dependency, it includes all features +that a binding MUST HAVE. Outside of includes used to support application logic, +common external headers used within bindings are: + +- *json-c/json.h*: should be include to handle json objects; +- *systemd/sd-event.h*: should be include to access event main loop; +- *systemd/sd-bus.h*: should be include for dbus connections. + +The *tictactoe* binding does not leverage systemd features, also only json.h +is used on top of mandatory afb/afb-binding.h. + +When including *afb/afb-binding.h*, the macro **_GNU_SOURCE** MUST be +defined. + +Choosing names +-------------- + +Designers of bindings should define a unique name for every API binding +as well as for methods VERBs. They should also define names for request +arguments passed as name/value pair in URI. + +While forging names, designers should respect few rules to +ensure that created names are valid and easy to use across platforms. + +All names and strings are UTF-8 encoded. + +### Names for API (binding) + +Binding API name are checked. +All characters are authorised except: + +- the control characters (\u0000 .. \u001f) +- the characters of the set { ' ', '"', '#', '%', '&', + '\'', '/', '?', '`', '\x7f' } + +In other words the set of forbidden characters is +{ \u0000..\u0020, \u0022, \u0023, \u0025..\u0027, + \u002f, \u003f, \u0060, \u007f }. + +Afb-daemon makes no distinction between lower case +and upper case when searching for API/VERB. + +### Names for methods + +The names of methods VERBs are totally free and not checked. + +However, the validity rules for method's VERB name are the +same as for Binding API name except that the dot(.) character +is forbidden. + +Afb-daemon makes no case distinction when searching for an API by name. + +### Names for arguments + +Argument's name are not restricted and can be everything you wish. + +> Warning arguments search is case sensitive and "index" and "Index" +> are not two different arguments. + +### Forging names widely available + +The key names of javascript object can be almost +anything using the arrayed notation: + + object[key] = value + +Nevertheless this is not the case with javascript dot notation: + + object.key = value + +Using the dot notation, the key must be a valid javascript +identifier and dash(-) as well as few other reserved characters cannot be used. + +For this reason, we advise developers to chose name compatible with both +javascript and HTML notation. + +It is a good practice, even for arguments not to rely on case sensitivity. +This may reduce headache strength at debug time, especially with interpreted +language like javascript that may not warn you that a variable was not defined. + +Declaration of methods and initialisation of the bindings +--------------------------------------------------------- + +### Declaration of methods + +To be active, binding's methods should be declared to +***afb-daemon***. Furthermore, the binding itself must be recorded. + +The registration mechanism is very basic: when ***afb-daemon*** starts, +it loads all bindings listed in: command line or configuration file. + +Loading a binding follows the following steps: + +1. Afb-daemon loads the binding with *dlopen*. + +2. Afb-daemon searches for a symbol named **afbBindingV1Register** using *dlsym*. +This symbol is assumed to be the exported initialisation function of the binding. + +3. Afb-daemon builds an interface object for the binding. + +4. Afb-daemon calls the found function **afbBindingV1Register** with interface pointer +as parameter. + +5. Function **afbBindingV1Register** setups the binding and initialises it. + +6. Function **afbBindingV1Register** returns the pointer to a structure +describing the binding: version, name (prefix or API name), and list of methods. + +7. Afb-daemon checks that the returned version and name can be managed. +If so, binding and its methods are register to become usable as soon as +***afb-daemon*** initialisation is finished. + +### Initialisation of bindings + +The bindings initialisation is the final step made at the end of declaration of +methods. This will initialize the binding and make its ***afb-daemon***'s +interface fully functional. + +So, afb-daemon binder call **afbBindingV1ServiceInit** as final step to a +binding. This will allows the binding to call features in its name and as saw in +[Binder events guide](afb-events-guide.md) you can create an event only at this +moment and not before. Before that it will fail because afb-daemon doesn't know +the binding name. + +**afbBindingV1ServiceInit** is defined as below: + +```C +/* + * When a binding have an exported implementation of the + * function 'afbBindingV1ServiceInit', defined below, + * the framework calls it for initialising the service after + * registration of all bindings. + * + * The object 'service' should be recorded. It has functions that + * allows the binding to call features with its own personality. + * + * The function should return 0 in case of success or, else, should return + * a negative value. + */ +extern int afbBindingV1ServiceInit(struct afb_service service); +``` + +### Application binding example: tic-tac-toe + +If we continue our tic-tac-toe example, here after the code used for +**afbBindingV1Register** implementation from binding *tic-tac-toe*: + +```C +/* + * 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 +} +``` + +It is a very minimal initialisation function because *tic-tac-toe* binding doesn't +have any application related initialisation step. It merely record daemon's interface +and returns its description. + +The variable **afbitf** is a binding global variable. It keeps the +interface to ***afb-daemon*** that should be used for logging and pushing events. +Here is its declaration: + +```C +/* + * the interface to afb-daemon + */ +const struct afb_binding_interface *afbitf; +``` + +The description of the binding is defined here after. + +```C +/* + * array of the methods exported to afb-daemon + */ +static const struct afb_verb_desc_v1 binding_methods[] = { + /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ + { .name= "new", .session= AFB_SESSION_NONE, .callback= new, .info= "Starts a new game" }, + { .name= "play", .session= AFB_SESSION_NONE, .callback= play, .info= "Asks the server to play" }, + { .name= "move", .session= AFB_SESSION_NONE, .callback= move, .info= "Tells the client move" }, + { .name= "board", .session= AFB_SESSION_NONE, .callback= board, .info= "Get the current board" }, + { .name= "level", .session= AFB_SESSION_NONE, .callback= level, .info= "Set the server level" }, + { .name= "join", .session= AFB_SESSION_CHECK,.callback= join, .info= "Join a board" }, + { .name= "undo", .session= AFB_SESSION_NONE, .callback= undo, .info= "Undo the last move" }, + { .name= "wait", .session= AFB_SESSION_NONE, .callback= wait, .info= "Wait for a change" }, + { .name= NULL } /* marker for end of the array */ +}; + +/* + * description of the binding for afb-daemon + */ +static const struct afb_binding binding_description = +{ + /* description conforms to VERSION 1 */ + .type= AFB_BINDING_VERSION_1, + .v1= { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */ + .prefix= "tictactoe", /* the API name (or binding name or prefix) */ + .info= "Sample tac-tac-toe game", /* short description of of the binding */ + .methods = binding_methods /* the array describing the methods of the API */ + } +}; +``` + +The structure **binding_description** describes the binding. +It declares the type and version of the binding, its name, a short description +and its methods list. + +The list of methods is an array of structures describing the methods and terminated by a NULL marker. + +In version one of afb-damon binding, a method description contains 4 fields: + +- the name of the method, + +- the session management flags, + +- the implementation function to be call for the method, + +- a short description. + +The structure describing methods is defined as follows: + +```C +/* + * Description of one method of the API provided by the binding + * This enumeration is valid for bindings of type 1 + */ +struct afb_verb_desc_v1 +{ + const char *name; /* name of the method */ + enum AFB_session_v1 session; /* authorisation and session requirements of the method */ + void (*callback)(struct afb_req req); /* callback function implementing the method */ + const char *info; /* textual description of the method */ +}; +``` + +For technical reasons, the enumeration **enum AFB_session_v1** is not exactly an +enumeration but the wrapper of constant definitions that can be mixed using bitwise or +(the C operator |). + +The constants that can bit mixed are: + +Constant name | Meaning +-------------------------|------------------------------------------------------------- +**AFB_SESSION_CREATE** | Equals to AFB_SESSION_LOA_EQ_0|AFB_SESSION_RENEW +**AFB_SESSION_CLOSE** | Closes the session after the reply and set the LOA to 0 +**AFB_SESSION_RENEW** | Refreshes the token of authentification +**AFB_SESSION_CHECK** | Just requires the token authentification +**AFB_SESSION_LOA_LE_0** | Requires the current LOA to be lesser then or equal to 0 +**AFB_SESSION_LOA_LE_1** | Requires the current LOA to be lesser then or equal to 1 +**AFB_SESSION_LOA_LE_2** | Requires the current LOA to be lesser then or equal to 2 +**AFB_SESSION_LOA_LE_3** | Requires the current LOA to be lesser then or equal to 3 +**AFB_SESSION_LOA_GE_0** | Requires the current LOA to be greater then or equal to 0 +**AFB_SESSION_LOA_GE_1** | Requires the current LOA to be greater then or equal to 1 +**AFB_SESSION_LOA_GE_2** | Requires the current LOA to be greater then or equal to 2 +**AFB_SESSION_LOA_GE_3** | Requires the current LOA to be greater then or equal to 3 +**AFB_SESSION_LOA_EQ_0** | Requires the current LOA to be equal to 0 +**AFB_SESSION_LOA_EQ_1** | Requires the current LOA to be equal to 1 +**AFB_SESSION_LOA_EQ_2** | Requires the current LOA to be equal to 2 +**AFB_SESSION_LOA_EQ_3** | Requires the current LOA to be equal to 3 + +If any of this flag is set, ***afb-daemon*** requires an authentication token +as if **AFB_SESSION_CHECK** flag was also set. + +The special value **AFB_SESSION_NONE** is zero and can be used to bypass token check. + +> Note that **AFB_SESSION_CREATE** and **AFB_SESSION_CLOSE** might be removed in later versions. + +Sending messages to the log system +---------------------------------- + +Afb-daemon provides 4 levels of verbosity and 5 methods for logging messages. + +The verbosity is managed. Options allow the change the verbosity of ***afb-daemon*** +and the verbosity of the bindings can be set binding by binding. + +The methods for logging messages are defined as macros that test the +verbosity level and that call the real logging function only if the +message must be output. This avoid evaluation of arguments of the +formatting messages if the message must not be output. + +### Verbs for logging messages + +The 5 logging methods are: + +Macro | Verbosity | Meaning | syslog level +--------|:---------:|-----------------------------------|:-----------: +ERROR | 0 | Error conditions | 3 +WARNING | 1 | Warning conditions | 4 +NOTICE | 1 | Normal but significant condition | 5 +INFO | 2 | Informational | 6 +DEBUG | 3 | Debug-level messages | 7 + +You can note that the 2 methods **WARNING** and **NOTICE** have the same level +of verbosity. But they don't have the same *syslog level*. It means that +they are output with a different level on the logging system. + +All of these methods have the same signature: + +```C +void ERROR(const struct afb_binding_interface *afbitf, const char *message, ...); +``` + +The first argument **afbitf** is the interface to afb daemon that the +binding received at initialisation time when **afbBindingV1Register** is called. + +The second argument **message** is a formatting string compatible with printf/sprintf. + +The remaining arguments are arguments of the formating message like with printf. + +### Managing verbosity + +Depending on the level of verbosity, the messages are output or not. +The following table explains what messages will be output depending +ont the verbosity level. + +Level of verbosity | Outputed macro +:-----------------:|-------------------------- +0 | ERROR +1 | ERROR + WARNING + NOTICE +2 | ERROR + WARNING + NOTICE + INFO +3 | ERROR + WARNING + NOTICE + INFO + DEBUG + +### Output format and destination + +The syslog level is used for forging a prefix to the message. +The prefixes are: + +syslog level | prefix +:-----------:|--------------- +0 | <0> EMERGENCY +1 | <1> ALERT +2 | <2> CRITICAL +3 | <3> ERROR +4 | <4> WARNING +5 | <5> NOTICE +6 | <6> INFO +7 | <7> DEBUG + + +The message is pushed to standard error. +The final destination of the message depends on how systemd service +was configured through its variable **StandardError**. It can be +journal, syslog or kmsg. (See man sd-daemon). + +Sending events +-------------- + +Specific documentation exists about [sending events](afb-events-guide.md). + +The binding *tic-tac-toe* broadcasts events when the board changes. This is done +in the function ***changed***: + +```C +/* + * signals a change of the board + */ +static void changed(struct board *board, const char *reason) +{ + ... + struct json_object *description; + + /* get the description */ + description = describe(board); + + ... + + afb_daemon_broadcast_event(afbitf->daemon, reason, description); +} +``` + +The description of the changed board is pushed via the daemon interface. + +Within binding *tic-tac-toe*, *reason* indicates the origin of +the change. In function **afb_daemon_broadcast_event** the second +parameter is the name of broadcasted event. The third argument is the +object that is transmitted with the event. + +Function **afb_daemon_broadcast_event** is defined here after: + +```C +/* + * Broadcasts widely the event of 'name' with the data 'object'. + * 'object' can be NULL. + * 'daemon' MUST be the daemon given in interface when activating the binding. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object); +``` + +> Be aware, as with reply functions **object** is automatically released using +> **json_object_put** when using this function. Call **json_object_get** before +> calling **afb_daemon_broadcast_event** to keep **object** available +> after function returns. + +Event name received by listeners is prefixed with binding name. +So when a change occurs after a move, the reason is **move** and every clients +receive an event **tictactoe/move**. + +> Note that nothing is said about case sensitivity of event names. +> However, the event is always prefixed with the name that the binding +> declared, with the same case, followed with a slash /. +> Thus it is safe to compare event using a case sensitive comparison. + +Writing a synchronous method implementation +----------------------------------------- + +The method **tictactoe/board** is a synchronous implementation. +Here is its listing: + +```C +/* + * get the board + */ +static void board(struct afb_req req) +{ + struct board *board; + struct json_object *description; + + /* retrieves the context for the session */ + board = board_of_req(req); + INFO(afbitf, "method 'board' called for boardid %d", board->id); + + /* describe the board */ + description = describe(board); + + /* send the board's description */ + afb_req_success(req, description, NULL); +} +``` + +This example shows many aspects of a synchronous +method implementation. Let summarise it: + +1. The function **board_of_req** retrieves the context stored +for the binding: the board. + +2. The macro **INFO** sends a message of kind *INFO* +to the logging system. The global variable named **afbitf** +used represents the interface to ***afb-daemon***. + +3. The function **describe** creates a json_object representing +the board. + +4. The function **afb_req_success** sends the reply, attaching to +it the object *description*. + +### The incoming request + +For any implementation, the request is received by a structure of type +**struct afb_req**. + +> Note that this is a PLAIN structure, not a pointer to a structure. + +The definition of **struct afb_req** is: + +```C +/* + * Describes the request by bindings from afb-daemon + */ +struct afb_req { + const struct afb_req_itf *itf; /* the interfacing functions */ + void *closure; /* the closure for functions */ +}; +``` + +It contains two pointers: first one *itf*, points to functions used +to handle internal request. Second one *closure* point onto function closure. + +> The structure must never be used directly. +> Instead developer should use the intended functions provided +> by ***afb-daemon*** as described here after. + +*req* is used to get arguments of the request, to send +answer, to store session data. + +This object and its interface is defined and documented +in the file names *afb/afb-req-itf.h* + +The above example uses twice *req* object request. + +The first time, to retrieve the board attached to the session of the request. + +The second time, to send the reply: an object that describes the current board. + +### Associating a client context to a session + +When *tic-tac-toe* binding receives a request, it musts get +the board describing the game associated to the session. + +For a binding, having data associated to a session is common. +This data is called "binding context" for the session. +Within *tic-tac-toe* binding the context is the board. + +Requests *afb_req* offer four functions for storing and retrieving session +associated context. + +These functions are: + +- **afb_req_context_get**: + retrieves context data stored for current binding. + +- **afb_req_context_set**: + store context data of current binding. + +- **afb_req_context**: + if exist retrieves context data of current binding. + if context does not yet exist, creates a new context and store it. + +- **afb_req_context_clear**: + reset the stored context data. + +The binding *tictactoe* use a convenient function to retrieve +its context: the board. This function is *board_of_req*: + +```C +/* + * retrieves the board of the request + */ +static inline struct board *board_of_req(struct afb_req req) +{ + return afb_req_context(req, (void*)get_new_board, (void*)release_board); +} +``` + +The function **afb_req_context** ensures an existing context +for the session of the request. +Its two last arguments are functions to allocate and free context. +Note function type casts to avoid compilation warnings. + +Here is the definition of the function **afb_req_context** + +```C +/* + * Gets the pointer stored by the binding for the session of 'req'. + * If the stored pointer is NULL, indicating that no pointer was + * already stored, afb_req_context creates a new context by calling + * the function 'create_context' and stores it with the freeing function + * 'free_context'. + */ +static inline void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*)) +{ + void *result = afb_req_context_get(req); + if (result == NULL) { + result = create_context(); + afb_req_context_set(req, result, free_context); + } + return result; +} +``` + +The second argument if the function that creates the context. +For binding *tic-tac-toe* (function **get_new_board**). +The function **get_new_board** creates a new board and set usage its count to 1. +The boards are checking usage count to free resources when not used. + +The third argument is a function that frees context resources. +For binding *tic-tac-toe* (function **release_board**). +The function **release_board** decrease usage count of the board passed in +argument. When usage count falls to zero, data board are freed. + +Definition of other functions dealing with contexts: + +```C +/* + * Gets the pointer stored by the binding for the session of 'req'. + * When the binding has not yet recorded a pointer, NULL is returned. + */ +void *afb_req_context_get(struct afb_req req); + +/* + * Stores for the binding the pointer 'context' to the session of 'req'. + * The function 'free_context' will be called when the session is closed + * or if binding stores an other pointer. + */ +void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*)); + +/* + * Frees the pointer stored by the binding for the session of 'req' + * and sets it to NULL. + * + * Shortcut for: afb_req_context_set(req, NULL, NULL) + */ +static inline void afb_req_context_clear(struct afb_req req) +{ + afb_req_context_set(req, NULL, NULL); +} +``` + +### Sending reply to a request + +Two kinds of replies: successful or failure. + +> Sending a reply to a request MUST be done once and only once. + +It exists two functions for "success" replies: **afb_req_success** and **afb_req_success_f**. + +```C +/* + * Sends a reply of kind success to the request 'req'. + * The status of the reply is automatically set to "success". + * Its send the object 'obj' (can be NULL) with an + * informationnal comment 'info (can also be NULL). + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_success(struct afb_req req, struct json_object *obj, const char *info); + +/* + * Same as 'afb_req_success' but the 'info' is a formatting + * string followed by arguments. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...); +``` + +It exists two functions for "failure" replies: **afb_req_fail** and **afb_req_fail_f**. + +```C +/* + * Sends a reply of kind failure to the request 'req'. + * The status of the reply is set to 'status' and an + * 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. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_fail(struct afb_req req, const char *status, const char *info); + +/* + * Same as 'afb_req_fail' but the 'info' is a formatting + * string followed by arguments. + * + * For convenience, the function calls 'json_object_put' for 'obj'. + * Thus, in the case where 'obj' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...); +``` + +> For convenience, these functions automatically call **json_object_put** to release **obj**. +> Because **obj** usage count is null after being passed to a reply function, it SHOULD not be used anymore. +> If exceptionally **obj** needs to remain usable after reply function then using **json_object_get** on **obj** +> to increase usage count and cancels the effect the **json_object_put** is possible. + +Getting argument of invocation +------------------------------ + +Many methods expect arguments. Afb-daemon's bindings +retrieve arguments by name and not by position. + +Arguments are passed by requests through either HTTP +or WebSockets. + +For example, the method **join** of binding **tic-tac-toe** +expects one argument: the *boardid* to join. Here is an extract: + +```C +/* + * Join a board + */ +static void join(struct afb_req req) +{ + struct board *board, *new_board; + const char *id; + + /* retrieves the context for the session */ + board = board_of_req(req); + INFO(afbitf, "method 'join' called for boardid %d", board->id); + + /* retrieves the argument */ + id = afb_req_value(req, "boardid"); + if (id == NULL) + goto bad_request; + ... +``` + +The function **afb_req_value** searches in the request *req* +for argument name passed in the second argument. When argument name +is not passed, **afb_req_value** returns NULL. + +> The search is case sensitive and *boardid* is not equivalent to *BoardId*. +> Nevertheless having argument names that only differ by name case is not a good idea. + +### Basic functions for querying arguments + +The function **afb_req_value** is defined here after: + +```C +/* + * Gets from the request 'req' the string value of the argument of 'name'. + * Returns NULL if when there is no argument of 'name'. + * Returns the value of the argument of 'name' otherwise. + * + * Shortcut for: afb_req_get(req, name).value + */ +static inline const char *afb_req_value(struct afb_req req, const char *name) +{ + return afb_req_get(req, name).value; +} +``` + +It is defined as a shortcut to call the function **afb_req_get**. +That function is defined here after: + +```C +/* + * Gets from the request 'req' the argument of 'name'. + * Returns a PLAIN structure of type 'struct afb_arg'. + * When the argument of 'name' is not found, all fields of result are set to NULL. + * When the argument of 'name' is found, the fields are filled, + * in particular, the field 'result.name' is set to 'name'. + * + * There is a special name value: the empty string. + * The argument of name "" is defined only if the request was made using + * an HTTP POST of Content-Type "application/json". In that case, the + * argument of name "" receives the value of the body of the HTTP request. + */ +struct afb_arg afb_req_get(struct afb_req req, const char *name); +``` + +That function takes 2 parameters: the request and the name +of the argument to retrieve. It returns a PLAIN structure of +type **struct afb_arg**. + +There is a special name that is defined when the request is +of type HTTP/POST with a Content-Type being application/json. +This name is **""** (the empty string). In that case, the value +of this argument of empty name is the string received as a body +of the post and is supposed to be a JSON string. + +The definition of **struct afb_arg** is: + +```C +/* + * Describes an argument (or parameter) of a request + */ +struct afb_arg { + const char *name; /* name of the argument or NULL if invalid */ + const char *value; /* string representation of the value of the argument */ + /* original filename of the argument if path != NULL */ + const char *path; /* if not NULL, path of the received file for the argument */ + /* when the request is finalized this file is removed */ +}; +``` + +The structure returns the data arguments that are known for the +request. This data include a field named **path**. This **path** +can be accessed using the function **afb_req_path** defined here after: + +```C +/* + * Gets from the request 'req' the path for file attached to the argument of 'name'. + * Returns NULL if when there is no argument of 'name' or when there is no file. + * Returns the path of the argument of 'name' otherwise. + * + * Shortcut for: afb_req_get(req, name).path + */ +static inline const char *afb_req_path(struct afb_req req, const char *name) +{ + return afb_req_get(req, name).path; +} +``` + +The path is only defined for HTTP/POST requests that send file. + +### Arguments for received files + +As it is explained above, clients can send files using HTTP/POST requests. + +Received files are attached to "file" argument name. For example, the +following HTTP fragment (from test/sample-post.html) +will send an HTTP/POST request to the method +**post/upload-image** with 2 arguments named *file* and +*hidden*. + +```html +

Sample Post File

+
+ + +
+ +
+``` + +Argument named **file** should have both its value and path defined. + +The value is the name of the file as it was set by the HTTP client. +Generally it is the filename on client side. + +The path is the effective path of saved file on the temporary local storage +area of the application. This is a randomly generated and unique filename. +It is not linked with the original filename as used on client side. + +After success the binding can use the uploaded file directly from local storage path with no restriction: +read, write, remove, copy, rename... +Nevertheless when request reply is set and query terminated, the uploaded temporary file at +path is destroyed. + +### Arguments as a JSON object + +Bindings may also request every arguments of a given call as one single object. +This feature is provided by the function **afb_req_json** defined here after: + +```C +/* + * 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); +``` + +It returns a json object. This object depends on how the request was built: + +- For HTTP requests, this json object uses key names mapped on argument name. +Values are either string for common arguments or object ie: { "file": "...", "path": "..." } + +- For WebSockets requests, returned directly the object as provided by the client. + +> In fact, for Websockets requests, the function **afb_req_value** +> can be seen as a shortcut to +> ***json_object_get_string(json_object_object_get(afb_req_json(req), name))*** + + +Writing an asynchronous method implementation +------------------------------------------- + +The *tic-tac-toe* example allows two clients or more to share the same board. +This is implemented by the method **join** that illustrated partly how to +retrieve arguments. + +When two or more clients are sharing a same board, one of them can wait +until the state of the board changes, but this could also be implemented using +events because an event is generated each time the board changes. + +In this case, the reply to the wait is sent only when the board changes. +See the diagram below: + +![tic-tac-toe_diagram][tic-tac-toe_diagram] + +Here, this is an invocation of the binding by an other client that +unblock the suspended *wait* call. +Nevertheless in most case this should be a timer, a hardware event, a sync with +a concurrent process or thread, ... + +Common case of an asynchronous implementation. + +Here is the listing of the function **wait**: + +```C +static void wait(struct afb_req req) +{ + struct board *board; + struct waiter *waiter; + + /* retrieves the context for the session */ + board = board_of_req(req); + INFO(afbitf, "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; +} +``` + +After retrieving the board, the function adds a new waiter to +waiters list and returns without setting a reply. + +Before returning, it increases **req** request's reference count using **afb_req_addref** function. + +> When a method returns without setting a reply, +> it **MUST** increment request's reference count +> using **afb_req_addref**. If unpredictable behaviour may pop up. + +Later, when a board changes, it calls *tic-tac-toe* **changed** function +with reason of change in parameter. + +Here is the full listing of the function **changed**: + +```C +/* + * signals a change of the 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_event_sender_push(afb_daemon_get_event_sender(afbitf->daemon), reason, description); +} +``` + +The list of waiters is walked and a reply is sent to each waiter. +After sending the reply, the reference count of the request +is decremented using **afb_req_unref** to allow resources to be freed. + +> The reference count **MUST** be decremented using **afb_req_unref** to free +> resources and avoid memory leaks. +> This usage count decrement should happen **AFTER** setting reply or +> bad things may happen. + +Sending messages to the log system +---------------------------------- + +Afb-daemon provides 4 levels of verbosity and 5 methods for logging messages. + +The verbosity is managed. Options allow the change the verbosity of ***afb-daemon*** +and the verbosity of the bindings can be set binding by binding. + +The methods for logging messages are defined as macros that test the +verbosity level and that call the real logging function only if the +message must be output. This avoid evaluation of arguments of the +formatting messages if the message must not be output. + +### Verbs for logging messages + +The 5 logging methods are: + +Macro | Verbosity | Meaning | syslog level +--------|:---------:|-----------------------------------|:-----------: +ERROR | 0 | Error conditions | 3 +WARNING | 1 | Warning conditions | 4 +NOTICE | 1 | Normal but significant condition | 5 +INFO | 2 | Informational | 6 +DEBUG | 3 | Debug-level messages | 7 + +You can note that the 2 methods **WARNING** and **NOTICE** have the same level +of verbosity. But they don't have the same *syslog level*. It means that +they are output with a different level on the logging system. + +All of these methods have the same signature: + +```C +void ERROR(const struct afb_binding_interface *afbitf, const char *message, ...); +``` + +The first argument **afbitf** is the interface to afb daemon that the +binding received at initialisation time when **afbBindingV1Register** is called. + +The second argument **message** is a formatting string compatible with printf/sprintf. + +The remaining arguments are arguments of the formating message like with printf. + +### Managing verbosity + +Depending on the level of verbosity, the messages are output or not. +The following table explains what messages will be output depending +ont the verbosity level. + +Level of verbosity | Outputed macro +:-----------------:|-------------------------- +0 | ERROR +1 | ERROR + WARNING + NOTICE +2 | ERROR + WARNING + NOTICE + INFO +3 | ERROR + WARNING + NOTICE + INFO + DEBUG + +### Output format and destination + +The syslog level is used for forging a prefix to the message. +The prefixes are: + +syslog level | prefix +:-----------:|--------------- +0 | <0> EMERGENCY +1 | <1> ALERT +2 | <2> CRITICAL +3 | <3> ERROR +4 | <4> WARNING +5 | <5> NOTICE +6 | <6> INFO +7 | <7> DEBUG + + +The message is pushed to standard error. +The final destination of the message depends on how systemd service +was configured through its variable **StandardError**. It can be +journal, syslog or kmsg. (See man sd-daemon). + +Sending events +-------------- + +Since version 0.5, bindings can broadcast events to any potential listener. +As today only unattended events are supported. Targeted events are expected for +next coming version. + +The binding *tic-tac-toe* broadcasts events when the board changes. +This is done in the function **changed**: + +```C +/* + * signals a change of the board + */ +static void changed(struct board *board, const char *reason) +{ + ... + struct json_object *description; + + /* get the description */ + description = describe(board); + + ... + + afb_daemon_broadcast_event(afbitf->daemon, reason, description); +} +``` + +The description of the changed board is pushed via the daemon interface. + +Within binding *tic-tac-toe*, *reason* indicates the origin of +the change. In function **afb_daemon_broadcast_event** the second +parameter is the name of broadcasted event. The third argument is the +object that is transmitted with the event. + +Function **afb_daemon_broadcast_event** is defined here after: + +```C +/* + * Broadcasts widely the event of 'name' with the data 'object'. + * 'object' can be NULL. + * 'daemon' MUST be the daemon given in interface when activating the binding. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + */ +void afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object); +``` + +> Be aware, as with reply functions **object** is automatically released using +> **json_object_put** when using this function. Call **json_object_get** before +> calling **afb_daemon_broadcast_event** to keep **object** available +> after function returns. + +Event name received by listeners is prefixed with binding name. +So when a change occurs after a move, the reason is **move** and every clients +receive an event **tictactoe/move**. + +> Note that nothing is said about case sensitivity of event names. +> However, the event is always prefixed with the name that the binding +> declared, with the same case, followed with a slash /. +> Thus it is safe to compare event using a case sensitive comparison. + +How to build a binding +--------------------- + +Afb-daemon provides a *pkg-config* configuration file that can be +queried by providing ***afb-daemon*** in command line arguments. +This configuration file provides data that should be used +for bindings compilation. Examples: + +```bash +$ pkg-config --cflags afb-daemon +$ pkg-config --libs afb-daemon +``` + +### Example for cmake meta build system + +This example is the extract for building the binding *afm-main* using *CMAKE*. + +```cmake +pkg_check_modules(afb afb-daemon) +if(afb_FOUND) + message(STATUS "Creation afm-main-binding for AFB-DAEMON") + add_library(afm-main-binding MODULE afm-main-binding.c) + target_compile_options(afm-main-binding PRIVATE ${afb_CFLAGS}) + target_include_directories(afm-main-binding PRIVATE ${afb_INCLUDE_DIRS}) + target_link_libraries(afm-main-binding utils ${afb_LIBRARIES}) + set_target_properties(afm-main-binding PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/afm-main-binding.export-map" + ) + install(TARGETS afm-main-binding LIBRARY DESTINATION ${binding_dir}) +else() + message(STATUS "Not creating the binding for AFB-DAEMON") +endif() +``` + +Let now describe some of these lines. + +```cmake +pkg_check_modules(afb afb-daemon) +``` + +This first lines searches to the *pkg-config* configuration file for +**afb-daemon**. Resulting data are stored in the following variables: + +Variable | Meaning +------------------|------------------------------------------------ +afb_FOUND | Set to 1 if afb-daemon binding development files exist +afb_LIBRARIES | Only the libraries (w/o the '-l') for compiling afb-daemon bindings +afb_LIBRARY_DIRS | The paths of the libraries (w/o the '-L') for compiling afb-daemon bindings +afb_LDFLAGS | All required linker flags for compiling afb-daemon bindings +afb_INCLUDE_DIRS | The '-I' preprocessor flags (w/o the '-I') for compiling afb-daemon bindings +afb_CFLAGS | All required cflags for compiling afb-daemon bindings + +If development files are found, the binding can be added to the set of +target to build. + +```cmake +add_library(afm-main-binding MODULE afm-main-binding.c) +``` + +This line asks to create a shared library having a single +source file named afm-main-binding.c to be compiled. +The default name of the created shared object is +**libafm-main-binding.so**. + +```cmake +set_target_properties(afm-main-binding PROPERTIES + PREFIX "" + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/afm-main-binding.export-map" +) +``` + +This lines are doing two things: + +1. It renames the built library from **libafm-main-binding.so** to **afm-main-binding.so** +by removing the implicitly added prefix *lib*. This step is not mandatory +because afb-daemon doesn't check names of files at load time. +The only filename convention used by afb-daemon relates to **.so** termination. +*.so pattern is used when afb-daemon automatically discovers binding from a directory hierarchy. + +2. It applies a version script at link time to only export the reserved name +**afbBindingV1Register** for registration entry point. By default, when building +a shared library linker exports all the public symbols (C functions that are not **static**). + +Next line are: + +```cmake +target_include_directories(afm-main-binding PRIVATE ${afb_INCLUDE_DIRS}) +target_link_libraries(afm-main-binding utils ${afb_LIBRARIES}) +``` + +As you can see it uses the variables computed by ***pkg_check_modules(afb afb-daemon)*** +to configure the compiler and the linker. + +### Exporting the function afbBindingV1Register + +The function **afbBindingV1Register** MUST be exported. This can be achieved +using a version script at link time. Here after is a version script used for +*tic-tac-toe* (bindings/samples/export.map). + + { global: afbBindingV1Register; local: *; }; + +This sample [version script](https://sourceware.org/binutils/docs-2.26/ld/VERSION.html#VERSION) +exports as global the symbol *afbBindingV1Register* and hides any +other symbols. + +This version script is added to the link options using the +option **--version-script=export.map** is given directly to the +linker or using the option **-Wl,--version-script=export.map** +when the option is given to the C compiler. + +### Building within yocto + +Adding a dependency to afb-daemon is enough. See below: + + DEPENDS += " afb-daemon " + + +[tic-tac-toe_diagram]: pictures/tic-tac-toe.svg diff --git a/old-docs/afb-daemon-vocabulary.md b/old-docs/afb-daemon-vocabulary.md new file mode 100644 index 00000000..c3b7c1ea --- /dev/null +++ b/old-docs/afb-daemon-vocabulary.md @@ -0,0 +1,98 @@ + +Vocabulary for AFB-DAEMON +========================= + +## Binding + +A shared library object intended to add a functionality to an afb-daemon +instance. It implements an API and may provide a service. + +Binding made for services can have specific entry point called after +initialisation and before serving. + +## Event + +Message with data propagated from the services to the client and not expecting +any reply. + +The current implementation allows to widely broadcast events to all clients. + +## Level of assurance (LOA) + +This level that can be from 0 to 3 represent the level of +assurance that the services can expect from the session. + +The exact definition of the meaning of these levels and how to use it remains to +be achieved. + +## Plugin + +Old name for binding, see binding. + +## Request + +A request is an invocation by a client to a binding method using a message +transferred through some protocol: HTTP, WebSocket, DBUS... and served by +***afb-daemon*** + +## Reply/Response + +This is a message sent to client as the result of the request. + +## Service + +Service are made of bindings running by their side on their binder. +It can serve many client. Each one attached to one session. + +The framework establishes connection between the services and +the clients. Using DBus currently but other protocols are considered. + +## Session + +A session is meant to be the unique instance context of a client, +which identify that instance across requests. + +Each session has an identifier. Session identifier generated by afb-daemon are +UUIDs. + +Internally, afb-daemon offers a mechanism to attach data to sessions. +When the session is closed or disappears, the data attached to that session +are freed. + +## Token + +The token is an identifier that the client must give to be authenticated. + +At start, afb-daemon get an initial token. This initial token must be presented +by incoming client to be authenticated. + +A token is valid only for a period. + +The token must be renewed periodically. When the token is renewed, afb-daemon +sends the new token to the client. + +Tokens generated by afb-daemon are UUIDs. + +## UUID + +It stand for Universal Unique IDentifier. + +It is designed to create identifier in a way that avoid has much as possible +conflicts. It means that if two different instances create an UUID, the +probability that they create the same UUID is very low, near to zero. + +## x-afb-reqid + +Argument name that can be used with HTTP request. When this argument is given, +it is automatically added to the "request" object of the answer. + +## x-afb-token + +Argument name meant to give the token without ambiguity. +You can also use the name **token** but it may conflicts with others arguments. + +## x-afb-uuid + +Argument name for giving explicitly the session identifier without ambiguity. +You can also use the name **uuid** but it may conflicts with others arguments. + diff --git a/old-docs/afb-events-guide.md b/old-docs/afb-events-guide.md new file mode 100644 index 00000000..aaa09be1 --- /dev/null +++ b/old-docs/afb-events-guide.md @@ -0,0 +1,475 @@ +Guide for developing with events +================================ + +Signaling agents are services that send events to any clients that +subscribed for receiving it. The sent events carry any data. + +To have a good understanding of how to write a signaling agent, the +actions of subscribing, unsubscribing, producing, sending and receiving +events must be described and explained. + +Overview of events +------------------ + +The basis of a signaling agent is shown in the following figure: + +![scenario of using events](pictures/signaling-basis.svg) + +This figure shows the main role of the signaling framework for the events +propagation. + +For people not familiar with the framework, a signaling agent and +a “binding” are similar. + +### Subscribing and unsubscribing + +Subscribing is the action that makes a client able to receive data from a +signaling agent. Subscription must create resources for generating the data, and +for delivering the data to the client. These two aspects are not handled by the +same piece of software. Generating the data is the responsibility of the +developer of the signaling agent while delivering the data is handled by the +framework. + +When a client subscribes for data, the agent must: + +1. check that the subscription request is correct; +2. establish the computation chain of the required data, if not already + done; +3. create a named event for the computed data, if not already done; +4. ask the framework to establish the subscription to the event for the + request; +5. optionally give indications about the event in the reply to + the client. + +The first two steps are not involving the framework. They are linked to +the business logic of the binding. The request can be any description of +the requested data and the computing stream can be of any nature, this +is specific to the binding. + +As said before, the framework uses and integrates **libsystemd** and its event +loop. Within the framework, **libsystemd** is the standard API/library for +bindings expecting to setup and handle I/O, timer or signal events. + +Steps 3 and 4 are bound to the framework. + +The agent must create an object for handling the propagation of produced +data to its clients. That object is called “event” in the framework. An +event has a name that allows clients to distinguish it from other +events. + +Events are created using the ***afb\_daemon\_make\_event*** function +that takes the name of the event. Example: + +```C + event = afb_daemon_make_event(afb_daemon, name); +``` + +Once created, the event can be used either to push data to its +subscribers or to broadcast data to any listener. + +The event must be used to establish the subscription for the requesting +client. This is done using the ***afb\_req\_subscribe*** function +that takes the current request object and event and associates them +together. Example: + +```C + rc = afb_req_subscribe(afb_req, event); +``` + +When successful, this function make the connection between the event and +the client that emitted the request. The client becomes a subscriber of +the event until it unsubscribes or disconnects. The +***afb\_req\_subscribe*** function will fail if the client +connection is weak: if the request comes from a HTTP link. To receive +signals, the client must be connected. The AGL framework allows connections +using WebSocket. + +The name of the event is either a well known name or an ad hoc name +forged for the use case. + +Let's see a basic example: client A expects to receive the speed in km/h +every second while client B expects the speed in mph twice a second. In +that case, there are two different events because it is not the same +unit and it is not the same frequency. Having two different events +allows to associate clients to the correct event. But this doesn't tell +any word about the name of these events. The designer of the signaling +agent has two options for naming: + +1. names can be the same (“speed” for example) with sent data + self describing itself or having a specific tag (requiring from + clients awareness about requesting both kinds of speed isn't safe). +2. names of the event include the variations (by example: + “speed-km/h-1Hz” and “speed-mph-2Hz”) and, in that case, sent data + can self describe itself or not. + +In both cases, the signaling agent might have to send the name of the +event and/or an associated tag to its client in the reply of the +subscription. This is part of the step 5 above. + +The framework only uses the event (not its name) for subscription, +unsubscription and pushing. + +When the requested data is already generated and the event used for +pushing it already exists, the signaling agent must not instantiate a +new processing chain and must not create a new event object for pushing +data. The signaling agent must reuse the existing chain and event. + +Unsubscribing is made by the signaling agent on a request of its client. +The ***afb\_req\_unsubscribe*** function tells the framework to +remove the requesting client from the event's list of subscribers. +Example: + +```C + afb_req_unsubscribe(afb_req, event); +``` + +Subscription count does not matter to the framework: subscribing the +same client several times has the same effect that subscribing only one +time. Thus, when unsubscribing is invoked, it becomes immediately +effective. + +#### More on naming events + +Within the AGL framework, a signaling agent is a binding that has an API +prefix. This prefix is meant to be unique and to identify the binding +API. The names of the events that this signaling agent creates are +automatically prefixed by the framework, using the API prefix of the +binding. + +Thus, if a signaling agent of API prefix ***api*** creates an event +of name ***event*** and pushes data to that event, the subscribers +will receive an event of name ***api/event***. + +### Generating and pushing signals and data + +This of the responsibility of the designer of the signaling agent to +establish the processing chain for generating events. In many cases, +this can be achieved using I/O or timer or signal events inserted in the +main loop. For this case, the AGL framework uses **libsystemd** and +provide a way to integrates to the main loop of this library using +afb\_daemon\_get\_event\_loop. Example: + +```C + sdev = afb_daemon_get_event_loop(af_daemon); + rc = sd_event_add_io(sdev, &source, fd, EPOLLIN, myfunction, NULL); +``` + +In some other cases, the events are coming from D-Bus. In that case, the +framework also uses **libsystemd** internally to access D-Bus. It provides +two methods to get the available D-Bus objects, already existing and +bound to the main**libsystemd**event loop. Use either +***afb\_daemon\_get\_system\_bus*** or +***afb\_daemon\_get\_user\_bus*** to get the required instance. Then +use functions of **libsystemd** to handle D-Bus. + +In some rare cases, the generation of the data requires to start a new +thread. + +When a data is generated and ready to be pushed, the signaling agent +should call the function ***afb\_event\_push***. Example: + +```C + rc = afb_event_push(event, JSON); + if (rc == 0) { + stop_generating(event); + afb_event_drop(event); + } +``` + +The function ***afb\_event\_push*** pushes json data to all the +subscribers. It then returns the count of subscribers. When the count is +zero, there is no subscriber listening for the event. The example above +shows that in that case, the signaling agent stops to generate data for +the event and delete the event using afb\_event\_drop. This is one +possible option. Other valuable options are: do nothing and continue to +generate and push the event or just stop to generate and push the data +but keep the event existing. + +### Receiving the signals + +Understanding what a client expects when it receives signals, events or +data shall be the most important topic of the designer of a signaling +agent. The good point here is that because JSON[^1] is the exchange +format, structured data can be sent in a flexible way. + +The good design is to allow as much as possible the client to describe +what is needed with the goal to optimize the processing to the +requirements only. + +### The exceptional case of wide broadcast + +Some data or events have so much importance that they can be widely +broadcasted to alert any listening client. Examples of such an alert +are: + +- system is entering/leaving “power safe” mode +- system is shutting down +- the car starts/stops moving +- ... + +An event can be broadcasted using one of the two following methods: +***afb\_daemon\_broadcast\_event*** or +***afb\_event\_broadcast***. + +Example 1: + +```C + afb_daemon_broadcast_event(afb_daemon, name, json); +``` + +Example 2: + +```C + event = afb_daemon_make_event(afb_daemon, name); + . . . . + afb_event_broadcast(event, json); +``` + +As for other events, the name of events broadcasted using +***afb\_daemon\_broadcast\_event*** are automatically prefixed by +the framework with API prefix of the binding (signaling agent). + +Reference of functions +---------------------- + +### Function afb\_event afb\_daemon\_make\_event + +The function ***afb\_daemon\_make\_event*** that is defined as below: + +```C +/* + * Creates an event of 'name' and returns it. + * 'daemon' MUST be the daemon given in interface when activating the binding. + */ +struct afb_event afb_daemon_make_event(struct afb_daemon daemon, const char *name); +``` + +The daemon is the handler to the application framework binder daemon +received during initialisation steps of the binding. + +Calling the function ***afb\_daemon\_make\_event*** within the initialisation +function ***afbBindingV1Register*** will _fail_ because the binding +name is not known at this time. + +The correct way to create the event at initialisation is to call the function +***afb\_daemon\_make\_event*** within the initialisation +function ***afbBindingV1ServiceInit***. + +### Function afb\_event\_push + +The function ***afb\_event\_push*** is defined as below: + +```C +/* + * Pushes the 'event' with the data 'object' to its observers. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_event_push(struct afb_event event, struct json_object *object); +``` + +As the function ***afb\_event\_push*** returns 0 when there is no +more subscriber, a binding can remove such unexpected event using the +function ***afb\_event\_drop***. + +### Function afb\_event\_drop + +The function ***afb\_event\_drop*** is defined as below: + +```C +/* + * Drops the data associated to the event + * After calling this function, the event + * MUST NOT BE USED ANYMORE. + */ +void afb_event_drop(struct afb_event event); +``` + +### Function afb\_req\_subscribe + +The function ***afb\_req\_subscribe*** is defined as below: + +```C +/* + * Establishes for the client link identified by 'req' a subscription + * to the 'event'. + * Returns 0 in case of successful subscription or -1 in case of error. + */ +int afb_req_subscribe(struct afb_req req, struct afb_event event); +``` + +The subscription adds the client of the request to the list of subscribers +to the event. + +### Function afb\_req\_unsubscribe + +The function ***afb\_req\_unsubscribe*** is defined as +below: + +```C +/* + * Revokes the subscription established to the 'event' for the client + * link identified by 'req'. + * Returns 0 in case of successful unsubscription or -1 in case of error. + */ +int afb_req_unsubscribe(struct afb_req req, struct afb_event event); +``` + +The unsubscription removes the client of the request of the list of subscribers +to the event. +When the list of subscribers to the event becomes empty, +the function ***afb\_event\_push*** will return zero. + +### Function afb\_event\_broadcast + +The function ***afb\_event\_broadcast*** is defined as below: + +```C +/* + * Broadcasts widely the 'event' with the data 'object'. + * 'object' can be NULL. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_event_broadcast(struct afb_event event, struct json_object *object); +``` + +This uses an existing event (created with ***afb\_daemon\_make\_event***) +for broadcasting an event having its name. + + +### Function afb\_daemon\_broadcast\_event + +The function ***afb\_daemon\_broadcast\_event*** is defined as below: + +```C +/* + * Broadcasts widely the event of 'name' with the data 'object'. + * 'object' can be NULL. + * 'daemon' MUST be the daemon given in interface when activating the binding. + * + * For convenience, the function calls 'json_object_put' for 'object'. + * Thus, in the case where 'object' should remain available after + * the function returns, the function 'json_object_get' shall be used. + * + * Returns the count of clients that received the event. + */ +int afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object); +``` + +The name is given here explicitly. The name is automatically prefixed +with the name of the binding. For example, a binding of prefix "xxx" +would broadcat the event "xxx/name". + +### Function afbBindingV1ServiceEvent + +Binding can implement function **afbBindingV1ServiceEvent** which will +be called when an event is broadcasted or if service subscribed to an event. +That allow a service to react to an event and do what it is to do if this is +relevant for it (ie: car back camera detects imminent collision and broadcast +it, then appropriate service enable parking brake.). Here is the +**afbBindingV1ServiceEvent** definition: + +```C +/* + * When a binding have an implementation of the function 'afbBindingV1ServiceEvent', + * defined below, the framework calls that function for any broadcasted event or for + * events that the service subscribed to in its name. + * + * It receive the 'event' name and its related data in 'object' (be aware that 'object' + * might be NULL). + */ +extern void afbBindingV1ServiceEvent(const char *event, struct json_object *object); + +The binding *tic-tac-toe* broadcasts events when the board changes. +This is done in the function **changed**: +``` + +Architectural digressions +------------------------- + +Based on their dependencies to hardware, signaling agents can be split +into 2 categories: low-level signaling agents and high-level signaling +agents. + +Low-level signaling agents are bound to the hardware and focused on +interfacing and driving. + +High-level signaling agent are independent of the hardware and focused on +providing service. + +This separation (that may in the corner look artificial) aim to help in +the systems design. The main idea here is that high-level signaling +agents are providing “business logic”, also known as “application +logic”, that is proper to the car industry and that can be reused and +that can evolve as a foundation for the future of the industry. + +The implementation of this decomposition may follow 2 paths: strict +separation or soft composition. + +### Strict separation + +The strict separation implements the modularity composition of signaling +agent through the framework. The high-level signaling agent subscribes +to the low level signaling agent using the standard client API. + +Advantages: + +- Modularity +- Separation of responsibilities +- Possible aggregation of multiple sources +- Soft binding of agent good for maintenance + +Drawbacks: + +- Cost of propagation of data (might serialize) +- Difficulties to abstract low-level signaling agent or to find a + trade-off between abstracting and specializing + +The key is modularity versus cost of propagation. It can be partly +solved when logical group of signaling agent are launched together in +the same binder process. In that particular case, the cost of +propagation of data between agents is reduced[^2] because there is no +serialization. + +This reduction of the propagation cost (and of the resources used) +precludes implementation of strong security between the agents because +they share the same memory. + +### Soft composition + +The soft composition implements the business logic of high-level +signaling agents as libraries that can then be used directly by the low +level signaling agents. + +Advantages: + +- No propagation: same memory, sharing of native structures + +Drawbacks: + +- Cannot be used for aggregation of several sources +- Difficulties to abstract low-level signaling agent or to find a + trade-off between abstracting and specializing +- Source code binding not good for maintenance + +[^1]: There are two aspect in using JSON: the first is the flexible data + structure that mixes common types (booleans, numbers, strings, + arrays, dictionaries, nulls), the second, is the streaming + specification. Streaming is often seen as the bottleneck of using + JSON (see http://bjson.org). When the agent share the same process, + there is no streaming at all. + +[^2]: Within the same process, there is not serialization, the + propagation has the cost of wrapping a json data and calling + callbacks with the benefit of having a powerful callback manager: + the event mechanism of the framework. diff --git a/old-docs/afb-overview.md b/old-docs/afb-overview.md new file mode 100644 index 00000000..eec3f91a --- /dev/null +++ b/old-docs/afb-overview.md @@ -0,0 +1,315 @@ + +Overview of AFB-DAEMON +====================== + +Roles of afb-daemon +------------------- + +The name **afb-daemon** stands for *Application +Framework Binder Daemon*. That is why afb-daemon +is also named ***the binder***. + +**Afb-daemon** is in charge to bind one instance of +an application to the AGL framework and AGL system. + +On the following figure, you can use a typical use +of afb-daemon: + +

Figure: binder afb-daemon, basis

+ +![binder-basis][binder-basis] + +The application and its companion binder run in secured and isolated +environment set for them. Applications are intended to access to AGL +system through the binder. + +The binder afb-daemon serves multiple purposes: + +1. It acts as a gateway for the application to access the system; + +2. It acts as an HTTP server for serving files to HTML5 applications; + +3. It allows HTML5 applications to have native extensions subject +to security enforcement for accessing hardware resources or +for speeding parts of algorithm. + +Use cases of the binder afb-daemon +---------------------------------- + +This section tries to give a better understanding of the binder +usage through several use cases. + +### Remotely running application + +One of the most interesting aspect of using the binder afb-daemon +is the ability to run applications remotely. This feature is +possible because the binder afb-daemon implements native web +protocols. + +So the [figure binder, basis](#binder-fig-basis) would become +when the application is run remotely: + +

Figure: binder afb-daemon and remotely running application

+ + +### Adding native features to HTML5/QML applications + +Applications can provide with their packaged delivery a binding. +That binding will be instantiated for each application instance. +The methods of the binding will be accessible by applications and +will be executed within the security context. + +### Offering services to the system + +It is possible to run the binder afb-daemon as a daemon that provides the +API of its bindings. + +This will be used for: + +1. offering common APIs + +2. provide application's services (services provided as application) + +In that case, the figure showing the whole aspects is + +

Figure: binder afb-daemon for services

+ +![afb-for-services][afb-for-services] + +For this case, the binder afb-daemon takes care to attribute one single session +context to each client instance. It allows bindings to store and retrieve data +associated to each of its client. + +The bindings of the binder afb-daemon +------------------------------------ + +The binder can instantiate bindings. The primary use of bindings +is to add native methods that can be accessed by applications +written with any language through web technologies ala JSON RPC. + +This simple idea is declined to serves multiple purposes: + +1. add native feature to applications + +2. add common API available by any applications + +3. provide customers services + +A specific document explains how to write an afb-daemon binder binding: +[HOWTO WRITE a BINDING for AFB-DAEMON](afb-bindings-writing.html) + + +Launching the binder afb-daemon +------------------------------- + +The launch options for binder **afb-daemon** are: + + --help + + Prints help with available options + + --version + + Display version and copyright + + --verbose + + Increases the verbosity, can be repeated + + --quiet + + Decreases the verbosity, can be repeated + + --port=xxxx + + HTTP listening TCP port [default 1234] + + --workdir=xxxx + + Directory where the daemon must run [default: $PWD if defined + or the current working directory] + + --uploaddir=xxxx + + Directory where uploaded files are temporarily stored [default: workdir] + + --rootdir=xxxx + + Root directory of the application to serve [default: workdir] + + --roothttp=xxxx + + Directory of HTTP served files. If not set, files are not served + but apis are still accessibles. + + --rootbase=xxxx + + Angular Base Root URL [default /opa] + + This is used for any application of kind OPA (one page application). + When set, any missing document whose url has the form /opa/zzz + is translated to /opa/#!zzz + + --rootapi=xxxx + + HTML Root API URL [default /api] + + The bindings are available within that url. + + --alias=xxxx + + Maps a path located anywhere in the file system to the + a subdirectory. The syntax for mapping a PATH to the + subdirectory NAME is: --alias=/NAME:PATH. + + Example: --alias=/icons:/usr/share/icons maps the + content of /usr/share/icons within the subpath /icons. + + This option can be repeated. + + --no-httpd + + Tells to not start the HTTP server. + + --apitimeout=xxxx + + binding API timeout in seconds [default 20] + + Defines how many seconds maximum a method is allowed to run. + 0 means no limit. + + --cntxtimeout=xxxx + + Client Session Timeout in seconds [default 3600] + + --cache-eol=xxxx + + Client cache end of live [default 100000 that is 27,7 hours] + + --session-max=xxxx + + Maximum count of simultaneous sessions [default 10] + + --ldpaths=xxxx + + Load bindings from given paths separated by colons + as for dir1:dir2:binding1.so:... [default = $libdir/afb] + + You can mix path to directories and to bindings. + The sub-directories of the given directories are searched + recursively. + + The bindings are the files terminated by '.so' (the extension + so denotes shared object) that contain the public entry symbol. + + --binding=xxxx + + Load the binding of given path. + + --token=xxxx + + Initial Secret token to authenticate. + + If not set, no client can authenticate. + + If set to the empty string, then any initial token is accepted. + + --random-token + + Generate a random starting token. See option --exec. + + --mode=xxxx + + Set the mode: either local, remote or global. + + The mode indicate if the application is run locally on the host + or remotely through network. + + --readyfd=xxxx + + Set the #fd to signal when ready + + If set, the binder afb-daemon will write "READY=1\n" on the file + descriptor whose number if given (/proc/self/fd/xxx). + + --dbus-client=xxxx + + Transparent binding to a binder afb-daemon service through dbus. + + It creates an API of name xxxx that is implemented remotely + and queried via DBUS. + + --dbus-server=xxxx + + Provides a binder afb-daemon service through dbus. + + The name xxxx must be the name of an API defined by a binding. + This API is exported through DBUS. + + --ws-client=xxxx + + Transparent binding to a binder afb-daemon service through a WebSocket. + + The value of xxxx is either a unix naming socket, of the form "unix:path/api", + or an internet socket, of the form "host:port/api". + + --ws-server=xxxx + + Provides a binder afb-daemon service through WebSocket. + + The value of xxxx is either a unix naming socket, of the form "unix:path/api", + or an internet socket, of the form "host:port/api". + + --foreground + + Get all in foreground mode (default) + + --daemon + + Get all in background mode + + --no-httpd + + Forbids HTTP serve + + --exec + + Must be the last option for afb-daemon. The remaining + arguments define a command that afb-daemon will launch. + The sequences @p, @t and @@ of the arguments are replaced + with the port, the token and @. + + --tracereq=xxxx + + Trace the processing of requests in the log file. + + Valid values are 'no' (default), 'common', 'extra' or 'all'. + + + + + +Future development of afb-daemon +-------------------------------- + +- The binder afb-daemon would launch the applications directly. + +- The current setting of mode (local/remote/global) might be reworked to a +mechanism for querying configuration variables. + +- Implements "one-shot" initial token. It means that after its first +authenticated use, the initial token is removed and no client can connect +anymore. + +- Creates some intrinsic APIs. + +- Make the service connection using WebSocket not DBUS. + +- Management of targeted events. + +- Securing LOA. + +- Integration of the protocol JSON-RPC for the websockets. + +[binder-basis]: pictures/AFB_overview.svg +[afb-for-services]: pictures/AFB_for_services.svg diff --git a/old-docs/afb-tests-overview.md b/old-docs/afb-tests-overview.md new file mode 100644 index 00000000..d6f619fe --- /dev/null +++ b/old-docs/afb-tests-overview.md @@ -0,0 +1,89 @@ + +Overview of tests shipped with AFB-Daemon +========================================= + +List of tests +------------- + +Here are the tests shipped in the source tree: + +* **afb-client-demo** (command-line WebSockets) + +* **token-websock.qml** (Qt/QML WebSockets) + +* ***.html** (HTML5/JS HTTP-REST & WebSockets) + + +Detail of tests +--------------- + +### afb-client-demo (command-line WebSockets) + +This clients interactively calls bindings APIs from the command line, using the binder +[WebSockets](https://en.wikipedia.org/wiki/WebSocket) facility. + +If _afb-daemon_ has been launched with the following parameters: + + + $ afb-daemon --port=1234 --token=123456 [...] + + +Then run the client with : + + afb-client-demo ws://localhost:1234/api?token=123456 [ []] + +For instance, to initialize the Audio binding from the command line : + + afb-client-demo ws://localhost:1234/api?token=123456 + +The command doesn't return. You should type requests of type []. +So, try: + + auth connect + hello pingjson true + +
+ + + +### token-websock.qml (Qt/QML WebSockets) + +If _afb-daemon_ has been launched with the following parameters: + + $ afb-daemon --port=1234 --token=123456 [...] + +and Qt5 is installed. + +For installing Qt5 on **Ubuntu 16.04**: + + $ apt-get install qmlscene qml-module-qtwebsockets qml-module-qtquick-controls + +For installing Qt5 on **Fedora >= 22** : + + $ dnf install qt5-qtdeclarative-devel qt5-qtwebsockets-devel qt5-qtquickcontrols + + +Then run the client with : + + qmlscene test/token-websock.qml + +and interactively press the buttons, "Connect", "Refresh", "Logout". + +
+ + +### *.html (HTML5/JS HTTP-REST & WebSockets) + +If _afb-daemon_ has been launched with the following parameters: + + $ afb-daemon --port=1234 --rootdir=$PWD/test [...] + +_("$PWD/test_" being the "test" subdirectory of the source tree)_ + + +Then open your preferred Web browser, connect to the following URL: + + http://localhost:1234 + +and interactively run the various tests. + diff --git a/old-docs/index.md b/old-docs/index.md new file mode 120000 index 00000000..81c25433 --- /dev/null +++ b/old-docs/index.md @@ -0,0 +1 @@ +afb-overview.md \ No newline at end of file diff --git a/old-docs/pictures/AFB_for_services.svg b/old-docs/pictures/AFB_for_services.svg new file mode 100644 index 00000000..6e536c50 --- /dev/null +++ b/old-docs/pictures/AFB_for_services.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Isolated security context + + + + + + + + APPLICATION + + + + + + + + binderAFB-DAEMON + + + + + + + + BINDINGS + + + + + + + + + + + + + + + + + + + + + D-Bus & CYNARA + + + + + + + + Isolated security context A + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS A + + + + + + + + + + + + + + + Isolated security context B + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS B + + + + + + + + + + + + + + + Isolated security context C + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS C + + + + + + + + + + + + + + \ No newline at end of file diff --git a/old-docs/pictures/AFB_overview.svg b/old-docs/pictures/AFB_overview.svg new file mode 100644 index 00000000..240dae89 --- /dev/null +++ b/old-docs/pictures/AFB_overview.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Isolated security context + + + + + + + + APPLICATION + + + + + + + + binderAFB-DAEMON + + + + + + + + BINDINGS + + + + + + AGL SYSTEM + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/old-docs/pictures/signaling-basis.svg b/old-docs/pictures/signaling-basis.svg new file mode 100644 index 00000000..b13fcf17 --- /dev/null +++ b/old-docs/pictures/signaling-basis.svg @@ -0,0 +1,145 @@ + + + + + + + request-data + + + + + + client 1 + + + + + + + + client 2 + + + + + + + + : framework + + + + + + + + signaling agent + + + + + + + + + + + request-data + + + + + + afb_daemon_make_event + + + + + + + + + afb_req_subscribe + + + + + reply of request-data + + + + + + afb_req_subscribe + + + + + reply of request-data + + + + + + device + + + + + + + + + setup + + + + + << wake up >> + + + + + afb_event_push + + + + + << event >> + + + + + << event >> + + + + + reply of afb_event_push + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/old-docs/pictures/tic-tac-toe.svg b/old-docs/pictures/tic-tac-toe.svg new file mode 100644 index 00000000..7a5fb84e --- /dev/null +++ b/old-docs/pictures/tic-tac-toe.svg @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tic-Tac-Toe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + move + + + + + + wait + + + + + + success of move + + + + + + success of wait + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/old-docs/pictures/triskel_iot_bzh.svg b/old-docs/pictures/triskel_iot_bzh.svg new file mode 100644 index 00000000..096f4244 --- /dev/null +++ b/old-docs/pictures/triskel_iot_bzh.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + -- cgit 1.2.3-korg