1 Migration from binding V1 to binding V2
2 =======================================
4 The ***binding*** interface evolved from version 1 to version 2
5 for the following reasons:
7 - integration of the security requirements within the bindings
8 - simplification of the API (after developer feedbacks)
9 - removal of obscure features, cleanup
11 The ***binder*** can run ***bindings*** v1 and/or v2 in any combination.
12 Thus moving from v1 to v2 is not enforced. There is no real need.
14 More, it is possible to write a dual ***binding***: a ***binding*** that
15 implements the version 1 AND the version 2.
17 However, IT IS HIGHLY RECOMMENDED TO SWITCH TO ONLY VERSION 2:
19 - any new development SHOULD start using ***binding*** V2
20 - existing ***bindings*** SHOULD migrate to the version 2
22 This guide covers the migration of bindings from version 1 to version 2.
24 It also explains some of the rationale taken when migrating from version 1 to version 2.
26 In the future, if ***binding*** api evolves to fresh versions (3, 4, ...)
27 it might be necessarily to write bindings implementing more than
28 just one version. For example, a ***binding*** being v2 AND v3 will resolve
29 the issue of running on older AND newer version of AGL. This should always
30 be possible even if more complicated.
32 Important things to known when migrating
33 ----------------------------------------
35 One of the most important change when migrating from v1 to v2 is
36 that many functions use an hidden *common* variable.
37 This affects the functions of the following classes:
39 - functions of class **daemon**:
40 * functions starting with **afb_daemon_...**
41 * functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG**
42 - functions of class **service**:
43 * functions starting with **afb_service_...**
45 * the register function (that is removed)
46 * the service init function
47 * the onevent function
49 For these functions, the first parameter is now implicit.
51 Let takes an example. For ***binding*** v1 you had to write:
54 afb_daemon_broadcast_event(afbitf->daemon, reason, description);
57 For ***binding*** v2, you simply write:
60 afb_daemon_broadcast_event(reason, description);
63 This simplification is possible because the header files included for the bindings
64 now provide a common variable for storing the **daemon** and **service** data.
66 As a programmer, you shouldn't care much about that hidden variable.
67 It simplifies the job, that's all and that is the reason of the change.
69 An other important difference is between the version 1 and the version 2 is
70 on how the ***binding***'s **API** is documented. The version 2 emphasis the
71 **OpenAPI v3** description of the **API**. For this reason, to avoid
72 duplication of descriptions, only one description is expected: the **OpenAPI** one.
74 Task list for the migration
75 ---------------------------
79 1. Enforce use of binding v2 by setting **AFB_BINDING_VERSION**
80 2. Rewrite the main structure and the list of exported verbs
81 3. Adapt the init and callback functions
82 4. Removes the first parameter of functions of classes **daemon**
84 5. Consider where to emit logs for requests
85 6. Take care of store/unstore changes
86 7. Consider use of synchronous (sub)call requests
87 8. Optionally, removes explicit struct
89 The remaining chapters explain these task with more details.
91 Enforce use of binding v2 by setting AFB_BINDING_VERSION
92 --------------------------------------------------------
94 By defining **AFB_BINDING_VERSION** to **2** you switch to version 2.
95 This is done as below.
98 #define AFB_BINDING_VERSION 2
99 #include <afb/afb-binding.h>
102 After that you will get many errors when compiling.
104 Rewrite the main structures and the list of exported verbs
105 ---------------------------------------------------------
107 The structures describing the ***binding** changed from version 1 to version 2.
109 The structure for describing verbs changed to include security
110 requirements. In version 1 it was:
113 struct afb_verb_desc_v1
115 const char *name; /* name of the verb */
116 enum afb_session_flags_v1 session; /* authorization and session requirements of the verb */
117 void (*callback)(struct afb_req req); /* callback function implementing the verb */
118 const char *info; /* textual description of the verb */
122 In version 2 it becomes:
127 const char *verb; /* name of the verb */
128 void (*callback)(struct afb_req req); /* callback function implementing the verb */
129 const struct afb_auth *auth; /* required authorization */
130 uint32_t session; /* authorization and session requirements of the verb */
135 The migration of instances of that structure requires the following actions:
137 - rename field **name** to **verb**
138 - remove field **info**
139 - adapt field **session** if needed
140 - set field **auth** to NULL
145 { .name= "new", .session= AFB_SESSION_NONE, .callback= new, .info= "Starts a new game" }
151 { .verb = "new", .session = AFB_SESSION_NONE, .callback = new, .auth = NULL }
154 The field **auth** can be set to a value describing the requested
157 The main describing structure also changed. In version 1 it was:
160 struct afb_binding_desc_v1
162 const char *info; /* textual information about the binding */
163 const char *prefix; /* required prefix name for the binding */
164 const struct afb_verb_desc_v1 *verbs; /* array of descriptions of verbs terminated by a NULL name */
168 In version 2 it becomes:
171 struct afb_binding_v2
173 const char *api; /* api name for the binding */
174 const char *specification; /* textual specification of the binding */
175 const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */
176 int (*preinit)(); /* callback at load of the binding */
177 int (*init)(); /* callback for starting the service */
178 void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */
179 unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */
183 The migration of instances of that structure requires the following actions:
185 - declare, explore, name the structure as ```const struct afb_binding_v2 afbBindingV2```
186 - rename the field **prefix** to **api**
187 - remove the field **info**
188 - setup the fields **preinit**, **init**, **onevent** according to the next section
189 - set the field **noconcurrency** to the right value:
190 * to 1 if you want to avoid concurrent calls to verbs.
191 * to 0 if you allow concurrent calls to verbs.
196 static const struct afb_binding plugin_desc = {
197 .type = AFB_BINDING_VERSION_1,
199 .info = "Minimal Hello World Sample",
207 const struct afb_binding_v2 afbBindingV2 = {
209 .specification = NULL,
216 The **binder** now relies only on the exported names
217 to deduce the type of the binding. This make the main
218 structure more simple.
220 Adapt the init and callback functions
221 -------------------------------------
223 The ***bindings*** version 1 defined 3 exported functions:
225 - **afbBindingV1Register**
226 - **afbBindingV1ServiceInit**
227 - **afbBindingV1ServiceEvent**
229 These function should not be exported any more and there definition changed.
231 The function **afbBindingV1Register** is no more used to describe the binding.
232 When a binding has to take actions when it is loaded, it must set the field
233 **preinit** of the structure **afbBindingV2**. This field, this preinit, might
234 be used to check features at load. When it returns a negative number, the
235 ***binder*** stops before initializing any ***binding***.
237 The function **afbBindingV1ServiceInit** is replaced by the field **init**
238 of the structure **afbBindingV2**. The init function should return 0 in case
239 of success or a negative error code in case of problem. It is called during
240 initialization of services.
242 The function **afbBindingV1ServiceEvent**is replaced by the field **onevent**
243 of the structure **afbBindingV2**.
245 The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**,
246 were taking as parameter the ***binder*** interface and the service interface respectively.
247 These interfaces are now managed hiddenly for the **binding** by the **binder**.
248 So the variable that ***bindings*** version used to store the ***binder*** interface
249 and the service interface are no more needed and can be removed.
254 const struct afb_binding_interface *interface;
255 struct afb_service service;
257 static const struct afb_binding plugin_desc = {
258 .type = AFB_BINDING_VERSION_1,
260 .info = "Minimal Hello World Sample",
266 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
269 NOTICE(interface, "binding register");
273 int afbBindingV1ServiceInit(struct afb_service svc)
276 NOTICE(interface, "binding init");
280 void afbBindingV1ServiceEvent(const char *event, struct json_object *object)
282 NOTICE(interface, "onevent %s", event);
291 AFB_NOTICE("binding preinit (was register)");
297 AFB_NOTICE("binding init");
301 static void onevent(const char *event, struct json_object *object)
303 AFB_NOTICE("onevent %s", event);
306 const struct afb_binding_v2 afbBindingV2 = {
308 .specification = NULL,
316 The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**,
317 were taking as parameter the ***binder*** interface and the service interface respectively.
318 These interfaces are now managed hiddenly for the **binding** by the **binder**.
319 So the variable that ***bindings*** version used to store the ***binder*** interface
320 and the service interface are no more needed and can be removed.
322 On the above example the following lines were removed:
324 const struct afb_binding_interface *interface;
325 struct afb_service service;
334 Removes the first parameter of functions of classes **daemon** and **service**
335 ------------------------------------------------------------------------------
337 As explained before, many functions loose there first
338 arguments, this are the functions of the following classes:
340 - functions of class **daemon**:
341 * functions starting with **afb_daemon_...**
342 * functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG**
343 - functions of class **service**:
344 * functions starting with **afb_service_...**
345 - callback functions:
346 * the register function (that is removed)
347 * the service init function
348 * the onevent function
350 For these functions, the first parameter is now implicit.
355 afb_daemon_broadcast_event(afbitf->daemon, reason, description);
361 afb_daemon_broadcast_event(reason, description);
364 Also, to avoid possible conflicts, we introduced prefixed logging functions:
365 the macros **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG** have now
366 a prefixed version: **AFB\_ERROR**, **AFB\_WARNING**, **AFB\_NOTICE**,
367 **AFB\_INFO**, **AFB\_DEBUG**. It is now recommended to use the prefixed version.
372 NOTICE(interface, "hello plugin comes to live");
378 NOTICE("hello plugin comes to live");
384 AFB_NOTICE("hello plugin comes to live");
387 To remove definition of the un-prefixed versions of logging macros **ERROR**, **WARNING**,
388 **NOTICE**, **INFO**, **DEBUG** and just define **AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX**
389 before to include **afb/afb-binding.h**.
392 #define AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX
393 #define AFB_BINDING_VERSION 2
394 #include <afb/afb-binding.h>
397 Consider where to emit logs for requests
398 ----------------------------------------
400 The ***bindings*** v2 now allows to emit log messages associated to ***requests***.
401 This feature is valuable when debugging because it allows to return
402 side information associated to a ***request***.
404 The defined macros for logging to requests are: **AFB_REQ_ERROR**,
405 **AFB_REQ_WARNING**, **AFB_REQ_NOTICE**, **AFB_REQ_INFO**, **AFB_REQ_DEBUG**.
407 We encourage the use of these new logging facilities everywhere it makes sense.
412 INFO(afbitf, "method 'new' called for boardid %d", board->id);
418 AFB_REQ_INFO(req, "method 'new' called for boardid %d", board->id);
421 Take care of store/unstore change
422 ---------------------------------
424 For efficiency, the version 2 redefined how storing/un-storing of
425 requests works. Storing request is needed for asynchronous handling
428 For ***bindings*** version, the signature of the functions were:
431 struct afb_req *afb_req_store(struct afb_req req);
432 struct afb_req afb_req_unstore(struct afb_req *req);
435 For version 2 it becomes
438 struct afb_stored_req *afb_req_store(struct afb_req req);
439 struct afb_req afb_req_unstore(struct afb_stored_req *sreq);
442 Where the structure ```struct afb_stored_req``` is opaque.
444 It should require few code change.
446 Also check the following chapter that explain that asynchronous (sub)calls
447 can be replaced by synchronous one, avoiding the need to store/unstore
450 Consider use of synchronous (sub)call requests
451 ----------------------------------------------
453 ***Bindings*** can emit requests for themselves (calls) or for
454 their clients (subcalls). With ***bindings*** version 2 comes
455 also synchronous requests for both cases.
457 So when migrating to bindings version 2, a developer can consider
458 to replace the asynchronous requests (with asynchronous call back)
461 See functions ***afb_service_call_sync*** and ***afb_req_subcall_sync***.
463 Optionally, removes explicit struct
464 -----------------------------------
466 The new definitions now includes **typedefs** for common
467 structures, as shown on below sample:
470 typedef struct afb_daemon afb_daemon;
471 typedef struct afb_event afb_event;
472 typedef struct afb_arg afb_arg;
473 typedef struct afb_req afb_req;
474 typedef struct afb_service afb_service;
477 So you can remove the keyword **struct** if it bores you.
482 static void verb(struct afb_req req)
491 static void verb(afb_req req)
500 The first ***binding*** that migrated from v1 to v2 was
501 the sample **HelloWorld**. Here is shown the differences between
502 the version 1 and the version 2.
505 diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c
506 index c6fa779..505aee3 100644
507 --- a/bindings/samples/HelloWorld.c
508 +++ b/bindings/samples/HelloWorld.c
511 #include <json-c/json.h>
513 +#define AFB_BINDING_VERSION 2
514 #include <afb/afb-binding.h>
516 -const struct afb_binding_interface *interface;
517 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
520 @@ -79,7 +80,7 @@ static int event_add(const char *tag, const char *name)
524 - e->event = afb_daemon_make_event(interface->daemon, name);
525 + e->event = afb_daemon_make_event(name);
526 if (!e->event.closure) { free(e); return -1; }
529 @@ -140,7 +141,7 @@ static void pingBug (struct afb_req request)
530 static void pingEvent(struct afb_req request)
532 json_object *query = afb_req_json(request);
533 - afb_daemon_broadcast_event(interface->daemon, "event", json_object_get(query));
534 + afb_daemon_broadcast_event("event", json_object_get(query));
535 ping(request, json_object_get(query), "event");
538 @@ -288,38 +289,43 @@ static void exitnow (struct afb_req request)
542 +static int preinit()
544 + AFB_NOTICE("hello binding comes to live");
550 + AFB_NOTICE("hello binding starting");
554 // NOTE: this sample does not use session to keep test a basic as possible
555 // in real application most APIs should be protected with AFB_SESSION_CHECK
556 -static const struct afb_verb_desc_v1 verbs[]= {
557 - {"ping" , AFB_SESSION_NONE, pingSample , "Ping Application Framework"},
558 - {"pingfail" , AFB_SESSION_NONE, pingFail , "Fails"},
559 - {"pingnull" , AFB_SESSION_NONE, pingNull , "Return NULL"},
560 - {"pingbug" , AFB_SESSION_NONE, pingBug , "Do a Memory Violation"},
561 - {"pingJson" , AFB_SESSION_NONE, pingJson , "Return a JSON object"},
562 - {"pingevent", AFB_SESSION_NONE, pingEvent , "Send an event"},
563 - {"subcall", AFB_SESSION_NONE, subcall , "Call api/verb(args)"},
564 - {"subcallsync", AFB_SESSION_NONE, subcallsync , "Call api/verb(args)"},
565 - {"eventadd", AFB_SESSION_NONE, eventadd , "adds the event of 'name' for the 'tag'"},
566 - {"eventdel", AFB_SESSION_NONE, eventdel , "deletes the event of 'tag'"},
567 - {"eventsub", AFB_SESSION_NONE, eventsub , "subscribes to the event of 'tag'"},
568 - {"eventunsub",AFB_SESSION_NONE, eventunsub , "unsubscribes to the event of 'tag'"},
569 - {"eventpush", AFB_SESSION_NONE, eventpush , "pushs the event of 'tag' with the 'data'"},
570 - {"exit", AFB_SESSION_NONE, exitnow , "exits from afb-daemon"},
572 +static const struct afb_verb_v2 verbs[]= {
573 + { "ping" , pingSample , NULL, AFB_SESSION_NONE },
574 + { "pingfail" , pingFail , NULL, AFB_SESSION_NONE },
575 + { "pingnull" , pingNull , NULL, AFB_SESSION_NONE },
576 + { "pingbug" , pingBug , NULL, AFB_SESSION_NONE },
577 + { "pingJson" , pingJson , NULL, AFB_SESSION_NONE },
578 + { "pingevent", pingEvent , NULL, AFB_SESSION_NONE },
579 + { "subcall", subcall , NULL, AFB_SESSION_NONE },
580 + { "subcallsync", subcallsync, NULL, AFB_SESSION_NONE },
581 + { "eventadd", eventadd , NULL, AFB_SESSION_NONE },
582 + { "eventdel", eventdel , NULL, AFB_SESSION_NONE },
583 + { "eventsub", eventsub , NULL, AFB_SESSION_NONE },
584 + { "eventunsub", eventunsub , NULL, AFB_SESSION_NONE },
585 + { "eventpush", eventpush , NULL, AFB_SESSION_NONE },
586 + { "exit", exitnow , NULL, AFB_SESSION_NONE },
590 -static const struct afb_binding plugin_desc = {
591 - .type = AFB_BINDING_VERSION_1,
593 - .info = "Minimal Hello World Sample",
597 +const struct afb_binding_v2 afbBindingV2 = {
599 + .specification = NULL,
601 + .preinit = preinit,
605 -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
608 - NOTICE(interface, "hello plugin comes to live");
609 - return &plugin_desc;