ba2e676ac1ea76bb1592bac70c5f879015300269
[src/app-framework-binder.git] / doc / writing-afb-plugins.md
1 HOWTO WRITE a PLUGIN for AFB-DAEMON
2 ===================================
3     version: 1
4     Date:    25 May 2016
5     Author:  José Bollo
6
7 TABLE-OF-CONTENT-HERE
8
9 Summary
10 -------
11
12 The binder afb-daemon serves files through
13 the HTTP protocol and offers access to API's through
14 HTTP or WebSocket protocol.
15
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
19 by developpers.
20
21 Before going into details, through a tiny example,
22 a short overview plugins basis is needed.
23
24 ### Nature of a plugin
25
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
28 starts.
29
30 Technically, a plugin is not linked to any library of afb-daemon.
31  
32 ### Live cycle of a plugin within afb-daemon
33
34 The plugins are loaded and activated when afb-daemon starts.
35
36 At start, the plugin initialise itself.
37 If it fails to initialise then afb-daemon stops.
38
39 Conversely, if it success to initialize, it must declare
40 a name, that must be unique, and a list of API's verbs.
41
42 When initialized, the functions implementing the API's verbs
43 of the plugin are activated on call.
44
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.
49
50 ### Content of a plugin
51
52 For afb-daemon, a plugin contains 2 different
53 things: names and functions.
54
55 There is two kind of names:
56  - the name of the plugin,
57  - the names of the verbs.
58
59 There is two kind of functions:
60  - the initialisation function
61  - functions implementing verbs
62
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.
70
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**
74 are equals.
75
76 #### The name of the plugin
77
78 The name of the plugin is also known as the name
79 of the API that defines the plugin.
80
81 This name is also known as the prefix.
82
83 The name of a plugin MUST be unique within afb-daemon.
84
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**.
90
91 #### Names of verbs
92
93 Each plugin exposes a set of verbs that can be called
94 by client of afb-daemon.
95
96 The name of a verb MUST be unique within a plugin.
97
98 Plugins link verbs to functions that are called
99 when clients emit requests for that verb.
100
101 For example, when a client of afb-daemon
102 calls a method named **foo/bar**.
103
104 #### The initialisation function
105
106 The initialisation function serves several purposes.
107
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.
113
114 2. It allows the plugin to initialise itself.
115
116 3. It serves to the plugin to declare names, descriptions,
117 requirements and implmentations of the verbs that it exposes.
118
119 #### Functions implementing verbs
120
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.
124
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.
128
129 A plugin MUST send an answer to the request.
130
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.
135
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*.
140
141 Asynchronous implementations typically initiate an
142 asynchronous action and record to send the reply
143 on completion of this action.
144
145 The Tic-Tac-Toe example
146 -----------------------
147
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*.
152
153 This plugin is named ***tictactoe***.
154
155 Choosing names
156 --------------
157
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.
161
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.
165
166 The names and strings used ALL are UTF-8 encoded.
167
168 ### Names for API (plugin)
169
170 The names of the API are checked.
171 All characters are authorised except:
172
173 - the control characters (\u0000 .. \u001f)
174 - the characters of the set { ' ', '"', '#', '%', '&',
175   '\'', '/', '?', '`', '\x7f' }
176
177 In other words the set of forbidden characters is
178 { \u0000..\u0020, \u0022, \u0023, \u0025..\u0027,
179   \u002f, \u003f, \u0060, \u007f }.
180
181 Afb-daemon make no distinction between lower case
182 and upper case when searching for an API by its name.
183
184 ### Names for verbs
185
186 The names of the verbs are not checked.
187
188 However, the validity rules for verb's names are the
189 same as for API's names except that the dot (.) character
190 is forbidden.
191
192 Afb-daemon make no distinction between lower case
193 and upper case when searching for an API by its name.
194
195 ### Names for arguments
196
197 The names for arguments are not restricted and can be
198 anything.
199
200 The arguments are searched with the case sensitive
201 string comparison. Thus the names "index" and "Index"
202 are not the same.
203
204 ### Forging names widely available
205
206 The key names of javascript object can be almost
207 anything using the arrayed notation:
208
209         object[key] = value
210
211 That is not the case with the dot notation:
212
213         object.key = value
214
215 Using the dot notation, the key must be a valid javascript
216 identifier.
217
218 For this reason, the chosen names should better be
219 valid javascript identifier.
220
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.
224
225 Options to set when compiling plugins
226 -------------------------------------
227
228 Afb-daemon provides a configuration file for *pkg-config*.
229 Typing the command
230
231         pkg-config --cflags afb-daemon
232
233 will print the flags to use for compiling, like this:
234
235         $ pkg-config --cflags afb-daemon
236         -I/opt/local/include -I/usr/include/json-c 
237
238 For linking, you should use
239
240         $ pkg-config --libs afb-daemon
241         -ljson-c
242
243 As you see, afb-daemon automatically includes dependency to json-c.
244 This is done through the **Requires** keyword of pkg-config.
245
246 If this behaviour is a problem, let us know.
247
248 Header files to include
249 -----------------------
250
251 The plugin *tictactoe* has the following lines for its includes:
252
253         #define _GNU_SOURCE
254         #include <stdio.h>
255         #include <string.h>
256         #include <json-c/json.h>
257         #include <afb/afb-plugin.h>
258
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
261 if it needs it:
262
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.
266
267 The *tictactoe* plugin does not use systemd features so it is not included.
268
269 When including *afb/afb-plugin.h*, the macro **_GNU_SOURCE** must be
270 defined.
271
272 Writing a synchronous verb implementation
273 -----------------------------------------
274
275 The verb **tictactoe/board** is a synchronous implementation.
276 Here is its listing:
277
278         /*
279          * get the board
280          */
281         static void board(struct afb_req req)
282         {
283                 struct board *board;
284                 struct json_object *description;
285
286                 /* retrieves the context for the session */
287                 board = board_of_req(req);
288                 INFO(afbitf, "method 'board' called for boardid %d", board->id);
289
290                 /* describe the board */
291                 description = describe(board);
292
293                 /* send the board's description */
294                 afb_req_success(req, description, NULL);
295         }
296
297 This examples show many aspects of writing a synchronous
298 verb implementation. Let summarize it:
299
300 1. The function **board_of_req** retrieves the context stored
301 for the plugin: the board.
302
303 2. The macro **INFO** sends a message of kind *INFO*
304 to the logging system. The global variable named **afbitf**
305 used represents the interface to afb-daemon.
306
307 3. The function **describe** creates a json_object representing
308 the board.
309
310 4. The function **afb_req_success** sends the reply, attaching to
311 it the object *description*.
312
313 ### The incoming request
314
315 For any implementation,  the request is received by a structure of type
316 **struct afb_req**.
317
318 ***Important: note that this is a PLAIN structure, not a pointer to a structure.***
319
320 This structure, here named *req*, is used
321
322 *req* is used to get arguments of the request, to send
323 answer, to store session data.
324
325 This object and its interface is defined and documented
326 in the file names *afb/afb-req-itf.h*
327
328 The above example uses 2 times the request object *req*.
329
330 The first time, it is used for retrieving the board attached to
331 the session of the request.
332
333 The second time, it is used to send the reply: an object that
334 describes the current board.
335
336 ### Associating an object to the session for the plugin
337
338 When the plugin *tic-tac-toe* receives a request, it musts regain
339 the board that describes the game associated to the session.
340
341 For a plugin, having data associated to a session is a common case.
342 This data is called the context of the plugin for the session.
343 For the plugin *tic-tac-toe*, the context is the board.
344
345 The requests *afb_req* offer four functions for
346 storing and retrieving the context associated to the session.
347
348 These functions are:
349
350 - **afb_req_context_get**:
351   retrieves the context data stored for the plugin.
352
353 - **afb_req_context_set**:
354   store the context data of the plugin.
355
356 - **afb_req_context**:
357   retrieves the context data of the plugin,
358   if needed, creates the context and store it.
359
360 - **afb_req_context_clear**:
361   reset the stored data.
362
363 The plugin *tictactoe* use a convenient function to retrieve
364 its context: the board. This function is *board_of_req*:
365
366         /*
367          * retrieves the board of the request
368          */
369         static inline struct board *board_of_req(struct afb_req req)
370         {
371                 return afb_req_context(req, (void*)get_new_board, (void*)release_board);
372         }
373
374 The function **afb_req_context** ensure an existing context
375 for the session of the request.
376 Its two last arguments are functions. Here, the casts are required
377 to avoid a warning when compiling.
378
379 Here is the definition of the function **afb_req_context**
380
381         /*
382          * Gets the pointer stored by the plugin for the session of 'req'.
383          * If the stored pointer is NULL, indicating that no pointer was
384          * already stored, afb_req_context creates a new context by calling
385          * the function 'create_context' and stores it with the freeing function
386          * 'free_context'.
387          */
388         static inline void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*))
389         {
390                 void *result = afb_req_context_get(req);
391                 if (result == NULL) {
392                         result = create_context();
393                         afb_req_context_set(req, result, free_context);
394                 }
395                 return result;
396         }
397
398 The second argument if the function that creates the context.
399 For the plugin *tic-tac-toe* it is the function **get_new_board**.
400 The function **get_new_board** creates a new board and set its
401 count of use to 1. The boards are counting their count of use
402 to free there ressources when no more used.
403
404 The third argument if the function that frees the context.
405 For the plugin *tic-tac-toe* it is the function **release_board**.
406 The function **release_board** decrease the the count of use of
407 the board given as argument. If the use count decrease to zero,
408 the board data are freed.
409
410 ### Sending the reply to a request
411
412 Sending a reply to a request must be done at most one time.
413
414 Two kinds of replies can be made: successful replies and
415 failure replies.
416
417 The functions to send replies are defined as below:
418
419         /*
420          * Sends a reply of kind success to the request 'req'.
421          * The status of the reply is automatically set to "success".
422          * Its send the object 'obj' (can be NULL) with an
423          * informationnal comment 'info (can also be NULL).
424          */
425         static inline void afb_req_success(struct afb_req req, struct json_object *obj, const char *info)
426         {
427                 req.itf->success(req.closure, obj, info);
428         }
429
430         /*
431          * Same as 'afb_req_success' but the 'info' is a formatting
432          * string followed by arguments.
433          */
434         static inline void afb_req_success_f(struct afb_req req, struct json_object *obj, const char *info, ...)
435         {
436                 char *message;
437                 va_list args;
438                 va_start(args, info);
439                 if (info == NULL || vasprintf(&message, info, args) < 0)
440                         message = NULL;
441                 va_end(args);
442                 afb_req_success(req, obj, message);
443                 free(message);
444         }
445
446         /*
447          * Sends a reply of kind failure to the request 'req'.
448          * The status of the reply is set to 'status' and an
449          * informationnal comment 'info' (can also be NULL) can be added.
450          *
451          * Note that calling afb_req_fail("success", info) is equivalent
452          * to call afb_req_success(NULL, info). Thus even if possible it
453          * is strongly recommanded to NEVER use "success" for status.
454          */
455         static inline void afb_req_fail(struct afb_req req, const char *status, const char *info)
456         {
457                 req.itf->fail(req.closure, status, info);
458         }
459
460         /*
461          * Same as 'afb_req_fail' but the 'info' is a formatting
462          * string followed by arguments.
463          */
464         static inline void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...)
465         {
466                 char *message;
467                 va_list args;
468                 va_start(args, info);
469                 if (info == NULL || vasprintf(&message, info, args) < 0)
470                         message = NULL;
471                 va_end(args);
472                 afb_req_fail(req, status, message);
473                 free(message);
474         }
475
476
477
478 Getting argument of invocation
479 ------------------------------
480
481 Sending messages to the log system
482 ----------------------------------
483
484 How to build a plugin
485 ---------------------
486
487 Afb-daemon provides a *pkg-config* configuration file.
488
489