adds documentation for websocket C clients
[src/app-framework-binder.git] / doc / afb-plugin-writing.md
index 734b15a..57b2609 100644 (file)
@@ -1,7 +1,7 @@
 HOWTO WRITE a PLUGIN for AFB-DAEMON
 ===================================
     version: 1
 HOWTO WRITE a PLUGIN for AFB-DAEMON
 ===================================
     version: 1
-    Date:    27 mai 2016
+    Date:    29 mai 2016
     Author:  José Bollo
 
 TABLE-OF-CONTENT-HERE
     Author:  José Bollo
 
 TABLE-OF-CONTENT-HERE
@@ -9,95 +9,84 @@ TABLE-OF-CONTENT-HERE
 Summary
 -------
 
 Summary
 -------
 
-The binder afb-daemon serves files through
-the HTTP protocol and offers access to API's through
+The binder afb-daemon serves files through HTTP protocol
+and offers to developers the capability to expose application APIs through
 HTTP or WebSocket protocol.
 
 HTTP or WebSocket protocol.
 
-The plugins are used to add API's to afb-daemon.
+Binder plugins are used to add API to afb-daemon.
 This part describes how to write a plugin for afb-daemon.
 Excepting this summary, this part is intended to be read
 This part describes how to write a plugin for afb-daemon.
 Excepting this summary, this part is intended to be read
-by developpers.
+by developers.
 
 
-Before going into details, through a tiny example,
-a short overview plugins basis is needed.
+Before moving further through an example, here after
+a short overview of binder plugins fundamentals.
 
 ### Nature of a plugin
 
 
 ### Nature of a plugin
 
-A plugin is a separate piece of code made of a shared library.
-The plugin is loaded and activated by afb-daemon when afb-daemon
-starts.
+A plugin is an independent piece of software, self contain and expose as a dynamically loadable library.
+A plugin is loaded by afb-daemon that exposes contained API dynamically at runtime.
 
 
-Technically, a plugin is not linked to any library of afb-daemon.
+Technically, a binder plugins does not reference and is not linked with any library from afb-daemon.
 
 
-### Kinds of plugins
+### Class of plugins
 
 
-There is two kinds of plugins: application plugins and service
-plugins.
+Application binder supports two kinds of plugins: application plugins and service
+plugins. Technically both class of plugin are equivalent and coding API is shared. Only sharing mode and security context diverge.
 
 
-#### Application plugins
+#### Application-plugins
 
 
-Application plugins are intended to be instanciated for each
-application: when an application using that plugin is started,
-its binder starts a new instance of the plugin.
+Application-plugins implements the glue in between application's UI and services. Every AGL application
+has a corresponding binder that typically activates one or many plugins to interface the application logic with lower platform services.
+When an application is started by AGL application framework, a dedicate binder is started that loads/activates application plugin(s). 
+The API expose by application-plugin are executed within corresponding application security context.
 
 
-It means that the application plugins mainly have only one
-context to manage for one client.
+Application plugins 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 plugin is used within multiple application each of those
+application get a new and private instance of this "shared" plugin.
 
 
-#### Service plugins
+#### Service-plugins
 
 
-Service plugins are intended to be instanciated only one time
-only and connected to many clients.
+Service-plugins enable API activation within corresponding service security context and not within calling application context. 
+Service-plugins are intended to run as a unique instance that is shared in between multiple clients.
 
 
-So either it does not manage context at all or otherwise,
-if it manages context, it should be able to manage one context
-per client.
+Service-plugins can either be stateless or manage client context. When managing context each client get a private context.
 
 
-In details, it may be useful to have service plugins at a user
-level.
+Sharing may either be global to the platform (ie: GPS service) or dedicated to a given user (ie: preference management)
  
  
-### Live cycle of a plugin within afb-daemon
+### Live cycle of plugins within afb-daemon
 
 
-The plugins are loaded and activated when afb-daemon starts.
+Application and service plugins are loaded and activated each time a new afb-daemon is started.
 
 
-At start, the plugin initialise itself.
-If it fails to initialise then afb-daemon stops.
+At launch time, every loaded plugin initialise itself.
+If a single plugin initialisation fail corresponding instance of afb-daemon self aborts.
 
 
-Conversely, if it success to initialize, it must declare
-a name, that must be unique, and a list of API's verbs.
+Conversely, when plugin initialisation succeeds, it should register 
+its unique name and the list of API verbs it exposes.
 
 
-When initialized, the functions implementing the API's verbs
-of the plugin are activated on call.
+When initialised, on request from clients plugin's function corresponding to expose API verbs
+are activated by the afb-daemon instance attached to the application or service.
 
 
-At the end, nothing special is done by afb-daemon.
-Consequently, developpers of plugins should use 'atexit'
-or 'on_exit' during initialisation if they need to
-perform specific actions when stopping.
+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 plugin initialisation sequence to register a custom exit function.
 
 
-### Content of a plugin
+### Plugin Contend
 
 
-For afb-daemon, a plugin contains 2 different
-things: names and functions.
+Afb-daemon's plugin register two classes of objects: names and functions.
 
 
-There is two kind of names:
- - the name of the plugin,
- - the names of the verbs.
+Plugins declare categories of names:
+ - A unique plugin name,
+ - Multiple API verb's names.
 
 
-There is two kind of functions:
- - the initialisation function
- - functions implementing verbs
+Plugins declare two categories of functions:
+ - initialisation function
+ - API functions implementing verbs
 
 
-Afb-daemon translates the name of the method that is
-invoked to a pair of API and verb names. For example,
-the method named **foo/bar** translated to the API
-name **foo** and the verb name **bar**.
-To serve it, afb-daemon search the plugin that record
-the name **foo** and if it also recorded the verb **bar**,
-it calls the implementation function declared for this verb.
+Afb-daemon parses URI requests to extract plugin name and API verb.
+As an example, URI **foo/bar** translates to API verb named **bar** within plugin named **foo**.
+To serve such a request, afb-daemon looks for an active plugin named **foo** and then within this plugin for an API verb named **bar**.
+When find afb-daemon calls corresponding function with attached parameter if any.
 
 
-Afb-daemon make no distinction between lower case
-and upper case when searching for a method.
-Thus, The names **TicTacToe/Board** and **tictactoe/borad**
-are equals.
+Afb-daemon ignores letter case when parsing URI. Thus **TicTacToe/Board** and **tictactoe/board** are equivalent.
 
 #### The name of the plugin
 
 
 #### The name of the plugin
 
@@ -178,6 +167,65 @@ This plugin example is in *plugins/samples/tic-tac-toe.c*.
 
 This plugin is named ***tictactoe***.
 
 
 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
 --------------
 
 Choosing names
 --------------
 
@@ -212,7 +260,7 @@ and upper case when searching for an API by its name.
 The names of the verbs are not checked.
 
 However, the validity rules for verb's names are the
 The names of the verbs are not checked.
 
 However, the validity rules for verb's names are the
-same as for API's names except that the dot (.) character
+same as for API names except that the dot (.) character
 is forbidden.
 
 Afb-daemon make no distinction between lower case
 is forbidden.
 
 Afb-daemon make no distinction between lower case
@@ -248,53 +296,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.
 
 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
 -----------------------------------------
 
 Writing a synchronous verb implementation
 -----------------------------------------
 
@@ -489,12 +490,20 @@ The two functions to send a reply of kind "success" are
         * 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).
         * 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 conveniency, 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.
         */
        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 conveniency, 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, ...);
 
         */
        void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...);
 
@@ -509,15 +518,28 @@ The two functions to send a reply of kind "failure" are
         * Note that calling afb_req_fail("success", info) is equivalent
         * to call afb_req_success(NULL, info). Thus even if possible it
         * is strongly recommanded to NEVER use "success" for status.
         * Note that calling afb_req_fail("success", info) is equivalent
         * to call afb_req_success(NULL, info). Thus even if possible it
         * is strongly recommanded to NEVER use "success" for status.
+        *
+        * For conveniency, 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.
         */
        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 conveniency, 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, ...);
 
         */
        void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...);
 
+> For conveniency, these functions call **json_object_put** to release the object **obj**
+> that they send. Then **obj** can not be used after calling one of these reply functions.
+> When it is not the expected behaviour, calling the function **json_object_get** on the object **obj**
+> before cancels the effect of **json_object_put**.
+
 Getting argument of invocation
 ------------------------------
 
 Getting argument of invocation
 ------------------------------
 
@@ -755,7 +777,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" },
        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" },
           { .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 +942,165 @@ journal, syslog or kmsg. (See man sd-daemon).
 Sending events
 --------------
 
 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.
+        *
+        * For conveniency, 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 for reply functions, the **object** is automatically released using
+> **json_object_put** by the function. Then call **json_object_get** before
+> calling **afb_daemon_broadcast_event** to keep **object** available
+> after the returning of the function.
+
+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
 -------------------------------------------
 
 
 Writing an asynchronous verb implementation
 -------------------------------------------
 
+The *tic-tac-toe* example allows two clients or more to share the same board.
+This is implemented by the verb **join** that illustrated partly the 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. (This coulded 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 plugin by an other client that
+unblock the suspended *wait* call.
+But in general, this will be a timer, a hardware event, the sync with
+a concurrent process or thread, ...
+
+So the case is common, this is 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 the
+current list of waiters and returns without sending a reply.
+
+Before returning, it increases the reference count of the
+request **req** using the function **afb_req_addref**.
+
+> When the implentation of a verb returns without sending a reply,
+> it **MUST** increment the reference count of the request
+> using **afb_req_addref**. If it doesn't bad things can happen.
+
+Later, when the board changes, it calls the function **changed**
+of *tic-tac-toe* with the reason of the change.
+
+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 the sending the reply, the reference count of the request
+is decremented using **afb_req_unref** to allow its resources to be freed.
+
+> The reference count **MUST** be decremented using **afb_req_unref** because,
+> otherwise, there is a leak of resources.
+> It must be decremented **AFTER** the sending of the reply, because, otherwise,
+> bad things may happen.
 
 How to build a plugin
 ---------------------
 
 How to build a plugin
 ---------------------