From d96d0533b8326570db57d13b8f808bc62d1a7fa4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Fri, 27 May 2016 22:18:26 +0200 Subject: [PATCH 1/1] improves documentation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: Idbd1b735571c2e35daed23d43f8d5d3990881533 Signed-off-by: José Bollo --- doc/FAQ.html | 2 +- doc/FAQ.md | 2 +- doc/afb-daemon-vocabulary.html | 2 +- doc/afb-daemon-vocabulary.md | 2 +- doc/afb-plugin-writing.html | 202 +++++++++++++++++++++++++++++------------ doc/afb-plugin-writing.md | 179 ++++++++++++++++++++++++++---------- include/afb/afb-plugin.h | 21 ++++- plugins/samples/HelloWorld.c | 4 +- plugins/samples/tic-tac-toe.c | 4 +- 9 files changed, 300 insertions(+), 118 deletions(-) diff --git a/doc/FAQ.html b/doc/FAQ.html index ffda81af..98337815 100644 --- a/doc/FAQ.html +++ b/doc/FAQ.html @@ -8,7 +8,7 @@

Frequently Asked Question about AFB-DAEMON

version: 1
-Date:    26 mai 2016
+Date:    27 mai 2016
 Author:  José Bollo
 
diff --git a/doc/FAQ.md b/doc/FAQ.md index 93647311..61105823 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,7 +1,7 @@ Frequently Asked Question about AFB-DAEMON ========================================== version: 1 - Date: 26 mai 2016 + Date: 27 mai 2016 Author: José Bollo TABLE-OF-CONTENT-HERE diff --git a/doc/afb-daemon-vocabulary.html b/doc/afb-daemon-vocabulary.html index 096f5076..fadd1dee 100644 --- a/doc/afb-daemon-vocabulary.html +++ b/doc/afb-daemon-vocabulary.html @@ -8,7 +8,7 @@

Vocabulary for AFB-DAEMON

version: 1
-Date:    26 mai 2016
+Date:    27 mai 2016
 Author:  José Bollo
 
diff --git a/doc/afb-daemon-vocabulary.md b/doc/afb-daemon-vocabulary.md index 71771947..8427b736 100644 --- a/doc/afb-daemon-vocabulary.md +++ b/doc/afb-daemon-vocabulary.md @@ -1,7 +1,7 @@ Vocabulary for AFB-DAEMON ========================= version: 1 - Date: 26 mai 2016 + Date: 27 mai 2016 Author: José Bollo TABLE-OF-CONTENT-HERE diff --git a/doc/afb-plugin-writing.html b/doc/afb-plugin-writing.html index 9a98ffe9..9873b626 100644 --- a/doc/afb-plugin-writing.html +++ b/doc/afb-plugin-writing.html @@ -37,6 +37,8 @@ Author: José Bollo
  • The Tic-Tac-Toe example
  • +
  • Dependencies when compiling
  • +
  • Header files to include
  • Choosing names
  • -
  • Options to set when compiling plugins
  • -
  • Header files to include
  • Writing a synchronous verb implementation
    • The incoming request
    • @@ -265,6 +265,72 @@ This plugin example is in plugins/samples/tic-tac-toe.c.

      This plugin is named tictactoe.

      + +

      Dependencies when compiling

      + +

      Afb-daemon provides a configuration file for pkg-config. +Typing the command

      + +
      pkg-config --cflags afb-daemon
      +
      + +

      will print the flags to use for compiling, like this:

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

      As you see, afb-daemon automatically includes dependency to json-c. +This is done through the Requires keyword of pkg-config +because almost all plugin will use json-c.

      + +

      If this behaviour is a problem, let us know.

      + +

      Internally, afb-daemon uses libsystemd for its event loop +and for its binding to D-Bus. +Plugins developpers are encouraged to also use this library. +But it is a matter of choice. +Thus there is no dependency to libsystemd.

      + +

      Afb-daemon provides no library for plugins. +The functions that the plugin need to have are given +to the plugin at runtime through pointer using read-only +memory.

      + + +

      Header files to include

      + +

      The plugin tictactoe has the following lines for its includes:

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

      The header afb/afb-plugin.h includes all the features that a plugin +needs except two foreign header that must be included by the plugin +if it needs it:

      + +
        +
      • json-c/json.h: this header must be include to handle json objects;
      • +
      • systemd/sd-event.h: this must be include to access the main loop;
      • +
      • systemd/sd-bus.h: this may be include to use dbus connections.
      • +
      + + +

      The tictactoe plugin does not use systemd features so it is not included.

      + +

      When including afb/afb-plugin.h, the macro _GNU_SOURCE must be +defined.

      +

      Choosing names

      @@ -344,60 +410,6 @@ valid javascript identifier.

      rely on the case sensitivity and to avoid the use of names different only by the case.

      - -

      Options to set when compiling plugins

      - -

      Afb-daemon provides a configuration file for pkg-config. -Typing the command

      - -
      pkg-config --cflags afb-daemon
      -
      - -

      will print the flags to use for compiling, like this:

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

      As you see, afb-daemon automatically includes dependency to json-c. -This is done through the Requires keyword of pkg-config.

      - -

      If this behaviour is a problem, let us know.

      - - -

      Header files to include

      - -

      The plugin tictactoe has the following lines for its includes:

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

      The header afb/afb-plugin.h includes all the features that a plugin -needs except two foreign header that must be included by the plugin -if it needs it:

      - -
        -
      • json-c/json.h: this header must be include to handle json objects;
      • -
      • systemd/sd-event.h: this must be include to access the main loop;
      • -
      • systemd/sd-bus.h: this may be include to use dbus connections.
      • -
      - - -

      The tictactoe plugin does not use systemd features so it is not included.

      - -

      When including afb/afb-plugin.h, the macro _GNU_SOURCE must be -defined.

      -

      Writing a synchronous verb implementation

      @@ -879,7 +891,7 @@ const struct AFB_interface *afbitf; static const struct AFB_verb_desc_v1 plugin_verbs[] = { /* 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= "Tells the server to play" }, + { .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" }, @@ -1196,9 +1208,85 @@ journal, syslog or kmsg. (See man sd-daemon).

      Sending events

      +

      Since version 0.5, plugins can broadcast events to any potential listener. +This kind of bradcast is not targeted. Event targeted will come in a future +version of afb-daemon.

      + +

      The plugin 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 the plugin tic-tac-toe, the reason indicates the origin of +the change. For the function afb_daemon_broadcast_event, the second +parameter is the name of the broadcasted event. The third argument is the +object that is transmitted with the 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 plugin.
      + */
      +void afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object);
      +
      + +

      In fact the event name received by the listener is prefixed with +the name of the plugin. So when the change occurs after a move, the +reason is move and then the clients receive the event tictactoe/move.

      + +

      Note that nothing is said about the case sensitivity of event names. +However, the event is always prefixed with the name that the plugin +declared, with the same case, followed with a slash /. +Thus it is safe to compare event using a case sensitive comparison.

      +

      Writing an asynchronous verb implementation

      +

      / + * 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);
      +
      + +

      }

      +

      How to build a plugin

      diff --git a/doc/afb-plugin-writing.md b/doc/afb-plugin-writing.md index 734b15a5..7861021b 100644 --- a/doc/afb-plugin-writing.md +++ b/doc/afb-plugin-writing.md @@ -178,6 +178,65 @@ This plugin example is in *plugins/samples/tic-tac-toe.c*. This plugin is named ***tictactoe***. +Dependencies when compiling +--------------------------- + +Afb-daemon provides a configuration file for *pkg-config*. +Typing the command + + pkg-config --cflags afb-daemon + +will print the flags to use for compiling, like this: + + $ 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 + +As you see, afb-daemon automatically includes dependency to json-c. +This is done through the **Requires** keyword of pkg-config +because almost all plugin will use **json-c**. + +If this behaviour is a problem, let us know. + +Internally, afb-daemon uses **libsystemd** for its event loop +and for its binding to D-Bus. +Plugins developpers are encouraged to also use this library. +But it is a matter of choice. +Thus there is no dependency to **libsystemd**. + +> Afb-daemon provides no library for plugins. +> The functions that the plugin need to have are given +> to the plugin at runtime through pointer using read-only +> memory. + +Header files to include +----------------------- + +The plugin *tictactoe* has the following lines for its includes: + + #define _GNU_SOURCE + #include + #include + #include + #include + +The header *afb/afb-plugin.h* includes all the features that a plugin +needs except two foreign header that must be included by the plugin +if it needs it: + +- *json-c/json.h*: this header must be include to handle json objects; +- *systemd/sd-event.h*: this must be include to access the main loop; +- *systemd/sd-bus.h*: this may be include to use dbus connections. + +The *tictactoe* plugin does not use systemd features so it is not included. + +When including *afb/afb-plugin.h*, the macro **_GNU_SOURCE** must be +defined. + Choosing names -------------- @@ -248,53 +307,6 @@ It is also a good practice, even for arguments, to not rely on the case sensitivity and to avoid the use of names different only by the case. -Options to set when compiling plugins -------------------------------------- - -Afb-daemon provides a configuration file for *pkg-config*. -Typing the command - - pkg-config --cflags afb-daemon - -will print the flags to use for compiling, like this: - - $ 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 - -As you see, afb-daemon automatically includes dependency to json-c. -This is done through the **Requires** keyword of pkg-config. - -If this behaviour is a problem, let us know. - -Header files to include ------------------------ - -The plugin *tictactoe* has the following lines for its includes: - - #define _GNU_SOURCE - #include - #include - #include - #include - -The header *afb/afb-plugin.h* includes all the features that a plugin -needs except two foreign header that must be included by the plugin -if it needs it: - -- *json-c/json.h*: this header must be include to handle json objects; -- *systemd/sd-event.h*: this must be include to access the main loop; -- *systemd/sd-bus.h*: this may be include to use dbus connections. - -The *tictactoe* plugin does not use systemd features so it is not included. - -When including *afb/afb-plugin.h*, the macro **_GNU_SOURCE** must be -defined. - Writing a synchronous verb implementation ----------------------------------------- @@ -755,7 +767,7 @@ The description of the plugin is defined as below. static const struct AFB_verb_desc_v1 plugin_verbs[] = { /* 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= "Tells the server to play" }, + { .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" }, @@ -920,10 +932,81 @@ journal, syslog or kmsg. (See man sd-daemon). Sending events -------------- +Since version 0.5, plugins can broadcast events to any potential listener. +This kind of bradcast is not targeted. Event targeted will come in a future +version of afb-daemon. + +The plugin *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 the plugin *tic-tac-toe*, the *reason* indicates the origin of +the change. For the function **afb_daemon_broadcast_event**, the second +parameter is the name of the broadcasted event. The third argument is the +object that is transmitted with the 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 plugin. + */ + void afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object); + +In fact the event name received by the listener is prefixed with +the name of the plugin. So when the change occurs after a move, the +reason is **move** and then the clients receive the event **tictactoe/move**. + +> Note that nothing is said about the case sensitivity of event names. +> However, the event is always prefixed with the name that the plugin +> declared, with the same case, followed with a slash /. +> Thus it is safe to compare event using a case sensitive comparison. + Writing an asynchronous verb implementation ------------------------------------------- +/* + * 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); +} How to build a plugin --------------------- diff --git a/include/afb/afb-plugin.h b/include/afb/afb-plugin.h index cad55fbe..3d16c7ad 100644 --- a/include/afb/afb-plugin.h +++ b/include/afb/afb-plugin.h @@ -56,10 +56,10 @@ enum AFB_plugin_version */ enum AFB_session_v1 { - AFB_SESSION_NONE = 0, /* no session and no authentification required */ - AFB_SESSION_CREATE = 1, /* obsolete */ - AFB_SESSION_CLOSE = 2, /* closes the session after authentification */ - AFB_SESSION_RENEW = 4, /* refreshes the token after authentification */ + AFB_SESSION_NONE = 0, /* nothing required */ + AFB_SESSION_CREATE = 1, /* Obsolete */ + AFB_SESSION_CLOSE = 2, /* After token authentification, closes the session at end */ + AFB_SESSION_RENEW = 4, /* After token authentification, refreshes the token at end */ AFB_SESSION_CHECK = 8, /* Requires token authentification */ AFB_SESSION_LOA_GE = 16, /* check that the LOA is greater or equal to the given value */ @@ -67,12 +67,13 @@ enum AFB_session_v1 AFB_SESSION_LOA_EQ = 48, /* check that the LOA is equal to the given value */ AFB_SESSION_LOA_SHIFT = 6, /* shift for LOA */ - AFB_SESSION_LOA_MASK = 3, /* mask for LOA */ + AFB_SESSION_LOA_MASK = 7, /* mask for LOA */ AFB_SESSION_LOA_0 = 0, /* value for LOA of 0 */ AFB_SESSION_LOA_1 = 64, /* value for LOA of 1 */ AFB_SESSION_LOA_2 = 128, /* value for LOA of 2 */ AFB_SESSION_LOA_3 = 192, /* value for LOA of 3 */ + AFB_SESSION_LOA_4 = 256, /* value for LOA of 4 */ AFB_SESSION_LOA_LE_0 = AFB_SESSION_LOA_LE | AFB_SESSION_LOA_0, /* check LOA <= 0 */ AFB_SESSION_LOA_LE_1 = AFB_SESSION_LOA_LE | AFB_SESSION_LOA_1, /* check LOA <= 1 */ @@ -207,6 +208,16 @@ static inline struct sd_bus *afb_daemon_get_system_bus(struct afb_daemon daemon) return daemon.itf->get_system_bus(daemon.closure); } +/* + * 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 plugin. + */ +static inline void afb_daemon_broadcast_event(struct afb_daemon daemon, const char *name, struct json_object *object) +{ + return afb_event_sender_push(afb_daemon_get_event_sender(daemon), name, object); +} + /* * Send a message described by 'fmt' and following parameters * to the journal for the verbosity 'level'. diff --git a/plugins/samples/HelloWorld.c b/plugins/samples/HelloWorld.c index 78a1eafd..fe117846 100644 --- a/plugins/samples/HelloWorld.c +++ b/plugins/samples/HelloWorld.c @@ -54,8 +54,8 @@ static void pingBug (struct afb_req request) static void pingEvent(struct afb_req request) { json_object *query = afb_req_json(request); - afb_event_sender_push(afb_daemon_get_event_sender(interface->daemon), "event", query); - ping(request, json_object_get(query), "event"); + afb_daemon_broadcast_event(interface->daemon, "event", json_object_get(query)); + ping(request, query, "event"); } diff --git a/plugins/samples/tic-tac-toe.c b/plugins/samples/tic-tac-toe.c index 79aaaf58..c372e99f 100644 --- a/plugins/samples/tic-tac-toe.c +++ b/plugins/samples/tic-tac-toe.c @@ -299,7 +299,7 @@ static void changed(struct board *board, const char *reason) waiter = next; } - afb_event_sender_push(afb_daemon_get_event_sender(afbitf->daemon), reason, description); + afb_daemon_broadcast_event(afbitf->daemon, reason, description); } /* @@ -586,7 +586,7 @@ static void wait(struct afb_req req) static const struct AFB_verb_desc_v1 plugin_verbs[] = { /* 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= "Tells the server to play" }, + { .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" }, -- 2.16.6