3 title: LEGACY Migration from v1 to v2
5 https://git.automotivelinux.org/src/app-framework-binder/plain/docs/legacy/afb-migration-v1-to-v2.md?h=master
8 <!-- WARNING: This file is generated by fetch_docs.js using /home/boron/Documents/AGL/docs-webtemplate/site/_data/tocs/apis_services/master/app-framework-binder-developer-guides-api-services-book.yml -->
10 [LEGACY] Migration from binding V1 to binding V2
11 =======================================
13 > LEGACY!!! IT IS NOT EXPECTED THAT YOU STILL NEED THIS GUIDE.
15 > THIS GUIDE WILL BE REMOVED IN A NEAR FUTURE
18 The ***binding*** interface evolved from version 1 to version 2
19 for the following reasons:
21 - integration of the security requirements within the bindings
22 - simplification of the API (after developer feedbacks)
23 - removal of obscure features, cleanup
25 The ***binder*** can run ***bindings*** v1 and/or v2 in any combination.
26 Thus moving from v1 to v2 is not enforced, there is no real need.
28 More, it is possible to write a dual ***binding***:
30 - a ***binding*** that implements the version 1 and the version 2.
32 However, IT IS HIGHLY RECOMMENDED TO SWITCH TO ONLY VERSION 2:
34 - any new development SHOULD start using ***binding*** V2
35 - existing ***bindings*** SHOULD migrate to the version 2
37 This guide covers the migration of bindings from version 1 to version 2.
39 It also explains some of the rationale taken when migrating from version 1 to version 2.
41 In the future, if ***binding*** api evolves to fresh versions (3, 4, ...)
42 it might be necessarily to write bindings implementing more than
46 - a ***binding*** being v2 AND v3 will resolve the issue of running on older and newer version of AGL.
48 This should always be possible even if more complicated.
50 Important things to known when migrating
51 ----------------------------------------
53 One of the most important change when migrating from v1 to v2 is
54 that many functions use an hidden *common* variable.
55 This affects the functions of the following classes:
57 - functions of class **daemon**:
58 - functions starting with **afb_daemon_...**
59 - functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG**
60 - functions of class **service**:
61 - functions starting with **afb_service_...**
63 - the register function (that is removed)
64 - the service init function
65 - the onevent function
67 For these functions, the first parameter is now implicit.
70 For ***binding*** v1 you had to write:
73 afb_daemon_broadcast_event(afbitf->daemon, reason, description);
76 For ***binding*** v2, you simply write:
79 afb_daemon_broadcast_event(reason, description);
82 This simplification is possible because the header files included for the bindings
83 now provide a common variable for storing the **daemon** and **service** data.
85 As a programmer, you shouldn't care much about that hidden variable.
86 It simplifies the job, that's all and that is the reason of the change.
88 An other important difference is between the version 1 and the version 2 is
89 on how the ***binding***'s **API** is documented.
90 The version 2 emphasis the **OpenAPI v3** description of the **API**.
91 For this reason, to avoid duplication of descriptions, only one description is expected:
93 - The **OpenAPI** one.
95 Task list for the migration
96 ---------------------------
100 1. Enforce use of binding v2 by setting **AFB_BINDING_VERSION**
101 1. Rewrite the main structure and the list of exported verbs
102 1. Adapt the init and callback functions
103 1. Removes the first parameter of functions of classes **daemon** and **service**
104 1. Consider where to emit logs for requests
105 1. Take care of store/unstore changes
106 1. Consider use of synchronous (sub)call requests
107 1. Optionally, removes explicit struct
109 The remaining chapters explain these task with more details.
111 Enforce use of binding v2 by setting AFB_BINDING_VERSION
112 --------------------------------------------------------
114 By defining **AFB_BINDING_VERSION** to **2** you switch to version 2.
115 This is done as below.
118 #define AFB_BINDING_VERSION 2
119 #include <afb/afb-binding.h>
122 After that you will get many errors when compiling.
124 Rewrite the main structures and the list of exported verbs
125 ---------------------------------------------------------
127 The structures describing the ***binding** changed from version 1 to version 2.
129 The structure for describing verbs changed to include security
135 struct afb_verb_desc_v1
137 const char *name; /* name of the verb */
138 enum afb_session_flags_v1 session; /* authorization and session requirements of the verb */
139 void (*callback)(struct afb_req req); /* callback function implementing the verb */
140 const char *info; /* textual description of the verb */
144 In version 2 it becomes:
149 const char *verb; /* name of the verb */
150 void (*callback)(struct afb_req req); /* callback function implementing the verb */
151 const struct afb_auth *auth; /* required authorization */
152 uint32_t session; /* authorization and session requirements of the verb */
157 The migration of instances of that structure requires the following actions:
159 - rename field **name** to **verb**
160 - remove field **info**
161 - adapt field **session** if needed
162 - set field **auth** to NULL
167 { .name= "new", .session= AFB_SESSION_NONE, .callback= new, .info= "Starts a new game" }
173 { .verb = "new", .session = AFB_SESSION_NONE, .callback = new, .auth = NULL }
176 The field **auth** can be set to a value describing the requested
179 The main describing structure also changed.
184 struct afb_binding_desc_v1
186 const char *info; /* textual information about the binding */
187 const char *prefix; /* required prefix name for the binding */
188 const struct afb_verb_desc_v1 *verbs; /* array of descriptions of verbs terminated by a NULL name */
192 In version 2 it becomes:
195 struct afb_binding_v2
197 const char *api; /* api name for the binding */
198 const char *specification; /* textual specification of the binding */
199 const struct afb_verb_v2 *verbs; /* array of descriptions of verbs terminated by a NULL name */
200 int (*preinit)(); /* callback at load of the binding */
201 int (*init)(); /* callback for starting the service */
202 void (*onevent)(const char *event, struct json_object *object); /* callback for handling events */
203 unsigned noconcurrency: 1; /* avoids concurrent requests to verbs */
207 The migration of instances of that structure requires the following actions:
209 - declare, explore, name the structure as ```const struct afb_binding_v2 afbBindingV2```
210 - rename the field **prefix** to **api**
211 - remove the field **info**
212 - setup the fields **preinit**, **init**, **onevent** according to the next section
213 - set the field **noconcurrency** to the right value:
214 - to 1 if you want to avoid concurrent calls to verbs.
215 - to 0 if you allow concurrent calls to verbs.
220 static const struct afb_binding plugin_desc = {
221 .type = AFB_BINDING_VERSION_1,
223 .info = "Minimal Hello World Sample",
232 const struct afb_binding_v2 afbBindingV2 = {
234 .specification = NULL,
241 The **binder** now relies only on the exported names
242 to deduce the type of the binding.
243 This make the main structure more simple.
245 Adapt the init and callback functions
246 -------------------------------------
248 The ***bindings*** version 1 defined 3 exported functions:
250 - **afbBindingV1Register**
251 - **afbBindingV1ServiceInit**
252 - **afbBindingV1ServiceEvent**
254 These function should not be exported any more and there definition changed.
256 The function **afbBindingV1Register** is no more used to describe the binding.
257 When a binding has to take actions when it is loaded, it must set the field
258 **preinit** of the structure **afbBindingV2**.
259 This field, this preinit, might be used to check features at load.
260 When it returns a negative number, the ***binder*** stops before initializing any ***binding***.
262 The function **afbBindingV1ServiceInit** is replaced by the field **init**
263 of the structure **afbBindingV2**.
264 The init function should return 0 in case of success or a negative error code
266 It is called during initialization of services.
268 The function **afbBindingV1ServiceEvent**is replaced by the field **onevent**
269 of the structure **afbBindingV2**.
271 The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**,
272 were taking as parameter the ***binder*** interface and the service interface respectively.
273 These interfaces are now managed hiddenly for the **binding** by the **binder**.
274 So the variable that ***bindings*** version used to store the ***binder*** interface
275 and the service interface are no more needed and can be removed.
280 const struct afb_binding_interface *interface;
281 struct afb_service service;
283 static const struct afb_binding plugin_desc = {
284 .type = AFB_BINDING_VERSION_1,
286 .info = "Minimal Hello World Sample",
292 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
295 NOTICE(interface, "binding register");
299 int afbBindingV1ServiceInit(struct afb_service svc)
302 NOTICE(interface, "binding init");
306 void afbBindingV1ServiceEvent(const char *event, struct json_object *object)
308 NOTICE(interface, "onevent %s", event);
317 AFB_NOTICE("binding preinit (was register)");
323 AFB_NOTICE("binding init");
327 static void onevent(const char *event, struct json_object *object)
329 AFB_NOTICE("onevent %s", event);
332 const struct afb_binding_v2 afbBindingV2 = {
334 .specification = NULL,
342 The two functions **afbBindingV1Register** and **afbBindingV1ServiceInit**,
343 were taking as parameter the ***binder*** interface and the service interface respectively.
344 These interfaces are now managed hiddenly for the **binding** by the **binder**.
345 So the variable that ***bindings*** version used to store the ***binder*** interface
346 and the service interface are no more needed and can be removed.
348 On the above example the following lines were removed:
351 const struct afb_binding_interface *interface;
352 struct afb_service service;
359 Removes the first parameter of functions of classes **daemon** and **service**
360 ------------------------------------------------------------------------------
362 As explained before, many functions loose there first
363 arguments, this are the functions of the following classes:
365 - functions of class **daemon**:
366 - functions starting with **afb_daemon_...**
367 - functions for logging: **ERROR**, **WARNING**, **NOTICE**, **INFO**, **DEBUG**
368 - functions of class **service**:
369 - functions starting with **afb_service_...**
370 - callback functions:
371 - the register function (that is removed)
372 - the service init function
373 - the onevent function
375 For these functions, the first parameter is now implicit.
380 afb_daemon_broadcast_event(afbitf->daemon, reason, description);
386 afb_daemon_broadcast_event(reason, description);
389 Also, to avoid possible conflicts, we introduced prefixed logging functions:
398 have now a prefixed version:
406 It is now recommended to use the prefixed version.
411 NOTICE(interface, "hello plugin comes to live");
417 NOTICE("hello plugin comes to live");
423 AFB_NOTICE("hello plugin comes to live");
426 To remove definition of the un-prefixed versions of logging macros:
436 - **AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX**
438 before to include **afb/afb-binding.h**.
441 #define AFB_BINDING_PRAGMA_NO_VERBOSE_UNPREFIX
442 #define AFB_BINDING_VERSION 2
443 #include <afb/afb-binding.h>
446 Consider where to emit logs for requests
447 ----------------------------------------
449 The ***bindings*** v2 now allows to emit log messages associated to ***requests***.
450 This feature is valuable when debugging because it allows to return
451 side information associated to a ***request***.
453 The defined macros for logging to requests are:
456 - **AFB_REQ_WARNING**
461 We encourage the use of these new logging facilities everywhere it makes sense.
466 INFO(afbitf, "method 'new' called for boardid %d", board->id);
472 AFB_REQ_INFO(req, "method 'new' called for boardid %d", board->id);
475 Take care of store/unstore change
476 ---------------------------------
478 For efficiency, the version 2 redefined how storing/un-storing of
480 Storing request is needed for asynchronous handling of requests.
482 For ***bindings*** version, the signature of the functions were:
485 struct afb_req *afb_req_store(struct afb_req req);
486 struct afb_req afb_req_unstore(struct afb_req *req);
489 For version 2 it becomes
492 struct afb_stored_req *afb_req_store(struct afb_req req);
493 struct afb_req afb_req_unstore(struct afb_stored_req *sreq);
496 Where the structure ```struct afb_stored_req``` is opaque.
498 It should require few code change.
500 Also check the following chapter that explain that asynchronous (sub)calls
501 can be replaced by synchronous one, avoiding the need to store/unstore
504 Consider use of synchronous (sub)call requests
505 ----------------------------------------------
507 ***Bindings*** can emit requests for themselves (calls) or for
508 their clients (subcalls).
509 With ***bindings*** version 2 comes also synchronous requests for both cases.
511 So when migrating to bindings version 2, a developer can consider
512 to replace the asynchronous requests (with asynchronous call back)
515 See functions ***afb_service_call_sync*** and ***afb_req_subcall_sync***.
517 Optionally, removes explicit struct
518 -----------------------------------
520 The new definitions now includes **typedefs** for common
521 structures, as shown on below sample:
524 typedef struct afb_daemon afb_daemon;
525 typedef struct afb_event afb_event;
526 typedef struct afb_arg afb_arg;
527 typedef struct afb_req afb_req;
528 typedef struct afb_service afb_service;
531 So you can remove the keyword **struct** if it bores you.
536 static void verb(struct afb_req req)
545 static void verb(afb_req req)
554 The first ***binding*** that migrated from v1 to v2 was the sample **HelloWorld**.
555 Here is shown the differences between the version 1 and the version 2.
558 diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c
559 index c6fa779..505aee3 100644
560 --- a/bindings/samples/HelloWorld.c
561 +++ b/bindings/samples/HelloWorld.c
564 #include <json-c/json.h>
566 +#define AFB_BINDING_VERSION 2
567 #include <afb/afb-binding.h>
569 -const struct afb_binding_interface *interface;
570 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
573 @@ -79,7 +80,7 @@ static int event_add(const char *tag, const char *name)
577 - e->event = afb_daemon_make_event(interface->daemon, name);
578 + e->event = afb_daemon_make_event(name);
579 if (!e->event.closure) { free(e); return -1; }
582 @@ -140,7 +141,7 @@ static void pingBug (struct afb_req request)
583 static void pingEvent(struct afb_req request)
585 json_object *query = afb_req_json(request);
586 - afb_daemon_broadcast_event(interface->daemon, "event", json_object_get(query));
587 + afb_daemon_broadcast_event("event", json_object_get(query));
588 ping(request, json_object_get(query), "event");
591 @@ -288,38 +289,43 @@ static void exitnow (struct afb_req request)
595 +static int preinit()
597 + AFB_NOTICE("hello binding comes to live");
603 + AFB_NOTICE("hello binding starting");
607 // NOTE: this sample does not use session to keep test a basic as possible
608 // in real application most APIs should be protected with AFB_SESSION_CHECK
609 -static const struct afb_verb_desc_v1 verbs[]= {
610 - {"ping" , AFB_SESSION_NONE, pingSample , "Ping Application Framework"},
611 - {"pingfail" , AFB_SESSION_NONE, pingFail , "Fails"},
612 - {"pingnull" , AFB_SESSION_NONE, pingNull , "Return NULL"},
613 - {"pingbug" , AFB_SESSION_NONE, pingBug , "Do a Memory Violation"},
614 - {"pingJson" , AFB_SESSION_NONE, pingJson , "Return a JSON object"},
615 - {"pingevent", AFB_SESSION_NONE, pingEvent , "Send an event"},
616 - {"subcall", AFB_SESSION_NONE, subcall , "Call api/verb(args)"},
617 - {"subcallsync", AFB_SESSION_NONE, subcallsync , "Call api/verb(args)"},
618 - {"eventadd", AFB_SESSION_NONE, eventadd , "adds the event of 'name' for the 'tag'"},
619 - {"eventdel", AFB_SESSION_NONE, eventdel , "deletes the event of 'tag'"},
620 - {"eventsub", AFB_SESSION_NONE, eventsub , "subscribes to the event of 'tag'"},
621 - {"eventunsub",AFB_SESSION_NONE, eventunsub , "unsubscribes to the event of 'tag'"},
622 - {"eventpush", AFB_SESSION_NONE, eventpush , "pushs the event of 'tag' with the 'data'"},
623 - {"exit", AFB_SESSION_NONE, exitnow , "exits from afb-daemon"},
625 +static const struct afb_verb_v2 verbs[]= {
626 + { "ping" , pingSample , NULL, AFB_SESSION_NONE },
627 + { "pingfail" , pingFail , NULL, AFB_SESSION_NONE },
628 + { "pingnull" , pingNull , NULL, AFB_SESSION_NONE },
629 + { "pingbug" , pingBug , NULL, AFB_SESSION_NONE },
630 + { "pingJson" , pingJson , NULL, AFB_SESSION_NONE },
631 + { "pingevent", pingEvent , NULL, AFB_SESSION_NONE },
632 + { "subcall", subcall , NULL, AFB_SESSION_NONE },
633 + { "subcallsync", subcallsync, NULL, AFB_SESSION_NONE },
634 + { "eventadd", eventadd , NULL, AFB_SESSION_NONE },
635 + { "eventdel", eventdel , NULL, AFB_SESSION_NONE },
636 + { "eventsub", eventsub , NULL, AFB_SESSION_NONE },
637 + { "eventunsub", eventunsub , NULL, AFB_SESSION_NONE },
638 + { "eventpush", eventpush , NULL, AFB_SESSION_NONE },
639 + { "exit", exitnow , NULL, AFB_SESSION_NONE },
643 -static const struct afb_binding plugin_desc = {
644 - .type = AFB_BINDING_VERSION_1,
646 - .info = "Minimal Hello World Sample",
650 +const struct afb_binding_v2 afbBindingV2 = {
652 + .specification = NULL,
654 + .preinit = preinit,
658 -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
661 - NOTICE(interface, "hello plugin comes to live");
662 - return &plugin_desc;