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
-    Date:    27 mai 2016
+    Date:    29 mai 2016
     Author:  José Bollo
 
 TABLE-OF-CONTENT-HERE
@@ -9,95 +9,84 @@ TABLE-OF-CONTENT-HERE
 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.
 
-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
-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
 
-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
 
@@ -178,6 +167,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 <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
 --------------
 
@@ -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
-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
@@ -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.
 
-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
 -----------------------------------------
 
@@ -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).
+        *
+        * 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.
+        *
+        * 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, ...);
 
@@ -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.
+        *
+        * 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.
+        *
+        * 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, ...);
 
+> 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
 ------------------------------
 
@@ -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" },
-          { .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 +942,165 @@ 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.
+        *
+        * 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
 -------------------------------------------
 
+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
 ---------------------