Web of Things (WoT) スクリプティング API

W3C グループノート

この文書の詳細
このバージョン:
https://www.w3.org/TR/2023/NOTE-wot-scripting-api-20231003/
最新公開バージョン:
https://www.w3.org/TR/wot-scripting-api/
最新エディターズドラフト:
https://w3c.github.io/wot-scripting-api/
履歴:
https://www.w3.org/standards/history/wot-scripting-api/
コミット 履歴
編集者:
Zoltan Kis (Intel)
Daniel Peintner (Siemens AG)
Cristiano Aguzzi (招待専門家)
Johannes Hund (元編集者、Siemens AG 在籍時)
Kazuaki Nimura (元編集者、Fujitsu Ltd. 所属)
フィードバック:
GitHub w3c/wot-scripting-api (プル リクエスト, 新しい issue, 未解決の issue)
public-wot-wg@w3.org 宛てに、件名行を [wot-scripting-api] … メッセージのトピック … として送信してください (アーカイブ)
リポジトリ
GitHub 上
バグを 報告
コントリビューター
GitHub 上のコントリビューター

概要

Web of Things は、自身の 機能を機械が解釈可能な Thing Description (TD) で記述し、それらの機能を WoT Interface、すなわち Properties(値の読み取り および書き込み用)、Action(戻り値の有無にかかわらず リモート手続きを実行するため)および Event(通知を シグナルするため)としてモデル化されたネットワーク相互作用を通じて公開できるエンティティ(Thing)で構成されます。

主な Web of Things (WoT) の概念は、 Web of Things (WoT) Architecture 1.1 仕様で説明されています。

スクリプティングは WoT における任意の構成要素であり、通常は WoT Runtime および スクリプト管理を実行できるゲートウェイまたはブラウザーで使用され、WoT のサポートを新しい種類のエンドポイントに拡張し、 TD Directory などの WoT アプリケーションを実装する便利な方法を提供します。

この仕様は、スクリプトが Thing を発見し、操作し、またスクリプトによって指定された WoT Interactions によって特徴付けられるローカルに定義された Thing を公開できるようにする、WoT Interface を表すアプリケーションプログラミング インターフェイス (API) について説明します。

この文書で定義される API は、意図的に Web of Things (WoT) Thing Description 1.1 仕様に密接に従っています。これらの上により抽象的な API を実装すること、または WoT のネットワーク向けインターフェイス(すなわち WoT Interface)を直接実装することが可能です。

編集者注

この仕様は、少なくとも Eclipse Thingweb プロジェクト(node-wot としても知られる)によって実装されており、 現時点で参照用のオープンソース実装とみなされています。 ソース コードを含む)を確認してください。

この文書のステータス

この節は、公開時点におけるこの文書のステータスを説明するものです。 現在の W3C 公開物の一覧およびこの技術レポートの最新改訂版は、 https://www.w3.org/TR/ にある W3C 技術レポート インデックスで確認できます。

実装者は、この仕様が不安定であるとみなされていることを 認識しておく必要があります。この仕様が最終的に Candidate Recommendation 段階に到達する前に実装することに関心のあるベンダーは、 リポジトリを購読し、 議論に参加すべきです。

編集者注: W3C WoT WG はフィードバックを求めています

この草案には、 GitHub Issues ページ(WoT Scripting API リポジトリ)を使用して貢献してください。セキュリティおよびプライバシー に関する考慮事項へのフィードバックには、WoT Security and Privacy Issues を使用してください。

この文書は、Web of Things Working Group によって、Note track を使用して Group Note として公開されました。

この Group Note は Web of Things Working Group によって承認されていますが、W3C 自体またはその メンバーによって承認されているものではありません。

これは草案文書であり、いつでも他の文書によって更新、 置換、または廃止される可能性があります。この文書を進行中の作業以外のものとして 引用することは不適切です。

W3C Patent Policy は、 この文書に対していかなるライセンス要件またはコミットメントも 課しません。

この文書は、2023年6月12日版 W3C Process Document によって管理されます。

1. 序論

WoT は、Thing がどのように使用されるか、すなわち Web of Things (WoT) Architecture 1.1 の用語で定義される "consumed" および "exposed" に基づいて、階層化された相互運用性を提供します。

TD を消費することにより、クライアント Thing は、リモートデバイス上のサーバー Thing によって公開される PropertiesActions および Events へアクセスできる ローカル実行時リソースモデルを作成します。

Thing を公開するには、 次が必要です: この仕様は、スクリプトによって Thing を 公開および消費する方法を説明します。また、 Thing 発見のための汎用 API を定義します。

通常、スクリプトは、より単純なデバイスを WoT Thing として 公開および制御し、スクリプトを処理(たとえばインストール、アンインストール、更新など)して実行する 手段を持つブリッジまたはゲートウェイ上で使用されることを想定しています。

この仕様は、単一または 複数テナンシー、スクリプトのデプロイメントおよびライフサイクル管理を含め、 WoT Runtime がスクリプトをどのように処理し実行するかについては仮定しません。 この API は、たとえば Actions (アクションハンドラー)がスクリプトのライフサイクル管理操作を実装する管理用 Thing を公開することにより、スクリプト管理の実装を可能にする汎用メカニズムをすでにサポートしています。

2. ユースケースシナリオ

この節は非規範的です。

[WOT-USE-CASES] 文書に列挙されているビジネスユースケースは、ここで説明する スクリプティングのユースケースシナリオに基づいて、この API を使用して実装できます。

2.1 Thing を消費する

2.2 Thing を公開する

2.3 発見

3. 適合性

非規範的であると示された節と同様に、この仕様におけるすべての作成ガイドライン、 図、例、および注は非規範的です。この仕様におけるその他すべての内容は 規範的です。

この文書におけるキーワード MAYMUST、および SHOULD は、 ここに示すようにすべて大文字で現れる場合に限り、 BCP 14 [RFC2119] [RFC8174] に記述されているとおりに解釈されます。

編集者注

この仕様は、かつて W3C Recommendation になることが期待されていた Working Draft でした。しかし、現在は有益な記述のみを含む WG Note です。 したがって、この適合性の節内の記述をどのように扱うかを検討する必要があります。

この仕様は、以下の user agentUA)のクラスに対する 適合基準を説明します。

小規模な組み込み実装の要件により、 WoT クライアントインターフェイスとサーバーインターフェイスを分割する必要がありました。 また、発見は分散アプリケーションですが、典型的なシナリオはこの仕様における 汎用発見 API によってカバーされています。その結果、この API を実装する UA について、 クライアント用、サーバー用、および発見用の 3 つの適合クラスを使用することになりました。 この API を使用するアプリケーションは、 WoT API object 上の consume()produce() および discover() メソッドの存在を内省することで、 UA がどの適合クラスを実装しているかを判断できます。

WoT Consumer UA

この適合クラスの実装は、ConsumedThing インターフェイスおよび WoT API object 上の consume() メソッドを実装しなければなりません(MUST)。

WoT Producer UA

この適合クラスの実装は、ExposedThing インターフェイスおよび WoT API object 上の produce() メソッドを実装しなければなりません(MUST)。

WoT Discovery UA

この適合クラスの実装は、ThingDiscoveryProcess インターフェイス、discover() メソッド、 exploreDirectory() メソッド、および WoT API object 上の requestThingDescription() メソッドを 実装しなければなりません(MUST)。

これらの適合クラスは、単一の UA に実装されてもよい(MAY)。

この仕様は、複数のプログラミング言語で WoT Scripting API を実装するために使用できます。インターフェイス定義は [WEBIDL] で指定されています。

UA は、 ブラウザー内、または Node.js などの別個のランタイム環境、 あるいは小規模な組み込みランタイム内に実装できます。

この文書で定義される API を実装するためにブラウザー内で実行される ECMAScript を使用する実装は、 Web IDL 仕様 [WEBIDL] で定義される ECMAScript Bindings と整合する方法でそれらを実装しなければなりません(MUST)。

この文書で定義される API を実装するためにランタイム内で TypeScript または ECMAScript を使用する実装は、 TypeScript 仕様 [TYPESCRIPT] で定義される TypeScript Bindings と整合する方法でそれらを実装しなければなりません(MUST)。

4. 用語と規約

一般的な WoT 用語は [WOT-ARCHITECTURE] で定義されています: Thing, Thing Description (略して TD), Partial TD, Web of Things (略して WoT), WoT Interface, Protocol Bindings, WoT Runtime, Consuming a Thing Description, TD Directory, Property, Action, Event, DataSchema, Form, SecurityScheme, NoSecurityScheme などです。

WoT Interaction は、 Interaction Affordance の同義語です。Interaction Affordance(または短く affordance)は、 TD issue 282 で説明されているように、 Thing の機能を参照するときに [WOT-TD] で使用される用語です。しかし、この用語は TD の意味的コンテキストの外では 十分に理解されていません。そのため、可読性のために、この文書では以前の用語である WoT interaction、または単に interaction を代わりに使用します。

WoT network interface は、WoT Interface の同義語です。

JSON Schema は、 これらの 仕様で定義されています。

Promise, Error, JSON, JSON.stringify, JSON.parse, internal method および internal slot は、[ECMASCRIPT] で定義されています。

5. ThingDescription

WebIDLtypedef object ThingDescription;

[WOT-TD] で 定義される Thing DescriptionTD)を表します。 これは、 解析済み JSON オブジェクトであり、 JSON Schema validation を使用して検証されることが期待されます。

5.1 Thing Description のフェッチ

URL が与えられた TD のフェッチは、 Fetch API や HTTP クライアントライブラリのような外部メソッドを用いて行うべきです。これらは フェッチの詳細指定についてすでに標準化されたオプションを提供しています。

1: Thing Description のフェッチ
try {
  let res = await fetch('https://tds.mythings.biz/sensor11');
  // ... additional checks possible on res.headers
  let td = await res.json();
  let thing = await WOT.consume(td);
  console.log("Thing name: " + thing.getThingDescription().title);
} catch (err) {
  console.log("Fetching TD failed", err.message);
}

5.2 Thing Description の展開

Web of Things (WoT) Thing Description 1.1 仕様は、 デフォルトを用いた短縮された Thing Description の使用を許可しており、クライアントに対して、与えられた TD で明示的に定義されていないプロパティについて、 Web of Things (WoT) Thing Description 1.1 仕様で指定されるデフォルト値でそれらを展開することを求めている点に注意してください。

td が与えられたときに TD を展開するには、 次の手順を実行します:
  1. [WOT-TD] の TD default values 表の各項目について、その用語が td に定義されていない場合、 [WOT-TD] で指定されたデフォルト値を用いて、その用語定義を追加する。

5.3 Thing Description の検証

[WOT-TD] 仕様は、TD がどのように検証されるべきかを定義しています。したがって、 この API は、ThingDescription オブジェクトがパラメーターとして使用される前に検証されることを期待します。この 仕様は、次のように基本的な TD 検証を定義します。

td が与えられたときに TD を検証するには、 次の手順を実行します:
  1. td に対して JSON Schema validation が失敗した場合、 "TypeError" をthrowし、 停止する。
編集者注: デフォルト値の処理

必須フィールドのデフォルト値を埋めるための追加手順が追加される可能性があります。

6. WOT 名前空間

WoT API object をシングルトンとして定義し、適合クラスごとにグループ化された API メソッドを含みます。

WebIDL[SecureContext, Exposed=(Window,Worker)]
namespace WOT {
  // methods defined in UA conformance classes
};

6.1 consume() メソッド

WebIDLpartial namespace WOT {
  Promise<ConsumedThing> consume(ThingDescription td);
};
WoT Consumer 適合クラスに属します。 td 引数を期待し、 Thing を 操作するためのクライアントインターフェイスを表す ConsumedThing オブジェクトで解決される Promise を返します。 このメソッドは、次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. thing を、 td から構築された新しい ConsumedThing オブジェクトとする。
  4. [WOT-TD] および [WOT-PROTOCOL-BINDINGS] で説明されるように、td を内省することに基づいて WoT Interactions を設定する。 Protocol Bindings を初期化するように、基盤となるプラットフォームへ要求を行う。
    編集者注

    実装は、 WoT interactions を 実装するために Protocol Bindings をどのように使用するかの複雑さをカプセル化します。 将来的には、その要素が標準化される可能性があります。

  5. promisethingResolveする。
編集者注

ConsumedThing を構築することと、consume() メソッドを使用することの違いに注意してください。 後者はプロトコルバインディングも初期化しますが、単に構築されたオブジェクトでは、 呼び出されるまで WoT Interactions は初期化されません。

6.2 produce() メソッド

WebIDLtypedef object ExposedThingInit;

partial namespace WOT {
  Promise<ExposedThing> produce(ExposedThingInit init);
};
WoT Producer 適合クラスに属します。 init 引数を期待し、要求ハンドラーを定義する能力、 すなわちサーバーインターフェイスで ConsumedThing を拡張する ExposedThing オブジェクトで解決される Promise を返します。 init オブジェクトは、ExposedThingInit 型のインスタンスです。具体的には、 ExposedThingInit 値は ExposedThing の初期化に使用される辞書であり、 [WOT-ARCHITECTURE] で説明される Partial TD を表します。 そのため、これは Thing Description と同じ構造を持ちますが、一部の情報を省略することがあります。このメソッドは、次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. thing を、 init で構築された新しい ExposedThing オブジェクトとする。
  4. promisethingResolveする。

6.2.1 ExposedThingInit を展開する

init が与えられ、有効な td を結果として取得するために ExposedThingInit を展開するには、 次の手順を実行します:
  1. init に対して ExposedThingInit を検証する を実行する。それが失敗した場合、 SyntaxErrorthrowし、 停止する。
  2. td を、 init が与えられて clone を実行した結果とする。
  3. td.["securityDefinitions"] 内の各 scheme について、 それが少なくとも 1 つの Protocol Binding によってサポートされているかを確認するよう、基盤となるプラットフォームへ要求を行う。 サポートされていない場合は、td から scheme を削除する。
  4. td.["security"] が td.["securityDefinitions"] 内に 存在しない場合、 td から security を削除する。
  5. td.properties、td.actions、および td.events 内の各 affordance について、 次のサブ手順を実行する:
    1. affordance.forms 内の各 form について:
      1. form.contentType が ランタイムによって有効なものとして認識されない場合、form から contentType を削除する。
      2. form.href に未知のスキーマがある場合、form から href を削除する。
      3. form.href が絶対であり、その authority がランタイムによって有効なものとして 認識されない場合、 form から href を削除する。
      4. form.href が他の ExposedThings によってすでに使用されている場合、 form から href を削除する。
  6. TD JSON Schema に従って、 td 内の欠落している必須プロパティを検索する。
    編集者注

    編集者はこの手順が曖昧であると考えています。次の反復で改善または削除されます。

  7. missing プロパティについて、次のサブ手順を実行する:
    1. missingtitle の場合、 ランタイムで一意な名前を生成し、title に割り当てる。
    2. missing@context の場合、 サポートされている最新の Thing Description context URI を割り当てる。
    3. missinginstance の場合、 文字列 1.0.0 を割り当てる。
    4. missingforms の場合、 利用可能な Protocol Bindings および content types エンコーダーを使用して Forms のリストを生成する。次に、 得られたリストを forms に割り当てる。
    5. missingsecurity の場合、 securityDefinitions フィールド内の最初にサポートされる SecurityScheme のラベルを割り当てる。 SecurityScheme が見つからない場合は、nosec と呼ばれる NoSecurityScheme を生成し、文字列 nosecsecurity に割り当てる。
      Issue 1

      security の値を適切に生成する方法についての議論は まだ未解決です。issue #299 を参照してください

    6. missinghref の場合、 href を持たない部分的な Form として formStub を定義する。 formStub の要件を満たす最初の Protocol Binding を使用して、有効な url を生成する。urlhref に割り当てる。該当する Protocol Binding が見つからない場合は、td から formStub を削除する。
    7. missingvalue を 値として td に追加する
  8. td に対して TD を検証するを実行する。 それが失敗した場合、エラーを再throwし、 停止する
  9. td を返す

6.2.2 ExposedThingInit の検証

init が与えられたときに ExposedThingInit を検証するには、 次の手順を実行します:
  1. TD JSON Schema を解析し、 exposedThingInitSchema と呼ばれるオブジェクトに読み込む
  2. optional を、次の文字列を含むリストとする: title, @context, instance, forms, security, および href.
  3. exposedThingInitSchema 内の各プロパティおよびサブプロパティ keyrequired に等しい場合、次の手順を実行する:
    1. keyvalueArray である場合、optional 内の要素と等しい すべての要素を削除する
    2. keyvaluestring である場合、valueoptional 内のいずれかの要素と等しければ、 exposedThingInitSchema から key を削除する
  4. init および exposedThingInitSchema が与えられたときに JSON Schema で オブジェクトを検証する結果を返す。
    編集者注

    JSON Schema でオブジェクトを検証する 手順は、まだ議論中です。現在、この仕様は JSONSchema の検証プロセスを参照しています。 initexposedThingInitSchema で検証するときは、この 文書に従ってください。ワーキンググループが代替となる形式的アプローチを評価していることに 注意してください。

6.3 discover() メソッド

WebIDLpartial namespace WOT {
  Promise<ThingDiscoveryProcess> discover(optional ThingFilter filter = {});
};
WoT Discovery 適合クラスに属します。 型が ThingFilter である省略可能な filter 引数に一致する Thing Description のために ThingDescription オブジェクトを提供する発見プロセスを開始します。 このメソッドは、次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. 実装が発見をサポートしていない場合、 promise NotSupportedErrorrejectし、停止する。
  4. discovery を、新しい ThingDiscoveryProcess オブジェクトとする。
  5. discovery.[[filter]]filter に設定する。
  6. discovery.[[url]]undefined に設定する。
  7. 実装が一般にフィルターをサポートしておらず、 filterundefined または null でない場合、 promise NotSupportedErrorrejectし、停止する。
  8. 基盤となるプラットフォームによって発見を開始できない場合、 promiseOperationErrorrejectし、 停止する。
  9. discovery を渡し、スクリプトがアクセス権を持つ WoT Runtime 内でサポートおよびプロビジョニングされた任意の手段により、 発見プロセス を開始するよう、基盤となるプラットフォームに要求する。
  10. promisediscoveryResolveする。

6.4 exploreDirectory() メソッド

WebIDLpartial namespace WOT {
  Promise<ThingDiscoveryProcess> exploreDirectory(USVString url,
      optional ThingFilter filter = {});
};
WoT Discovery 適合クラスに属します。 TD Directory URL が与えられたときに、 型が ThingFilter である省略可能な filter 引数に一致する Thing Description のために ThingDescription オブジェクトを提供する発見プロセスを開始します。 このメソッドは、次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. 実装がディレクトリ発見をサポートしていない場合、 promise NotSupportedErrorrejectし、停止する。
  4. discovery を、新しい ThingDiscoveryProcess オブジェクトとする。
  5. discovery.[[url]]url に設定する。
  6. discovery.[[filter]]filter に設定する。
  7. ディレクトリ発見プロセスを開始するよう、基盤となるプラットフォームへ要求する。

    これは、発見アルゴリズムのより詳細な記述のためのプレースホルダーです。 実装は、 [WOT-DISCOVERY] および [WOT-PROTOCOL-BINDINGS] 仕様で説明される手順に従うべきです。 いくつかの規範的手順を以下に示します。

    1. url TD Directory でない場合、または基盤となる実装が url によって示される Protocol Binding をサポートできない場合、 promise NotSupportedErrorrejectし、 これらの手順を終了する。
    2. 実装が一般にフィルターをサポートしておらず、 filterundefined または null でない場合、 promise NotSupportedErrorrejectし、停止する。
    3. discovery が与えられたときに 発見 プロセスを実行する。

      この時点以降、エラーは error にのみ記録され、 もはや promise には影響しません。

  8. promisediscoveryResolveする。

6.5 requestThingDescription() メソッド

WebIDLpartial namespace WOT {
  Promise<ThingDescription> requestThingDescription(USVString url);
};
WoT Discovery 適合クラスに属します。 与えられた URL から Thing Description を要求します。このメソッドは、次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. 実装が Thing Description のフェッチをサポートしていない場合、 promise NotSupportedErrorrejectし、停止する。
  4. td を、 url によって指定された Protocol Binding を使用して Thing Description を取得するよう、基盤となるプラットフォームへ要求した結果とする。 td の取得に失敗した場合、 promiseNotFoundErrorrejectし、 停止する。
  5. promisetdResolveする。

7. 相互作用データの処理

Web of Things (WoT) Thing Description 1.1 仕様で指定されているように、WoT interactionsDataSchema を拡張し、 相互作用のために 1 つが選択される複数の可能な Form を含みます。 Form には、データを説明するための contentType が含まれます。 特定の content types については、JSON Schema に基づいて DataSchema が定義され、これらの内容を JavaScript 型として表現し、 最終的にデータに範囲制約を設定することが可能になります。

7.1 InteractionInput

WebIDLtypedef any DataSchemaValue;
typedef (ReadableStream or DataSchemaValue) InteractionInput;

WoT Consumer 適合クラスに属し、 アプリケーションスクリプトから UA に提供される WoT Interaction データを表します。

DataSchemaValue は、[WoT-TD] で定義される DataSchema に対して受け入れられる ECMAScript 値です。 取り得る値は、 null, boolean, number, string, array, または object 型でなければなりません(MUST)。

ReadableStream は、Thing Description 内に DataSchema を持たず、ストリームで表現できる FormcontentType のみを持つ WoT Interactions に使用されることを意図しています。

実際には、Thing Description 内に定義された DataSchema を持つ WoT Interactions、または 実装によって Thing Description 内で定義された FormcontentType にマッピングできる WoT Interactions には、任意の ECMAScript 値を使用できます。

この文書のアルゴリズムは、 WoT Interactions で入力データが正確にどのように使用されるかを指定します。

7.2 InteractionOutput インターフェイス

WoT Consumer 適合クラスに属します。 InteractionOutput オブジェクトは常に実装によって作成され、 WoT Interactions から返されたデータを アプリケーションスクリプトに公開します。

このインターフェイスは、IoT ユースケースの大部分をカバーするはずの便利な関数、 すなわち value() 関数を公開します。 その実装はデータを検査し、DataSchema に従う場合はそれを解析し、 そうでない場合は早期に失敗して、基盤となるストリームを乱さないままにします。 これにより、アプリケーションスクリプトが自分でストリームの読み取りを試みたり、 データを ArrayBuffer として処理したりできます。

WebIDL[SecureContext, Exposed=(Window,Worker)]
interface InteractionOutput {
  readonly attribute ReadableStream? data;
  readonly attribute boolean dataUsed;
  readonly attribute Form? form;
  readonly attribute DataSchema? schema;
  Promise<ArrayBuffer> arrayBuffer();
  Promise<DataSchemaValue> value();
};

data プロパティは、 WoT Interactions における生のペイロードを ReadableStream として表します。初期値は null です。

dataUsed プロパティは、 データストリームが disturbed されたかどうかを示します。初期値は false です。

form 属性は、 この WoT Interaction のために Thing Description から選択された Form を表します。初期値は null です。

schema 属性は、ペイロードの DataSchema([WoT-TD] で定義)を JSON オブジェクトとして表します。初期値は null です。

[[value]] 内部スロットは、解析済みの WoT Interaction の値を表します。初期値は undefined です(null は有効な値であることに注意してください)。

7.2.1 value() 関数

WoT Interaction によって返されたデータを解析し、存在する場合は相互作用の DataSchema によって記述される型、 または相互作用の FormcontentType によって記述される型の値を返します。このメソッドは 次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. this.[[value]]undefined でない場合、 promise をその値で resolveし、 停止する。
  3. this.data ReadableStream でない場合、または dataUsedtrue である場合、または formobject でない場合、または schema もしくはその typenull または undefined である場合、 promise NotReadableErrorrejectし、停止する。
  4. form.contentTypeapplication/json でなく、かつ form.contentType から [JSON-SCHEMA] へのマッピングが Protocol Bindings で利用できない場合、 promise NotSupportedErrorrejectし、停止する。
  5. reader を、data から リーダーを取得する結果とする。それが例外を throw した場合、 promise をその例外で rejectし、 停止する。
  6. bytes を、readerdata から すべての bytes を読み取る結果とする。
  7. dataUsedtrue に設定する。
  8. form.contentTypeapplication/json でなく、かつ form.contentType から [JSON-SCHEMA] へのマッピングが Protocol Bindings で利用できる場合、 そのマッピングで bytes を変換する。
  9. json を、bytes に対して bytes から JSON を解析するを実行した結果とする。それが throw した場合、 promise をその例外で rejectし、 停止する。
  10. [[value]] を、 jsonschema に対して check data schema を実行した結果に設定する。それが throw した場合、 promise をその例外で rejectし、 停止する。
  11. promise[[value]]Resolveする。

7.2.2 arrayBuffer() 関数

呼び出されたとき、次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. data ReadableStream でない場合、または dataUsedtrue である場合、 promise NotReadableErrorrejectし、停止する。
  3. reader を、data から リーダーを取得する結果とする。それが例外を throw した場合、 promise をその例外で rejectし、 停止する。
  4. bytes を、readerdata から すべての bytes を読み取る結果とする。
  5. dataUsedtrue に設定する。
  6. arrayBuffer を、内容が bytes である新しい ArrayBuffer とする。それが throw した場合、 promise をその例外で rejectし、 停止する。
  7. promisearrayBufferResolveする。

7.2.3 check data schema アルゴリズム

payloadschema に対して check data schema 手順を実行するには、
  1. typeschema.type とする。
  2. type"null" であり、 payloadnull でない場合、 TypeError を throw して停止する。そうでなければ null を返す。
  3. type"boolean" であり、 payload が falsy 値であるか、その byte length が 0 である場合は false を返し、そうでなければ true を返す。
  4. type"integer" または "number" である場合、
    1. payload が number でない場合、 TypeError を throw して停止する。
    2. form.minimum が定義されており payload がそれより小さい場合、または form.maximum が定義されており payload がそれより大きい場合、 RangeError を throw して停止する。
  5. type"string" である場合、 payload を返す。
  6. type"array" である場合、次の サブ手順を実行する:
    1. payload が array でない場合、 TypeError を throw して停止する。
    2. form.minItems が定義されており payload.length がそれ未満である場合、または form.maxItems が定義されており payload.length がそれより多い場合、 RangeError を throw して停止する。
    3. payload を、payload の各要素 itemschema.items に対して check data schema 手順を実行して得られる items の array とする。 これがいずれかの段階で throw した場合、その例外を再 throw して停止する。
  7. type"object" である場合、 次のサブ手順を実行する:
    1. payload または schema.propertiesobject でない場合、 TypeError を throw して停止する。
    2. payload 内の各 key について:
      1. proppayload[key] とする。
      2. propSchemainteraction.properties[key] とする。
      3. prop を、proppropSchema に対して check data schema 手順を実行した結果とする。 これが throw した場合、その例外を再 throw して停止する。
    3. required を、schema.required が array である場合はそれとし、そうでない場合は空 array とする。
    4. required 内の各 key について、 keypayload 内に存在しない場合、 SyntaxError を throw して停止する。
  8. payload を返す。

7.2.4 create interaction request アルゴリズム

与えられた ConsumedThing オブジェクト thing について、 sourceform および schema が与えられたときに create interaction request を行うため、次の手順を実行する:
  1. idata を新しい InteractionOutput オブジェクトとする。
  2. idata.formform に設定し、 idata.schemaschema に設定し、 |idata.datanull に設定し、 idata.[[value]]undefined に設定する。
  3. source ReadableStream オブジェクトである場合、 idata.datasource とし、 idata を返して停止する。
  4. schema およびその type が定義されており、null でない場合、次の サブ手順を実行する:
    1. type"null" であり、 source"null" でない場合、 TypeError を throw して停止する。
    2. type"boolean" であり、 source が falsy 値である場合、 idata.[[value]]false に設定し、そうでない場合は true に設定する。
    3. type"integer" または "number" であり、 source が number でない場合、または form.minimum が定義されており source がそれより小さい場合、または form.maximum が定義されており source がそれより大きい場合、 RangeError を throw して停止する。
    4. type"string" であり、 source が string でない場合、idata.[[value]] を、 source が与えられたときに JSON を bytes にシリアライズするを実行した結果とする。それが failure である場合、 SyntaxError を throw して停止する。
    5. type"array" である場合、 次のサブ手順を実行する:
      1. source が array でない場合、 TypeError を throw して停止する。
      2. lengthsource の length とする。
      3. form.minItems が定義されており length がそれ未満である場合、または form.maxItems が定義されており length がそれより多い場合、 RangeError を throw して停止する。
      4. source 内の各 item について、 itemschema schema.items とし、 item を、item, form および itemschema が与えられたときに create interaction request 手順を実行した結果とする。 これが throw した場合、その例外を再 throw して停止する。
      5. data.[[value]]source に設定する。
    6. type"object" である場合、 次のサブ手順を実行する:
      1. source が object でない場合、 TypeError を throw して停止する。
      2. schema.properties が object でない場合、 TypeError を throw して停止する。
      3. source 内の各 key について、
        1. valuesource[key] とする。
        2. propschemaproperties.interactions[key] とする。
        3. value を、value, form および propschema に対して create interaction request 手順を実行した結果とする。 これが throw した場合、その例外を再 throw して 停止する。
      4. schema.required が array である場合、required 内の各 item について、 itemsource 内の property name であるか確認する。 itemsource 内に見つからない場合、 SyntaxError を throw して停止する。
      5. data.[[value]]source に設定する。
  5. idata.data を、 idata.[[value]] internal slot をその underlying source として作成された新しい ReadableStream に設定する。
  6. idata を返す。

7.2.5 parse interaction response アルゴリズム

与えられた ConsumedThing オブジェクト thing について、 response, form および schema が与えられたときに parse interaction response を行うため、次の手順を実行する:
  1. result を新しい InteractionOutput オブジェクトとする。
  2. result.schemaschema とする。
  3. result.formform とする。
  4. result.data を、 response のペイロードデータをその underlying source とする新しい ReadableStream とする。
  5. result.dataUsedfalse とする。
  6. result を返す。

7.3 InteractionInput および InteractionOutput の使用

次の図に示されているように、 InteractionOutput インターフェイスは、実装がスクリプトにデータを提供するたびに使用され、 一方で InteractionInput は、スクリプトが実装にデータを渡すときに使用されます。

1 データを読み取るときに使用されるデータ構造

ConsumedThing がデータを読み取るとき、実装から InteractionOutput オブジェクトとしてデータを受け取ります。

ExposedThingread handler は、読み取られるデータを InteractionInput として実装に提供します。

2 データを書き込むときに使用されるデータ構造

ConsumedThing がデータを書き込むとき、それを InteractionInput として実装に提供します。

ExposedThingwrite handler は、実装から InteractionOutput オブジェクトとしてデータを受け取ります。

3 Action を呼び出すときに使用されるデータ構造

ConsumedThingAction を呼び出すとき、パラメーターを InteractionInput として提供し、Action の出力を InteractionOutput オブジェクトとして受け取ります。

ExposedThingaction handler は、実装から引数を InteractionOutput オブジェクトとして受け取り、 Action の出力を InteractionInput として実装に提供します。

7.4 エラー処理

この API のアルゴリズムは、アプリケーションスクリプトに報告されるエラーを定義します。

他方の通信エンドに報告されるエラーは、 Protocol Bindings によってマッピングされ、カプセル化されます。

4 WoT interactions におけるエラー 処理
編集者注

このトピックは Issue #200 でまだ議論されています。スクリプトエラーからプロトコルエラーへ、またその逆への マッピングの一貫性を確保するためには、標準化されたエラーマッピングが必要です。 特に、アルゴリズムが「Protocol Bindings から受け取ったエラー」と述べる場合、それは明示的なエラーマッピング アルゴリズムとして切り出される予定です。現時点では、それは実装によって カプセル化されています。

8. ConsumedThing インターフェイス

Thing を操作するためのクライアント API を表します。WoT Consumer 適合 クラスに属します。

WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing {
  constructor(ThingDescription td);
  Promise<InteractionOutput> readProperty(DOMString propertyName,
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readAllProperties(
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readMultipleProperties(
                              sequence<DOMString> propertyNames,
                              optional InteractionOptions options = {});
  Promise<undefined> writeProperty(DOMString propertyName,
                              InteractionInput value,
                              optional InteractionOptions options = {});
  Promise<undefined> writeMultipleProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});
  /*Promise<undefined> writeAllProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});*/
  Promise<InteractionOutput> invokeAction(DOMString actionName,
                              optional InteractionInput params = {},
                              optional InteractionOptions options = {});
  Promise<Subscription> observeProperty(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  Promise<Subscription> subscribeEvent(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  ThingDescription getThingDescription();
};

dictionary InteractionOptions {
  unsigned long formIndex;
  object uriVariables;
  any data;
};

[SecureContext, Exposed=(Window,Worker)]
interface Subscription {
  readonly attribute boolean active;
  Promise<undefined> stop(optional InteractionOptions options = {});
};

[SecureContext, Exposed=(Window,Worker)]
interface PropertyReadMap {
  readonly maplike<DOMString, InteractionOutput>;
};

[SecureContext, Exposed=(Window,Worker)]
interface PropertyWriteMap {
  readonly maplike<DOMString, InteractionInput>;
};

callback InteractionListener = undefined(InteractionOutput data);
callback ErrorListener = undefined(Error error);
編集者注: writeAllProperties メソッドは どこにあるのか?

writeAllProperties() メソッドは まだ議論中です。当面は、代わりに writeMultipleProperties() メソッドを使用してください。

8.1 ConsumedThing の内部スロット

ConsumedThing オブジェクトは、次の internal slots を持ちます:

内部スロット 初期値 説明(非規範的
[[td]] null ConsumedThingThing Description
[[activeSubscriptions]] {} Event を表す string name で keyed された ordered map であり、 valueSubscription オブジェクトです。
[[activeObservations]] {} Property を表す string name で keyed された ordered map であり、 valueSubscription オブジェクトです。

8.2 ConsumedThing の構築

フェッチした Thing Description を JSON オブジェクトとして取得した後、 ConsumedThing オブジェクトを作成できます。

ThingDescription td を用いて ConsumedThing を作成するには、次の手順を実行します:
  1. td に対して validate a TD 手順を実行する。 失敗した場合、 SyntaxErrorthrow して停止する。
  2. td に対して expand a TD 手順を実行する。 失敗した場合、そのエラーを再throw して停止する。
  3. thing を、新しい ConsumedThing オブジェクトとする。
  4. thing internal slot [[td]]td に設定する。
  5. thing を返す。

8.3 getThingDescription() メソッド

ConsumedThingThing Description を表す ConsumedThing オブジェクトの [[td]] を返します。 アプリケーションは、相互作用する前にその機能を内省するため、 [[td]] に格納された Thing metadata を参照できます。

8.4 readProperty() メソッド

Property 値を読み取ります。 引数として propertyName と、 任意で options を取ります。 Property 値を InteractionOutput オブジェクトとして表したもので解決される、またはエラーで拒否される Promise を返します。このメソッドは次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. interaction[[td]].properties.propertyName とする。
  4. interactionundefined の場合、 promiseNotFoundErrorrejectし、 停止する。
  5. option.formIndex が定義されている場合、 forminteraction.forms array 内の formIndex に関連付けられた Form とする。そうでない場合、 forminteraction.forms 内で opreadproperty である Form とし、実装によって選択されるものとする。
  6. form が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  7. formoptions.uriVariables に与えられた任意の URI templates を用いて、 propertyName Property の値を取得するため、 基盤となるプラットフォーム( Protocol Bindings 経由)へリクエストを行う。
  8. リクエストが失敗した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  9. response を、リクエストに対して受信した応答とする。
  10. data を、responseform および interaction に対して parse interaction response を実行した結果とする。 失敗した場合、 promiseSyntaxErrorrejectし、 停止する。
  11. promisedataResolveする。

8.5 readMultipleProperties() メソッド

1 つのリクエストで複数の Property 値を読み取ります。 引数として propertyNames と、任意で options を取ります。 このアルゴリズムによって返された値へ propertyNames のキーをマッピングする PropertyReadMap オブジェクトで解決される Promise を返します。このメソッドは次の手順を 実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. option.formIndex が定義されている場合、 form[[td]].forms array 内の formIndex に関連付けられた Form とする。そうでない場合、 form[[td]].forms array 内で opreadmultipleproperties である Form とし、 実装によって選択されるものとする。
  4. form が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  5. result を object とし、 propertyNames 内の各 string name について、 key が name で、値が null である property を追加する。
  6. formoptions' uriVariables に与えられた任意の URI templates を用いて、 propertyNames で与えられた Property 値を取得するため、 基盤となるプラットフォーム( Protocol Bindings 経由)へリクエストを行う。
  7. これを Protocol Bindings で単一のリクエストとして実行できない場合、 promise NotSupportedErrorrejectし、停止する。
  8. 応答を処理し、result 内の各 key について、 次のサブ手順を実行する:
    1. valueresult[key] とする。
    2. schemathis.[[td]].properties[key] とする。
    3. property を、valueform および schema に対して parse interaction response を実行した結果とする。
  9. 上記の手順がいずれかの時点で throw した場合、 promise をその例外で rejectし、 停止する。
  10. promiseresultResolveする。

8.6 readAllProperties() メソッド

1 つのリクエストで Thing のすべての properties を読み取ります。 任意引数として options を取ります。 このアルゴリズムによって返された値へ Property names のキーをマッピングする PropertyReadMap オブジェクトで解決される Promise を返します。このメソッドは次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. formssubscription.[[interaction]].forms とする。
  4. formsundefined の場合、 promiseSyntaxErrorrejectし、 停止する。
  5. option.formIndexundefined でなく、かつ forms.length より小さい場合、 subscription.[[form]]forms.[formIndex] に設定する。
  6. そうでない場合、 subscription.[[form]] を、 forms 内で op"readallproperties" である Form に設定し、実装によって選択されるものとする。
  7. subscription.[[form]] が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  8. formoptions.uriVariables 内の任意の URI templates を用いて、 TD からすべての Property 定義を取得するため、 Protocol Bindings を使用して基盤となるプラットフォームへリクエストを行う。
  9. ThingProtocol Bindings でこれを単一のリクエストとして実行できない場合、 promise NotSupportedErrorrejectし、停止する。
  10. リクエストが失敗した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  11. 応答を処理し、result を、応答で得られたキーと 値を持つ object とする。
  12. 応答を処理し、result 内の各 key について、 次のサブ手順を実行する:
    1. valueresult[key] とする。
    2. schemathis.[[td]].properties[key] とする。
    3. property を、valueform および schema に対して parse interaction response を実行した結果とする。
  13. promiseresultResolveする。

8.7 writeProperty() メソッド

単一の Property を書き込みます。 引数として propertyNamevalue、および 任意で options を取ります。 成功時に解決され、失敗時に拒否される Promise を返します。 このメソッドは次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. interactionthis.[[td]].properties[propertyName] とする。
  4. interactionundefined の場合、 promiseNotFoundErrorrejectし、 停止する。
  5. option.formIndexundefined でない場合、forminteraction.forms array 内の formIndex に関連付けられた Form とする。そうでない場合、forminteraction.forms 内で opwriteproperty である Form とし、 実装によって選択されるものとする。
  6. form が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  7. data を、valueform および interaction が与えられたときに create interaction request 手順を実行した結果とする。 それが throw した場合、 promise をその例外で rejectし、停止する。
  8. dataoptions' uriVariables に与えられた任意の URI templates を用いて、 propertyName で与えられた Property を書き込むため、 基盤となるプラットフォーム( Protocol Bindings 経由)へリクエストを行う。
  9. リクエストが失敗した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  10. そうでなければ、 promiseresolveする。
編集者注

Issue #193 で議論されているように、設計上の判断として、write interactions は成功またはエラーのみを返し、書き込まれた値は(任意でも)返しません。 TD は、精度や代替形式を含め、 Property 値の schema を 捕捉するべきです。相互作用から戻り値が期待される場合は、 Property の代わりに Action を使用するべきです。

8.8 writeMultipleProperties() メソッド

1 つのリクエストで複数の Property 値を書き込みます。 引数として、キーが Property names であり、値が Property values である object としての properties と、 任意で options を取ります。 成功時に解決され、失敗時に拒否される Promise を返します。このメソッドは次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. option.formIndex が定義されている場合、 form[[td]].forms array 内の formIndex に関連付けられた Form とする。そうでない場合、 form[[td]].forms array 内で opwritemultipleproperties である Form とし、 実装によって選択されるものとする。
  4. form が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  5. propertyNames を、 properties object のキーを要素とする string の array とする。
  6. propertyNames 内の各 name について、 propertythis.[[td]].properties[name] とする。
  7. propertynull または undefined である場合、または writeable でない場合、 promise NotSupportedErrorrejectし、停止する。
  8. result を object とし、 propertyNames 内の各 string name について、 key が name で、その値が null である property を追加する。
  9. schemas を object とし、 propertyNames 内の各 name について、 key が name で、その値が this.[[td]].properties[name] である property を追加する。
  10. properties 内の各 key key について、 properties[key]、form および schema[key] の値が与えられたときに create interaction request 手順を実行する。 いずれかの name についてそれが throw した場合、 promise をその例外で reject して停止する。
  11. options' uriVariables に与えられた任意の URI templates を用いて、 properties で提供される各 Property を書き込むため、 基盤となるプラットフォーム( Protocol Bindings 経由)へ単一のリクエストを行う。
  12. ThingProtocol Bindings でこれを単一のリクエストとして実行できない場合、 promise NotSupportedErrorrejectし、停止する。
  13. リクエストが失敗した場合、 Protocol Bindings から受け取ったエラーを返し、停止する。
  14. そうでなければ、 promiseresolveする。

8.9 observeProperty() メソッド

Property 値の変更 通知を要求します。引数として propertyNamelistener、および任意で onerroroptions を取ります。 成功時に解決され、失敗時に拒否される Promise を返します。
編集者注

このアルゴリズムは、各 Property ごとに有効な Subscription を 1 つだけ許可します。既存の Subscription が有効な間に新しい Subscription が作成されると、runtime は NotAllowedError を throw します。

このメソッドは次の手順を実行しなければなりません(MUST):
  1. thing を、この ConsumedThing オブジェクトの参照とする。
  2. Promise promise を返し、 次の手順を 並列に実行する。
  3. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  4. listenerFunction でない場合、 promise TypeErrorrejectし、 停止する。
  5. onerrornull でなく、かつ Function でない場合、 promise TypeErrorrejectし、 停止する。
  6. thing.[[activeObservations]][propertyName] [=map/exists] の場合、 promise NotAllowedErrorrejectし、停止する。
  7. subscription を、次のように internal slots を設定した新しい Subscription オブジェクトとする:
    • subscription.[[type]]"property" とする。
    • subscription.[[name]]propertyName とする。
    • subscription.[[interaction]][[td]].properties[propertyName] とする。
    • subscription.[[thing]]thing とする。
    • formssubscription.[[interaction]].forms とする。
    • formsundefined の場合、 promise SyntaxErrorrejectし、停止する。
    • option.formIndexundefined でなく、かつ forms.length より小さい場合、 subscription.[[form]]forms.[formIndex] に設定する。
    • そうでない場合、 subscription.[[form]]forms 内で op"observeproperty" である Form に設定し、実装によって選択されるものとする。
    • subscription.[[form]] が failure の場合、 promise SyntaxErrorrejectし、停止する。
    • subscription.[[interaction]]undefined の場合、 promise NotFoundErrorrejectし、停止する。
  8. formoptions' uriVariables に与えられた任意の URI templates を用いて、 propertyName で識別される Property を監視するため、 基盤となるプラットフォームへリクエストを行う。
  9. リクエストが失敗した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  10. thing.[[activeObservations]][|propertyName] を subscriptionSet し、 promiseresolveする。
  11. 基盤となるプラットフォームが、この subscription について propertyNamekeyed された通知を、新しい Propertyvalue とともに検出するたびに、次のサブ手順を実行する:
    • reply を、 value subscription.[[form]] および subscription.[[interaction]] を用いて parse interaction response を実行した結果とする。 それが throw した場合、 promise をその例外で rejectし、停止する。
    • reply が与えられた listener を呼び出す。
  12. 基盤となるプラットフォームがこの subscription のエラーを検出するたびに、 次のサブ手順を実行する:
    • エラーが回復不能で subscription を停止する場合、 subscription.activefalse に設定し、それ以降の 通知を抑制する。
    • error を新しい NetworkError とし、その message を基盤となるエラー条件を反映するように設定する。
    • onerrorFunction である場合、error が与えられたそれを呼び出す。

8.10 invokeAction() メソッド

Action の呼び出しを要求し、結果を返します。 引数として actionName、任意で params、および任意で options を取ります。 Action の結果を InteractionOutput オブジェクトとして表したもので解決される、またはエラーで拒否される Promise を返します。このメソッドは次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. interactionthis.[[td]].actions[actionName] とする。
  4. interactionobject でない場合、 promiseNotFoundErrorrejectし、 停止する。
  5. formssubscription.[[interaction]].forms とする。
  6. formsundefined の場合、 promiseSyntaxErrorrejectし、 停止する。
  7. option.formIndexundefined でなく、かつ forms.length より小さい場合、 subscription.[[form]]forms.[formIndex] に設定する。
  8. そうでない場合、 subscription.[[form]] を、 forms 内で op"invokeaction" である Form に設定し、実装によって選択されるものとする。
  9. subscription.[[form]] が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  10. args を、 paramsform および interaction に対して create interaction request 手順を実行した結果とする。 それが throw した場合、 promise をその例外で rejectし、停止する。
  11. argsoptions.uriVariables が与えられたときに、 actionName で識別される Action を呼び出すため、 基盤となるプラットフォーム( Protocol Bindings 経由)へリクエストを行う。
  12. リクエストがローカルで失敗するか、ネットワーク越しにエラーを返した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  13. value を、reply で返された応答とする。
  14. result を、 valueform および interaction を用いて parse interaction response を実行した結果とする。 それが throw した場合、 promise をその例外で rejectし、停止する。
  15. promiseresultResolveする。

8.11 subscribeEvent() メソッド

Event 通知への購読を要求します。 引数として eventNamelistener、および任意で onerroroptions を取ります。 成功または失敗を通知する Promise を返します。
編集者注

このアルゴリズムは、各 Event ごとに有効な Subscription を 1 つだけ許可します。既存の Subscription が有効な間に新しい Subscription が作成されると、runtime は NotAllowedError を throw します。

このメソッドは次の手順を実行しなければなりません(MUST):
  1. thing を、この ConsumedThing オブジェクトの参照とする。
  2. Promise promise を返し、 次の手順を 並列に実行する。
  3. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  4. listenerFunction でない場合、 promise TypeErrorrejectし、 停止する。
  5. onerrornull でなく、かつ Function でない場合、 promise TypeErrorrejectし、 停止する。
  6. thing.[[activeSubscriptions]][eventName] が存在しない場合、 promise NotAllowedErrorrejectし、停止する。
  7. subscription を、次のように internal slots を設定した新しい Subscription オブジェクトとする:
  8. [[form]]options.uriVariables に与えられた任意の URI templates、および options.data に与えられた任意の subscription data を用いて、 eventName で識別される Event を購読するため、 Protocol Bindings 経由で基盤となるプラットフォームへリクエストを行う。
  9. リクエストが失敗した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  10. eventNamething.[[activeSubscriptions]][eventName] から subscriptionSetする。
  11. promiseResolveする。
  12. 基盤となるプラットフォームが、 eventNamekeyed された Event subscription の通知を検出するたびに、 次のサブ手順を実行する:
    1. Event とともに提供されたデータ、 subscription.[[form]] および subscription.[[interaction]] に対して parse interaction response を実行した結果を与えて、 listener を呼び出す。
  13. 基盤となるプラットフォームが、 eventNamekeyed された Event subscription のエラーを検出するたびに、 次のサブ手順を実行する:
    • エラーが回復不能で subscription を停止する場合、 subscription.activefalse に設定し、それ以降の 通知を抑制する。
    • error を新しい NetworkError とし、その message を基盤となるエラー条件を反映するように設定する。
    • onerrorFunction である場合、error が与えられたそれを呼び出す。

8.12 InteractionOptions 辞書

Thing Description に従ってアプリケーションスクリプトに公開する必要がある interaction options を保持します。

formIndex プロパティは、定義されている場合、 与えられた WoT interaction に対して使用する TDForm 定義のうち、この index によって識別されるものについての アプリケーション hint を表します。実装は interaction を行うために この index の Form を使用するべきですが(SHOULD)、 index が見つからないか有効でない場合、この値を上書きしてもよいです(MAY)。 定義されていない場合、実装は、与えられた Wot Interaction について TD に列挙されている出現順に Form 定義を使用するよう試みるべきです(SHOULD)。

uriVariables プロパティは、定義されている場合、 [WOT-TD] で定義される 解析済み JSON オブジェクトとして表される、WoT Interaction で使用される URI template variables を表します。

編集者注

URI variables のサポートは、 Web of Things (WoT) Thing Description 1.1 仕様によって明らかにされた、それらを使用する既存の RESTful endpoints を記述できるようにする必要性に由来します。しかし、この種類の interactions を表現するために Action を使用し、 URI variables を action parameters としてモデル化する Thing Description を 書くことも可能であるべきです。その場合、実装は parameters を URI variables としてシリアライズできるため、 options parameter は不要にできます。

data プロパティは、定義されている場合、interaction に渡す必要がある追加の opaque data を表します。

8.13 PropertyReadMap

Property names から、 Property が取り得る値を表す InteractionOutput オブジェクトへの map を表します。複数の Properties が同時に関与する interactions の property bag として使用されます。

8.14 PropertyWriteMap

Property names から、 Property が取り得る値を表す InteractionInput への map を表します。複数の Properties が同時に関与する interactions の property bag として使用されます。

8.15 InteractionListener コールバック

ユーザーが提供する callback であり、型 InteractionOutput の引数が与えられ、 Property changes の監視および Event notifications の処理に使用されます。 Events への購読は WoT interactions であり、 options や data さえ取る可能性があるため、software events としてモデル化されません。

8.16 ErrorListener コールバック

ユーザーが提供する callback であり、型 Error の引数が与えられ、 Protocol Bindings から アプリケーションへ重大および非重大なエラーを伝達するために使用されます。

8.17 Subscription インターフェイス

Property change および Event interactions への subscription を表します。

active boolean プロパティは、subscription が active であるかどうか、すなわち エラーや stop() メソッドの呼び出しによって停止されていないかどうかを示します。

8.17.1 Subscription の内部スロット

Subscription オブジェクトは、次の internal slots を持ちます:
内部スロット 初期値 説明(非規範的
[[type]] null Subscription がどの WoT Interaction を参照するかを示します。値は "property""event"、または null のいずれかです。
[[name]] null Property または Event name。
[[interaction]] null WoT interaction を記述する Thing Description fragment。
[[form]] null subscription に関連付けられた Form
[[thing]] null subscription に関連付けられた ConsumedThing

8.17.2 stop() メソッド

subscription への通知の配信を停止します。 任意 parameter options を取り、 Promise を返します。呼び出されたとき、このメソッドは 次の手順を実行しなければなりません(MUST):

  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. options' の formIndex が定義されている場合、 unsubscribeForm[[interaction]]'s forms array 内の formIndex に関連付けられた Form とする。
  4. そうでない場合、unsubscribeForm [[form]] が与えられたときに find a matching unsubscribe form アルゴリズムを実行した結果とする。
  5. unsubscribeForm が failure の場合、 promiseSyntaxErrorrejectし、 停止する。
  6. [[type]] "property" である場合、 unsubscribeFormoptions' の uriVariables に与えられた任意の URI templates を用いて、 [[name]] で識別される Property の監視を停止するため、 Protocol Bindings 経由で基盤となるプラットフォームへリクエストを行う。
  7. そうでなく、[[type]]"event" である場合、 unsubscribeFormoptions' の uriVariables に与えられた任意の URI templates、および options.data に与えられた任意の unsubscribe data を用いて、 [[name]] で識別される Event の購読を解除するため、 Protocol Bindings 経由で基盤となるプラットフォームへリクエストを行う。
  8. リクエストが失敗した場合、 promiseProtocol Bindings から受け取ったエラーで rejectし、停止する。
  9. そうでなければ:
  10. 基盤となるプラットフォームがこの subscription について追加の 通知を受信した場合、実装はそれらを静かに抑制するべきです(SHOULD)。

8.17.3 購読解除 Form の検索

このアルゴリズムは開発中であり、 非規範的です。実装は、与えられた subscribe Form に一致する unsubscribe Form を検索するために、 別のアルゴリズムを選択してもよいです(MAY)。

Subscription オブジェクトのコンテキストで subscribeForm が与えられたときに、 一致する unsubscribe form を検索するには、 次の手順を実行します:
  1. results を空 array とする。
  2. [[interaction]].forms 内の各 form について、
    1. form 上に internal slot [[matchLevel]] を追加し、 その値を 0 に設定する。
    2. [[type]]"property" の場合に form.op"unobserveproperty" である場合、または [[type]]"event" の場合に form.op"unsubscribeevent" である場合、
      1. form 上の internal slot [[matchLevel]] を 1 に設定し、 formresults に追加する。
      2. form.href と [[subscribeForm]].href same origin-domain の場合、 form.[[matchLevel]] を増分する。
      3. form.contentType が [[subscribeForm]] の contentType と等しく、かつ form.[[matchLevel]] が 2 より大きい場合、 form.[[matchLevel]] を増分する。
  3. results が空の場合、 null を返し、これらの手順を終了する。
  4. results 内で最も高い [[matchLevel]] 値を持つ最初の form を返す。

8.18 ConsumedThing の例

次の例は、URL によって TD をフェッチし、 ConsumedThing を作成し、metadata(title)を読み取り、property 値を読み取り、property change に購読し、 WoT event に購読し、購読解除する方法を示します。

2: data value を用いた Thing Client API の例
try {
  let res = await fetch("https://tds.mythings.org/sensor11");
  let td = res.json();
  let thing = new ConsumedThing(td);
  console.log("Thing " + thing.getThingDescription().title + " consumed.");
} catch (e) {
  console.log("TD fetch error: " + e.message);
};

try {
  // subscribe to property change for “temperature”
  await thing.observeProperty("temperature", async (data) => {
    try {
      console.log("Temperature changed to: " + await data.value());
    } catch (error) {
      console.error("Cannot read the observed property temperature");
      console.error(error);
    }
  });
  // subscribe to the “ready” event defined in the TD
  await thing.subscribeEvent("ready", async (eventData) => {
    try {
      console.log("Ready; index: " + await eventData.value());
      // run the “startMeasurement” action defined by TD
      await thing.invokeAction("startMeasurement", { units: "Celsius" });
      console.log("Measurement started.");
    } catch (error) {
      console.error("Cannot read the ready event or startMeasurement failed");
      console.error(error)
    }
  });
} catch (e) {
  console.log("Error starting measurement.");
}

setTimeout(async () => {
  try {
    const temperatureData = await thing.readProperty("temperature")
    const temperature = await temperatureData.value();
    console.log("Temperature: " + temperature);

    await thing.unsubscribe("ready");
    console.log("Unsubscribed from the ‘ready’ event.");
  } catch (error) {
    console.log("Error in the cleanup function");
  }
}, 10000);

次に示すのは、 DataSchema なしで property を読み取るための InteractionOutput の高度な使用法です。

3: arrayBuffer を用いた Thing Client API の例
/*
* takePicture affordance form:
* "form": {
*   "op": "invokeaction",
*   "href" : "http://camera.example.com:5683/takePicture",
*   "response": {
*     "contentType": "image/jpeg",
*     "contentCoding": "gzip"
*   }
*}
* See https://www.w3.org/TR/wot-thing-description/#example-23
*/
let response;
let image;
try {
  response = await thing.invokeAction(“takePicture”));
  image = await response.value() // throws NotReadableError --> schema not defined
} catch(ex) {
  image = await response.arrayBuffer();
  // image: ArrayBuffer [0x1 0x2 0x3 0x5 0x15 0x23 ...]
}

最後に、次の 2 つの例は、 InteractionOutput からの ReadableStream の使用法を示します。

4: readable stream(例: video stream)を用いた Thing Client API の例
/*{
"video": {
  "description" : "the video stream of this camera",
  "forms": [
    {
      "op": "readproperty",
      "href": "http://camera.example.com/live",
      "subprotocol": "hls"
      "contentType": "video/mp4"
    }
  ]
}}*/

const video = await thing.readProperty("video")
const reader = video.data.getReader()
reader.read().then(function processVideo({ done, value }) {
  if (done) {
    console.log("live video stoped");
    return;
  }
  const decoded = decode(value)
  UI.show(decoded)
  // Read some more, and call this function again
  return reader.read().then(processText);
});

ここでは、JSON オブジェクトが大きすぎてメモリ内で全体を読み取れないと考えます。 したがって、リモート Web Thing によって記録された events の総数を取得するために、 streaming processing を使用します。

5: readable stream(例: counting json objects)を用いた Thing Client API の例
/*
* "eventHistory":
* {
*   "description" : "A long list of the events recorded by this thing",
*   "type": "array",
*   "forms": [
*     {
*       "op": "readproperty",
*       "href": "http://recorder.example.com/eventHistory",
*     }
*   ]
* }
*/

// Example of streaming processing: counting json objects
let objectCounter = 0
const parser = new Parser() //User library for json streaming parsing (i.e. https://github.com/uhop/stream-json/wiki/Parser)

parser.on('data', data => data.name === 'startObject' && ++objectCounter);
parser.on('end', () => console.log(`Found ${objectCounter} objects.`));

const response = await thing.readProperty(“eventHistory”)
await response.data.pipeTo(parser);

// Found N objects

9. ExposedThing インターフェイス

ExposedThing インターフェイスは、request handlers、PropertyAction、および Event interactions の定義を可能にする Thing を操作するためのサーバー API です。

WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ExposedThing {
  ExposedThing setPropertyReadHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyWriteHandler(DOMString name,
          PropertyWriteHandler handler);
  ExposedThing setPropertyObserveHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyUnobserveHandler(DOMString name,
          PropertyReadHandler handler);
  Promise<undefined> emitPropertyChange(DOMString name,
          optional InteractionInput data);

  ExposedThing setActionHandler(DOMString name, ActionHandler action);

  ExposedThing setEventSubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  ExposedThing setEventUnsubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  Promise<undefined> emitEvent(DOMString name,
          optional InteractionInput data);

  Promise<undefined> expose();
  Promise<undefined> destroy();

  ThingDescription getThingDescription();
};

callback PropertyReadHandler = Promise<InteractionInput>(
        optional InteractionOptions options = {});

callback PropertyWriteHandler = Promise<undefined>(
        InteractionOutput value,
        optional InteractionOptions options = {});

callback ActionHandler = Promise<InteractionInput>(
        InteractionOutput params,
        optional InteractionOptions options = {});

callback EventSubscriptionHandler = Promise<undefined>(
        optional InteractionOptions options = {});

9.1 ExposedThing の内部スロット

ExposedThing オブジェクトは、次の internal slots を持ちます:

内部スロット 初期値 説明(非規範的
[[td]] null ExposedThingThing Description
[[readHandlers]] {} property names をキーとし、 PropertyReadHandlers を値とする Map
[[writeHandlers]] {} property names をキーとし、 PropertyWriteHandlers を値とする Map
[[observeHandlers]] {} property names をキーとし、 PropertyReadHandlers を値とする Map
[[unobserveHandlers]] {} property names をキーとし、 Functions を値とする Map
[[actionHandlers]] {} action names をキーとし、 ActionHandlers を値とする Map
[[subscribeHandlers]] {} event names をキーとし、 EventSubscriptionHandlers を値とする Map
[[unsubscribeHandlers]] {} event names をキーとし、 EventSubscriptionHandlers を値とする Map
[[propertyObservers]] {} property names をキーとし、listeners の Array を値とする Map
[[eventListeners]] {} event names をキーとし、listeners の Array を値とする Map

9.2 ExposedThing の構築

ExposedThing インターフェイスは ConsumedThing を拡張します。 これは完全または部分的な ThingDescription オブジェクトから構築されます。

既存の ThingDescription オブジェクトは任意で変更できることに注意してください(たとえば、その propertiesactions、および events 内部 properties に要素を追加または削除することによって)。その結果のオブジェクトを ExposedThing オブジェクトの構築に使用できます。これは、PropertyAction、および Event 定義を追加および削除する現在の方法であり、 で示されています。

expose() を呼び出す前は、 ExposedThing オブジェクトは一切のリクエストを処理しないことに注意してください。これにより、まず ExposedThing を構築し、次に requests の処理を開始する前にその Properties と service handlers を初期化できます。

ExposedThingInit init を用いて ExposedThing を構築するには、次の手順を実行します:
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. init に対して expand an ExposedThingInit 手順を実行する。それが失敗した場合、 error を再throw して 停止する。そうでない場合、得られた td を保存する
  3. td に対して expand a TD 手順を実行する。 それが失敗した場合、error を再throw して停止する。
  4. thing を、新しい ExposedThing オブジェクトとする。
  5. thing[[td]]td に設定する。
  6. thing を返す。

9.3 getThingDescription() メソッド

ThingThing Description を表す ExposedThing オブジェクトの [[td]] を返します。 アプリケーションは、それと相互作用する前にその機能を内省するため、 [[td]] に格納された Thing metadata を参照できます。

9.4 PropertyReadHandler コールバック

Property を読み取る外部リクエストを受信したときに呼び出され、 そのような requests に対して何を行うかを定義する関数です。 Promise を返し、 ReadableStream オブジェクト、または DataSchema に適合する ECMAScript value で解決されるか、error で拒否されます。

9.5 setPropertyReadHandler() メソッド

引数として namehandler を取ります。 name に一致する指定された Property の読み取りリクエストを 受信したときに何を行うかを定義する service handler を設定します。 error 時に throw します。chaining をサポートするために this オブジェクトへの参照を返します。

編集者注

複数またはすべての Properties の読み取り requests を処理するために handlers を登録する必要はないことに注意してください。request と reply は単一の network request で送信されますが、 ExposedThing は単一 read handler への複数回の呼び出しを使用してそれらを実装できます。

handler callback function は Property の読み取りを実装するべきであり(SHOULD)、 基盤となるプラットフォームから Property を読み取る request が受信されたとき、 実装によって呼び出されるべきです。

任意の与えられた Property について handler は最大 1 つで なければならないため(MUST)、新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。 任意の与えられた Property について handler が 初期化されていない場合、実装は [[td]] internal slot に提供された Thing Description に基づく default property read handler を実装するべきです(SHOULD)。

namehandler が与えられてこのメソッドが呼び出されたとき、 実装は次の手順を実行しなければなりません(MUST):
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. [[td]].properties[name] が存在しない場合、 NotFoundErrorthrow して停止する。
  3. this.[[readHandlers]][name] を handler に設定する。

9.6 Property 読み取り requests の処理

Property name を読み取る network request が options とともに実装によって受信されたとき、 次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. value を、nameoptions を用いて server property を読み取る手順を実行した結果とする:
    1. interaction[[td]].properties.name とする。
    2. name を持つ Property が存在しない場合、 NotFoundError を throw して停止する。
    3. handlernull とする。
    4. interaction について [[readHandlers]] internal slot 内に、ユーザー提供の PropertyReadHandler が存在する場合、 handler をそれとする。
    5. そうでなく、実装によって提供される default read handler が存在する場合、 handler をそれとする。
    6. handlernull の場合、 NotSupportedError を throw して停止する。
    7. value を、 options を与えて handler を呼び出した結果とする。 それが失敗した場合、error を throw して停止する。
    8. value を返す。

      ここで返される value は、 DataSchema に適合するべきであるか(SHOULD)、 または handler によって作成された ReadableStream オブジェクトであるべきです(SHOULD)。

  4. 前の手順が error を throw した場合、 Protocol Bindings に従って作成された reply で error を返送し、 停止する。
  5. 返された value をシリアライズし、 Protocol Bindings に従って作成された reply に追加する。

9.7 複数 Properties の読み取り requests の処理

object propertyNames 内で与えられた複数の Properties を読み取る network request が options とともに受信されたとき、 propertyNamesoptions に対して 次の 複数 properties を読み取る手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. propertyNames に定義された key name を持つ各 property について、
    1. value を、nameoptions に対して server property を読み取る手順を実行した結果とする。 それが throw した場合、 Protocol Bindings に従って作成された reply で error を返送し、 停止する。
    2. propertyNames.namevalue に設定する。
  4. Protocol Bindings に従って propertyNames から作成された単一の reply を送信することで、 request に応答する。

9.8 すべての Properties の読み取り requests の処理

すべての Properties を読み取る network request が options とともに受信されたとき、 次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. properties を、Thing に定義された すべての properties から作成され、値が null に設定された object とする。
  4. propertiesoptions に対して 複数 properties を読み取る手順を実行する。

9.9 setPropertyObserveHandler() メソッド

引数として namehandler を取ります。 name に一致する指定された Property の観測 request を 受信したときに何を行うかを定義する service handler を設定します。 error 時に throw します。chaining をサポートするために this オブジェクトへの参照を返します。

handler callback function は Property の読み取りを実装し、 InteractionOutput オブジェクトでresolveするか、 error でrejectするべきです。

任意の与えられた Property について handler は最大 1 つで なければならないため(MUST)、新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。 任意の与えられた Property について handler が 初期化されていない場合、実装は Thing Description に基づく default property read handler を実装するべきです(SHOULD)。

namehandler が与えられてこのメソッドが呼び出されたとき、 実装は次の手順を実行しなければなりません(MUST):
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. this.[[td]].properties[name] が存在しない場合、 NotFoundErrorthrow して停止する。
  3. this[[observeHandlers]][name] を handler に設定する。

9.10 Property observe requests の処理

Property name を観測する network request が options とともに実装によって受信されたとき、 次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. this.[[td]].properties[name] が存在しない場合、 reply 内に NotFoundError を返送して停止する。
  4. Property 値の changes を通知できるようにするため、 request sender information を options および this.[[propertyObservers]][name] とともに内部的に保存する。

property の値が変化するたびに、 emitPropertyChange() は application script によって明示的に呼び出される必要があります。

9.11 setPropertyUnobserveHandler() メソッド

引数として namehandler を取ります。 name に一致する指定された Property の unobserving request を 受信したときに何を行うかを定義する service handler を設定します。 error 時に throw します。chaining をサポートするために this オブジェクトへの参照を返します。

handler callback function は、unobserve request が実装によって受信されたときに 何を行うかを実装するべきです。

任意の与えられた Property について handler は最大 1 つで なければならないため(MUST)、新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。 任意の与えられた Property について handler が 初期化されていない場合、実装は Thing Description に基づく default handler を 実装するべきです(SHOULD)。

namehandler が与えられてこのメソッドが呼び出されたとき、 実装は次の手順を実行しなければなりません(MUST):
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. this.[[td]].properties[name] が存在しない場合、 NotFoundErrorthrow して停止する。
  3. this.[[unobserveHandlers]][name] を handler に設定する。

9.12 Property unobserve requests の処理

Property name の unobserving network request が options とともに実装によって受信されたとき、 次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. this.[[td]].properties[name] が存在しない場合、 reply 内に NotFoundError を返送して停止する。
  4. handlerthis.[[unobserveHandlers]][name] とする。
  5. handlerFunction である場合、options が与えられたそれを呼び出し、 Protocol Bindings に従って reply を返送して停止する。
  6. そうでなく、 this.[[propertyObservers]][name] が存在する場合、 this.[[propertyObservers]] からそれを削除し、 Protocol Bindings で定義される reply を返送して停止する。
  7. そうでなければ、 Protocol Bindings で定義される reply 内に NotFoundError を返送して停止する。

9.13 emitPropertyChange() メソッド

Property name を示す name 引数と、 任意で data 引数を取ります。指定された Property のすべての observers に、 data 引数で提供された data による notification の発行をトリガーします。提供されない場合、 その Property に関連付けられた observe handler または read handler によって取得されます。このメソッドは 次の手順を実行しなければなりません(MUST):
  1. promise を新しい Promise とする。
  2. promise を返し、 次の手順を 並列に実行する。
  3. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  4. name を最初の 引数とする。
  5. propertythis.[[td]].properties[name] とする。
  6. propertyundefined の場合、 promiseNotFoundErrorrejectし、 停止する。
  7. data を 第 2 引数とする。
  8. dataundefined の場合、次のサブ手順を実行する:
    1. handlernull. とする。
    2. name [[readHandlers]]存在しない場合、 promisereject して停止する。
    3. handler [[readHandlers]][name] とする。
    4. handlernull または undefined の場合、 promisereject して停止する。
    5. handled を、 null が与えられた handler を呼び出した結果とする。
    6. handledrejected である場合、promise reject して停止する。
    7. そうでなく、handledvalueresolved した場合、datavalue とする。
  9. [[propertyObservers]][name] 内の各 observer について、 次のサブ手順を実行する:
    1. options を、 observer とともに保存された interaction options とする。
    2. Protocol Bindings に従って、 dataoptions から reply を作成するよう、基盤となるプラットフォームに要求する。
      編集者注

      この節は拡張が必要であり、および/または [WOT-PROTOCOL-BINDINGS] のアルゴリズムを参照する必要があります。

    3. replyobserver に送信する。
  10. promiseResolveする。

9.14 PropertyWriteHandler コールバック

Property を書き込む外部リクエストを受信したときに呼び出され、 そのような requests に対して何を行うかを定義する関数です。 引数として value を取り、 Promise を返します。これは、 handler の設定時に提供された name によって識別される Property の値が更新されたときに 解決され、property が見つからない場合または値を更新できない場合には error で拒否されます。

編集者注

この callback function 内の code は、必要に応じて古い値を把握するために、 更新前に property を読み取ることができることに注意してください。 したがって、この function には古い値は提供されません。

値は、streams のような DataSchema によって記述されていない値を 表現できるようにするため、実装によって InteractionOutput オブジェクトとして提供されます。

9.15 setPropertyWriteHandler() メソッド

引数として namehandler を取ります。 handler の設定時に与えられた name に一致する Property を書き込む request を 受信したときに何を行うかを定義する service handler を設定します。 error 時に throw します。chaining をサポートするために this オブジェクトへの参照を返します。

Issue 199 で説明されているように、readonly Properties であっても write handler を指定することが可能であることに注意してください。この場合、 write handler は、request を失敗させる方法をアプリケーション固有の方法で定義してもよいです。

任意の与えられた Property について write handler は最大 1 つでなければならないため(MUST)、 新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。 任意の与えられた Property について write handler が 初期化されていない場合、実装は Thing Description に基づいて、 Property が writeable であれば default property update を実装し、 Property が observable であれば change について observers に通知するべきです(SHOULD)。

namehandler が与えられてこのメソッドが呼び出されたとき、 実装は次の手順を実行しなければなりません(MUST):
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. this.[[td]].properties[name] が存在しない場合、 NotFoundErrorthrow して停止する。
  3. this.[[writeHandlers]][name] を handler に設定する。

9.16 Property 書き込み requests の処理

新しい値 value および options とともに、 Property name を書き込む network request が受信されたとき、 実装は、namevalueoptions が与えられ、 mode"single" に設定された 次の property を更新する 手順を実行しなければなりません(MUST):
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. interactionthis.[[td]].properties[name] とする。
  4. interactionundefined の場合、 reply 内に NotFoundError を返して停止する。
  5. handler this.[[writeHandlers]][name] とする。
  6. handlerundefined であり、かつ実装によって提供される default write handler が存在する場合、 handler をそれとする。
  7. handler undefined の場合、reply とともに NotSupportedError を返送して停止する。
  8. promise を、 name および options が与えられた handler を呼び出した結果とする。 失敗した場合、 reply 内に error を返して停止する。
  9. mode"single" の場合、 Protocol Bindings に従って、成功を報告して request に応答し、停止する。

9.17 複数 Properties の書き込み requests の処理

object propertyNames 内で与えられた複数の Properties を書き込む network request が options とともに受信されたとき、 次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. propertyNames に定義された key name および value value を持つ各 property について、 namevalueoptions が与えられ、 mode"multiple" に設定された property を更新する 手順を実行する。それが失敗した場合、その error で request に応答し、停止する。
  4. Protocol Bindings に従って単一の reply を送信することで、 request に応答する。

9.18 ActionHandler コールバック

Action を呼び出す外部 request を 受信したときに呼び出され、そのような requests に対して何を行うかを定義する関数です。 params が与えられて呼び出され、 任意で options object とともに呼び出されます。 error で拒否されるか、 Action によって返された値を InteractionInput として解決する Promise を返します。

Application scripts は ActionHandler から ReadableStream オブジェクトを返してもよいです(MAY)。 実装はその場合、stream を使用して Action の response を構築します。

9.19 setActionHandler() メソッド

引数として nameaction を取ります。 name に一致する Action を呼び出す request を受信したときに何を行うかを定義する handler function を設定します。error 時に throw します。 chaining をサポートするために this オブジェクトへの参照を返します。

action callback function は Action を実装し、 基盤となるプラットフォームから Action を呼び出す request を 受信したとき、実装によって呼び出されるべきです(SHOULD)。

任意の与えられた Action について handler は最大 1 つでなければならないため(MUST)、 新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。

nameaction が与えられてこのメソッドが呼び出されたとき、 次の手順を実行します:
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. interactionthis.[[td]].actions[name] とする。
  3. interactionundefined の場合、 NotFoundErrorthrow して停止する。
  4. this.[[actionHandlers]][name] を action に設定する。

9.20 Action requests の処理

inputs と任意で options が与えられて、 name で識別される Action を呼び出す network request が受信されたとき、 次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. interactionthis.[[td]].properties[name] とする。
  4. interactionundefined の場合、 reply 内に NotFoundError を返して停止する。
  5. handler this.[[actionHandlers]][name] とする。
  6. handler undefined の場合、 Protocol Bindings に従って作成された reply とともに NotSupportedError を返して停止する。
  7. promise を、 nameinputs、および options が与えられた handler を呼び出した結果とする。
  8. promise が rejects した場合、reply とともに error を送信して停止する。
  9. promisedata で resolves したとき、 Protocol Bindings に従って reply を作成して送信するために data を使用する。

9.21 EventSubscriptionHandler コールバック

Event に購読する外部 request を 受信したときに呼び出され、そのような requests に対して何を行うかを定義する関数です。 実装によって提供され、subscribers から来る options object が与えられて呼び出されます。 error で拒否されるか、subscription が受け入れられたときに解決する Promise を返します。

9.22 setEventSubscribeHandler() メソッド

引数として namehandler を取ります。 name に一致する指定された Event に対する subscription request を受信したときに何を行うかを定義する handler function を設定します。error 時に throw します。 chaining をサポートするために this オブジェクトへの参照を返します。

handler callback function は、 subscribe request が受信されたときに何を行うか、たとえば必要な initializations を実装するべきです(SHOULD)。 Events を発行するための handler は 別個に設定されることに注意してください。

任意の与えられた Event について event subscribe handler は最大 1 つでなければならないため(MUST)、 新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。

namehandler が与えられてこのメソッドが呼び出されたとき、 次の手順を実行します:
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. interactionthis.[[td]].events[name] とする。
  3. interactionundefined の場合、 NotFoundErrorthrow して停止する。
  4. this.[[subscribeHandlers]][name] を handler に設定する。
  5. this を返す。

9.23 Event subscribe requests の処理

name についての Event subscription request が、任意の options とともに 基盤となるプラットフォームによって受信されたとき、次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. interactionthis.[[td]].events[name] とする。
  4. interactionundefined の場合、 NotFoundError を返送して停止する。
  5. this.[[subscribeHandlers]][name] が Function である場合、 options が与えられたそれを呼び出し、停止する。
  6. そうでなければ default subscriber mechanism を実装する:
    1. subscriber を、 options (そこから uriVariablesdata を使用してもよい)と、 Event notification response を作成するために必要な subscriber information からなる tuple とする。
    2. this.[[eventListeners]][name] を subscriber に設定する。

9.24 setEventUnsubscribeHandler() メソッド

引数として namehandler を取ります。 name に一致する指定された Event が購読解除されたときに何を行うかを定義する handler function を設定します。error 時に throw します。 chaining をサポートするために this オブジェクトへの参照を返します。

handler callback function は、 unsubscribe request が受信されたときに何を行うかを 実装するべきです(SHOULD)。

任意の与えられた Event について handler は最大 1 つで なければならないため(MUST)、 新しく追加された handlers は以前の handlers を置き換えなければなりません(MUST)。

namehandler が与えられてこのメソッドが呼び出されたとき、 次の手順を実行します:
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. interactionthis.[[td]].events[name] とする。
  3. interactionundefined の場合、 NotFoundErrorthrow して停止する。
  4. this.[[unsubscribeHandlers]][name] を handler に設定する。
  5. this を返す。

9.25 Event unsubscribe requests の処理

name についての Event unsubscribe request が、任意で options とともに 基盤となるプラットフォームによって受信されたとき、次の手順を実行します:
  1. この operation がサポートされていない場合、 Protocol Bindings に従って NotSupportedError を返送して停止する。
  2. この operation が許可されていない場合、 Protocol Bindings に従って NotAllowedError を返送して停止する。
  3. interactionthis.[[td]].events[name] とする。
  4. interactionundefined の場合、 NotFoundError を返送して停止する。
  5. this.[[unsubscribeHandlers]][name] が存在し、 かつ Function である場合、 options が与えられたそれを呼び出し、停止する。
  6. そうでなく、namethis.[[eventListeners]] 内に [=map/exists] する場合、 nameremove する。
  7. this を返す。

9.26 Events の処理

name name を持つ Event が、emitEvent() メソッドによって data とともに発行されたとき、 次の手順を実行します:
  1. listeners[[eventListeners]].name とする。
  2. listeners 内の各 subscriber について、 次のサブ手順を実行する:
    1. datasubscriber(その options を含む)から、 Protocol Bindings に従って Event notification response を作成する。
    2. dataundefined の場合、notification responseProtocol Bindings によって指定されるとおり、空の data payload を含むと仮定する。
    3. 基盤となる protocol stack が event errors の伝達を許可し、 かつ UA によって error condition が検出された場合、 Protocol Bindings に従い、 datasubscriber およびその options を使用して、 response を error notification として作成する。

      error reporting は protocol specific であり、実装によってカプセル化されます。client 側では、 client UA が error を検出した場合、subscription とともに渡された error listener が呼び出されます。

    4. subscriber によって識別される subscriber に response を送信する。

9.27 emitEvent() メソッド

Event name を示す name と、 任意で data を引数として取ります。 任意の data とともに Event を発行することをトリガーします。このメソッドは 次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. interaction[[td]].events.name とする。
  4. name という name を持つ Event が見つからない場合、 promiseNotFoundErrorrejectし、 停止する。
  5. 任意の data とともに Event を発行するため、 基盤となるプラットフォームへリクエストを行う。 events の処理手順を呼び出す。

9.28 expose() メソッド

Thing に対する外部 requests の処理を開始し、 PropertiesActions、および Events を使用する WoT Interactions を可能にします。このメソッドは 次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. [[td]] に対して expand a TD 手順を実行する。
  4. [[td]] に対して validate a TD を実行する。 それが失敗した場合、 promise TypeErrorrejectし、 停止する。
  5. [[td]].properties 内の各 key について、 value changes について observers に通知するために必要な observe request data を格納するため、 this.[[propertyObservers]].key を空の Array に初期化する。
  6. this.[[td]].events 内の各 key について、 event emission について subscribers に通知するために必要な subscribe request data を格納するため、 this.[[eventListeners]].key を空の Array に初期化する。
  7. [WOT-TD] および [WOT-PROTOCOL-BINDINGS] で説明されるとおり、 [[td]] を内省することに基づいて WoT Interactions を設定する。基盤となるプラットフォームに Protocol Bindings を初期化するよう要求し、次に Protocol Bindings に基づいて、 WoT InteractionsProperties の read、write、observe、 Actions の invoke、および Event subscriptions の管理) に対する外部 requests の処理を開始する。 実装は任意の理由でこの手順を reject してもよいです(MAY) (例: interaction forms に対して追加の checks と constraints を強制したい場合)。
  8. request 中に error があった場合、 promise Error object errorrejectし、 error.messageProtocol Bindings によって見られた error code に設定して停止する。
  9. そうでなければ、 promiseresolve して停止する。

9.29 destroy() メソッド

Thing に対する外部 requests の処理を停止し、オブジェクトを破棄します。 最終的な unregistering は、このメソッドを呼び出す前に行われるべきであることに注意してください。 このメソッドは次の手順を実行しなければなりません(MUST):
  1. Promise promise を返し、 次の手順を 並列に実行する。
  2. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 promiseSecurityErrorrejectし、 停止する。
  3. Protocol Bindings に基づいて、 WoT Interactions に対する外部 requests の処理を停止するため、 基盤となるプラットフォームへリクエストを行う。
  4. request 中に error があった場合、 promise Error object errorrejectし、 その messageProtocol Bindings によって見られた error code に設定して停止する。
  5. そうでなければ、 promiseresolve して停止する。

9.30 ExposedThing の例

次の例は、事前に構築された部分的な TD object に基づいて ExposedThing を作成する方法を示します。

6: 単純な Property を用いた ExposedThing の作成
try {
  let temperaturePropertyDefinition = {
    type: "number",
    minimum: -50,
    maximum: 10000
  };
  let tdFragment = {
    properties: {
      temperature: temperaturePropertyDefinition
    },
    actions: {
      reset: {
        description: "Reset the temperature sensor",
        input: {
          temperature: temperatureValueDefinition
        },
        output: null,
        forms: []
      },
    },
    events: {
      onchange: temperatureValueDefinition
    }
  };
  let thing1 = await WOT.produce(tdFragment);
  // initialize Properties
  await thing1.writeProperty("temperature", 0);
  // add service handlers
  thing1.setPropertyReadHandler("temperature", () => {
     return readLocalTemperatureSensor();  // Promise
  });
  // start serving requests
  await thing1.expose();
} catch (err) {
   console.log("Error creating ExposedThing: " + err);
}

次の例は、既存の ExposedThing 上で Property 定義を追加または変更する方法を示します: その td property を取得し、追加または変更してから、 それを用いて別の ExposedThing を作成します。

7: object Property の追加
try {
  // create a deep copy of thing1's TD
  let instance = JSON.parse(JSON.stringify(thing1.td));
  const statusValueDefinition = {
    type: "object",
    properties: {
      brightness: {
        type: "number",
        minimum: 0.0,
        maximum: 100.0,
        required: true
      },
      rgb: {
        type: "array",
        "minItems": 3,
        "maxItems": 3,
        items : {
            "type" : "number",
            "minimum": 0,
            "maximum": 255
        }
      }
  };
  instance["name"] = "mySensor";
  instance.properties["brightness"] = {
    type: "number",
    minimum: 0.0,
    maximum: 100.0,
    required: true,
  };
  instance.properties["status"] = statusValueDefinition;
  instance.actions["getStatus"] = {
    description: "Get status object",
    input: null,
    output: {
      status : statusValueDefinition;
    },
    forms: [...]
  };
  instance.events["onstatuschange"] = statusValueDefinition;
  instance.forms = [...];  // update
  var thing2 = new ExposedThing(instance);
  // TODO: add service handlers
  await thing2.expose();
  });
} catch (err) {
   console.log("Error creating ExposedThing: " + err);
}

以下では、 expand an ExposedThingInit 手順を使用して、 ExposedThingInit から Thing Description を生成する一連の例を扱います。仮定として、runtime は HTTP および COAP protocol bindings をサポートし、192.168.0.1 でホストされています。

次の例は、 ExposedThingInit を活用して、default values を持つ 1 つの Property を備えた単純な Thing Description を作成する方法を示します。

編集者注

TODO: ExposedThingInit が、algorithm によって置き換えられる suggested values を含む例をさらに追加する。

10. ThingDiscoveryProcess インターフェイス

Discovery は、参加する network nodes (clients、servers、directory services)からの provisioning と support を必要とする分散アプリケーションです。この API は、さまざまな IoT deployments によってサポートされる典型的な discovery schemes の client 側をモデル化します。

ThingDiscoveryProcess オブジェクトは、discovery process を制御し、結果を返す properties と methods を提供します。

WebIDL[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscoveryProcess {
  constructor(optional ThingFilter filter = {});
  readonly attribute boolean done;
  readonly attribute Error? error;
  undefined stop();
  async iterable<ThingDescription>;
};

ThingDiscoveryProcess オブジェクトは、次の internal slots を持ちます。

内部スロット 初期値 説明(非規範的
[[filter]] undefined discovery で使用される ThingFilter オブジェクト。
[[url]] undefined discovery における TD Directory を表す URL

done property は、discovery が停止されているか、報告すべき結果が もうなく完了している場合に true です。

error property は、discovery process 中に発生した最後の error を表します。通常、discovery を停止する重大な errors に 使用されます。

ThingDiscoveryProcess オブジェクトは async iterator 概念を実装します。

10.1 ThingDiscoveryProcess の構築

filter を用いて ThingDiscoveryProcess を作成するには、次の手順を実行します:
  1. filter が object または null でない場合、 TypeErrorthrowして 停止する。
  2. discovery を新しい ThingDiscoveryProcess オブジェクトとする。
  3. discovery.[[filter]]filter に設定する。
  4. discovery.donefalse に設定する。
  5. discovery.errornull に設定する。
  6. discovery を返す。

10.2 ThingFilter dictionary

Things を発見するための制約を key-value pairs として含む object を表します。

WebIDLdictionary ThingFilter {
  object? fragment;
  
};

fragment property は、発見された Things に対して property ごとに照合するために 使用される template object を表します。

編集者注

query property は、WoT Discovery task force で標準化されるまで、 ThingFilter から一時的に削除されました。これは、実装によって受け入れられる query string、たとえば SPARQL または JSON query を表していました。 Support は WoT Runtime 内でローカルに、 または TD Directory 内の service として リモートに実装される予定でした。

編集者注

url property は削除されました。これは、discovery request を処理する target entity、たとえば TD Directory の URL、または直接対象とされた Thing の URL を 表していましたが、現在これらは専用の methods によって実装されています。

10.3 discovery process アルゴリズム

すでに開始された discovery process の間に何を行うかを記述します。 discovery が与えられたこの algorithm は、 次の手順を実行します:
  1. Thing Description への新しい link が発見され、基盤となるプラットフォームによって 提供されるたびに、次のサブ手順を実行する:
    1. 基盤となる discovery process によって使用される Protocol Bindinglink によって指定される)を使用して、 td を JSON object として取得する。 HTTP(S) Binding の場合、この process は td の取得に Fetch API を使用できます。
    2. それが失敗した場合、discovery.error property を SyntaxError に設定し、td を破棄して discovery process を続行する。
  2. Thing Description td が発見され、 基盤となるプラットフォームまたは前の手順によって提供されるたびに、 次のサブ手順を実行する:

    この時点で実装は、discovery process の flow を制御してもよいです(MAY) (たとえば memory constraints に応じて、結果を queue に入れる、 queue が大きくなりすぎた場合に discovery を一時的に停止する、 または queue が十分に空になったときに discovery を再開するなど)。 これらの手順は、発見/取得された各 td に対して実行されます。

    1. fragmentdiscovery.[[filter]].fragment とする。
    2. fragmentobject である場合、その中で定義された各 key について:
      1. その keyjson 内に 存在する か、および json[key fragment.key と等しいかを確認する。
      2. いずれかの checks でこれが失敗した場合、 td を破棄し、 discovery process を続行する。
    3. asyncIterator を使用して td を yield する。
      編集者注

      適切な asyncIterator terminology を使用して この手順を改善する。

  3. discovery process 中に error が発生するたびに、 次のサブ手順を実行する:

    最後の error が保持されます。 実装は、それを報告すべきだと判断した場合、 discovery process を停止することを選択してもよいです(MAY)。

    1. error を新しい Error object とする。 error.name"DiscoveryError" に設定する。
    2. Protocol Bindings によって error code または message が提供されていた場合、 error.message をその値の string に設定する。
    3. discovery.errorerror に設定する。
    4. error が回復不能であり、基盤となるプラットフォームによって discovery が 停止されている場合、または実装が discovery process を停止して error を報告することを決定した場合、 discovery.donetrue に設定し、これらの手順を終了する。

10.4 stop() メソッド

discovery process を停止または抑制します。これはすべての discovery methods および endpoints によってサポートされるとは限りませんが、 以後の discovery results または errors は破棄され、 discovery は done としてマークされます。このメソッドは次の手順を実行しなければなりません(MUST):
  1. セキュリティ上の理由により、現在のスクリプティングコンテキストで このメソッドの呼び出しが許可されていない場合、 SecurityErrorthrow して停止する。
  2. discovery process を停止するよう基盤となるプラットフォームに要求する。 これが error を返す場合、またはたとえば discovery が open ended multicast requests に基づく場合のように不可能な場合、 実装は以後の discovered items を破棄するべきです(SHOULD)。
  3. done property を true に設定する。

10.5 Discovery の例

次の例は、local hardware によって公開される Things の ThingDescription objects を、実行されている WoT Runtime の instances の数にかかわらず見つけます。Discovery object によって提供される asyncIterator を使用して、結果を非同期に反復し、 得られた ThingDescription objects で operations を実行できます。

9: Thing の Thing Description を取得する
let url = "https://mythings.com/thing1";
let td = await WOT.requestThingDescription(url);
console.log("Found Thing Description for " + td.title);

次の例は、TD Directory service に listed された Things の ThingDescription objects を見つけます。安全のため timeout を設定します。

10: directory 経由で Things を発見する
let discovery = await WOT.exploreDirectory("http://directory.wotservice.org");
setTimeout( () => {
    discovery.stop();
    console.log("Discovery stopped after timeout.");
  },
  3000);
for await (const td of discovery) {
  console.log("Found Thing Description for " + td.title);
  let thing = new ConsumedThing(td);
  console.log("Thing name: " + thing.getThingDescription().title);
};
if (discovery.error) {
  console.log("Discovery stopped because of an error: " + error.message);
}

次の例は、WOT runtime に provisioned された任意の手段による generic discovery のためのもので、利用可能な場合は local Things も含みます。

11: network 内の Things を発見する
let discovery = await WOT.discover();
setTimeout( () => {
    discovery.stop();
    console.log("Stopped open-ended discovery");
  },
  10000);
for await (const td of discovery) {
  console.log("Found Thing Description for " + td.title);
};
if (discovery.error) {
  console.log("Discovery stopped because of an error: " + error.message);
}

11. Security and Privacy

さまざまな状況に適応できる threat model を含む、 Web of Things の security and privacy considerations についての詳細な議論は、 参考情報文書 [WOT-SECURITY] で提示されています。この section では、scripts および WoT Scripting API に直接関連する security and privacy risks と possible mitigations のみを議論します。

WoT devices and services の security を改善するための best practices の推奨セットは [WOT-SECURITY] に文書化されています。その文書は security measures の進化に応じて更新される可能性があります。 これらの practices に従っても security が保証されるわけではありませんが、 一般に知られている vulnerabilities を回避する助けになる可能性があります。

WoT security risks と possible mitigations は、 次の groups に関係します:

11.1 Scripting Runtime Security and Privacy Risks

この section は規範的であり、WoT Scripting Runtime に関連する specific risks を含みます。

11.1.1 Corrupted Input Security and Privacy Risk

任意の process を侵害する典型的な方法は、公開された interfaces のいずれかを介して corrupted input を送信することです。これは、script instance が公開する WoT interface を使用して行うことができます。

Mitigation:
この API の実装者は、すべての script inputs に対して validation を実行するべきです(SHOULD)。 input validation に加えて、input processing が正しく行われていることを検証するために fuzzing を使用するべきです。そのような validation を行うための tools や techniques は 多数存在します。詳細は [WOT-SECURITY] にあります。

11.1.2 Physical Device Direct Access Security and Privacy Risk

script が侵害されたり不正に動作したりした場合、script が直接公開された native device interfaces を使用できると、基盤となる physical device (および潜在的には周囲の environment)が損傷する可能性があります。 そのような interfaces が inputs に対する safety checks を欠く場合、 基盤となる physical device(または environment)を unsafe state(すなわち device が過熱して爆発する)にする可能性があります。

Mitigation:
WoT Scripting Runtime は、native device interfaces を script developers に直接公開することを避けるべきです(SHOULD)。 代わりに、WoT Scripting Runtime は native device interfaces にアクセスするための hardware abstraction layer を提供するべきです。 そのような hardware abstraction layer は、device(または environment)を unsafe state に置く可能性のある commands の実行を拒否するべきです。 さらに、script が侵害された場合に physical WoT device への損害を軽減するため、 特定の script に公開またはアクセス可能な interfaces の数を、 その機能に基づいて最小化することが重要です。

11.1.3 Provisioning and Update Security Risk

WoT Scripting Runtime が、製造後の scripts、WoT Scripting Runtime または関連 data(security credentials を含む)の provisioning や updates をサポートする場合、 それは major attack vector になり得ます。attacker は update または provisioning process 中に上記の要素のいずれかを変更しようとしたり、 単に attacker の code と data を直接 provision したりできます。

Mitigation:
scripts、WoT Scripting Runtime、または関連 data の製造後の provisioning または update は、安全な方法で行われるべきです。 secure update および post-manufacturing provisioning に関する recommendations のセットは [WOT-SECURITY] にあります。

11.1.4 Security Credentials Storage Security and Privacy Risk

通常、WoT Scripting Runtime は、WoT network で動作するために WoT device に provisioned された security credentials を保存する必要があります。 attacker がこれらの credentials の confidentiality または integrity を侵害できる場合、 WoT assets への access を取得し、WoT things または devices になりすまし、 または Denial-Of-Service (DoS) attacks を作成できます。

Mitigation:
WoT Scripting Runtime は、provisioned security credentials を安全に保存し、 その integrity と confidentiality を保証するべきです。1 つの WoT-enabled device 上に 複数の tenant が存在する場合、WoT Scripting Runtime は、各 tenant の provisioned security credentials の isolation を保証するべきです。 さらに、provisioned security credentials が侵害される risk を最小限にするため、 WoT Scripting Runtime は scripts が provisioned security credentials を照会するための API を一切公開するべきではありません。

11.2 Script Security and Privacy Risks

この section は非規範的です。

この section は、script developers に関連する specific risks を記述します。

11.2.1 Corrupted Script Input Security and Privacy Risk

script instance は、TD によって定義された data formats、または applications によって定義された data formats を受信する可能性があります。WoT Scripting Runtime は TD によって定義された すべての input fields に対して validation を実行するべきですが(SHOULD)、 scripts は依然として input data によって exploited される可能性があります。

Mitigation:
Script developers は、すべての application defined script inputs に対して validation を実行するべきです。input validation に加えて、input processing が正しく行われていることを検証するために fuzzing を使用できます。そのような validation を行うための tools や techniques は 多数存在します。詳細は [WOT-SECURITY] にあります。

11.2.2 Denial Of Service Security Risk

script が、request が認証される前に受信 requests に対して重い functional processing を行う場合、Denial-Of-Service (DOS) attacks に対して大きな risk となります。

Mitigation:
Scripts は、requestor の事前の成功した authentication なしに重い functional processing を行うことを避けるべきです。推奨される authentication mechanisms のセットは [WOT-SECURITY] にあります。

A. API 設計の根拠

API rationale は通常、別の文書に属しますが、WoT の場合、 context の複雑さにより、基本的な rationale をここに含めることが正当化されます。

A.1 WoT application development へのアプローチ

WoT Interest Group と Working Group は、WoT における application development への さまざまなアプローチを検討してきており、それらはすべて実装およびテストされています。

A.1.1 Scripting API なし

WoT network interface のみを使用する WoT applications を開発することは可能です。 これは通常、clients に対して RESTful API を提示し、サポートされた IoT deployments と通信する IoT protocol plugins を実装する WoT gateway によって公開されます。 そのような実装の 1 つが Mozilla WebThings platform です。

A.1.2 Simple Scripting API

WoT Things は software objects と良好な synergy を示すため、 Thing は software object として表現でき、 Properties は object properties として、Actions は methods として、 Events は events として表現できます。さらに、metadata は special properties に格納されます。 Consuming と exposing は、remote Thing とその interactions を直接表す software object を生成する factory methods で行われます。 そのような実装の 1 つが Arena Web Hub project です。

次の例では、lock との interactions を表す Thing は 次のようになります: status property と open() method が object 上で直接公開されます。

12: simple API で lock を開く
let lock = await WoT.consume(‘https://td.my.com/lock-00123’);
console.log(lock.status);
lock.open('withThisKey');

A.1.3 Web of Things (WoT) Thing Description 1.1 仕様と整合したこの API

Things から software objects への直接 mapping には いくつかの課題があったため、この仕様では、software objects を公開して Thing metadata を data property として、WoT interactions を methods として表す別の approach を採ります。実装の 1 つが node-wot であり、これは Eclipse ThingWeb project に含まれ、この文書で指定される API の現在の reference implementation です。

同じ例は現在、次のようになります: status property と open() method は間接的に表現されます。

13: lock を開く
let res = await fetch(‘https://td.my.com/lock-00123’);
let td = await res.json();
let lock = new ConsumedThing(td);
console.log(lock.readProperty(‘status’));
lock.invokeAction(‘open’, 'withThisKey');

結論として、WoT WG は Web of Things (WoT) Thing Description 1.1 仕様に密接に従う第 3 の option を検討することを決定しました。 これに基づいて、simple API も実装できます。Scripting は WoT における optional module であるため、WoT network interface のみを使用する applications の余地が残されます。 したがって、上記 3 つの approaches はすべて Web of Things (WoT) Thing Description 1.1 仕様によってサポートされます。

さらに、WoT network interface は、多くの languages と runtimes で実装できます。 この API は、WoT のための Scripting API を設計する際に考慮する必要があることの example と考えてください。

A.2 TD の取得と検証

fetch(url) method は、この API の以前の versions に含まれていました。 しかし現在、URL が与えられた TD の取得は、 Fetch API や HTTP client library などの外部 method で行うべきです。これらは、fetch details の指定に関する すでに標準化された options を提供します。その理由は、simple fetch operations(ほとんどの use cases をカバーする)はこの API で行えたとしても、 さまざまな fetch options が必要になった場合に、既存の work を重複して この API でそれらの options を再公開する意味がなかったためです。

TD の取得は scoped out されており、 TD validation も Web of Things (WoT) Thing Description 1.1 仕様で外部的に定義されるため、これも scoped out されています。この仕様は、 Web of Things (WoT) Thing Description 1.1 仕様に従って検証された parsed JSON object としての TD を 期待します。

A.3 Factory と constructors

Things を consume および expose するための factory methods は非同期であり、input TD を完全に検証します。さらに、 parsed かつ validated された TD を提供することで、 ConsumedThing および ExposedThing も構築できます。Platform initialization は、その後 WoT interactions 中に必要に応じて行われます。

A.4 Observers

以前の drafts では Observer construct が使用されていましたが、標準になっていないため、embedded implementations に十分軽量な新しい design が必要でした。したがって、 Property changes の observing と WoT Events の処理は callback registrations で行われます。

A.5 Events の使用

この API は最終的に software events を一切使用しませんでした。その理由は次のとおりです:
  • WoT Events への subscription は、 software events の処理とは異なる可能性があります(subscription が parameters を必要としたり、security tokens などを伴ったりする可能性があります)。
  • ほとんどの実装は Node.js 用であり、browser implementations は native implementations での dependency management issues の可能性から、 libraries になる可能性が高く、Events の使用は困難でした。
  • Property changes の observing と WoT Events の処理は、 上記の solution で行われます。

A.6 Polymorphic functions

generic polymorphic な read() function ではなく、 readProperty()readMultipleProperties() などの function names を使用する理由は、 現在の names が Web of Things (WoT) Thing Description 1.1 仕様の Form 定義に由来する "op" vocabulary に正確に対応するためです。

B. 変更点

以下は、この文書に対する主要な変更の一覧です。 この仕様の major versions は次のとおりです:

変更の完全な一覧については、github change log を参照してください。 最近 close された issues も確認できます。

C. 完全な Web IDL

WebIDLtypedef object ThingDescription;

[SecureContext, Exposed=(Window,Worker)]
namespace WOT {
  // methods defined in UA conformance classes
};

partial namespace WOT {
  Promise<ConsumedThing> consume(ThingDescription td);
};

typedef object ExposedThingInit;

partial namespace WOT {
  Promise<ExposedThing> produce(ExposedThingInit init);
};

partial namespace WOT {
  Promise<ThingDiscoveryProcess> discover(optional ThingFilter filter = {});
};

partial namespace WOT {
  Promise<ThingDiscoveryProcess> exploreDirectory(USVString url,
      optional ThingFilter filter = {});
};

partial namespace WOT {
  Promise<ThingDescription> requestThingDescription(USVString url);
};

typedef any DataSchemaValue;
typedef (ReadableStream or DataSchemaValue) InteractionInput;

[SecureContext, Exposed=(Window,Worker)]
interface InteractionOutput {
  readonly attribute ReadableStream? data;
  readonly attribute boolean dataUsed;
  readonly attribute Form? form;
  readonly attribute DataSchema? schema;
  Promise<ArrayBuffer> arrayBuffer();
  Promise<DataSchemaValue> value();
};

[SecureContext, Exposed=(Window,Worker)]
interface ConsumedThing {
  constructor(ThingDescription td);
  Promise<InteractionOutput> readProperty(DOMString propertyName,
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readAllProperties(
                              optional InteractionOptions options = {});
  Promise<PropertyReadMap> readMultipleProperties(
                              sequence<DOMString> propertyNames,
                              optional InteractionOptions options = {});
  Promise<undefined> writeProperty(DOMString propertyName,
                              InteractionInput value,
                              optional InteractionOptions options = {});
  Promise<undefined> writeMultipleProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});
  /*Promise<undefined> writeAllProperties(
                              PropertyWriteMap valueMap,
                              optional InteractionOptions options = {});*/
  Promise<InteractionOutput> invokeAction(DOMString actionName,
                              optional InteractionInput params = {},
                              optional InteractionOptions options = {});
  Promise<Subscription> observeProperty(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  Promise<Subscription> subscribeEvent(DOMString name,
                              InteractionListener listener,
                              optional ErrorListener onerror,
                              optional InteractionOptions options = {});
  ThingDescription getThingDescription();
};

dictionary InteractionOptions {
  unsigned long formIndex;
  object uriVariables;
  any data;
};

[SecureContext, Exposed=(Window,Worker)]
interface Subscription {
  readonly attribute boolean active;
  Promise<undefined> stop(optional InteractionOptions options = {});
};

[SecureContext, Exposed=(Window,Worker)]
interface PropertyReadMap {
  readonly maplike<DOMString, InteractionOutput>;
};

[SecureContext, Exposed=(Window,Worker)]
interface PropertyWriteMap {
  readonly maplike<DOMString, InteractionInput>;
};

callback InteractionListener = undefined(InteractionOutput data);
callback ErrorListener = undefined(Error error);

[SecureContext, Exposed=(Window,Worker)]
interface ExposedThing {
  ExposedThing setPropertyReadHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyWriteHandler(DOMString name,
          PropertyWriteHandler handler);
  ExposedThing setPropertyObserveHandler(DOMString name,
          PropertyReadHandler handler);
  ExposedThing setPropertyUnobserveHandler(DOMString name,
          PropertyReadHandler handler);
  Promise<undefined> emitPropertyChange(DOMString name,
          optional InteractionInput data);

  ExposedThing setActionHandler(DOMString name, ActionHandler action);

  ExposedThing setEventSubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  ExposedThing setEventUnsubscribeHandler(DOMString name,
          EventSubscriptionHandler handler);
  Promise<undefined> emitEvent(DOMString name,
          optional InteractionInput data);

  Promise<undefined> expose();
  Promise<undefined> destroy();

  ThingDescription getThingDescription();
};

callback PropertyReadHandler = Promise<InteractionInput>(
        optional InteractionOptions options = {});

callback PropertyWriteHandler = Promise<undefined>(
        InteractionOutput value,
        optional InteractionOptions options = {});

callback ActionHandler = Promise<InteractionInput>(
        InteractionOutput params,
        optional InteractionOptions options = {});

callback EventSubscriptionHandler = Promise<undefined>(
        optional InteractionOptions options = {});

[SecureContext, Exposed=(Window,Worker)]
interface ThingDiscoveryProcess {
  constructor(optional ThingFilter filter = {});
  readonly attribute boolean done;
  readonly attribute Error? error;
  undefined stop();
  async iterable<ThingDescription>;
};

dictionary ThingFilter {
  object? fragment;
  
};

D. 謝辞

この仕様を開発した元 editor の Johannes Hund(2017 年 8 月まで、 Siemens AG 在籍時)および Kazuaki Nimura(2018 年 12 月まで)に 特別な感謝を表します。また、editors は Dave Raggett、Matthias Kovatsch、 Michael Koster、Elena Reshetova、Michael McCool、およびその他の WoT WG members に対し、comments、contributions、guidance に感謝します。

E. 参考文献

E.1 規範的参考文献

[ECMASCRIPT]
ECMAScript Language Specification. Ecma International. URL: https://tc39.es/ecma262/multipage/
[fetch]
Fetch Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://fetch.spec.whatwg.org/
[html]
HTML Standard. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[JSON-SCHEMA]
JSON Schema: A Media Type for Describing JSON Documents. Austin Wright; Henry Andrews; Ben Hutton; Greg Dennis. Internet Engineering Task Force (IETF). 8 December 2020. Internet-Draft. URL: https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[streams]
Streams Standard. Adam Rice; Domenic Denicola; Mattias Buelens; 吉野剛史 (Takeshi Yoshino). WHATWG. Living Standard. URL: https://streams.spec.whatwg.org/
[TYPESCRIPT]
TypeScript Language Specification. Microsoft. 1 October 2012. URL: https://www.typescriptlang.org/docs/handbook/intro.html
[url]
URL Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/
[WOT-ARCHITECTURE]
Web of Things (WoT) Architecture 1.1. W3C. 19 January 2023. URL: https://www.w3.org/TR/2023/CR-wot-architecture11-20230119/
[WOT-PROTOCOL-BINDINGS]
Web of Things (WoT) Binding Templates. W3C. 30 January 2020. URL: https://www.w3.org/TR/2020/NOTE-wot-binding-templates-20200130/
[WOT-SECURITY]
Web of Things (WoT) Security and Privacy Guidelines. W3C. 6 November 2019. URL: https://www.w3.org/TR/2019/NOTE-wot-security-20191106/
[WOT-TD]
Web of Things (WoT) Thing Description 1.1. W3C. 19 January 2023. URL: https://www.w3.org/TR/2023/CR-wot-thing-description11-20230119/

E.2 参考情報

[WOT-DISCOVERY]
Web of Things (WoT) Discovery. W3C. 19 January 2023. URL: https://www.w3.org/TR/2023/CR-wot-discovery-20230119/
[WOT-USE-CASES]
Web of Things (WoT): Use Cases and Requirements. W3C. 7 March 2022. URL: https://www.w3.org/TR/2022/NOTE-wot-usecases-20220307/