From dc040f08d9ffa6fa111c774e55c4b6d81ab35926 Mon Sep 17 00:00:00 2001
From: Zoltan Kis
- The UA may be implemented in the browser, or in a separate runtime environment. + This specification can be used for implementing the WoT Scripting API in multiple language bindings. Currently ECMAScript and TypeScript definitions are described in this document. For specifying bindings in other languages, extensions of this document may be created later.
- This specification can be used for implementing the WoT Scripting API in multiple language bindings. Currently ECMAScript and TypeScript definitions are described in this document. For specifying bindings in other languages, extensions of this document may be created later. + The UA may be implemented in the browser, or in a separate runtime environment, such as [Node.js](https://nodejs.org/en/) or small embedded runtimes such as the [JavaScript Runtime for Zephyr OS](https://www.zephyrproject.org/community/blog/introducing-javascript-runtime-zephyr-os).
Implementations that use ECMAScript executed in a browser to implement the APIs defined in this document MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]].
- Implementations that use TypeScript or ECMAScript in a RunTime to implement the APIs defined in this document MUST implement them in a manner consistent with the TypeScript Bindings defined in the TypeScript specification [[!TYPESCRIPT]]. + Implementations that use TypeScript or ECMAScript in a runtime to implement the APIs defined in this document MUST implement them in a manner consistent with the TypeScript Bindings defined in the TypeScript specification [[!TYPESCRIPT]].
This document serves a general description of the WoT Scripting API. Language and runtime specific issues are discussed in separate extensions of this document.
@@ -124,9 +124,6 @@
- A WoT runtime or simply Runtime is defined as a software stack that manages the lifecycle of WoT application scripts (see also the [Wikipedia definition](https://en.wikipedia.org/wiki/Runtime_system)). In the case of ECMAScript and TypeScript scripts, it consists of an ECMAScript interpreter, script lifecycle management, and an operating system API that provides access to local and remote resources. A Runtime can be modeled as a virtual machine in the sense that it should be completely isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc. A runtime may be for instance a Node.js environment, an embedded runtime based on a small JavaScript engine, or provided by a browser.
-
The following terms are defined in [[!WOT-PRACTICES]]:
Consuming a Thing Description means parsing the Thing Description and building a resource model with the use of Protocol Bindings that can be used in a script for accessing and controlling the Thing. A Thing when starts up, consumes its own TD, then it exposes its WoT interface as a server. Note that a script on a Thing may consume other TDs and expose a combined interface of the consumed Things.
+ A WoT Runtime or WR is defined as a software stack that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses an operating system API that provides access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc. For instance, a WR may be implemented in a Node.js environment, or in an embedded runtime based on a small JavaScript engine, or in a browser.
+
+ In this version of the specification, a WR MAY run either an idle event loop, or a script that has been deployed to it by a method that is out of scope of this document. However, new Things can be added and Things running in the WR can be updated by using the methods of this API from a script run in another WR.
+
+ A Thing is represented either as a ConsumedThing (for Things obtained by discovery or retrieve operations) or ExposedThing (for Things created with this API inside the WR). All ExposedThings contained in a WR are serving external requests through the same event loop, and are said to be local Things to each other. All other Things that run in a different WR, even if on the same physical hardware, are said to be remote Things to each other. Note that there may also be local ConsumedThing objects as well.
+
The terms URL and
@@ -255,7 +260,7 @@
- The trust model, attacker model, threat model and possible mitigation
- proposals for the Wot Scripting API are presented in the [Security and Privacy document](http://w3c.github.io/wot-scripting-api/security-privacy.html). This section presents the chosen
- security and privacy model through normative requirements to implementations.
-
- Things discoverable and accessible in a WoT network SHOULD be identified and authenticated.
-
- The integrity of WoT communication SHOULD be ensured by implementations.
-
- The main threats are summarized in the [Security and Privacy document](http://w3c.github.io/web-nfc/security-privacy.html#threats-and-possible-solutions).
-
- In this specification the following threats are considered of the highest priority:
- Terminology and conventions
- @context
property with a defining URI [[!JSON-LD]].
Security and Privacy
- Chain of Trust
- Threat Model
-
-
-
- This section summarizes the security policies which are specified as - normative requirements in the respective algorithms of this - specification. -
-@@ -370,34 +319,52 @@
- The API object provides access obtain Things by discovery or creation. A Thing is represented either as a ConsumedThing or ExposedThing. + The API object represents an implementation of the WoT Runtime and provides functionality to obtain Things by discovery or creation.
The WoT object exposes only functions and has no internal state.
-- Because of this, implementations MAY use a global object, or provide a constructor, or provide the API object, or by other means (e.g. by `require()`). Since the common denominator across various Runtime types would be to use a constructor, this would be recommended. As a consequence, the ConsumedThing and ExposedThing objects could also be constructed, complete with an asynchronous fetch functionality. -
- The WebIDL interfaces presented in this initial version of the document are based on the [[!WOT-PRACTICES]]. It is expected to be updated soon. + Browser implementations SHOULD use a namespace object such as `wot`, and [Node.js](https://nodejs.org/en/)-like runtimes MAY provide the API object through the [`require()`](https://nodejs.org/api/modules.html) mechanism.
+ // [SecureContext] + // [NamespaceObject] interface WoT { - Promise<void> discover(ThingFilter filter, ThingDiscoveryCallback onfound); - - Promise<ConsumedThing> retrieve((USVString or Dictionary) thingReference); - + Observable<ConsumedThing> discover(optional ThingFilter filter); + Promise<ConsumedThing> retrieve(USVString url); Promise<ExposedThing> createThing(ThingInit init); }; dictionary ThingInit { DOMString name; USVString url; - object description; + Dictionary description; + }; + + dictionary ThingFilter: ThingInit { + boolean local; }; - callback ThingDiscoveryCallback = void (ConsumedThing thing);+ +
+ The discover()
method returns an [Observable](https://github.com/tc39/proposal-observable) object that can be subscribed and unsubscribed to.
+
+ let subscription = wot.discover().subscribe( + thing => { console.log("Found Thing " + thing.url); }, + error => { console.log("Discovery finished because an error: " + error.message); }, + () => { console.log("Discovery finished successfully");} + ); + + setTimeout( + () => { subscription.unsubscribe(); console.log("Discovery timeout"); }, + 5000); ++
+ Note that canceling a discovery (through unsubscribe) may not be successful in all cases, for instance when discovery is based on open ended broadcast requests. However, once `unsubscribe()` has been called, implementations MUST suppress further event handling ( i.e. further discoveries and errors) on the Observable. Also, a discovery error may not mean the end of the discovery process. However, in order to respect Observable semantics (error always terminates processing), implementations MUST close or suppress further event handling on the Observable. +
+ The trust model, attacker model, threat model and possible mitigation + proposals for the Wot Scripting API are presented in the WoT Security and Privacy document. + This section presents the chosen security and privacy model through normative requirements to implementations. +
+ ++ Things discoverable and accessible in a WoT network SHOULD be identified and authenticated. +
++ The integrity of WoT communication SHOULD be ensured by implementations. +
++ The main threats are summarized in the WoT Security and Privacy document. +
++ In this specification the following threats are considered of the highest priority: +
+ This section summarizes the security policies which are specified as + normative requirements in the respective algorithms of this + specification. +
+The following is a list of major changes to the document. For a complete list of changes, see the [github change log](https://github.com/w3c/wot-scripting-api/commits/master). You can also view the [recently closed bugs](https://github.com/w3c/wot-scripting-api/issues?page=1&state=closed). @@ -494,16 +517,15 @@
The following problems are being discussed and need most attention:
- The editors would like to thank Dave Raggett, Matthias Kovatsch, and Michael Koster for their - comments and guidance to this document. + The editors would like to thank Dave Raggett, Matthias Kovatsch, and Michael Koster for their comments and guidance to this document.
- A WoT Runtime or WR is defined as a software stack that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses an operating system API that provides access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc. For instance, a WR may be implemented in a Node.js environment, or in an embedded runtime based on a small JavaScript engine, or in a browser. + A WoT Runtime or WR is defined as a software stack that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses an operating system API that provides access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc.
In this version of the specification, a WR MAY run either an idle event loop, or a script that has been deployed to it by a method that is out of scope of this document. However, new Things can be added and Things running in the WR can be updated by using the methods of this API from a script run in another WR. @@ -333,7 +333,7 @@ interface WoT { Observable<ConsumedThing> discover(optional ThingFilter filter); Promise<ConsumedThing> retrieve(USVString url); - Promise<ExposedThing> createThing(ThingInit init); + Promise<ExposedThing> create(ThingInit init, optional USVString target); }; dictionary ThingInit { @@ -342,10 +342,11 @@ Dictionary description; }; + enum DiscoveryType { "any", "local", "directory", "broadcast" }; + dictionary ThingFilter: ThingInit { - boolean local; + DiscoveryType type = "any"; }; -
@@ -381,20 +382,36 @@ ConsumedThing addListener(DOMString eventName, ThingEventListener listener); ConsumedThing removeListener(DOMString eventName, ThingEventListener listener); ConsumedThing removeAllListeners(DOMString eventName); + + Promise<ExposedThing> acquire(); }; callback ThingEventListener = void (ConsumedThing thing); + + enum ConsumedThingEvents { + "propertychanged", + "propertyremoved", + "propertyadded", + "actionchanged" + };
interface ExposedThing { + + // define TD modifiers ExposedThing addProperty(ThingProperty property); + ExposedThing removeProperty(ThingProperty property); + ExposedThing addAction(ThingAction action); + ExposedThing removeAction(ThingAction action); + ExposedThing addEvent(ThingEvent event); + ExposedThing removeEvent(ThingEvent event); - Promise<void> register(); + Promise<void> register(optional USVString directory); Promise<void> unregister(); Promise<void> start(); @@ -402,24 +419,25 @@ Promise<void> emitEvent(DOMString eventName, any payload); - // define request handlers - ExposedThing onPropertyRetrieve(PropertyRetrieveHandler handler); - ExposedThing onPropertyUpdate(PropertyHandler handler); + // define request handlers (one per request type, so no events here) + ExposedThing onRetrieveProperty(PropertyHandler handler); + ExposedThing onAddProperty(PropertyHandler handler); + ExposedThing onRemoveProperty(PropertyHandler handler); - ExposedThing onActionInvocation(ActionHandler handler); + ExposedThing onInvokeAction(ActionHandler handler); - ExposedThing onObserve(DOMString event, ObserveHandler handler); - ExposedThing onUnobserve(DOMString event, UnobserveHandler handler); + ExposedThing onAddEventHandler(DOMString event, ObserveHandler handler); + ExposedThing onRemoveEventHandler(DOMString event, ObserveHandler handler); - any onSemanticTranslate(Property property, SemanticType type); + ExposedThing onAddSemanticTranslator(SemanticTranslator handler); }; ExposedThing implements ConsumedThing; - callback PropertyRetrieveHandler = void (ThingProperty property, USVString url); - callback PropertyUpdateHandler = void (ThingProperty property, USVString url); - callback ActionHandler = void (ThingAction action, USVString url); - callback ObserveHandler = void (DOMString eventName, USVString url); + callback PropertyHandler = void (ThingProperty property, USVString from); + callback ActionHandler = void (ThingAction action, USVString from); + callback EventHandler = void (DOMString eventName, USVString from); + callback SemanticTranslator = any (Property property, SemanticType type); dictionary SemanticType { DOMString name; From 157df10a515da52b7ca82d1ce2b5f1cd144c9283 Mon Sep 17 00:00:00 2001 From: Zoltan KisDate: Tue, 11 Apr 2017 17:39:17 +0300 Subject: [PATCH 03/12] Update rationale with factories vs constructors, discovery, WoT Runtime vs Applications vs Scripts Signed-off-by: Zoltan Kis --- rationale.md | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/rationale.md b/rationale.md index 69411e98..c1fb9632 100644 --- a/rationale.md +++ b/rationale.md @@ -2,6 +2,46 @@ This document attempts to explain why various decision for [W3C WoT(Web of Things) Scripting API](https://w3c.github.io/wot-scripting-api/index.html) were made the way they were. -## 1\. Why Constructor is used instead of Factory? +## Using factories vs constructors +As discussed in [issue 3](https://github.com/w3c/wot-scripting-api/issues/3), and as suggested [here](https://github.com/w3c/wot-scripting-api/issues/3#issuecomment-283746764), the guidelines are these: + +> The root WoT object should not be constructible. It represents the UA's magic ability to discover things, similar to how the Navigator object represents the UA's magic ability to do a bunch of stuff. A namespace might be a good replacement here, if it truly has no state. + +> Avoid constructor overloads. A true constructor should be something that directly copies the given essential data into internal fields. If there is a way to infer the essential data from some other data, then that should be a factory. So maybe ThingDescription is the essential data, and if we can infer that from a name or URL, then factory should be used (perhaps static factory, e.g. ExposedThing.fromName()). + +> The idea of using a builder pattern (first create an X, then call X.expose() on it to turn into another object, or X-with-UA-magic) is rather unidiomatic in JavaScript. The better way to represent something without UA magic is just a dictionary. Having the same class represent two very distinct things is not great. + + +Resolutions: +- The WoT API uses a namespace object `wot` in the browser, or provided by `require()` in standalone runtimes. +- The `ConsumedThing` and `ExposedThing` objects are created by factory methods. + +## Discovery API + +Based on [WoT Current Practices](https://w3c.github.io/wot/current-practices/wot-practices.html#td-discovery), there are different discovery types: local (to the hardware), proximity based (such as BLE or NFC), registry (directory) based, and broadcast/multicast based. The discovery type is specific to the underlying protocol bindings. + +The discovery results may be filtered either at the source or at reception, by constraints made on the Thing Description. + +Based on [issue 16](https://github.com/w3c/wot-scripting-api/issues/16) there is a need to be able to tell the WoT Runtime to stop discovery (or in the case of open ended requests, suppress further discovery results). Therefore returning `Promise` was not an option any more, since cancellable `Promise`s were [dropped](https://github.com/tc39/proposal-cancelable-promises). + +Resolutions: +- Use [Observables](https://github.com/tc39/proposal-observable) for controlling the discovery process (subscribe, unsubscribe). +- Use a single filter definition that also contains a property for discovery type, defaulting to `"any"`. It is simpler and more intuitive to use than having a separate parameter for discovery type. Some of the discovery types, such as registry/directory based discovery also require another parameter for the address of the directory. This can be provided as a required property in the discovery filter, described in the discovery algorithm. + +## WoT Runtime, Applications, Scripts, Things + +Based on the discussion in [issue 2](https://github.com/w3c/wot-scripting-api/issues/2), there is a use case for deploying WoT functionality to WoT Runtimes. This functionality is called an Application, and has an associated security identity and access rights. + +An Application may be defined as a script, or a set of scripts, eventually with added configuration data and manifest data. + +Alternatively, an Application may also be represented by a set of Things that are created and deployed in a WoT Runtime. The functionality is characterized by the Thing Descriptions of the participating Things. With this assumption, there is no new concepts needed for fulfilling the deployment use case. The WoT Scripting API just needs to provide methods for creating a Thing on a remote WoT Runtime, and modify existing Things on a remote Runtime. + +The draft algorithm for creating a remote Thing is the following: +1. A script running in the initiating (controlling) WoT Runtime (WR) invokes the `wot.create()` API with the destination specified as the target (controlled) WoT Runtime. The method specifies the Thing Description and optionally also security related metadata (e.g. policy on further modification accesses). The implementation (bindings) of the participating WRs has been provisioned with identity, authentication mechanism, and access management functionality. +2. The target WR authenticates the initiating WR and checks for access rights, using either a local or a network based policy. If there are not sufficient rights for the request, reject the request with a security error. +3. If access rights are granted, the target WR creates the required Thing (involving full lifecycle integration, such as event loop, secure storage etc) and records the security metadata of the transaction (e.g. creator identity, group/security level, access policy etc). If creating fails, the transaction is rolled back and the request is rejected with an error. +4. If creating succeeds, the initiating WR generates an `ExposedThing` object for controlling the newly created Thing. Further modification requests are separately authenticated or a session may be maintained, depending on the capabilities of the underlying protocols. + + + -It would be simpler to expose the WoT object with a constructor. Also, for ExposedThing and ConsumedThing we could provide constructors instead of factories. That would be more aligned with ECMAScript best practices (e.g. an ExposedThing object could be created for testing purposes, shaped locally, then exposed). From 85703e7f991c672fbf1d91fb791391f33b7334b8 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Tue, 11 Apr 2017 17:40:35 +0300 Subject: [PATCH 04/12] Remove rationale.html Signed-off-by: Zoltan Kis --- rationale.html | 519 ------------------------------------------------- 1 file changed, 519 deletions(-) delete mode 100644 rationale.html diff --git a/rationale.html b/rationale.html deleted file mode 100644 index 463bca04..00000000 --- a/rationale.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - - rationale - - -Rationale for Scripting API design
-This document attempts to explain why various decision for W3C WoT(Web of Things) Scripting API were made the way they were.
-1. Why Constructor is used instead of Factory?
-It would be simpler to expose the WoT object with a constructor. Also, for ExposedThing and ConsumedThing we could provide constructors instead of factories. That would be more aligned with ECMAScript best practices (e.g. an ExposedThing object could be created for testing purposes, shaped locally, then exposed).
- From c529a74c504ece81cc8a377bada14661ed3322f0 Mon Sep 17 00:00:00 2001 From: Zoltan KisDate: Tue, 11 Apr 2017 17:44:45 +0300 Subject: [PATCH 05/12] Update README Signed-off-by: Zoltan Kis --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 13deed1b..164a9d25 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Specification 'Web of Things (WoT) Scripting API' -Each commit here will sync it to the master, which will expose the content to http://w3c.github.io/wot-scripting-api/. +The main deliverable is the [WoT Scripting API Specification](./index.html). See the rendered version here: [http://w3c.github.io/wot-scripting-api/](http://w3c.github.io/wot-scripting-api/) + +See the [rationale.md](./rationale.md) for explanation on API design choices. + +See the [primer.md](./primer.md) for explaining and illustrating the usage of the API. To make contributions, please provide pull-requests to the html file, see [github help](https://help.github.com/articles/using-pull-requests/). From 7ab86ee547ba8190fee96c6f4cd17d78f791d2c6 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Sat, 15 Apr 2017 17:26:48 +0300 Subject: [PATCH 06/12] Remove remote Thing management Signed-off-by: Zoltan Kis --- index.html | 27 ++++++++++++--------------- rationale.md | 18 ------------------ 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/index.html b/index.html index 34f5ba79..794f13d6 100644 --- a/index.html +++ b/index.html @@ -147,11 +147,10 @@ Consuming a Thing Description means parsing the Thing Description and building a resource model with the use of Protocol Bindings that can be used in a script for accessing and controlling the Thing. A Thing when starts up, consumes its own TD, then it exposes its WoT interface as a server. Note that a script on a Thing may consume other TDs and expose a combined interface of the consumed Things. - A WoT Runtime or WR is defined as a software stack that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses an operating system API that provides access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc. + A WoT Runtime or WR is defined as a script execution environment that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses an operating system API that provides access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc.
- In this version of the specification, a WR MAY run either an idle event loop, or a script that has been deployed to it by a method that is out of scope of this document. However, new Things can be added and Things running in the WR can be updated by using the methods of this API from a script run in another WR. -
+ In this version of the specification, a WR is assumed to run a single script that uses this API to define one or more Things that share a common event loop. Script deployment methods are out of scope of this version. In future versions, running multiple scripts (as modules) may be possible, and script deployment MAY be implemented using a manager Thing whose actions permit script lifecycle management operations.A Thing is represented either as a ConsumedThing (for Things obtained by discovery or retrieve operations) or ExposedThing (for Things created with this API inside the WR). All ExposedThings contained in a WR are serving external requests through the same event loop, and are said to be local Things to each other. All other Things that run in a different WR, even if on the same physical hardware, are said to be remote Things to each other. Note that there may also be local ConsumedThing objects as well.
@@ -162,7 +161,7 @@The following terms are defined in [[!HTML5]] and are used in the context of browser implementations: - + browsing context, @@ -174,9 +173,6 @@ incumbent settings object, - - script execution environment, - Document, @@ -215,7 +211,7 @@ Document objects are presented to the user. A given browsing context has a single
WindowProxy
object, but it can have manyDocument
objects, with their associated -Window
objects. The script execution environment +Window
objects. The script execution context associated with the browsing context identifies the entity which invokes this API, which can be a web app, a web page, or an iframe. @@ -226,6 +222,8 @@ secure context is defined in [[!WEBAPPSEC]].+ + script execution context, Promise, @@ -286,10 +284,7 @@
Create and expose a local Thing based on a Thing Description. Programmatically create and expose a local Thing. This may include the following use cases: Register handler for semantic translation of property values. +Register the Thing. +Unregister the Thing. +Start the exposed Thing in order to process external requests. +Stop the exposed Thing. @@ -333,7 +332,7 @@ interface WoT { Observable<ConsumedThing> discover(optional ThingFilter filter); Promise<ConsumedThing> retrieve(USVString url); - Promise<ExposedThing> create(ThingInit init, optional USVString target); + Promise<ExposedThing> createLocalThing(ThingInit init); }; dictionary ThingInit { @@ -382,8 +381,6 @@ ConsumedThing addListener(DOMString eventName, ThingEventListener listener); ConsumedThing removeListener(DOMString eventName, ThingEventListener listener); ConsumedThing removeAllListeners(DOMString eventName); - - Promise<ExposedThing> acquire(); }; callback ThingEventListener = void (ConsumedThing thing); diff --git a/rationale.md b/rationale.md index c1fb9632..34b25d3f 100644 --- a/rationale.md +++ b/rationale.md @@ -27,21 +27,3 @@ Based on [issue 16](https://github.com/w3c/wot-scripting-api/issues/16) there is Resolutions: - Use [Observables](https://github.com/tc39/proposal-observable) for controlling the discovery process (subscribe, unsubscribe). - Use a single filter definition that also contains a property for discovery type, defaulting to `"any"`. It is simpler and more intuitive to use than having a separate parameter for discovery type. Some of the discovery types, such as registry/directory based discovery also require another parameter for the address of the directory. This can be provided as a required property in the discovery filter, described in the discovery algorithm. - -## WoT Runtime, Applications, Scripts, Things - -Based on the discussion in [issue 2](https://github.com/w3c/wot-scripting-api/issues/2), there is a use case for deploying WoT functionality to WoT Runtimes. This functionality is called an Application, and has an associated security identity and access rights. - -An Application may be defined as a script, or a set of scripts, eventually with added configuration data and manifest data. - -Alternatively, an Application may also be represented by a set of Things that are created and deployed in a WoT Runtime. The functionality is characterized by the Thing Descriptions of the participating Things. With this assumption, there is no new concepts needed for fulfilling the deployment use case. The WoT Scripting API just needs to provide methods for creating a Thing on a remote WoT Runtime, and modify existing Things on a remote Runtime. - -The draft algorithm for creating a remote Thing is the following: -1. A script running in the initiating (controlling) WoT Runtime (WR) invokes the `wot.create()` API with the destination specified as the target (controlled) WoT Runtime. The method specifies the Thing Description and optionally also security related metadata (e.g. policy on further modification accesses). The implementation (bindings) of the participating WRs has been provisioned with identity, authentication mechanism, and access management functionality. -2. The target WR authenticates the initiating WR and checks for access rights, using either a local or a network based policy. If there are not sufficient rights for the request, reject the request with a security error. -3. If access rights are granted, the target WR creates the required Thing (involving full lifecycle integration, such as event loop, secure storage etc) and records the security metadata of the transaction (e.g. creator identity, group/security level, access policy etc). If creating fails, the transaction is rolled back and the request is rejected with an error. -4. If creating succeeds, the initiating WR generates an `ExposedThing` object for controlling the newly created Thing. Further modification requests are separately authenticated or a session may be maintained, depending on the capabilities of the underlying protocols. - - - - From 874bb3a3fbc50bb9f82f42d6a1533470743ffffe Mon Sep 17 00:00:00 2001 From: Zoltan KisDate: Tue, 25 Apr 2017 10:50:53 +0300 Subject: [PATCH 07/12] Correct text on using lower level APIs from a WoT Runtime Signed-off-by: Zoltan Kis --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 794f13d6..1e121962 100644 --- a/index.html +++ b/index.html @@ -147,7 +147,7 @@ Consuming a Thing Description means parsing the Thing Description and building a resource model with the use of Protocol Bindings that can be used in a script for accessing and controlling the Thing. A Thing when starts up, consumes its own TD, then it exposes its WoT interface as a server. Note that a script on a Thing may consume other TDs and expose a combined interface of the consumed Things. - A WoT Runtime or WR is defined as a script execution environment that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses an operating system API that provides access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc. + A WoT Runtime or WR is defined as a script execution environment that manages the lifecycle of WoT application scripts, implements a script interpreter, an event loop, a security enforcement point for access management and uses lower-level APIs to provide access to local and remote resources. A WR should be isolated from other execution environments on memory address space, storage address space (file system), network namespace, etc.
In this version of the specification, a WR is assumed to run a single script that uses this API to define one or more Things that share a common event loop. Script deployment methods are out of scope of this version. In future versions, running multiple scripts (as modules) may be possible, and script deployment MAY be implemented using a manager Thing whose actions permit script lifecycle management operations. From 70c7bef332d724a278c3e571524a30eea9fb6618 Mon Sep 17 00:00:00 2001 From: Zoltan Kis
Date: Tue, 25 Apr 2017 23:20:38 +0300 Subject: [PATCH 08/12] Handle review feedback, make API consistent for events and types. Signed-off-by: Zoltan Kis --- index.html | 151 +++++++++++++++++++++++++++++++-------------------- rationale.md | 3 +- 2 files changed, 95 insertions(+), 59 deletions(-) diff --git a/index.html b/index.html index 1e121962..47383df6 100644 --- a/index.html +++ b/index.html @@ -324,7 +324,7 @@ The WoT object exposes only functions and has no internal state. - Browser implementations SHOULD use a namespace object such as `wot`, and [Node.js](https://nodejs.org/en/)-like runtimes MAY provide the API object through the [`require()`](https://nodejs.org/api/modules.html) mechanism. + Browser implementations SHOULD use a namespace object such as `wot`, and [Node.js](https://nodejs.org/en/)-like runtimes MAY provide the API object through the [`require()`](https://nodejs.org/api/modules.html) or [`import`](http://www.ecma-international.org/ecma-262/6.0/#sec-imports) mechanism.
// [SecureContext] @@ -341,7 +341,8 @@ Dictionary description; }; - enum DiscoveryType { "any", "local", "directory", "broadcast" }; + // TBD: if extensible by applications + enum DiscoveryType { "any", "local", "nearby", "directory", "broadcast" }; dictionary ThingFilter: ThingInit { DiscoveryType type = "any"; @@ -367,46 +368,21 @@
- interface ConsumedThing { - readonly attribute DOMString name; - readonly attribute USVString url; - readonly attribute Dictionary description; - - Promise<void> invokeAction(ThingAction action); - Promise<void> setProperty(ThingProperty property); - Promise<void> getProperty(ThingProperty property); - - ConsumedThing addListener(DOMString eventName, ThingEventListener listener); - ConsumedThing removeListener(DOMString eventName, ThingEventListener listener); - ConsumedThing removeAllListeners(DOMString eventName); - }; - - callback ThingEventListener = void (ConsumedThing thing); - - enum ConsumedThingEvents { - "propertychanged", - "propertyremoved", - "propertyadded", - "actionchanged" - }; --
interface ExposedThing { // define TD modifiers - ExposedThing addProperty(ThingProperty property); - ExposedThing removeProperty(ThingProperty property); + ExposedThing addProperty(ThingPropertyInit property); + ExposedThing removeProperty(DOMString name); - ExposedThing addAction(ThingAction action); - ExposedThing removeAction(ThingAction action); + ExposedThing addAction(ThingActionInit action); + ExposedThing removeAction(DOMString name); - ExposedThing addEvent(ThingEvent event); - ExposedThing removeEvent(ThingEvent event); + ExposedThing addEvent(ThingEventInit event); + ExposedThing removeEvent(DOMString name); + + ExposedThing addSemanticTranslator(SemanticTranslator handler); Promise<void> register(optional USVString directory); Promise<void> unregister(); @@ -417,52 +393,111 @@ Promise<void> emitEvent(DOMString eventName, any payload); // define request handlers (one per request type, so no events here) - ExposedThing onRetrieveProperty(PropertyHandler handler); - ExposedThing onAddProperty(PropertyHandler handler); - ExposedThing onRemoveProperty(PropertyHandler handler); - - ExposedThing onInvokeAction(ActionHandler handler); + // TBD: ExposedThing onAddProperty(PropertyRequestHandler handler); + // TBD: ExposedThing onRemoveProperty(PropertyRequestHandler handler); + ExposedThing onRetrieveProperty(PropertyRequestHandler handler); + ExposedThing onUpdateProperty(PropertyRequestHandler handler); - ExposedThing onAddEventHandler(DOMString event, ObserveHandler handler); - ExposedThing onRemoveEventHandler(DOMString event, ObserveHandler handler); + ExposedThing onInvokeAction(ActionRequestHandler handler); - ExposedThing onAddSemanticTranslator(SemanticTranslator handler); + ExposedThing onAddEventListener(DOMString event, USVString from); + ExposedThing onRemoveEventListener(DOMString event, USVString from); }; ExposedThing implements ConsumedThing; - callback PropertyHandler = void (ThingProperty property, USVString from); - callback ActionHandler = void (ThingAction action, USVString from); - callback EventHandler = void (DOMString eventName, USVString from); - callback SemanticTranslator = any (Property property, SemanticType type); + callback PropertyRequestHandler = void (ThingPropertyInit property, USVString from); + callback ActionRequestHandler = void (ThingActionInit action, USVString from); + callback EventRequestHandler = void (ThingEventInit event, USVString from); + callback SemanticTranslator = any (DOMString propertyName, SemanticType type); dictionary SemanticType { DOMString name; DOMString context; }; - dictionary ThingAction { + dictionary ThingPropertyInit { DOMString name; - object inputType; - object outputType; + boolean configurable = true; + boolean enumerable = true; + boolean writable = true; SemanticType[] semanticTypes; - Function action; - sequence<any> parameters; - any returnValue; + Dictionary typeDescription; + any value; }; - dictionary ThingProperty { + dictionary ThingEventInit { DOMString name; - object contentType; SemanticType[] semanticTypes; - any value; + Dictionary typeDescription; + // TBD: value for event data not needed here }; - dictionary ThingEvent { + dictionary ThingActionInit { DOMString name; - object payloadType; + Dictionary returnTypeDescription; // TBD + sequence<Dictionary> inputTypeDescriptions; // TBD SemanticType[] semanticTypes; + Function action; + // TBD: actual parameters and return value not needed here + }; ++
+ interface ConsumedThing { + readonly attribute DOMString name; + readonly attribute USVString url; + readonly attribute Dictionary description; + + Promise<any> invokeAction(DOMString name, sequence<any> parameters); + Promise<void> setProperty(DOMString name, any value); + Promise<any> getProperty(DOMString name); + + ConsumedThing addListener(DOMString eventName, ThingEventListener listener); + ConsumedThing removeListener(DOMString eventName, ThingEventListener listener); + ConsumedThing removeAllListeners(DOMString eventName); }; + + callback ThingEventListener = void (Event event); + + [Constructor(PropertyChangeEventInit init)] + interface PropertyChangeEvent: Event { + // TBD if Node or DOM style + }; + + [Constructor(ActionInvocationEventInit init)] + interface ActionInvocationEvent: Event { + // TBD if Node or DOM style + }; + + [Constructor(ThingDescriptionChangeEventInit init)] + interface ThingDescriptionChangeEvent: Event { + // TBD if Node or DOM style + }; + + dictionary PropertyChangeEventInit { + DOMString name; + any value; + any oldValue; + }; + + dictionary ActionInvocationEventInit { + DOMString actionName; + any returnValue; + }; + + dictionary ThingDescriptionChangeEventInit { + TDChangeType type; + TDChangeMethod method; + DOMString name; + (ThingPropertyInit or ThingActionInit or ThingEventInit) description; + }; + + enum TDChangeMethod { "add", "remove", "change" }; + enum TDChangeType { "property", "action", "event" }; +
As described in the [WoT Current Practices](http://w3c.github.io/wot/current-practices/wot-practices.html#vision), the Web of Things is made of Things that can describe their capabilities in a machine-interpretable format, the Thing Description (TD). By consuming a TD, a Thing creates a runtime resource model that allows accessing the Thing by an application. + + The overall WoT concepts are described in the [WoT Architecture](https://w3c.github.io/wot-architecture/) document.
The following scripting use cases are covered in this specification:
+ The following use cases are being considered for next versions: +
+ WoT provides a unified representation for data exchange between Things, standardized in the [Wot Things Description](https://w3c.github.io/wot-thing-description/) specification. + Thing Descriptions are represented as dictionary objects in this API.
The API object represents an implementation of the WoT Runtime and provides functionality to obtain Things by discovery or creation.
@@ -342,7 +360,7 @@ }; // TBD: if extensible by applications - enum DiscoveryType { "any", "local", "nearby", "directory", "broadcast" }; + enum DiscoveryType { "any", "local", "nearby", "directory", "broadcast", "other" }; dictionary ThingFilter: ThingInit { DiscoveryType type = "any"; @@ -382,8 +400,6 @@ ExposedThing addEvent(ThingEventInit event); ExposedThing removeEvent(DOMString name); - ExposedThing addSemanticTranslator(SemanticTranslator handler); - Promise<void> register(optional USVString directory); Promise<void> unregister(); @@ -393,8 +409,6 @@ Promise<void> emitEvent(DOMString eventName, any payload); // define request handlers (one per request type, so no events here) - // TBD: ExposedThing onAddProperty(PropertyRequestHandler handler); - // TBD: ExposedThing onRemoveProperty(PropertyRequestHandler handler); ExposedThing onRetrieveProperty(PropertyRequestHandler handler); ExposedThing onUpdateProperty(PropertyRequestHandler handler); @@ -409,11 +423,11 @@ callback PropertyRequestHandler = void (PropertyRequest request); callback ActionRequestHandler = void (ActionRequest request); callback ObserveRequestHandler = void (ObserveRequest request); - callback SemanticTranslator = any (DOMString propertyName, SemanticType type); dictionary PropertyRequest { USVString from; ThingPropertyInit property; + Dictionary options; }; dictionary ActionRequest { @@ -430,7 +444,7 @@ enum ObserveType { "property", "action", "event", "td" }; - dictionary SemanticType { + dictionary SemanticType { // TBD what is the use case? DOMString name; DOMString context; }; diff --git a/rationale.md b/rationale.md index 752153de..9ee343f3 100644 --- a/rationale.md +++ b/rationale.md @@ -28,3 +28,11 @@ Based on [issue 16](https://github.com/w3c/wot-scripting-api/issues/16) there is Resolutions: - Use [Observables](https://github.com/tc39/proposal-observable) for controlling the discovery process (subscribe, unsubscribe). - Use a single filter definition that also contains a property for discovery type, defaulting to `"any"`. It is simpler and more intuitive to use than having a separate parameter for discovery type. Some of the discovery types, such as registry/directory based discovery also require another parameter for the address of the directory. This can be provided as a required property in the discovery filter, described in the discovery algorithm. + +## Server API (`ExposedThing`) +Scripts that define Exposed Things should ensure the following: +1. define properties, actions and events according to the Thing Description. +2. define request handler functions to implement the serving end for the Client API. + +## Client API (`ConsumedThing`) +Scripts that use the Client API are basically sending requests to servers in order to retrieve or update properties, invoke actions, and observe properties, actions and events. When the `ConsumedThing` is fetched, its Thing Description is also fetched, then client scripts can track changes by subscribing to events that signal TD changes. From c4a272857a5f2166a7c3cb7ee619d56e845b0129 Mon Sep 17 00:00:00 2001 From: Johannes Hund