1 HOWTO WRITE a PLUGIN for AFB-DAEMON
2 ===================================
12 The binder afb-daemon serves files through
13 the HTTP protocol and offers access to API's through
14 HTTP or WebSocket protocol.
16 The plugins are used to add API's to afb-daemon.
17 This part describes how to write a plugin for afb-daemon.
18 Excepting this summary, this part is intended to be read
21 Before going into details, through a tiny example,
22 a short overview plugins basis is needed.
24 ### Nature of a plugin
26 A plugin is a separate piece of code made of a shared library.
27 The plugin is loaded and activated by afb-daemon when afb-daemon
30 Technically, a plugin is not linked to any library of afb-daemon.
32 ### Live cycle of a plugin within afb-daemon
34 The plugins are loaded and activated when afb-daemon starts.
36 At start, the plugin initialise itself.
37 If it fails to initialise then afb-daemon stops.
39 Conversely, if it success to initialize, it must declare
40 a name, that must be unique, and a list of API's verbs.
42 When initialized, the functions implementing the API's verbs
43 of the plugin are activated on call.
45 At the end, nothing special is done by afb-daemon.
46 Consequently, developpers of plugins should use 'atexit'
47 or 'on_exit' during initialisation if they need to
48 perform specific actions when stopping.
50 ### Content of a plugin
52 For afb-daemon, a plugin contains 2 different
53 things: names and functions.
55 There is two kind of names:
56 - the name of the plugin,
57 - the names of the verbs.
59 There is two kind of functions:
60 - the initialisation function
61 - functions implementing verbs
63 Afb-daemon translates the name of the method that is
64 invoked to a pair of API and verb names. For example,
65 the method named **foo/bar** translated to the API
66 name **foo** and the verb name **bar**.
67 To serve it, afb-daemon search the plugin that record
68 the name **foo** and if it also recorded the verb **bar**,
69 it calls the implementation function declared for this verb.
71 Afb-daemon make no distinction between lower case
72 and upper case when searching for a method.
73 Thus, The names **TicTacToe/Board** and **tictactoe/borad**
76 #### The name of the plugin
78 The name of the plugin is also known as the name
79 of the API that defines the plugin.
81 This name is also known as the prefix.
83 The name of a plugin MUST be unique within afb-daemon.
85 For example, when a client of afb-daemon
86 calls a method named **foo/bar**. Afb-daemon
87 extracts the prefix **foo** and the suffix **bar**.
88 **foo** is the API name and must match a plugin name,
89 the plugin that implements the verb **bar**.
93 Each plugin exposes a set of verbs that can be called
94 by client of afb-daemon.
96 The name of a verb MUST be unique within a plugin.
98 Plugins link verbs to functions that are called
99 when clients emit requests for that verb.
101 For example, when a client of afb-daemon
102 calls a method named **foo/bar**.
104 #### The initialisation function
106 The initialisation function serves several purposes.
108 1. It allows afb-daemon to check the version
109 of the plugin using the name of the initialisation
110 functions that it found. Currently, the initialisation
111 function is named **pluginAfbV1Register**. It identifies
112 the first version of plugins.
114 2. It allows the plugin to initialise itself.
116 3. It serves to the plugin to declare names, descriptions,
117 requirements and implmentations of the verbs that it exposes.
119 #### Functions implementing verbs
121 When a method is called, afb-daemon constructs a request
122 object and pass it to the implementation function for verb
123 within the plugin of the API.
125 An implementation function receives a request object that
126 is used to get arguments of the request, to send
127 answer, to store session data.
129 A plugin MUST send an answer to the request.
131 But it is not mandatory to send the answer
132 before to return from the implementing function.
133 This behaviour is important for implementing
134 asynchronous actions.
136 Implementation functions that always reply to the request
137 before returning are named *synchronous implementations*.
138 Those that don't always reply to the request before
139 returning are named *asynchronous implementations*.
141 Asynchronous implementations typically initiate an
142 asynchronous action and record to send the reply
143 on completion of this action.
145 The Tic-Tac-Toe example
146 -----------------------
148 This part explains how to write an afb-plugin.
149 For the sake of being practical we will use many
150 examples from the tic-tac-toe example.
151 This plugin example is in *plugins/samples/tic-tac-toe.c*.
153 This plugin is named ***tictactoe***.
158 The designer of a plugin must defines names for its plugin
159 (or its API) and for the verbs of its API. He also
160 must defines names for arguments given by name.
162 While forging names, the designer should take into account
163 the rules for making valid names and some rules that make
164 the names easy to use across plaforms.
166 The names and strings used ALL are UTF-8 encoded.
168 ### Names for API (plugin)
170 The names of the API are checked.
171 All characters are authorised except:
173 - the control characters (\u0000 .. \u001f)
174 - the characters of the set { ' ', '"', '#', '%', '&',
175 '\'', '/', '?', '`', '\x7f' }
177 In other words the set of forbidden characters is
178 { \u0000..\u0020, \u0022, \u0023, \u0025..\u0027,
179 \u002f, \u003f, \u0060, \u007f }.
181 Afb-daemon make no distinction between lower case
182 and upper case when searching for an API by its name.
186 The names of the verbs are not checked.
188 However, the validity rules for verb's names are the
189 same as for API's names except that the dot (.) character
192 Afb-daemon make no distinction between lower case
193 and upper case when searching for an API by its name.
195 ### Names for arguments
197 The names for arguments are not restricted and can be
200 The arguments are searched with the case sensitive
201 string comparison. Thus the names "index" and "Index"
204 ### Forging names widely available
206 The key names of javascript object can be almost
207 anything using the arrayed notation:
211 That is not the case with the dot notation:
215 Using the dot notation, the key must be a valid javascript
218 For this reason, the chosen names should better be
219 valid javascript identifier.
221 It is also a good practice, even for arguments, to not
222 rely on the case sensitivity and to avoid the use of
223 names different only by the case.
225 Options to set when compiling plugins
226 -------------------------------------
228 Afb-daemon provides a configuration file for *pkg-config*.
231 pkg-config --cflags afb-daemon
233 will print the flags to use for compiling, like this:
235 $ pkg-config --cflags afb-daemon
236 -I/opt/local/include -I/usr/include/json-c
238 For linking, you should use
240 $ pkg-config --libs afb-daemon
243 As you see, afb-daemon automatically includes dependency to json-c.
244 This is done through the **Requires** keyword of pkg-config.
246 If this behaviour is a problem, let us know.
248 Header files to include
249 -----------------------
251 The plugin *tictactoe* has the following lines for its includes:
256 #include <json-c/json.h>
257 #include <afb/afb-plugin.h>
259 The header *afb/afb-plugin.h* includes all the features that a plugin
260 needs except two foreign header that must be included by the plugin
263 - *json-c/json.h*: this header must be include to handle json objects;
264 - *systemd/sd-event.h*: this must be include to access the main loop;
265 - *systemd/sd-bus.h*: this may be include to use dbus connections.
267 The *tictactoe* plugin does not use systemd features so it is not included.
269 When including *afb/afb-plugin.h*, the macro **_GNU_SOURCE** must be
272 Writing a synchronous verb implementation
273 -----------------------------------------
275 The verb **tictactoe/board** is a synchronous implementation.
281 static void board(struct afb_req req)
284 struct json_object *description;
286 /* retrieves the context for the session */
287 board = board_of_req(req);
288 INFO(afbitf, "method 'board' called for boardid %d", board->id);
290 /* describe the board */
291 description = describe(board);
293 /* send the board's description */
294 afb_req_success(req, description, NULL);
297 This examples show many aspects of writing a synchronous
300 ### The incoming request
302 For any implementation, the request is received by a structure of type
305 ***Important: note that this is a PLAIN structure, not a pointer to a structure.***
307 This structure, here named *req*, is used
309 *req* is used to get arguments of the request, to send
310 answer, to store session data.
312 This object and its interface is defined and documented
313 in the file names *afb/afb-req-itf.h*
315 The above example uses 2 times the request object *req*.
317 The first time, it is used for retrieving the board attached to
318 the session of the request.
320 The second time, it is used to send the reply: an object that
321 describes the current board.
323 ### Associating an object to the session for the plugin
325 When the plugin *tic-tac-toe* receives a request, it musts regain
326 the board that describes the game associated to the session.
328 For a plugin, having data associated to a session is a common case.
329 This data is called the context of the plugin for the session.
330 For the plugin *tic-tac-toe*, the context is the board.
332 The requests *afb_req* offer four functions for
333 storing and retrieving the context associated to the session.
337 - **afb_req_context_get**:
338 retrieves the context data stored for the plugin.
340 - **afb_req_context_set**:
341 store the context data of the plugin.
343 - **afb_req_context**:
344 retrieves the context data of the plugin,
345 if needed, creates the context and store it.
347 - **afb_req_context_clear**:
348 reset the stored data.
350 The plugin *tictactoe* use a convenient function to retrieve
351 its context: the board. This function is *board_of_req*:
354 * retrieves the board of the request
356 static inline struct board *board_of_req(struct afb_req req)
358 return afb_req_context(req, (void*)get_new_board, (void*)release_board);
361 This function is very simple because it merely wraps
362 a call to the function **afb_req_context**, providing
363 all needed arguments.
364 The casts are required to avoid a warning when compiling.
366 Here is the definition of the function **afb_req_context**
369 * Gets the pointer stored by the plugin for the session of 'req'.
370 * If the stored pointer is NULL, indicating that no pointer was
371 * already stored, afb_req_context creates a new context by calling
372 * the function 'create_context' and stores it with the freeing function
375 static inline void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*))
377 void *result = afb_req_context_get(req);
378 if (result == NULL) {
379 result = create_context();
380 afb_req_context_set(req, result, free_context);
385 This powerful function ensures that the context exists and is
386 stored for the session.
388 The function **get_new_board** creates a new board and set its
389 count of use to 1. The boards are counting their count of use
390 to free there ressources when no more used.
392 The function **release_board**
394 ### Sending the reply to a request
396 Getting argument of invocation
397 ------------------------------
399 How to build a plugin
400 ---------------------
402 Afb-daemon provides a The packaging of afb-daemon