From 71d4728f61f2b650449838a6d96034697a36736d Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Mon, 21 Nov 2016 23:25:02 +0100 Subject: [PATCH] Fix typo, get diagrams pictures and reordering doc Change-Id: Id8327460cf59b330283a98db8cef3a89ef505d30 Signed-off-by: Romain Forlot --- doc/FAQ.html | 28 - doc/FAQ.md | 1 - doc/afb-application-writing.html | 250 --------- doc/afb-application-writing.md | 67 ++- doc/afb-bindings-overview.html | 154 ------ doc/afb-bindings-overview.md | 45 +- doc/afb-bindings-writing.html | 974 --------------------------------- doc/afb-bindings-writing.md | 854 +++++++++++++++++------------ doc/afb-daemon-vocabulary.html | 79 --- doc/afb-daemon-vocabulary.md | 50 +- doc/afb-events-guide.html | 282 ---------- doc/afb-events-guide.md | 79 ++- doc/afb-overview.html | 316 ----------- doc/afb-overview.md | 107 +--- doc/afb-tests-overview.html | 76 --- doc/afb-tests-overview.md | 2 +- doc/doc.css | 40 -- doc/index.md | 1 + doc/pictures/AFB_for_services.svg | 238 ++++++++ doc/pictures/AFB_overview.svg | 140 +++++ doc/{ => pictures}/signaling-basis.svg | 0 doc/pictures/tic-tac-toe.svg | 289 ++++++++++ doc/{ => pictures}/triskel_iot_bzh.svg | 0 doc/updt.sh | 53 -- mkdocs.yml | 11 + 25 files changed, 1354 insertions(+), 2782 deletions(-) delete mode 100644 doc/FAQ.html delete mode 100644 doc/afb-application-writing.html delete mode 100644 doc/afb-bindings-overview.html delete mode 100644 doc/afb-bindings-writing.html delete mode 100644 doc/afb-daemon-vocabulary.html delete mode 100644 doc/afb-events-guide.html delete mode 100644 doc/afb-overview.html delete mode 100644 doc/afb-tests-overview.html delete mode 100644 doc/doc.css create mode 120000 doc/index.md create mode 100644 doc/pictures/AFB_for_services.svg create mode 100644 doc/pictures/AFB_overview.svg rename doc/{ => pictures}/signaling-basis.svg (100%) create mode 100644 doc/pictures/tic-tac-toe.svg rename doc/{ => pictures}/triskel_iot_bzh.svg (100%) delete mode 100755 doc/updt.sh create mode 100644 mkdocs.yml diff --git a/doc/FAQ.html b/doc/FAQ.html deleted file mode 100644 index f3584e0e..00000000 --- a/doc/FAQ.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - Frequently Asked Question about AFB-DAEMON - - - - - -
-

Frequently Asked Question about AFB-DAEMON

-

José Bollo

-

24 juin 2016

-
- -

Frequently Asked Question about AFB-DAEMON

- - diff --git a/doc/FAQ.md b/doc/FAQ.md index d485c97e..5063ed74 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,4 +1,3 @@ - Frequently Asked Question about AFB-DAEMON ========================================== diff --git a/doc/afb-application-writing.html b/doc/afb-application-writing.html deleted file mode 100644 index 9d051d5e..00000000 --- a/doc/afb-application-writing.html +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - - - - HOWTO WRITE an APPLICATION above AGL FRAMEWORK - - - - - - -
-

HOWTO WRITE an APPLICATION above AGL FRAMEWORK

-

José Bollo

-

Fulup Ar Foll

-

24 juin 2016

-
- -

HOWTO WRITE an APPLICATION above AGL FRAMEWORK

-

Programmation 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 plugins to improve application behavior. Server side plugins 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 current x-afb-json1 protocol.

-

Two examples of HTML5 applications are given:

- -

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 avaliable..

- -

Writing "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.

-

Current implementation relies on libsystemd and file descriptors. This model might be review in the future to support secure sockets and free the dependency with libsystemd.

-

Handling sessions within applications

-

Applications should understand sessions and tokens management when interacting with afb-daemon binder.

-

Applications are communicating with their private binder(afb-daemon) using a network connection or potentially any other connection channel. While current version does not yet implement unix domain this feature might be added in a near future. Developers need to be warn that HTTP protocol is a none connected protocol. This prevents from using HTTP socket connection to authenticate clients.

-

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

-

Plugins and other binder feature need to keep track of client instances. This is especially important for plugins 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 access to some plugin'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 plugin 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:

-
{
-   "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:

-
{
-   "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-application-writing.md b/doc/afb-application-writing.md index 14199f62..cc513b48 100644 --- a/doc/afb-application-writing.md +++ b/doc/afb-application-writing.md @@ -1,8 +1,7 @@ +How to write an application on top of AGL FRAMEWORK +==================================================== -HOWTO WRITE an APPLICATION above AGL FRAMEWORK -============================================== - -Programmation Languages for Applications +Programming Languages for Applications ----------------------------------------- ### Writing an HTML5 application @@ -11,11 +10,12 @@ 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 plugins to improve -application behavior. Server side plugins return an application/json mine-type +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 current x-afb-json1 protocol. +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: @@ -25,14 +25,16 @@ Two examples of HTML5 applications are given: ### Writing a Qt application -Writing Qt applications is also supported. Qt offers standard API to send request through HTTP or WebSockets. +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 avaliable.. +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 "C" application +### Writing a "C" application C applications can use afb-daemon binder through a websocket connection. @@ -46,18 +48,20 @@ Source code is available here Current implementation relies on libsystemd and file descriptors. This model might be review in the future to support secure sockets -and free the dependency with libsystemd. +and get rid of libsystemd dependency. Handling sessions within applications ------------------------------------- -Applications should understand sessions and tokens management when interacting with afb-daemon binder. +Applications should understand sessions and token management when interacting +with afb-daemon binder. -Applications are communicating with their private binder(afb-daemon) using -a network connection or potentially any other connection channel. While current version -does not yet implement unix domain this feature might be added in a near future. -Developers need to be warn that HTTP protocol is a none connected protocol. This prevents -from using HTTP socket connection to authenticate clients. +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 @@ -68,25 +72,25 @@ how authentication and sessions are managed. ### Handling sessions -Plugins and other binder feature need to keep track of client -instances. This is especially important for plugins running as services +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. +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". +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 -access to some plugin's methods. +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**. @@ -95,11 +99,12 @@ 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: +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** plugin is requested as default. +making the expectation that **AuthLogin** binding is requested as default. #### Using curl @@ -197,8 +202,8 @@ 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**. +This object contains at least 2 mandatory fields of name **jtype** and +**request** and one optional field of name **response**. ### Template @@ -250,11 +255,13 @@ or when the token is refreshed. **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. +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. +This field response optionally contains an object returned when request +succeeded. Format of events ---------------- diff --git a/doc/afb-bindings-overview.html b/doc/afb-bindings-overview.html deleted file mode 100644 index 0ffc769a..00000000 --- a/doc/afb-bindings-overview.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - Overview of bindings shipped with AFB-Daemon - - - - - -
-

Overview of bindings shipped with AFB-Daemon

-

José Bollo

-

24 juin 2016

-
- -

Overview of bindings shipped with AFB-Daemon

-

List of bindings

-

Here are the bindings shipped in the source tree:

- -

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:

- -


-

Authentication

-

An 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:

- -


-

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:

- -


-

Audio

-

A sample Audio binding with 2 backends:

- -

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:

- -

(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:

- -

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:

- -

(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:

- -

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:

- -

(if GUPnP/GSSDP development libraries are not fund 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, afb-radio**

-

Sample Qt/QML applications: test/token-websock.qml

- - diff --git a/doc/afb-bindings-overview.md b/doc/afb-bindings-overview.md index 1d3632ee..c79e17f4 100644 --- a/doc/afb-bindings-overview.md +++ b/doc/afb-bindings-overview.md @@ -14,7 +14,8 @@ Here are the bindings shipped in the source tree: * 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. +All bindings may not be built, depending on the development libraries present on +the system at build time. Detail of bindings @@ -24,7 +25,8 @@ Detail of bindings 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. +This binding provides a few unauthenticated requests, all beginning with +"ping", to demonstrate basic binder capabilities. **Verbs**: @@ -40,11 +42,14 @@ This binding provides a few unauthenticated requests, all beginning with "ping", ### Authentication -An sample Authentication binding for demonstration purposes. +A sample Authentication binding for demonstration purposes. -This binding provides a few requests to demonstrate the binder's token-based security mechanism. +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. +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**: @@ -61,7 +66,8 @@ Calling "_connect_" with a security token will initiate a session, calling "_ref 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. +This binding provides an interactive Tic Tac Toe game where the binder returns +the grid as a JSON response. **Verbs**: @@ -84,7 +90,8 @@ 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. +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**: @@ -95,11 +102,14 @@ This binding is able to initialize a specific soundcard, define volume levels, c * _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 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)_ +_(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**)_ +_(a specifc backend can be forced by using this syntax before running afb-daemon +: **$ export AFB_AUDIO_OUTPUT=Alsa**)_
@@ -110,7 +120,9 @@ 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). +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**: @@ -122,18 +134,20 @@ This binding is able to initialize specific RTL2832U dongles, switch between AM/ * _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)_ +_(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. +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**: @@ -147,7 +161,8 @@ This binding is able to detect a local Rygel UPnP media server, list audio files * _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 fund at build time, this binding will not be built)_ +_(if GUPnP/GSSDP development libraries are not found at build time, this binding +will not be built)_
diff --git a/doc/afb-bindings-writing.html b/doc/afb-bindings-writing.html deleted file mode 100644 index ea03801f..00000000 --- a/doc/afb-bindings-writing.html +++ /dev/null @@ -1,974 +0,0 @@ - - - - - - - - HOWTO WRITE a BINDING for AFB-DAEMON - - - - - - -
-

HOWTO WRITE a BINDING for AFB-DAEMON

-

José Bollo

-

27 juillet 2016

-
- -

HOWTO WRITE a BINDING for AFB-DAEMON

-

Summary

-

Afb-daemon binders serve files through HTTP protocol and offers to developers the capability to expose application API methods through HTTP or WebSocket protocol.

-

Binder 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 are 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 fail corresponding instance of afb-daemon self aborts.

-

Conversely, when a binding initialisation succeeds, it should register its unique name as well as the list of verbs attached to the methods it exposes.

-

When initialised, on request from application clients to the right API/verb, 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 Contend

-

Afb-daemon's binding register two classes of objects: names and functions.

-

Bindings declare categories of names: - A unique binding name to access all API expose by this binding, - One name for each methods/verbs provided by this binding.

-

Bindings declare two categories of functions: - function use for the initialisation - functions implementing 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 find afb-daemon calls corresponding method with attached parameter if any.

-

Afb-daemon ignores letter case 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 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 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 binding version depending on initialisation function name. As today, the only supported initialisation function is afbBindingV1Register. This identifies version "one" of bindings.

  2. -
  3. It allows bindings to initialise itself.

  4. -
  5. It enables names declarations: descriptions, requirements and implementations of exposed API/VERB.

  6. -
-

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 that is used to: get arguments of the request, send answer, store session data.

-

A binding MUST set an answer to every received requests.

-

Nevertheless it is not mandatory to set the answer before returning from API/VERB implementing function. This behaviour is important for asynchronous actions.

-

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 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 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 ever you rather not use it, feel free to do so.

-
-

Afb-daemon binding are fully self contain. 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:

-
#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <json-c/json.h>
-#include <afb/afb-binding.h>
-

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:

- -

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:

- -

In other words the set of forbidden characters is { 000..020, 022, 023, 025..027, 02f, 03f, 060, 07f }.

-

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 developper 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.

-

Writing a synchronous method implementation

-

The method tictactoe/board is a synchronous implementation. Here is its listing:

-
/*
- * 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. -
  3. 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.

  4. -
  5. The function describe creates a json_object representing the board.

  6. -
  7. The function afb_req_success sends the reply, attaching to it the object description.

  8. -
-

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:

-
/*
- * 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:

- -

The binding tictactoe use a convenient function to retrieve its context: the board. This function is board_of_req:

-
/*
- * 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

-
/*
- * 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:

-
/*
- * 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.

-
/*
- * 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.

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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.

-
<h2>Sample Post File</h2>
-<form enctype="multipart/form-data">
-    <input type="file" name="file" />
-    <input type="hidden" name="hidden" value="bollobollo" />
-    <br>
-    <button formmethod="POST" formaction="api/post/upload-image">Post File</button>
-</form>
-

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:

-
/*
- * 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:

- -
-

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))

-
-

Initialisation of the binding and 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-need 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. -
  3. Afb-daemon searches for a symbol named afbBindingV1Register using dlsym. This symbol is assumed to be the exported initialisation function of the binding.

  4. -
  5. Afb-daemon builds an interface object for the binding.

  6. -
  7. Afb-daemon calls the found function afbBindingV1Register with interface pointer as parameter.

  8. -
  9. Function afbBindingV1Register setups the binding and initialises it.

  10. -
  11. Function afbBindingV1Register returns the pointer to a structure describing the binding: version, name (prefix or API name), and list of methods.

  12. -
  13. 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.

  14. -
-

Here after the code used for afbBindingV1Register from binding tic-tac-toe:

-
/*
- * 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:

-
/*
- * the interface to afb-daemon
- */
-const struct afb_binding_interface *afbitf;
-

The description of the binding is defined here after.

-
/*
- * 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 structure describing methods is defined as follows:

-
/*
- * 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 nameMeaning
AFB_SESSION_CREATEEquals to AFB_SESSION_LOA_EQ_0
AFB_SESSION_CLOSECloses the session after the reply and set the LOA to 0
AFB_SESSION_RENEWRefreshes the token of authentification
AFB_SESSION_CHECKJust requires the token authentification
AFB_SESSION_LOA_LE_0Requires the current LOA to be lesser then or equal to 0
AFB_SESSION_LOA_LE_1Requires the current LOA to be lesser then or equal to 1
AFB_SESSION_LOA_LE_2Requires the current LOA to be lesser then or equal to 2
AFB_SESSION_LOA_LE_3Requires the current LOA to be lesser then or equal to 3
AFB_SESSION_LOA_GE_0Requires the current LOA to be greater then or equal to 0
AFB_SESSION_LOA_GE_1Requires the current LOA to be greater then or equal to 1
AFB_SESSION_LOA_GE_2Requires the current LOA to be greater then or equal to 2
AFB_SESSION_LOA_GE_3Requires the current LOA to be greater then or equal to 3
AFB_SESSION_LOA_EQ_0Requires the current LOA to be equal to 0
AFB_SESSION_LOA_EQ_1Requires the current LOA to be equal to 1
AFB_SESSION_LOA_EQ_2Requires the current LOA to be equal to 2
AFB_SESSION_LOA_EQ_3Requires 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:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MacroVerbosityMeaningsyslog level
ERROR0Error conditions3
WARNING1Warning conditions4
NOTICE1Normal but significant condition5
INFO2Informational6
DEBUG3Debug-level messages7
-

You can note that the 2 methods WARNING and INFO 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:

-
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 verbosityOutputed macro
0ERROR
1ERROR + WARNING + NOTICE
2ERROR + WARNING + NOTICE + INFO
3ERROR + WARNING + NOTICE + INFO + DEBUG
-

Output format and destination

-

The syslog level is used for forging a prefix to the message. The prefixes are:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
syslog levelprefix
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 even 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:

-
/*
- * 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:

-
/*
- * 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 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 even 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:

-
CLIENT A       CLIENT B         TIC-TAC-TOE
-   |              |                  |
-   +--------------|----------------->| wait . . . . . . . .
-   |              |                  |                     .
-   :              :                  :                      .
-   :              :                  :                      .
-   |              |                  |                      .
-   |              +----------------->| move . . .           .
-   |              |                  |          V           .
-   |              |<-----------------+ success of move      .
-   |              |                  |                    .
-   |<-------------|------------------+ success of wait  <
-

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:

-
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:

-
/*
- * 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.

-
-

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:

-
$ 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.

-
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.

-
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:

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VariableMeaning
afb_FOUNDSet to 1 if afb-daemon binding development files exist
afb_LIBRARIESOnly the libraries (w/o the '-l') for compiling afb-daemon bindings
afb_LIBRARY_DIRSThe paths of the libraries (w/o the '-L') for compiling afb-daemon bindings
afb_LDFLAGSAll required linker flags for compiling afb-daemon bindings
afb_INCLUDE_DIRSThe '-I' preprocessor flags (w/o the '-I') for compiling afb-daemon bindings
afb_CFLAGSAll required cflags for compiling afb-daemon bindings
-

If development files are found, the binding can be added to the set of target to build.

-
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.

-
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. -
  3. 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).

  4. -
-

Next line are:

-
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 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 "
- - diff --git a/doc/afb-bindings-writing.md b/doc/afb-bindings-writing.md index 6327734e..1db5a435 100644 --- a/doc/afb-bindings-writing.md +++ b/doc/afb-bindings-writing.md @@ -1,16 +1,16 @@ -HOWTO WRITE a BINDING for AFB-DAEMON +How to write a binding for AFB-DAEMON =================================== Summary ------- -Afb-daemon binders serve files through HTTP protocol -and offers to developers the capability to expose application API methods through -HTTP or WebSocket protocol. +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. -Binder bindings are used to add API to afb-daemon. -This part describes how to write a binding for afb-daemon. +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. @@ -19,132 +19,148 @@ 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. +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. +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 are use the same coding convention. Only sharing mode and security context diverge. +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 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. +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 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. +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) -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 +### Live cycle of bindings within ***afb-daemon*** -Application and service bindings are loaded and activated each time a new afb-daemon is started. +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 fail corresponding instance of afb-daemon self aborts. +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 attached to the methods it exposes. +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/verb, binding methods -are activated by the afb-daemon attached to the application or service. +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. +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 Contend +### Binding Content -Afb-daemon's binding register two classes of objects: names and functions. +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 expose by this binding, + - 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 use for the initialisation - - functions implementing exposed API methods + - 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 find afb-daemon calls corresponding method with attached parameter if any. +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 ignores letter case when parsing URI. Thus **TicTacToe/Board** and **tictactoe/board** are equivalent. +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. +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** a VERB attached to some method. +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. +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 corresponding methods. -When clients emit requests on a given API/VERB corresponding method is called by afb-daemon. +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 binding version depending on initialisation function name. -As today, the only supported initialisation function is **afbBindingV1Register**. This identifies -version "one" of bindings. +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. +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. +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 that -is used to: get arguments of the request, send -answer, store session data. +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 it is not mandatory to set the answer -before returning from API/VERB implementing function. -This behaviour is important for asynchronous actions. +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*. -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 answer to the request only at completion of asynchronous actions. +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 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***. @@ -159,25 +175,27 @@ Typing the command Print flags use for compilation: $ pkg-config --cflags afb-daemon - -I/opt/local/include -I/usr/include/json-c + -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 dependency to json-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 ever -you rather not use it, feel free to do so. - -> Afb-daemon binding are fully self contain. 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 +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 @@ -266,11 +284,342 @@ Nevertheless this is not the case with javascript dot notation: 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 developper to chose name compatible with both javascript and HTML notation. +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. +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 ----------------------------------------- @@ -307,7 +656,7 @@ 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. +used represents the interface to ***afb-daemon***. 3. The function **describe** creates a json_object representing the board. @@ -335,11 +684,11 @@ struct afb_req { ``` It contains two pointers: first one *itf*, points to functions used -to handle internal request. Second one *closure* point onto function closure. +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. +> by ***afb-daemon*** as described here after. *req* is used to get arguments of the request, to send answer, to store session data. @@ -362,7 +711,8 @@ 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. +Requests *afb_req* offer four functions for storing and retrieving session +associated context. These functions are: @@ -394,7 +744,7 @@ static inline struct board *board_of_req(struct afb_req req) 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. +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** @@ -425,8 +775,8 @@ 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. +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: @@ -669,7 +1019,7 @@ 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. +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: @@ -692,7 +1042,7 @@ 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. +- 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. @@ -701,168 +1051,106 @@ Values are either string for common arguments or object ie: { "file": "...", "pa > can be seen as a shortcut to > ***json_object_get_string(json_object_object_get(afb_req_json(req), name))*** -Initialisation of the binding and 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-need 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. +Writing an asynchronous method implementation +------------------------------------------- -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. +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. -Here after the code used for **afbBindingV1Register** from binding *tic-tac-toe*: +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. -```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 -} -``` +In this case, the reply to the wait is sent only when the board changes. +See the diagram below: -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. +![tic-tac-toe_diagram][tic-tac-toe_diagram] -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: +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, ... -```C -/* - * the interface to afb-daemon - */ -const struct afb_binding_interface *afbitf; -``` +Common case of an asynchronous implementation. -The description of the binding is defined here after. +Here is the listing of the function **wait**: ```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 = +static void wait(struct afb_req req) { - /* 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. + struct board *board; + struct waiter *waiter; -The list of methods is an array of structures describing the methods and terminated by a NULL marker. + /* retrieves the context for the session */ + board = board_of_req(req); + INFO(afbitf, "method 'wait' called for boardid %d", board->id); -In version one of afb-damon binding, a method description contains 4 fields: + /* 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; +} +``` -- the name of the method, +After retrieving the board, the function adds a new waiter to +waiters list and returns without setting a reply. -- the session management flags, +Before returning, it increases **req** request's reference count using **afb_req_addref** function. -- the implementation function to be call for the method, +> 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. -- a short description. +Later, when a board changes, it calls *tic-tac-toe* **changed** function +with reason of change in parameter. -The structure describing methods is defined as follows: +Here is the full listing of the function **changed**: ```C /* - * Description of one method of the API provided by the binding - * This enumeration is valid for bindings of type 1 + * signals a change of the board */ -struct afb_verb_desc_v1 +static void changed(struct board *board, const char *reason) { - 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 |). + struct waiter *waiter, *next; + struct json_object *description; -The constants that can bit mixed are: + /* get the description */ + description = describe(board); -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 + 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; + } -If any of this flag is set, afb-daemon requires an authentication token -as if **AFB_SESSION_CHECK** flag was also set. + afb_event_sender_push(afb_daemon_get_event_sender(afbitf->daemon), reason, description); +} +``` -The special value **AFB_SESSION_NONE** is zero and can be used to bypass token check. +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. -> Note that **AFB_SESSION_CREATE** and **AFB_SESSION_CLOSE** might be removed in later versions. +> 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 +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 @@ -882,7 +1170,7 @@ 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 **INFO** have the same level +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. @@ -938,8 +1226,8 @@ Sending events -------------- Since version 0.5, bindings can broadcast events to any potential listener. -As today only unattended even are supported. Targeted events are expected for next -coming version. +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**: @@ -998,117 +1286,11 @@ receive an event **tictactoe/move**. > declared, with the same case, followed with a slash /. > Thus it is safe to compare event using a case sensitive comparison. - - -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 even 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: - - CLIENT A CLIENT B TIC-TAC-TOE - | | | - +--------------|----------------->| wait . . . . . . . . - | | | . - : : : . - : : : . - | | | . - | +----------------->| move . . . . - | | | V . - | |<-----------------+ success of move . - | | | . - |<-------------|------------------+ success of wait < - -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. - 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. +queried by providing ***afb-daemon*** in command line arguments. This configuration file provides data that should be used for bindings compilation. Examples: @@ -1185,7 +1367,7 @@ 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 +**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: @@ -1221,3 +1403,5 @@ Adding a dependency to afb-daemon is enough. See below: DEPENDS += " afb-daemon " + +[tic-tac-toe_diagram]: pictures/tic-tac-toe.svg (Tic-Tac-Toe sequences diagram) diff --git a/doc/afb-daemon-vocabulary.html b/doc/afb-daemon-vocabulary.html deleted file mode 100644 index 5a585c23..00000000 --- a/doc/afb-daemon-vocabulary.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - Vocabulary for AFB-DAEMON - - - - - -
-

Vocabulary for AFB-DAEMON

-

José Bollo

-

24 juin 2016

-
- -

Vocabulary for AFB-DAEMON

-

Binding

-

A shared library object intended to be add a functionnality to an afb-daemon instance. It implements an API. It 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 this levels and of how to use it remains to be achived.

-

Plugin

-

Old name for binding, see binding.

-

Request

-

A request is an invocation by a client to a method of a binding using a message transfered through some protocol: HTTP, WebSocket, DBUS... served by afb-daemon

-

Reply/Response

-

This is a message sent to client as the result of the request.

-

Service

-

Service are made of binding runnning by their side on their binder. It can serve many client. Each one being attached to one session.

-

The framework establishes the connection between the services and the clients. Using DBus currently but other protocols are considered.

-

Session

-

A session is meant to be the unic context of an instance of client, identifying 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 the client must give to be authentificated.

-

At start, afb-daemon get an initial token. This initial token must be presented incoming client to be authentificated.

-

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 Unic IDentifier.

-

Its is designed to create identifier in a way that avoid has much as possible conflicts. It means that if two differents instance create a 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 for giving the token without ambiguity. You can also use the name token but it may conflicts with other arguments.

-

x-afb-uuid

-

Argument name for giving explicitely the session identifier without ambiguity. You can also use the name uuid but it may conflicts with other arguments.

- - diff --git a/doc/afb-daemon-vocabulary.md b/doc/afb-daemon-vocabulary.md index 897e4db1..c3b7c1ea 100644 --- a/doc/afb-daemon-vocabulary.md +++ b/doc/afb-daemon-vocabulary.md @@ -4,8 +4,8 @@ Vocabulary for AFB-DAEMON ## Binding -A shared library object intended to be add a functionnality to an afb-daemon -instance. It implements an API. It may provide a service. +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. @@ -22,8 +22,8 @@ The current implementation allows to widely broadcast events to all clients. 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 this levels and of -how to use it remains to be achived. +The exact definition of the meaning of these levels and how to use it remains to +be achieved. ## Plugin @@ -31,8 +31,9 @@ Old name for binding, see binding. ## Request -A request is an invocation by a client to a method of a binding using a message -transfered through some protocol: HTTP, WebSocket, DBUS... served by afb-daemon +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 @@ -40,18 +41,19 @@ This is a message sent to client as the result of the request. ## Service -Service are made of binding runnning by their side on their binder. -It can serve many client. Each one being attached to one session. +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 the connection between the services and +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 unic context of an instance of client, -identifying that instance across requests. +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. +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 @@ -59,10 +61,10 @@ are freed. ## Token -The token is an identifier that the the client must give to be authentificated. +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 -incoming client to be authentificated. +by incoming client to be authenticated. A token is valid only for a period. @@ -73,24 +75,24 @@ Tokens generated by afb-daemon are UUIDs. ## UUID -It stand for Universal Unic IDentifier. +It stand for Universal Unique IDentifier. -Its is designed to create identifier in a way that avoid has much as possible conflicts. -It means that if two differents instance create a UUID, the probability that they create the same UUID is very low, near to zero. +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. +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 for giving the token without ambiguity. -You can also use the name **token** but it may conflicts with other arguments. +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 explicitely the session identifier without ambiguity. -You can also use the name **uuid** but it may conflicts with other arguments. +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.html b/doc/afb-events-guide.html deleted file mode 100644 index c554feab..00000000 --- a/doc/afb-events-guide.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - Guide for developing with events - - - - - - -
-

Guide for developing with events

-

José Bollo

-

19 septembre 2016

-
- -

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, receiving events must be described and explained.

-

Overview of events

-

The basis of a signaling agent is shown on the following figure:

-
-scenario of using events
scenario of using events
-
-

This figure shows the main role of the signaling framework for the propagation of events.

-

For people not familiar with the framework, a signaling agent and a “binding” are similar.

-

Subscribing and unsubscribing

-

Subscribing and subscription 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. -
  3. establish the computation chain of the required data, if not already done;
  4. -
  5. create a named event for the computed data, if not already done;
  6. -
  7. ask the framework to establish the subscription to the event for the request;
  8. -
  9. optionally give indications about the event in the reply to the client.
  10. -
-

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:

-
    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:

-
    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 usecase.

-

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. -
  3. 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.
  4. -
-

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:

-
    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:

-
    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:

-
    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 JSON1 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:

- -

An event can be broadcasted using one of the two following methods: afb_daemon_broadcast_event or afb_event_broadcast.

-

Example 1:

-
    afb_daemon_broadcast_event(afb_daemon, name, json);
-

Example 2:

-
    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:

-
/*
- * 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 plugin 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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:

-
/*
- * 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 explicitely. The name is automatically prefixed with the name of the binding. For example, a binding of prefix "xxx" would broadcat the event "xxx/name".

-

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 ocused 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:

- -

Drawbacks:

- -

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 reduced2 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:

- -

Drawbacks:

- -
-
-
    -
  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. -
  3. 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.↩

  4. -
-
- - diff --git a/doc/afb-events-guide.md b/doc/afb-events-guide.md index f24bef3f..aaa09be1 100644 --- a/doc/afb-events-guide.md +++ b/doc/afb-events-guide.md @@ -5,30 +5,30 @@ 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, receiving +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 on the following figure: +The basis of a signaling agent is shown in the following figure: -![scenario of using events](signaling-basis.svg) +![scenario of using events](pictures/signaling-basis.svg) -This figure shows the main role of the signaling framework for the -propagation of events. +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 and subscription 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. +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: @@ -46,8 +46,8 @@ 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 +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. @@ -81,11 +81,11 @@ 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. +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 usecase. +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 @@ -96,11 +96,11 @@ 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 + 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. + 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 @@ -145,7 +145,7 @@ will receive an event of name ***api/event***. 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 +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: @@ -155,12 +155,12 @@ afb\_daemon\_get\_event\_loop. Example: ``` 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 +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 +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. +use functions of **libsystemd** to handle D-Bus. In some rare cases, the generation of the data requires to start a new thread. @@ -169,7 +169,7 @@ 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); + rc = afb_event_push(event, JSON); if (rc == 0) { stop_generating(event); afb_event_drop(event); @@ -248,7 +248,7 @@ 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 plugin +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 @@ -366,10 +366,33 @@ The function ***afb\_daemon\_broadcast\_event*** is defined as below: int afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object); ``` -The name is given here explicitely. The name is automatically prefixed +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 ------------------------- @@ -381,7 +404,7 @@ 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 ocused on +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 @@ -410,7 +433,7 @@ Drawbacks: - Cost of propagation of data (might serialize) - Difficulties to abstract low-level signaling agent or to find a - trade-of between abstracting and specializing + 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 @@ -436,7 +459,7 @@ Drawbacks: - Cannot be used for aggregation of several sources - Difficulties to abstract low-level signaling agent or to find a - trade-of between abstracting and specializing + 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 diff --git a/doc/afb-overview.html b/doc/afb-overview.html deleted file mode 100644 index 707443cc..00000000 --- a/doc/afb-overview.html +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - Overview of AFB-DAEMON - - - - - -
-

Overview of AFB-DAEMON

-

José Bollo

-

24 juin 2016

-
- -

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 -

-

-
. . . . . . . . . . . . . . . . . . . . . . . . . .
-.        Isolated security context                .
-.                                                 .
-.        +------------------------------+         .
-.        |                              |         .
-.        |    A P P L I C A T I O N     |         .
-.        |                              |         .
-.        +--------------+---------------+         .
-.                       |                         .
-.                       |                         .
-.   +-------------------+----------------------+  .
-.   |                            :             |  .
-.   |        b i n d e r         :             |  .
-.   |    A F B - D A E M O N     :  BINDINGS   |  .
-.   |                            :             |  .
-.   +-------------------+----------------------+  .
-.                       |                         .
-. . . . . . . . . . . . | . . . . . . . . . . . . .
-                        |
-                        v
-                   AGL SYSTEM
-

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. -
  3. It acts as an HTTP server for serving files to HTML5 applications;

  4. -
  5. It allows HTML5 applications to have native extensions subject to security enforcement for accessing hardware ressources or for speeding parts of algorithm.

  6. -
-

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 interresting 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 would become when the application is run remotely:

- -

-Figure: binder afb-daemon and remotely running application -

-

-
             +------------------------------+
-             |                              |
-             |    A P P L I C A T I O N     |
-             |                              |
-             +--------------+---------------+
-                            |
-                       ~ ~ ~ ~ ~ ~
-                      :  NETWORK  :
-                       ~ ~ ~ ~ ~ ~
-                            |
-. . . . . . . . . . . . . . | . . . . . . . . . . . . . .
-. Isolated security         |                           .
-.   context                 |                           .
-.                           |                           .
-.     . . . . . . . . . . . . . . . . . . . . . . . .   .
-.     .                                             .   .
-.     .               F I R E W A L L               .   .
-.     .                                             .   .
-.     . . . . . . . . . . . . . . . . . . . . . . . .   .
-.                           |                           .
-.       +-------------------+----------------------+    .
-.       |                            :             |    .
-.       |    A F B - D A E M O N     :   BINDINGS  |    .
-.       |                            :             |    .
-.       +-------------------+----------------------+    .
-.                           |                           .
-. . . . . . . . . . . . . . | . . . . . . . . . . . . . .
-                            |
-                            v
-                       AGL SYSTEM
-

Adding native features to HTML5/QML applications

-

Applications can provide with their packaged delivery a binding. That binding will be instanciated for each application instance. The methods of the binding will be accessible by applications and will be excuted 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. -
  3. provide application's services (services provided as application)

  4. -
-

In that case, the figure showing the whole aspects is

- -

-Figure: binder afb-daemon for services -

-

-
. . . . . . . . . . . . . . . . . . . . . . 
-.  Isolated security context application  . 
-.                                         . 
-.    +------------------------------+     . 
-.    |                              |     . 
-.    |    A P P L I C A T I O N     |     . 
-.    |                              |     . 
-.    +--------------+---------------+     .     . . . . . . . . . . . . . . . . . . . . . .
-.                   |                     .     .        Isolated security context A      .
-.                   |                     .     .                                         .
-. +-----------------+------------------+  .     . +------------------------------------+  .
-. |                        :           |  .     . |                        :           |  .
-. |      b i n d e r       :           |  .     . |      b i n d e r       :  service  |  .
-. |  A F B - D A E M O N   : BINDINGS  |  .     . |  A F B - D A E M O N   : BINDINGS  |  .
-. |                        :           |  .     . |                        :     A     |  .
-. +-----------------+------------------+  .     . +-----------------+------------------+  .
-.                   |                     .     .                   |                     .
-. . . . . . . . . . | . . . . . . . . . . .     . . . . . . . . . . | . . . . . . . . . . .
-                    |                                               |
-                    v                                               v
-         ================================================================================
-                                     D - B U S   &   C Y N A R A
-         ================================================================================
-                    ^                                               ^
-                    |                                               |
-. . . . . . . . . . | . . . . . . . . . . .     . . . . . . . . . . | . . . . . . . . . . .
-.                   |                     .     .                   |                     .
-. +-----------------+------------------+  .     . +-----------------+------------------+  .
-. |                        :           |  .     . |                        :           |  .
-. |      b i n d e r       :  service  |  .     . |      b i n d e r       :  service  |  .
-. |  A F B - D A E M O N   : BINDINGS  |  .     . |  A F B - D A E M O N   : BINDINGS  |  .
-. |                        :     B     |  .     . |                        :     C     |  .
-. +------------------------------------+  .     . +------------------------------------+  .
-.                                         .     .                                         .
-.        Isolated security context B      .     .        Isolated security context C      .
-. . . . . . . . . . . . . . . . . . . . . .     . . . . . . . . . . . . . . . . . . . . . .
-

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 instanciate 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. -
  3. add common API available by any applications

  4. -
  5. provide customers services

  6. -
-

A specific document explains how to write an afb-daemon binder binding: HOWTO WRITE a BINDING for AFB-DAEMON

-

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
-
-  --port=xxxx
-
-    HTTP listening TCP port  [default 1234]
-
-  --rootdir=xxxx
-
-    HTTP Root Directory [default $AFBDIR or else $HOME/.AFB]
-
-  --rootbase=xxxx
-
-    Angular Base Root URL [default /opa]
-
-    This is used for any application of kind OPA (one page application).
-    When set, any missing document whose url has the form /opa/zzz
-    is translated to /opa/#!zzz
-
-  --rootapi=xxxx
-
-    HTML Root API URL [default /api]
-
-    The bindings are available within that url.
-
-  --alias=xxxx
-
-    Maps a path located anywhere in the file system to the
-    a subdirectory. The syntax for mapping a PATH to the
-    subdirectory NAME is: --alias=/NAME:PATH.
-
-    Example: --alias=/icons:/usr/share/icons maps the
-    content of /usr/share/icons within the subpath /icons.
-
-    This option can be repeated.
-
-  --apitimeout=xxxx
-
-    binding API timeout in seconds [default 20]
-
-    Defines how many seconds maximum a method is allowed to run.
-    0 means no limit.
-
-  --cntxtimeout=xxxx
-
-    Client Session Timeout in seconds [default 3600]
-
-  --cache-eol=xxxx
-
-    Client cache end of live [default 100000 that is 27,7 hours]
-
-  --sessiondir=xxxx
-
-    Sessions file path [default rootdir/sessions]
-
-  --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.
-
-  --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.
-
-  --foreground
-
-    Get all in foreground mode (default)
-
-  --daemon
-
-    Get all in background mode
-

Future development of afb-daemon

- - - diff --git a/doc/afb-overview.md b/doc/afb-overview.md index 343a4f30..75703442 100644 --- a/doc/afb-overview.md +++ b/doc/afb-overview.md @@ -17,27 +17,7 @@ of afb-daemon:

Figure: binder afb-daemon, basis

- . . . . . . . . . . . . . . . . . . . . . . . . . . - . Isolated security context . - . . - . +------------------------------+ . - . | | . - . | A P P L I C A T I O N | . - . | | . - . +--------------+---------------+ . - . | . - . | . - . +-------------------+----------------------+ . - . | : | . - . | b i n d e r : | . - . | A F B - D A E M O N : BINDINGS | . - . | : | . - . +-------------------+----------------------+ . - . | . - . . . . . . . . . . . . | . . . . . . . . . . . . . - | - v - AGL SYSTEM +![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 @@ -61,53 +41,23 @@ usage through several use cases. ### Remotely running application -One of the most interresting aspect of using the binder afb-daemon +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-1) would become +So the [figure binder, basis](#binder-fig-basis) would become when the application is run remotely:

Figure: binder afb-daemon and remotely running application

- +------------------------------+ - | | - | A P P L I C A T I O N | - | | - +--------------+---------------+ - | - ~ ~ ~ ~ ~ ~ - : NETWORK : - ~ ~ ~ ~ ~ ~ - | - . . . . . . . . . . . . . . | . . . . . . . . . . . . . . - . Isolated security | . - . context | . - . | . - . . . . . . . . . . . . . . . . . . . . . . . . . . - . . . . - . . F I R E W A L L . . - . . . . - . . . . . . . . . . . . . . . . . . . . . . . . . . - . | . - . +-------------------+----------------------+ . - . | : | . - . | A F B - D A E M O N : BINDINGS | . - . | : | . - . +-------------------+----------------------+ . - . | . - . . . . . . . . . . . . . . | . . . . . . . . . . . . . . - | - v - AGL SYSTEM ### Adding native features to HTML5/QML applications Applications can provide with their packaged delivery a binding. -That binding will be instanciated for each application instance. +That binding will be instantiated for each application instance. The methods of the binding will be accessible by applications and -will be excuted within the security context. +will be executed within the security context. ### Offering services to the system @@ -124,43 +74,7 @@ In that case, the figure showing the whole aspects is

Figure: binder afb-daemon for services

- . . . . . . . . . . . . . . . . . . . . . . - . Isolated security context application . - . . - . +------------------------------+ . - . | | . - . | A P P L I C A T I O N | . - . | | . - . +--------------+---------------+ . . . . . . . . . . . . . . . . . . . . . . . - . | . . Isolated security context A . - . | . . . - . +-----------------+------------------+ . . +------------------------------------+ . - . | : | . . | : | . - . | b i n d e r : | . . | b i n d e r : service | . - . | A F B - D A E M O N : BINDINGS | . . | A F B - D A E M O N : BINDINGS | . - . | : | . . | : A | . - . +-----------------+------------------+ . . +-----------------+------------------+ . - . | . . | . - . . . . . . . . . . | . . . . . . . . . . . . . . . . . . . . . | . . . . . . . . . . . - | | - v v - ================================================================================ - D - B U S & C Y N A R A - ================================================================================ - ^ ^ - | | - . . . . . . . . . . | . . . . . . . . . . . . . . . . . . . . . | . . . . . . . . . . . - . | . . | . - . +-----------------+------------------+ . . +-----------------+------------------+ . - . | : | . . | : | . - . | b i n d e r : service | . . | b i n d e r : service | . - . | A F B - D A E M O N : BINDINGS | . . | A F B - D A E M O N : BINDINGS | . - . | : B | . . | : C | . - . +------------------------------------+ . . +------------------------------------+ . - . . . . - . Isolated security context B . . Isolated security context C . - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - +![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 @@ -169,7 +83,7 @@ associated to each of its client. The bindings of the binder afb-daemon ------------------------------------ -The binder can instanciate bindings. The primary use of bindings +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. @@ -335,10 +249,11 @@ anymore. - Make the service connection using WebSocket not DBUS. -- Management of targetted events. +- Management of targeted events. -- Securisation of LOA. +- Securing LOA. - Integration of the protocol JSON-RPC for the websockets. - +[binder-basis]: pictures/AFB_overview.svg (Binder AFB daemon basis) +[afb-for-services]: pictures/AFB_for_services.svg (Binder AFB daemon for services) diff --git a/doc/afb-tests-overview.html b/doc/afb-tests-overview.html deleted file mode 100644 index 27231a08..00000000 --- a/doc/afb-tests-overview.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - Overview of tests shipped with AFB-Daemon - - - - - -
-

Overview of tests shipped with AFB-Daemon

-

Manuel Bachmann

-

José Bollo

-

24 juin 2016

-
- -

Overview of tests shipped with AFB-Daemon

-

List of tests

-

Here are the tests shipped in the source tree:

- -

Detail of tests

-

afb-client-demo (command-line WebSockets)

-

This clients interactively calls bindings APIs from the command line, using the binder WebSockets 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 [<api> <verb> [<json-data>]]
-

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 23 :

-
$ 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/afb-tests-overview.md b/doc/afb-tests-overview.md index b70eda12..d6f619fe 100644 --- a/doc/afb-tests-overview.md +++ b/doc/afb-tests-overview.md @@ -58,7 +58,7 @@ For installing Qt5 on **Ubuntu 16.04**: $ apt-get install qmlscene qml-module-qtwebsockets qml-module-qtquick-controls -For installing Qt5 on **Fedora 23** : +For installing Qt5 on **Fedora >= 22** : $ dnf install qt5-qtdeclarative-devel qt5-qtwebsockets-devel qt5-qtquickcontrols diff --git a/doc/doc.css b/doc/doc.css deleted file mode 100644 index f3d55f9d..00000000 --- a/doc/doc.css +++ /dev/null @@ -1,40 +0,0 @@ -body { - background: #fff url(triskel_iot_bzh.svg) no-repeat fixed right top; - font-family: "Verdana"; - color: #000; -} - -h1, h2, h3, h4 { - color: #306; - text-decoration: underline; -} - -pre { - border: medium dashed #306; - border-width: 0.1em; - background-color: #eee; - margin-left: 2em; - margin-right: 2em; - padding: 1em; - outline: #555; -} - -blockquote { - border-left: solid thick black; - background-color: #ff8; - font: bolder; - padding: 0.7em 1.5em; -} - -table { - margin-left: 2em; - background-color: #dff; - outline: 0.25em solid #a6f; -/* padding: 0.25em;*/ -} -thead {background-color: #a6f;} -tr:nth-child(even) {background-color: #aee;} -td { padding: 0.1em 0.5em; } - -figure img {width: 80%;} -figure {text-align: center;} diff --git a/doc/index.md b/doc/index.md new file mode 120000 index 00000000..81c25433 --- /dev/null +++ b/doc/index.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..6e536c50 --- /dev/null +++ b/doc/pictures/AFB_for_services.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Isolated security context + + + + + + + + APPLICATION + + + + + + + + binderAFB-DAEMON + + + + + + + + BINDINGS + + + + + + + + + + + + + + + + + + + + + D-Bus & CYNARA + + + + + + + + Isolated security context A + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS A + + + + + + + + + + + + + + + Isolated security context B + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS B + + + + + + + + + + + + + + + Isolated security context C + + + + + + + + binderAFB-DAEMON + + + + + + + + serviceBINDINGS C + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/pictures/AFB_overview.svg b/doc/pictures/AFB_overview.svg new file mode 100644 index 00000000..240dae89 --- /dev/null +++ b/doc/pictures/AFB_overview.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Isolated security context + + + + + + + + APPLICATION + + + + + + + + binderAFB-DAEMON + + + + + + + + BINDINGS + + + + + + AGL SYSTEM + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/signaling-basis.svg b/doc/pictures/signaling-basis.svg similarity index 100% rename from doc/signaling-basis.svg rename to doc/pictures/signaling-basis.svg diff --git a/doc/pictures/tic-tac-toe.svg b/doc/pictures/tic-tac-toe.svg new file mode 100644 index 00000000..7a5fb84e --- /dev/null +++ b/doc/pictures/tic-tac-toe.svg @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tic-Tac-Toe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + move + + + + + + wait + + + + + + success of move + + + + + + success of wait + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/triskel_iot_bzh.svg b/doc/pictures/triskel_iot_bzh.svg similarity index 100% rename from doc/triskel_iot_bzh.svg rename to doc/pictures/triskel_iot_bzh.svg diff --git a/doc/updt.sh b/doc/updt.sh deleted file mode 100755 index d0c02e7a..00000000 --- a/doc/updt.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -title() { - sed '/^[ \t]*$/d' "$1" | - sed '/^===/Q' | - sed '/^---/Q' | - sed 's/^# //;T;Q' | - sed 's/^## //;T;Q' | - sed '/^---/Q' -} - -authors() { - git log --numstat --format='A %aN' -- "$1" | - awk '$1=="A"{sub(/^A /,"");a=$0; s[a]+=0; next}NF==3{s[a]+=($1+0)}END{for(a in s)print s[a]" : "a}' | - sort -nr | - sed 's/[^:]* : //' | - sed '1!s/^/; /' | - tr -d '\n' -} - -dateof() { - local file="$1" - local t=$(git log -n 1 --format=%ct "$file") - [[ -n "$t" ]] || t=$(stat -c %Y "$file") - LANG= date -d @$t +"%d %B %Y" -} - -meta() { - local file="$1" - local t=$(title "$file") - local a=$(authors "$file") - local d=$(dateof "$file") - echo "% $t" - echo "% $a" - echo "% $d" - cat "$file" -} - - -# make the html file for $1 -mkhtml() { - local x=$1 - local h=${x%%.md}.html - echo updating $h from $x - meta "$x" | - pandoc --css doc.css -f markdown -t html5 --toc > "$h" -} - -# apply -for x in *.md; do - mkhtml $x -done - diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..87bd6230 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,11 @@ +site_name: AGL Application Framework Binder +theme: readthedocs +docs_dir: doc +pages: + - 'Overview' : 'index.md' + - 'Binder daemon vocabulary' : 'afb-daemon-vocabulary.md' + - 'Binder events guide' : 'afb-events-guide.md' + - 'Binder Application writing guide' : 'afb-application-writing.md' + - 'Binding writing guide' : 'afb-bindings-writing.md' + - 'Binder tests overview' : 'afb-tests-overview.md' + - 'Bindings samples' : 'afb-bindings-overview.md' -- 2.16.6