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 --- doc/FAQ.md | 5 - doc/afb-application-writing.md | 301 -------- doc/afb-bindings-overview.md | 180 ----- doc/afb-bindings-writing.md | 1407 ------------------------------------- doc/afb-daemon-vocabulary.md | 98 --- doc/afb-events-guide.md | 475 ------------- doc/afb-overview.md | 315 --------- doc/afb-tests-overview.md | 89 --- doc/index.md | 1 - doc/pictures/AFB_for_services.svg | 238 ------- doc/pictures/AFB_overview.svg | 140 ---- doc/pictures/signaling-basis.svg | 145 ---- doc/pictures/tic-tac-toe.svg | 289 -------- doc/pictures/triskel_iot_bzh.svg | 110 --- 14 files changed, 3793 deletions(-) delete mode 100644 doc/FAQ.md delete mode 100644 doc/afb-application-writing.md delete mode 100644 doc/afb-bindings-overview.md delete mode 100644 doc/afb-bindings-writing.md delete mode 100644 doc/afb-daemon-vocabulary.md delete mode 100644 doc/afb-events-guide.md delete mode 100644 doc/afb-overview.md delete mode 100644 doc/afb-tests-overview.md delete mode 120000 doc/index.md delete mode 100644 doc/pictures/AFB_for_services.svg delete mode 100644 doc/pictures/AFB_overview.svg delete mode 100644 doc/pictures/signaling-basis.svg delete mode 100644 doc/pictures/tic-tac-toe.svg delete mode 100644 doc/pictures/triskel_iot_bzh.svg (limited to 'doc') diff --git a/doc/FAQ.md b/doc/FAQ.md deleted file mode 100644 index 5063ed74..00000000 --- a/doc/FAQ.md +++ /dev/null @@ -1,5 +0,0 @@ -Frequently Asked Question about AFB-DAEMON -========================================== - - - diff --git a/doc/afb-application-writing.md b/doc/afb-application-writing.md deleted file mode 100644 index cc513b48..00000000 --- a/doc/afb-application-writing.md +++ /dev/null @@ -1,301 +0,0 @@ -How to write an application on top of AGL FRAMEWORK -==================================================== - -Programming Languages for Applications ------------------------------------------ - -### Writing an HTML5 application - -Developers of HTML5 applications (client side) can easily create -applications for AGL framework using their preferred -HTML5 framework. - -Developers may also take advantage of powerful server side bindings to improve -application behavior. Server side bindings return an application/json mine-type -and can be accessed though either HTTP or Websockets. - -In a near future, JSON-RPC protocol should be added to complete the current -x-afb-json1 protocol. - -Two examples of HTML5 applications are given: - -- [afb-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afb-client) a simple "hello world" application template - -- [afm-client](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-demo.git;a=tree;f=afm-client) a simple "Home screen" application template - -### Writing a Qt application - -Writing Qt applications is also supported. Qt offers standard API to send -request through HTTP or WebSockets. - -It is also possible to write QML applications. A sample QML application -[token-websock] is available: - -- [token-websock](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=test/token-websock.qml) -a simple "hello world" application in QML - -### Writing a "C" application - -C applications can use afb-daemon binder through a websocket connection. - -The library **libafbwsc** is provided for C clients that need -to connect with an afb-daemon binder. - -The program **afb-client-demo** is the C example that use -**libafbwsc** library. -Source code is available here -[src/afb-client-demo.c](https://gerrit.automotivelinux.org/gerrit/gitweb?p=src/app-framework-binder.git;a=blob;f=src/afb-client-demo.c). - -Current implementation relies on libsystemd and file descriptors. -This model might be review in the future to support secure sockets -and get rid of libsystemd dependency. - -Handling sessions within applications -------------------------------------- - -Applications should understand sessions and token management when interacting -with afb-daemon binder. - -Applications communicate with their private binder(afb-daemon) using -a network connection or potentially any other connection channel. While the -current version does not yet implement Unix socket, this feature might be added -in the near future. Developers need to be warn that HTTP protocol is a none -connected protocol and that using HTTP socket connection to authenticate -clients is not supported. - -For this reason, the binder should authenticate the application -by using a shared secret. The secret is named "token" and the identification -of client is named "session". - -The examples **token-websock.qml** and **afb-client** are demonstrating -how authentication and sessions are managed. - -### Handling sessions - -Bindings and other binder features need to keep track of client -instances. This is especially important for bindings running as services -as they may typically have to keep each client's data separated. - -For HTML5 applications, the web runtime handles the cookie of session -that the binder afb-daemon automatically sets. - -Session identifier can be set using the parameter **uuid** or **x-afb-uuid** in -URI requests. Within current version of the framework session UUID is supported -by both HTTP requests and websocket negotiation. - -### Exchanging tokens - -At application start, AGL framework communicates a shared secret to both binder -and client application. This initial secret is called the "**initial token**". - -For each of its client application, the binder manages a current active -token for session management. This authentication token can be use to restrict -the access to some binding's methods. - -The token must be included in URI request on HTTP or during websockets -connection using parameter **token** or **x-afb-token**. - -To ensure security, tokens must be refreshed periodically. - -### Example of session management - -In following examples, we suppose that **afb-daemon** is launched with something -equivalent to: - - $ afb-daemon --port=1234 --token=123456 [...] - -making the expectation that **AuthLogin** binding is requested as default. - -#### Using curl - -First, connects with the initial token, 123456: - - $ curl http://localhost:1234/api/auth/connect?token=123456 - { - "jtype": "afb-reply", - "request": { - "status": "success", - "token": "0aef6841-2ddd-436d-b961-ae78da3b5c5f", - "uuid": "850c4594-1be1-4e9b-9fcc-38cc3e6ff015" - }, - "response": {"token": "A New Token and Session Context Was Created"} - } - -It returns an answer containing session UUID, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015, -and a refreshed token, 850c4594-1be1-4e9b-9fcc-38cc3e6ff015. - -Check if session and token is valid: - - $ curl http://localhost:1234/api/auth/check?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 - { - "jtype": "afb-reply", - "request": {"status":"success"}, - "response": {"isvalid":true} - } - -Refresh the token: - - $ curl http://localhost:1234/api/auth/refresh?token=0aef6841-2ddd-436d-b961-ae78da3b5c5f\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 - { - "jtype": "afb-reply", - "request": { - "status":"success", - "token":"b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9" - }, - "response": {"token":"Token was refreshed"} - } - -Close the session: - - curl http://localhost:1234/api/auth/logout?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 - { - "jtype": "afb-reply", - "request": {"status": "success"}, - "response": {"info":"Token and all resources are released"} - } - -Checking on closed session for uuid should be refused: - - curl http://localhost:1234/api/auth/check?token=b8ec3ec3-6ffe-448c-9a6c-efda69ad7bd9\&uuid=850c4594-1be1-4e9b-9fcc-38cc3e6ff015 - { - "jtype": "afb-reply", - "request": { - "status": "failed", - "info": "invalid token's identity" - } - } - -#### Using afb-client-demo - -> The program is packaged within AGL in the rpm **libafbwsc-dev** - -Here is an example of exchange using **afb-client-demo**: - - $ afb-client-demo ws://localhost:1234/api?token=123456 - auth connect - ON-REPLY 1:auth/connect: {"jtype":"afb-reply","request":{"status":"success", - "token":"63f71a29-8b52-4f9b-829f-b3028ba46b68","uuid":"5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1"}, - "response":{"token":"A New Token and Session Context Was Created"}} - auth check - ON-REPLY 2:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} - auth refresh - ON-REPLY 4:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", - "token":"8b8ba8f4-1b0c-48fa-962d-4a00a8c9157e"},"response":{"token":"Token was refreshed"}} - auth check - ON-REPLY 5:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} - auth refresh - ON-REPLY 6:auth/refresh: {"jtype":"afb-reply","request":{"status":"success", - "token":"e83b36f8-d945-463d-b983-5d8ed73ba529"},"response":{"token":"Token was refreshed"}} - -After closing connection, reconnect as here after: - - $ afb-client-demo ws://localhost:1234/api?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 auth check - ON-REPLY 1:auth/check: {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} - -Same connection check using **curl**: - - $ curl http://localhost:1234/api/auth/check?token=e83b36f8-d945-463d-b983-5d8ed73ba529\&uuid=5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1 - {"jtype":"afb-reply","request":{"status":"success"},"response":{"isvalid":true}} - -Format of replies ------------------ - -Replies use javascript object returned as serialized JSON. - -This object contains at least 2 mandatory fields of name **jtype** and -**request** and one optional field of name **response**. - -### Template - -This is a template of replies: - -```json -{ - "jtype": "afb-reply", - "request": { - "status": "success", - "info": "informationnal text", - "token": "e83b36f8-d945-463d-b983-5d8ed73ba52", - "uuid": "5fcc3f3d-4b84-4fc7-ba66-2d8bd34ae7d1", - "reqid": "application-generated-id-23456" - }, - "response": ....any response object.... -} -``` - -### Field jtype - -The field **jtype** must have a value of type string equal to **"afb-reply"**. - -### Field request - -The field **request** must have a value of type object. This request object -has at least one field named **status** and four optional fields named -**info**, **token**, **uuid**, **reqid**. - -#### Subfield request.status - -**status** must have a value of type string. This string is equal to **"success"** -only in case of success. - -#### Subfield request.info - -**info** is of type string and represent optional information added to the reply. - -#### Subfield request.token - -**token** is of type string. It is sent either at session creation -or when the token is refreshed. - -#### Subfield request.uuid - -**uuid** is of type string. It is sent at session creation. - -#### Subfield request.reqid - -**reqid** is of type string. It is sent in response to HTTP requests -that added a parameter of name **reqid** or **x-afb-reqid** at request time. -Value returns in the reply has the exact same value as the one received in the -request. - -### Field response - -This field response optionally contains an object returned when request -succeeded. - -Format of events ----------------- - -Events are javascript object serialized as JSON. - -This object contains at least 2 mandatory fields of name **jtype** and **event** -and one optional field of name **data**. - -### Template - -Here is a template of event: - -```json -{ - "jtype": "afb-event", - "event": "sample_api_name/sample_event_name", - "data": ...any event data... -} -``` - -### Field jtype - -The field **jtype** must have a value of type string equal to **"afb-event"**. - -### Field event - -The field **event** carries the event's name. - -The name of the event is made of two parts separated by a slash: -the name of the name of the API that generated the event -and the name of event within the API. - -### Field data - -This field data if present holds the data carried by the event. - diff --git a/doc/afb-bindings-overview.md b/doc/afb-bindings-overview.md deleted file mode 100644 index c79e17f4..00000000 --- a/doc/afb-bindings-overview.md +++ /dev/null @@ -1,180 +0,0 @@ - -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/doc/afb-bindings-writing.md b/doc/afb-bindings-writing.md deleted file mode 100644 index d8335086..00000000 --- a/doc/afb-bindings-writing.md +++ /dev/null @@ -1,1407 +0,0 @@ - -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/doc/afb-daemon-vocabulary.md b/doc/afb-daemon-vocabulary.md deleted file mode 100644 index c3b7c1ea..00000000 --- a/doc/afb-daemon-vocabulary.md +++ /dev/null @@ -1,98 +0,0 @@ - -Vocabulary for AFB-DAEMON -========================= - -## Binding - -A shared library object intended to add a functionality to an afb-daemon -instance. It implements an API and may provide a service. - -Binding made for services can have specific entry point called after -initialisation and before serving. - -## Event - -Message with data propagated from the services to the client and not expecting -any reply. - -The current implementation allows to widely broadcast events to all clients. - -## Level of assurance (LOA) - -This level that can be from 0 to 3 represent the level of -assurance that the services can expect from the session. - -The exact definition of the meaning of these levels and how to use it remains to -be achieved. - -## Plugin - -Old name for binding, see binding. - -## Request - -A request is an invocation by a client to a binding method using a message -transferred through some protocol: HTTP, WebSocket, DBUS... and served by -***afb-daemon*** - -## Reply/Response - -This is a message sent to client as the result of the request. - -## Service - -Service are made of bindings running by their side on their binder. -It can serve many client. Each one attached to one session. - -The framework establishes connection between the services and -the clients. Using DBus currently but other protocols are considered. - -## Session - -A session is meant to be the unique instance context of a client, -which identify that instance across requests. - -Each session has an identifier. Session identifier generated by afb-daemon are -UUIDs. - -Internally, afb-daemon offers a mechanism to attach data to sessions. -When the session is closed or disappears, the data attached to that session -are freed. - -## Token - -The token is an identifier that the client must give to be authenticated. - -At start, afb-daemon get an initial token. This initial token must be presented -by incoming client to be authenticated. - -A token is valid only for a period. - -The token must be renewed periodically. When the token is renewed, afb-daemon -sends the new token to the client. - -Tokens generated by afb-daemon are UUIDs. - -## UUID - -It stand for Universal Unique IDentifier. - -It is designed to create identifier in a way that avoid has much as possible -conflicts. It means that if two different instances create an UUID, the -probability that they create the same UUID is very low, near to zero. - -## x-afb-reqid - -Argument name that can be used with HTTP request. When this argument is given, -it is automatically added to the "request" object of the answer. - -## x-afb-token - -Argument name meant to give the token without ambiguity. -You can also use the name **token** but it may conflicts with others arguments. - -## x-afb-uuid - -Argument name for giving explicitly the session identifier without ambiguity. -You can also use the name **uuid** but it may conflicts with others arguments. - diff --git a/doc/afb-events-guide.md b/doc/afb-events-guide.md deleted file mode 100644 index aaa09be1..00000000 --- a/doc/afb-events-guide.md +++ /dev/null @@ -1,475 +0,0 @@ -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/doc/afb-overview.md b/doc/afb-overview.md deleted file mode 100644 index eec3f91a..00000000 --- a/doc/afb-overview.md +++ /dev/null @@ -1,315 +0,0 @@ - -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/doc/afb-tests-overview.md b/doc/afb-tests-overview.md deleted file mode 100644 index d6f619fe..00000000 --- a/doc/afb-tests-overview.md +++ /dev/null @@ -1,89 +0,0 @@ - -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/doc/index.md b/doc/index.md deleted file mode 120000 index 81c25433..00000000 --- a/doc/index.md +++ /dev/null @@ -1 +0,0 @@ -afb-overview.md \ No newline at end of file diff --git a/doc/pictures/AFB_for_services.svg b/doc/pictures/AFB_for_services.svg deleted file mode 100644 index 6e536c50..00000000 --- a/doc/pictures/AFB_for_services.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Isolated security context - - - - - - - - APPLICATION - - - - - - - - binderAFB-DAEMON - - - - - - - - BINDINGS - - - - - - - - - - - - - - - - - - - - - D-Bus & CYNARA - - - - - - - - Isolated security context A - - - - - - - - binderAFB-DAEMON - - - - - - - - serviceBINDINGS A - - - - - - - - - - - - - - - Isolated security context B - - - - - - - - binderAFB-DAEMON - - - - - - - - serviceBINDINGS B - - - - - - - - - - - - - - - Isolated security context C - - - - - - - - binderAFB-DAEMON - - - - - - - - serviceBINDINGS C - - - - - - - - - - - - - - \ No newline at end of file diff --git a/doc/pictures/AFB_overview.svg b/doc/pictures/AFB_overview.svg deleted file mode 100644 index 240dae89..00000000 --- a/doc/pictures/AFB_overview.svg +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Isolated security context - - - - - - - - APPLICATION - - - - - - - - binderAFB-DAEMON - - - - - - - - BINDINGS - - - - - - AGL SYSTEM - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/doc/pictures/signaling-basis.svg b/doc/pictures/signaling-basis.svg deleted file mode 100644 index b13fcf17..00000000 --- a/doc/pictures/signaling-basis.svg +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - 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/doc/pictures/tic-tac-toe.svg b/doc/pictures/tic-tac-toe.svg deleted file mode 100644 index 7a5fb84e..00000000 --- a/doc/pictures/tic-tac-toe.svg +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Client A - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Client B - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Tic-Tac-Toe - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - move - - - - - - wait - - - - - - success of move - - - - - - success of wait - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/doc/pictures/triskel_iot_bzh.svg b/doc/pictures/triskel_iot_bzh.svg deleted file mode 100644 index 096f4244..00000000 --- a/doc/pictures/triskel_iot_bzh.svg +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - -- cgit 1.2.3-korg