aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Bollo <jose.bollo@iot.bzh>2019-05-27 16:58:07 +0200
committerJose Bollo <jose.bollo@iot.bzh>2019-11-27 09:07:23 +0100
commitcf81979fcb253a7674cc2433a51e09a1dc594844 (patch)
tree4e54ffe41b2821de475278a65a1dcdadf5cc8b41
parent40b7650e4c95481889c1e37dea57be7de018e37d (diff)
Change-Id: I8866607b734f001d39af7748bcf5a1441e28c55b Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/devtools/example-api-gps.yml156
-rw-r--r--src/devtools/idl-monitor.json56
-rw-r--r--src/devtools/main-genskel.c26
-rw-r--r--src/devtools/spec-afbidl.md365
4 files changed, 561 insertions, 42 deletions
diff --git a/src/devtools/example-api-gps.yml b/src/devtools/example-api-gps.yml
new file mode 100644
index 00000000..1a530bb9
--- /dev/null
+++ b/src/devtools/example-api-gps.yml
@@ -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
diff --git a/src/devtools/idl-monitor.json b/src/devtools/idl-monitor.json
index 5afc29d0..6fc6c900 100644
--- a/src/devtools/idl-monitor.json
+++ b/src/devtools/idl-monitor.json
@@ -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_",
@@ -17,33 +18,30 @@
"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": {
@@ -162,7 +160,7 @@
"json",
"life",
"ref",
- "reply",
+ "reply",
"result",
"session",
"session_close",
diff --git a/src/devtools/main-genskel.c b/src/devtools/main-genskel.c
index bad7ee97..718452f1 100644
--- a/src/devtools/main-genskel.c
+++ b/src/devtools/main-genskel.c
@@ -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
index 00000000..74256659
--- /dev/null
+++ b/src/devtools/spec-afbidl.md
@@ -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
+```
+