summaryrefslogtreecommitdiffstats
path: root/doc/afb-plugin-writing.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/afb-plugin-writing.md')
-rw-r--r--doc/afb-plugin-writing.md742
1 files changed, 401 insertions, 341 deletions
diff --git a/doc/afb-plugin-writing.md b/doc/afb-plugin-writing.md
index f5966092..bc43e4e4 100644
--- a/doc/afb-plugin-writing.md
+++ b/doc/afb-plugin-writing.md
@@ -189,11 +189,13 @@ Header files to include
Plugin *tictactoe* has following includes:
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <string.h>
- #include <json-c/json.h>
- #include <afb/afb-plugin.h>
+```C
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <json-c/json.h>
+#include <afb/afb-plugin.h>
+```
Header *afb/afb-plugin.h* is the only hard dependency, it includes all features
that a plugin MUST HAVE. Outside of includes used to support application logic,
@@ -280,24 +282,26 @@ 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;
+```C
+/*
+ * get the board
+ */
+static void board(struct afb_req req)
+{
+ struct board *board;
+ struct json_object *description;
- /* retrieves the context for the session */
- board = board_of_req(req);
- INFO(afbitf, "method 'board' called for boardid %d", board->id);
+ /* 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);
+ /* describe the board */
+ description = describe(board);
- /* send the board's description */
- afb_req_success(req, description, NULL);
- }
+ /* send the board's description */
+ afb_req_success(req, description, NULL);
+}
+```
This example shows many aspects of a synchronous
method implementation. Let summarise it:
@@ -324,13 +328,15 @@ For any implementation, the request is received by a structure of type
The definition of **struct afb_req** is:
- /*
- * Describes the request by plugins from afb-daemon
- */
- struct afb_req {
- const struct afb_req_itf *itf; /* the interfacing functions */
- void *closure; /* the closure for functions */
- };
+```C
+/*
+ * Describes the request by plugins 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.
@@ -380,13 +386,15 @@ These functions are:
The plugin *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);
- }
+```C
+/*
+ * retrieves the board of the request
+ */
+static inline struct board *board_of_req(struct afb_req req)
+{
+ return afb_req_context(req, (void*)get_new_board, (void*)release_board);
+}
+```
The function **afb_req_context** ensures an existing context
for the session of the request.
@@ -395,22 +403,24 @@ Note function type casts to avoid compilation warnings.
Here is the definition of the function **afb_req_context**
- /*
- * Gets the pointer stored by the plugin 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;
+```C
+/*
+ * Gets the pointer stored by the plugin 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 plugin *tic-tac-toe* (function **get_new_board**).
@@ -424,29 +434,31 @@ When usage count falls to zero, data board are freed.
Definition of other functions dealing with contexts:
- /*
- * Gets the pointer stored by the plugin for the session of 'req'.
- * When the plugin has not yet recorded a pointer, NULL is returned.
- */
- void *afb_req_context_get(struct afb_req req);
-
- /*
- * Stores for the plugin the pointer 'context' to the session of 'req'.
- * The function 'free_context' will be called when the session is closed
- * or if plugin 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 plugin 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);
- }
+```C
+/*
+ * Gets the pointer stored by the plugin for the session of 'req'.
+ * When the plugin has not yet recorded a pointer, NULL is returned.
+ */
+void *afb_req_context_get(struct afb_req req);
+
+/*
+ * Stores for the plugin the pointer 'context' to the session of 'req'.
+ * The function 'free_context' will be called when the session is closed
+ * or if plugin 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 plugin 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
@@ -456,54 +468,58 @@ Two kinds of replies: successful or failure.
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 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, ...);
+```C
+/*
+ * Sends a reply of kind success to the request 'req'.
+ * The status of the reply is automatically set to "success".
+ * Its send the object 'obj' (can be NULL) with an
+ * informationnal comment 'info (can also be NULL).
+ *
+ * For 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, ...);
+```
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 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, ...);
+```C
+/*
+ * Sends a reply of kind failure to the request 'req'.
+ * The status of the reply is set to 'status' and an
+ * informational comment 'info' (can also be NULL) can be added.
+ *
+ * Note that calling afb_req_fail("success", info) is equivalent
+ * to call afb_req_success(NULL, info). Thus even if possible it
+ * is strongly recommended to NEVER use "success" for status.
+ *
+ * For 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 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.
@@ -522,23 +538,25 @@ or WebSockets.
For example, the method **join** of plugin **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;
- ...
+```C
+/*
+ * Join a board
+ */
+static void join(struct afb_req req)
+{
+ struct board *board, *new_board;
+ const char *id;
+
+ /* retrieves the context for the session */
+ board = board_of_req(req);
+ INFO(afbitf, "method 'join' called for boardid %d", board->id);
+
+ /* retrieves the argument */
+ id = afb_req_value(req, "boardid");
+ if (id == NULL)
+ goto bad_request;
+ ...
+```
The function **afb_req_value** searches in the request *req*
for argument name passed in the second argument. When argument name
@@ -551,34 +569,38 @@ is not passed, **afb_req_value** returns NULL.
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;
- }
+```C
+/*
+ * Gets from the request 'req' the string value of the argument of 'name'.
+ * Returns NULL if when there is no argument of 'name'.
+ * Returns the value of the argument of 'name' otherwise.
+ *
+ * Shortcut for: afb_req_get(req, name).value
+ */
+static inline const char *afb_req_value(struct afb_req req, const char *name)
+{
+ return afb_req_get(req, name).value;
+}
+```
It is defined as a shortcut to call the function **afb_req_get**.
That function is defined here after:
- /*
- * 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);
+```C
+/*
+ * Gets from the request 'req' the argument of 'name'.
+ * Returns a PLAIN structure of type 'struct afb_arg'.
+ * When the argument of 'name' is not found, all fields of result are set to NULL.
+ * When the argument of 'name' is found, the fields are filled,
+ * in particular, the field 'result.name' is set to 'name'.
+ *
+ * There is a special name value: the empty string.
+ * The argument of name "" is defined only if the request was made using
+ * an HTTP POST of Content-Type "application/json". In that case, the
+ * argument of name "" receives the value of the body of the HTTP request.
+ */
+struct afb_arg afb_req_get(struct afb_req req, const char *name);
+```
That function takes 2 parameters: the request and the name
of the argument to retrieve. It returns a PLAIN structure of
@@ -592,32 +614,36 @@ 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 */
- };
+```C
+/*
+ * Describes an argument (or parameter) of a request
+ */
+struct afb_arg {
+ const char *name; /* name of the argument or NULL if invalid */
+ const char *value; /* string representation of the value of the argument */
+ /* original filename of the argument if path != NULL */
+ const char *path; /* if not NULL, path of the received file for the argument */
+ /* when the request is finalized this file is removed */
+};
+```
The structure returns the data arguments that are known for the
request. This data include a field named **path**. This **path**
can be accessed using the function **afb_req_path** defined here after:
- /*
- * 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;
- }
+```C
+/*
+ * Gets from the request 'req' the path for file attached to the argument of 'name'.
+ * Returns NULL if when there is no argument of 'name' or when there is no file.
+ * Returns the path of the argument of 'name' otherwise.
+ *
+ * Shortcut for: afb_req_get(req, name).path
+ */
+static inline const char *afb_req_path(struct afb_req req, const char *name)
+{
+ return afb_req_get(req, name).path;
+}
+```
The path is only defined for HTTP/POST requests that send file.
@@ -631,13 +657,15 @@ 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>
+```html
+<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.
@@ -658,11 +686,13 @@ path is destroyed.
Plugins 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);
+```C
+/*
+ * Gets from the request 'req' the json object hashing the arguments.
+ * The returned object must not be released using 'json_object_put'.
+ */
+struct json_object *afb_req_json(struct afb_req req);
+```
It returns a json object. This object depends on how the request was built:
@@ -707,14 +737,16 @@ afb-daemon initialisation is finished.
Here after the code used for **pluginAfbV1Register** from plugin *tic-tac-toe*:
- /*
- * activation function for registering the plugin called by afb-daemon
- */
- const struct AFB_plugin *pluginAfbV1Register(const struct AFB_interface *itf)
- {
- afbitf = itf; // records the interface for accessing afb-daemon
- return &plugin_description; // returns the description of the plugin
- }
+```C
+/*
+ * activation function for registering the plugin called by afb-daemon
+ */
+const struct AFB_plugin *pluginAfbV1Register(const struct AFB_interface *itf)
+{
+ afbitf = itf; // records the interface for accessing afb-daemon
+ return &plugin_description; // returns the description of the plugin
+}
+```
It is a very minimal initialisation function because *tic-tac-toe* plugin doesn't
have any application related initialisation step. It merely record daemon's interface
@@ -724,42 +756,46 @@ The variable **afbitf** is a plugin 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_interface *afbitf;
+```C
+/*
+ * the interface to afb-daemon
+ */
+const struct AFB_interface *afbitf;
+```
The description of the plugin is defined here after.
- /*
- * array of the methods exported to afb-daemon
- */
- static const struct AFB_method_desc_v1 plugin_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 plugin for afb-daemon
- */
- static const struct AFB_plugin plugin_description =
- {
- /* description conforms to VERSION 1 */
- .type= AFB_PLUGIN_VERSION_1,
- .v1= { /* fills the v1 field of the union when AFB_PLUGIN_VERSION_1 */
- .prefix= "tictactoe", /* the API name (or plugin name or prefix) */
- .info= "Sample tac-tac-toe game", /* short description of of the plugin */
- .methods = plugin_methods /* the array describing the methods of the API */
- }
- };
+```C
+/*
+ * array of the methods exported to afb-daemon
+ */
+static const struct AFB_method_desc_v1 plugin_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 plugin for afb-daemon
+ */
+static const struct AFB_plugin plugin_description =
+{
+ /* description conforms to VERSION 1 */
+ .type= AFB_PLUGIN_VERSION_1,
+ .v1= { /* fills the v1 field of the union when AFB_PLUGIN_VERSION_1 */
+ .prefix= "tictactoe", /* the API name (or plugin name or prefix) */
+ .info= "Sample tac-tac-toe game", /* short description of of the plugin */
+ .methods = plugin_methods /* the array describing the methods of the API */
+ }
+};
+```
The structure **plugin_description** describes the plugin.
It declares the type and version of the plugin, its name, a short description
@@ -779,17 +815,19 @@ In version one of afb-damon plugin, a method description contains 4 fields:
The structure describing methods is defined as follows:
- /*
- * Description of one method of the API provided by the plugin
- * This enumeration is valid for plugins of type 1
- */
- struct AFB_method_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 */
- };
+```C
+/*
+ * Description of one method of the API provided by the plugin
+ * This enumeration is valid for plugins of type 1
+ */
+struct AFB_method_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
@@ -854,7 +892,9 @@ they are output with a different level on the logging system.
All of these methods have the same signature:
- void ERROR(const struct AFB_interface *afbitf, const char *message, ...);
+```C
+void ERROR(const struct AFB_interface *afbitf, const char *message, ...);
+```
The first argument **afbitf** is the interface to afb daemon that the
plugin received at initialisation time when **pluginAfbV1Register** is called.
@@ -871,10 +911,10 @@ 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
+0 | ERROR
+1 | ERROR + WARNING + NOTICE
+2 | ERROR + WARNING + NOTICE + INFO
+3 | ERROR + WARNING + NOTICE + INFO + DEBUG
### Output format and destination
@@ -883,14 +923,14 @@ 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
+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.
@@ -908,21 +948,23 @@ coming version.
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;
+```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);
+ /* get the description */
+ description = describe(board);
- ...
+ ...
- afb_daemon_broadcast_event(afbitf->daemon, reason, description);
- }
+ afb_daemon_broadcast_event(afbitf->daemon, reason, description);
+}
+```
The description of the changed board is pushed via the daemon interface.
@@ -933,16 +975,18 @@ 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 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);
+```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 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 with reply functions **object** is automatically released using
> **json_object_put** when using this function. Call **json_object_get** before
@@ -996,22 +1040,24 @@ 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;
- }
+```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.
@@ -1027,30 +1073,32 @@ 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);
+```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.
@@ -1068,32 +1116,38 @@ queried by providing **afb-daemon** in command line arguments.
This configuration file provides data that should be used
for plugins compilation. Examples:
- $ pkg-config --cflags afb-daemon
- $ pkg-config --libs afb-daemon
+```bash
+$ pkg-config --cflags afb-daemon
+$ pkg-config --libs afb-daemon
+```
### Example for cmake meta build system
This example is the extract for building the plugin *afm-main* using *CMAKE*.
- pkg_check_modules(afb afb-daemon)
- if(afb_FOUND)
- message(STATUS "Creation afm-main-plugin for AFB-DAEMON")
- add_library(afm-main-plugin MODULE afm-main-plugin.c)
- target_compile_options(afm-main-plugin PRIVATE ${afb_CFLAGS})
- target_include_directories(afm-main-plugin PRIVATE ${afb_INCLUDE_DIRS})
- target_link_libraries(afm-main-plugin utils ${afb_LIBRARIES})
- set_target_properties(afm-main-plugin PROPERTIES
- PREFIX ""
- LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/afm-main-plugin.export-map"
- )
- install(TARGETS afm-main-plugin LIBRARY DESTINATION ${plugin_dir})
- else()
- message(STATUS "Not creating the plugin for AFB-DAEMON")
- endif()
+```cmake
+pkg_check_modules(afb afb-daemon)
+if(afb_FOUND)
+ message(STATUS "Creation afm-main-plugin for AFB-DAEMON")
+ add_library(afm-main-plugin MODULE afm-main-plugin.c)
+ target_compile_options(afm-main-plugin PRIVATE ${afb_CFLAGS})
+ target_include_directories(afm-main-plugin PRIVATE ${afb_INCLUDE_DIRS})
+ target_link_libraries(afm-main-plugin utils ${afb_LIBRARIES})
+ set_target_properties(afm-main-plugin PROPERTIES
+ PREFIX ""
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/afm-main-plugin.export-map"
+ )
+ install(TARGETS afm-main-plugin LIBRARY DESTINATION ${plugin_dir})
+else()
+ message(STATUS "Not creating the plugin for AFB-DAEMON")
+endif()
+```
Let now describe some of these lines.
- pkg_check_modules(afb afb-daemon)
+```cmake
+pkg_check_modules(afb afb-daemon)
+```
This first lines searches to the *pkg-config* configuration file for
**afb-daemon**. Resulting data are stored in the following variables:
@@ -1110,17 +1164,21 @@ afb_CFLAGS | All required cflags for compiling afb-daemon plugins
If development files are found, the plugin can be added to the set of
target to build.
- add_library(afm-main-plugin MODULE afm-main-plugin.c)
+```cmake
+add_library(afm-main-plugin MODULE afm-main-plugin.c)
+```
This line asks to create a shared library having a single
source file named afm-main-plugin.c to be compiled.
The default name of the created shared object is
**libafm-main-plugin.so**.
- set_target_properties(afm-main-plugin PROPERTIES
- PREFIX ""
- LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/afm-main-plugin.export-map"
- )
+```cmake
+set_target_properties(afm-main-plugin PROPERTIES
+ PREFIX ""
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/afm-main-plugin.export-map"
+)
+```
This lines are doing two things:
@@ -1136,8 +1194,10 @@ a shared library linker exports all the public symbols (C functions that are not
Next line are:
- target_include_directories(afm-main-plugin PRIVATE ${afb_INCLUDE_DIRS})
- target_link_libraries(afm-main-plugin utils ${afb_LIBRARIES})
+```cmake
+target_include_directories(afm-main-plugin PRIVATE ${afb_INCLUDE_DIRS})
+target_link_libraries(afm-main-plugin 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.