wip sandbox/jobol/wip
authorJose Bollo <jose.bollo@iot.bzh>
Mon, 27 May 2019 14:58:07 +0000 (16:58 +0200)
committerJose Bollo <jose.bollo@iot.bzh>
Wed, 27 Nov 2019 08:07:23 +0000 (09:07 +0100)
Change-Id: I8866607b734f001d39af7748bcf5a1441e28c55b
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
src/devtools/example-api-gps.yml [new file with mode: 0644]
src/devtools/idl-monitor.json
src/devtools/main-genskel.c
src/devtools/spec-afbidl.md [new file with mode: 0644]

diff --git a/src/devtools/example-api-gps.yml b/src/devtools/example-api-gps.yml
new file mode 100644 (file)
index 0000000..1a530bb
--- /dev/null
@@ -0,0 +1,156 @@
+%YAML 1.3
+---
+afbidl: "0.1"
+
+info:
+  apiname: gps
+  title: Service for geolocation
+  description:
+        GPS service reports current WGS84 coordinates from GNSS devices
+        via the gpsd application.
+  version: "0.1"
+  author: AGL
+  maintainer: Scott Rifenbark
+  homepage: https://doc.automotivelinux.org/...
+
+tools:
+
+    afb-genskel:
+        scope: static
+        prefix: req_
+        postfix: _cb
+        init: init_gps
+
+    doc:
+        id: gps-api
+        keywords: gps
+        author:
+        version:
+        src_prefix: api-gps
+        chapters:
+        - name: Abstract
+          url: abstract.md
+        - name: User Guide
+          url: userguide.md
+
+verbs:
+
+    subscribe:
+        description: subscribe to gps/gnss events
+        request: $/schemas/subscription-desc
+        reply:
+            success:
+                schema: $/schemas/none
+                set-state:
+                    listening: yes
+
+    unsubscribe:
+        description: unsubscribe to gps/gnss events
+        request: $/schemas/subscription-desc
+        reply:
+            success:
+                schema: $/schemas/none
+                set-state:
+                    listening: no
+
+    location:
+        description: get current gps/gnss coordinates
+        request: $/schemas/none
+        reply:
+            success: $/schemas/location
+            _: An error can be returned when the service isn't ready
+
+    record:
+        description: |
+            Entering *record* mode you must send **{"state": "on"}** with the **record**
+            verb which will have a JSON response of **{"filename": "gps_YYYYMMDD_hhmm.log"}**
+            pointing to log under *app-data/agl-service-gps*
+
+            Now to enter *replaying* mode you must symlink or copy a GPS dump to
+            *app-data/agl-service-gps/recording.log* and restart the service.
+            From then on out the previously recorded GPS data will loop infinitely
+            which is useful for testing or demonstration purposes.
+        request: $/schemas/record/request
+        reply:
+            success:
+                schema: $/schemas/record/reply
+                set-state:
+                    recording: yes
+            _: An error can be returned when the service isn't ready
+
+events:
+    location:
+        schema: $/schemas/location
+        when-state:
+            listening: yes
+
+state-machines:
+    listening:
+        states: [ no, yes ]
+        initial: no
+    recording:
+        states: [ no, yes ]
+        initial: no
+
+# Follow JsonSchema specification (https://json-schema.org/)
+schemas:
+    subscription-desc:
+        title: Description of the event subscribed or unsubscribed
+        type: object
+        properties:
+            value: { enum: [ location ] }
+        required: [ value ]
+
+    location:
+        title: the location
+        type: object
+        properties:
+            altitude:
+                title: the altitude in meters above the normal geoide
+                type: number
+                minimum: -20000
+                maximum: 20000
+            latitude:
+                title: the latitude in degrees
+                type: number
+                minimum: -90
+                maximum: 90
+            longitude:
+                title: the longitude in degrees
+                type: number
+                minimum: -180
+                maximum: 180
+            speed:
+                title: the speed in meter per seconds m/s
+                type: number
+                minimum: 0
+                maximum: 6000
+            track:
+                title: the heading in degrees
+                type: number
+                minimum: 0
+                maximum: 360
+            timestamp:
+                title: time stamp of the location as a ISO8601 date
+                type: string #ISO8601
+                pattern: \d{4,}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9].*
+
+    record:
+        request:
+            type: object
+            properties:
+                state: { const: "on" }
+            required: [ state ]
+
+        reply:
+            type: object
+            properties:
+                filename:
+                    title: the name of the file that records the data of format gps_YYYYMMDD_hhmm.log
+                    type: string
+                    pattern: gps_\d{4}\d{2}\d{2}_\d{2}\d{2}.log
+            required: [ filename ]
+
+    none:
+        title: no value, just null
+        const: null
index 5afc29d..6fc6c90 100644 (file)
@@ -1,11 +1,12 @@
 {
   "afbidl": "0.1",
   "info": {
+    "apiname": "monitor",
     "description": "monitoring of bindings and internals",
     "title": "monitor",
     "version": "1.0"
   },
-  "generator": {
+  "tools": {
     "genskel": {
       "version": 2,
       "prefix": "f_",
       "private": true
     }
   },
-  "api": {
-    "name": "monitor",
-    "verbs": {
-      "get": {
-        "description": "Get monitoring data.",
-        "permissions": { "session": "check" },
-        "request": { "$ref": "#/schemas/get-request" },
-        "reply": { "$ref": "#/schemas/get-reply" }
-      },
-      "set": {
-        "description": "Set monitoring actions.",
-        "permissions": { "session": "check" },
-        "request": { "$ref": "#/schemas/set-request" },
-        "reply": { "$ref": "#/schemas/any" }
-      },
-      "trace": {
-        "description": "Set monitoring actions.",
-        "permissions": { "session": "check" },
-        "request": { "$ref": "#/schemas/trace-request" },
-        "reply": { "$ref": "#/schemas/any" }
-      },
-      "session": {
-        "description": "describes the session.",
-        "permissions": { "session": "check" },
-        "request": { "$ref": "#/schemas/session-request" },
-        "reply": { "$ref": "#/schemas/any" }
-      }
+  "verbs": {
+    "get": {
+      "description": "Get monitoring data.",
+      "permissions": { "session": "check" },
+      "request": { "$ref": "#/schemas/get-request" },
+      "reply": { "$ref": "#/schemas/get-reply" }
+    },
+    "set": {
+      "description": "Set monitoring actions.",
+      "permissions": { "session": "check" },
+      "request": { "$ref": "#/schemas/set-request" },
+      "reply": { "$ref": "#/schemas/any" }
+    },
+    "trace": {
+      "description": "Set monitoring actions.",
+      "permissions": { "session": "check" },
+      "request": { "$ref": "#/schemas/trace-request" },
+      "reply": { "$ref": "#/schemas/any" }
+    },
+    "session": {
+      "description": "describes the session.",
+      "permissions": { "session": "check" },
+      "request": { "$ref": "#/schemas/session-request" },
+      "reply": { "$ref": "#/schemas/any" }
     }
   },
   "schemas": {
         "json",
         "life",
         "ref",
-         "reply",
+        "reply",
         "result",
         "session",
         "session_close",
index bad7ee9..718452f 100644 (file)
@@ -464,18 +464,18 @@ void openapi_enum_verbs(void (*func)(const char *name, struct json_object *obj))
 
 void afbidl_getvars()
 {
-       getvar(&preinit, "#/generator/genskel/preinit", NULL);
-       getvar(&init, "#/generator/genskel/init", NULL);
-       getvar(&onevent, "#/generator/genskel/onevent", NULL);
-       getvar(&scope, "#/generator/genskel/scope", "static");
-       getvar(&prefix, "#/generator/genskel/prefix", "afb_verb_");
-       getvar(&postfix, "#/generator/genskel/postfix", "_cb");
-       getvar(&provideclass, "#/generator/genskel/provide-class", NULL);
-       getvar(&requireclass, "#/generator/genskel/require-class", NULL);
-       getvar(&requireapi, "#/generator/genskel/require-api", NULL);
-       getvarbool(&priv, "#/generator/genskel/private", 0);
-       getvarbool(&noconc, "#/generator/genskel/noconcurrency", 0);
-       getvar(&api, "#/api/name", NULL);
+       getvar(&preinit, "#/tools/afb-genskel/preinit", NULL);
+       getvar(&init, "#/tools/afb-genskel/init", NULL);
+       getvar(&onevent, "#/tools/afb-genskel/onevent", NULL);
+       getvar(&scope, "#/tools/afb-genskel/scope", "static");
+       getvar(&prefix, "#/tools/afb-genskel/prefix", "afb_verb_");
+       getvar(&postfix, "#/tools/afb-genskel/postfix", "_cb");
+       getvar(&provideclass, "#/tools/afb-genskel/provide-class", NULL);
+       getvar(&requireclass, "#/tools/afb-genskel/require-class", NULL);
+       getvar(&requireapi, "#/tools/afb-genskel/require-api", NULL);
+       getvarbool(&priv, "#/tools/afb-genskel/private", 0);
+       getvarbool(&noconc, "#/tools/afb-genskel/noconcurrency", 0);
+       getvar(&api, "#/info/apiname", NULL);
        getvar(&api, "#/info/title", "?");
        getvar(&info, "#/info/description", NULL);
 }
@@ -487,7 +487,7 @@ void afbidl_enum_verbs(void (*func)(const char *name, struct json_object *obj))
        const char *name;
 
        /* search the verbs */
-       verbs = get$ref(root, "#/api/verbs");
+       verbs = get$ref(root, "#/verbs");
        if (!verbs)
                return;
 
diff --git a/src/devtools/spec-afbidl.md b/src/devtools/spec-afbidl.md
new file mode 100644 (file)
index 0000000..7425665
--- /dev/null
@@ -0,0 +1,365 @@
+API specification for AGL
+=========================
+
+Micro service architectures on web mostly use OpenAPI
+for specifying and documenting their API (Application
+Programming Interface).
+Following that use, AGL's binder provides a tool to
+translate OpenAPI specifications to a code skeleton
+written either in C or C++ languages.
+
+However, the API descritpion language OpenAPI never
+provided some the requirement that AGL expected for
+a such tool:
+
+ - specify API that throws events
+ - describe the permission based security model
+
+Using OpenAPI also had the disavantage of implying
+some twist of the model and then some uglyness
+verbosity.
+
+Unfortunately, search for a replacement of OpenAPI
+that would fullfil below requirements failed.
+
+ - Describe JSON data of APIs
+ - Describe events
+ - Describe permission based security (even as extension)
+ - Suitable for generating:
+    * Documentation
+    * Code skeleton with/without parameter validation
+    * Automated test
+
+Consequently, a new API specification formalism has
+to be proposed.
+
+This document is the proposal for that new formalism.
+For the best, that proposal includes advanced designs
+introduced after discussions with Joël Champeau and
+Philippe Dhaussy, researchers at ENSTA Bretagne (National
+Institute of Advanced Technologies of Brittany) specialized
+in system modeling and formal verification.
+
+
+The goals of specifying APIs
+----------------------------
+
+The micro service architecture of AGL and its flexible
+IPC mechanism emphasis the decomposition of services or
+applications in tiny cooperative parts.
+This has big advantages in terms of flexibility and
+development process but, conversely, implies to
+correctly document interfaces.
+Documenting or specifying API are the same thing, except
+that, traditionnaly, specifying comes forward and
+documenting afterward.
+
+Specifying API can be done using simple text documents.
+Using text documents is great for humans but not for
+computers.
+For this reason, because machines can't exploit human
+structured texts, the use of simple text documents
+should be avoided as much as possible.
+In effect, here is the list of all items that computers
+can do based on API specifications:
+
+ - Automatic generation of documentation
+   in many formats and using customizable styles
+
+ - Automatic generation of code either
+   minimal or elaborate
+
+ - Automatic adaptation to tansport backend or
+   protocol
+
+ - Automatic generation of test cases
+
+ - Integration of advanced tools like supervision,
+   tracing, spying
+
+ - Proof of system properties, in particular
+   when assembling many API together
+
+Many IDL (Interface Description Language) exist
+but it rarely fit all that requirements.
+First of all, they generally are "languages",
+meaning that they are difficult to parse, to
+generate and to manipulate by tools.
+
+OpenAPI is not a language. It is a specification
+made by a data structure of JSON format [1][json-org],
+[2][json-rfc].
+Using JSON has the advantage that no parser has
+to be written because a standard one exists.
+JSON is not human friendly but its data model
+is quasi-isomorph with the one of YAML [3][yaml]
+that is more human friendly.
+
+For this reasons, the below proposal describes
+an API specification format based on YAML.
+
+Nevertheless, for specifying the values expected
+by APIs the format will use the JSON Schema formalism
+[4][json-schema]. This allows to describe complex
+values and their constraints using a format easy to
+integrate in tools.
+
+[json-org]:    http://json.org/                    "JSON format"
+[json-rfc]:    https://tools.ietf.org/html/rfc8259 "JSON format RFC"
+[yaml]:        https://yaml.org/                   "YAML format"
+[json-schema]: https://json-schema.org/            "JSON Schema"
+
+Content of API specifications
+-----------------------------
+
+### Top level structure
+
+An API specification has the following structure:
+
+```yaml
+%YAML 1.3
+---
+afbidl: "0.1"
+info: # description the content of the specification
+tools: # items for tools (doc, afb-genskel, ..)
+verbs: # description of verbs of the API
+events: # description of the events emitted by the API
+state-machines: # description of the state machines of the API
+examples: # examples of usage with or without timings
+schemas: # place holder for description of the types of items
+```
+
+The specification is designed to describe only one API.
+If needed (example: simulation of a complex system), the aggregation
+of multiple API descriptions can be done but externally with some
+other description.
+
+The heading line *%YAML 1.3* is recommended but not mandatory.
+
+The main item of the description is an object. Its fields are:
+
+ - afbidl: this field indicates that the description follows that
+   specification and the value precise what version of the specification
+   is used. Current version is 0.1
+
+ - info: this field contains an object that give informations about the
+   API. Its mandatory fields are:
+
+      - apiname: name of the API
+      - title: short explanation of the API
+      - description: long description of the API
+      - version: version of the API
+
+   Other fields are accepted, example: author, maintainer, homepage,
+   site, copyright, license, ...
+
+ - tools: this fields contains an object that can set properties for
+   processing tools. The fields are the names of tool to setup.
+
+ - verbs: this field contains an object whose fields are the names
+   of the verbs of the API. For each verb the value attached to the
+   field of the verb is the description of the verb.
+
+ - events: this field contains an object whose fields are the names
+   of the events thrown by the API. For each event the value attached
+   to the field describes the event.
+
+ - state-machines: this field contains an object whose fields are the
+   names of the state-machines of the API. For each state-machine the
+   value attached to the field describes the state machine.
+
+ - examples: TO BE SPECIFIED - object of named sequences/scenarii -
+
+ - schemas: this optionnal field is intended to group the schema of
+   the common types used by API.
+
+
+### Describing verbs
+
+The verbs are described using an object containing the fields
+
+```yaml
+title: # short explanation of the verb
+description: # detailed description of the verb
+permissions: # required permissions
+request: # schema of the request parameters
+reply: # describe the reply
+```
+
+### Describing events
+
+The events are described using an object containing the fields
+
+```yaml
+schema: # description of the data associated with the event
+when-state: # condition of emiting the event
+set-state: # when the event is associated to a state change
+```
+
+### Describing state machine
+
+
+
+
+Example of the API gps
+----------------------
+
+```yaml
+%YAML 1.3
+---
+afbidl: "0.1"
+
+info:
+  apiname: gps
+  title: Service for geolocation
+  description:
+        GPS service reports current WGS84 coordinates from GNSS devices
+        via the gpsd application.
+  version: "0.1"
+  author: AGL
+  maintainer: John Difool
+  homepage: https://doc.automotivelinux.org/...
+
+tools:
+
+    afb-genskel:
+        scope: static
+        prefix: req_
+        postfix: _cb
+        init: init_gps
+
+    doc:
+        id: gps-api
+        keywords: gps
+        author:
+        version:
+        src_prefix: api-gps
+        chapters:
+        - name: Abstract
+          url: abstract.md
+        - name: User Guide
+          url: userguide.md
+
+verbs:
+
+    subscribe:
+        description: subscribe to gps/gnss events
+        request: $/schemas/subscription-desc
+        reply:
+            success:
+                schema: $/schemas/none
+                set-state:
+                    listening: yes
+
+    unsubscribe:
+        description: unsubscribe to gps/gnss events
+        request: $/schemas/subscription-desc
+        reply:
+            success:
+                schema: $/schemas/none
+                set-state:
+                    listening: no
+
+    location:
+        description: get current gps/gnss coordinates
+        request: $/schemas/none
+        reply:
+            success: $/schemas/location
+            _: An error can be returned when the service isn't ready
+
+    record:
+        description: |
+            Entering *record* mode you must send **{"state": "on"}** with the **record**
+            verb which will have a JSON response of **{"filename": "gps_YYYYMMDD_hhmm.log"}**
+            pointing to log under *app-data/agl-service-gps*
+
+            Now to enter *replaying* mode you must symlink or copy a GPS dump to
+            *app-data/agl-service-gps/recording.log* and restart the service.
+            From then on out the previously recorded GPS data will loop infinitely
+            which is useful for testing or demonstration purposes.
+        request: $/schemas/record/request
+        reply:
+            success:
+                schema: $/schemas/record/reply
+                set-state:
+                    recording: yes
+            _: An error can be returned when the service isn't ready
+
+events:
+    location:
+        schema: $/schemas/location
+        when-state:
+            listening: yes
+
+state-machines:
+    listening:
+        states: [ no, yes ]
+        initial: no
+    recording:
+        states: [ no, yes ]
+        initial: no
+
+# Follow JsonSchema specification (https://json-schema.org/)
+schemas:
+    subscription-desc:
+        title: Description of the event subscribed or unsubscribed
+        type: object
+        properties:
+            value: { enum: [ location ] }
+        required: [ value ]
+
+    location:
+        title: the location
+        type: object
+        properties:
+            altitude:
+                title: the altitude in meters above the normal geoide
+                type: number
+                minimum: -20000
+                maximum: 20000
+            latitude:
+                title: the latitude in degrees
+                type: number
+                minimum: -90
+                maximum: 90
+            longitude:
+                title: the longitude in degrees
+                type: number
+                minimum: -180
+                maximum: 180
+            speed:
+                title: the speed in meter per seconds m/s
+                type: number
+                minimum: 0
+                maximum: 6000
+            track:
+                title: the heading in degrees
+                type: number
+                minimum: 0
+                maximum: 360
+            timestamp:
+                title: time stamp of the location as a ISO8601 date
+                type: string #ISO8601
+                pattern: \d{4,}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9].*
+
+    record:
+        request:
+            type: object
+            properties:
+                state: { const: "on" }
+            required: [ state ]
+
+        reply:
+            type: object
+            properties:
+                filename:
+                    title: the name of the file that records the data of format gps_YYYYMMDD_hhmm.log
+                    type: string
+                    pattern: gps_\d{4}\d{2}\d{2}_\d{2}\d{2}.log
+            required: [ filename ]
+
+    none:
+        title: no value, just null
+        const: null
+```
+