From 8784743e71e42ee09bcd070f351d437632b63fee Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Wed, 2 Aug 2023 09:35:45 +0200 Subject: [PATCH] add missing files... --- examples/scripts/countdown.js | 16 ++++--- packages/core/src/helpers.ts | 7 ++- packages/examples/src/scripts/countdown.ts | 45 +++++++++---------- .../examples/src/scripts/counter-client.ts | 24 +++++++--- packages/examples/src/scripts/counter.ts | 6 +-- .../scripts/smart-coffee-machine-client.ts | 18 +++++--- .../examples/src/security/oauth/consumer.ts | 17 +++++-- packages/examples/src/testthing/testclient.ts | 36 ++++++++++++--- packages/examples/tsconfig.json | 4 +- 9 files changed, 113 insertions(+), 60 deletions(-) diff --git a/examples/scripts/countdown.js b/examples/scripts/countdown.js index c0b9971f7..3c4f425bd 100644 --- a/examples/scripts/countdown.js +++ b/examples/scripts/countdown.js @@ -80,7 +80,7 @@ WoT.produce({ const listToDelete = []; for (const id of countdowns.keys()) { const as = countdowns.get(id); - if (as.output !== undefined) { + if (as !== undefined && as.output !== undefined) { const prev = as.output; as.output--; console.log("\t" + id + ", from " + prev + " to " + as.output); @@ -125,7 +125,7 @@ WoT.produce({ }; const ii = resp; console.log("init countdown value = " + JSON.stringify(resp)); - countdowns.set(resp.href, resp); + countdowns.set(resp.href !== undefined ? resp.href : "", resp); return ii; }); thing.setActionHandler("stopCountdown", async (params, options) => { @@ -133,10 +133,14 @@ WoT.produce({ const value = await params.value(); if (typeof value === "string" && countdowns.has(value)) { const as = countdowns.get(value); - as.output = 0; - as.status = Status.completed; - console.log("Countdown stopped for href: " + value); - return undefined; + if (as !== undefined) { + as.output = 0; + as.status = Status.completed; + console.log("Countdown stopped for href: " + value); + return null; + } else { + throw Error("Countdown value is undefined for href, " + value); + } } else { throw Error("Input provided for stopCountdown is no string or invalid href, " + value); } diff --git a/packages/core/src/helpers.ts b/packages/core/src/helpers.ts index 621615b17..ca19b648c 100644 --- a/packages/core/src/helpers.ts +++ b/packages/core/src/helpers.ts @@ -34,7 +34,7 @@ import * as TDT from "wot-thing-description-types"; import { ContentSerdes } from "./content-serdes"; import Ajv, { ValidateFunction, ErrorObject } from "ajv"; import TDSchema from "wot-thing-description-types/schema/td-json-schema-validation.json"; -import { DataSchemaValue, ExposedThingInit } from "wot-typescript-definitions"; +import { DataSchemaValue, ExposedThingInit, ThingDescription } from "wot-typescript-definitions"; import { SomeJSONSchema } from "ajv/dist/types/json-schema"; import { ThingInteraction, ThingModelHelpers } from "@node-wot/td-tools"; import { Resolver } from "@node-wot/td-tools/src/resolver-interface"; @@ -152,9 +152,8 @@ export default class Helpers implements Resolver { } } - // TODO: specialize fetch to retrieve just thing descriptions - public fetch(uri: string): Promise { - return new Promise((resolve, reject) => { + public fetch(uri: string): Promise { + return new Promise((resolve, reject) => { const client = this.srv.getClientFor(Helpers.extractScheme(uri)); debug(`WoTImpl fetching TD from '${uri}' with ${client}`); client diff --git a/packages/examples/src/scripts/countdown.ts b/packages/examples/src/scripts/countdown.ts index 922880a2f..e39604949 100644 --- a/packages/examples/src/scripts/countdown.ts +++ b/packages/examples/src/scripts/countdown.ts @@ -13,8 +13,6 @@ * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ -import { InteractionOptions } from "wot-typescript-definitions"; - function uuidv4(): string { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { const r = (Math.random() * 16) | 0; @@ -91,8 +89,8 @@ WoT.produce({ console.log("Update countdowns"); const listToDelete: string[] = []; for (const id of countdowns.keys()) { - const as: ActionStatus = countdowns.get(id); - if (as.output !== undefined) { + const as = countdowns.get(id); + if (as !== undefined && as.output !== undefined) { const prev = as.output; as.output--; console.log("\t" + id + ", from " + prev + " to " + as.output); @@ -117,20 +115,17 @@ WoT.produce({ }, 1000); // set property handlers (using async-await) - thing.setPropertyReadHandler( - "countdowns", - async (options: InteractionOptions): Promise => { - const cts: string[] = []; - for (const id of countdowns.keys()) { - cts.push(id); - } - return cts; + thing.setPropertyReadHandler("countdowns", async (options): Promise => { + const cts: string[] = []; + for (const id of countdowns.keys()) { + cts.push(id); } - ); + return cts; + }); // set action handlers (using async-await) thing.setActionHandler( "startCountdown", - async (params: WoT.InteractionOutput, options: InteractionOptions): Promise => { + async (params: WoT.InteractionOutput, options): Promise => { let initValue = 100; if (params) { const value = await params.value(); @@ -145,21 +140,25 @@ WoT.produce({ }; const ii: WoT.InteractionInput = resp; console.log("init countdown value = " + JSON.stringify(resp)); - countdowns.set(resp.href, resp); + countdowns.set(resp.href !== undefined ? resp.href : "", resp); return ii; } ); thing.setActionHandler( "stopCountdown", - async (params: WoT.InteractionOutput, options: InteractionOptions): Promise => { + async (params: WoT.InteractionOutput, options): Promise => { if (params) { const value = await params.value(); if (typeof value === "string" && countdowns.has(value)) { - const as: ActionStatus = countdowns.get(value); - as.output = 0; - as.status = Status.completed; - console.log("Countdown stopped for href: " + value); - return undefined; + const as = countdowns.get(value); + if (as !== undefined) { + as.output = 0; + as.status = Status.completed; + console.log("Countdown stopped for href: " + value); + return null; + } else { + throw Error("Countdown value is undefined for href, " + value); + } } else { throw Error("Input provided for stopCountdown is no string or invalid href, " + value); } @@ -170,11 +169,11 @@ WoT.produce({ ); thing.setActionHandler( "monitorCountdown", - async (params: WoT.InteractionOutput, options: InteractionOptions): Promise => { + async (params: WoT.InteractionOutput, options): Promise => { if (params) { const value = await params.value(); if (typeof value === "string" && countdowns.has(value)) { - const as: ActionStatus = countdowns.get(value); + const as = countdowns.get(value); return JSON.stringify(as); } else { throw Error("Input provided for monitorCountdown is no string or invalid href, " + value); diff --git a/packages/examples/src/scripts/counter-client.ts b/packages/examples/src/scripts/counter-client.ts index 376c72366..aa2c35e92 100644 --- a/packages/examples/src/scripts/counter-client.ts +++ b/packages/examples/src/scripts/counter-client.ts @@ -13,23 +13,33 @@ * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ -import { Helpers } from "@node-wot/core"; +import { Servient, Helpers } from "@node-wot/core"; +import { HttpClientFactory } from "@node-wot/binding-http"; +import { CoapClientFactory } from "@node-wot/binding-coap"; import { ThingDescription } from "wot-typescript-definitions"; -let WoTHelpers: Helpers; +// create Servient and add HTTP/CoAP binding +const servient = new Servient(); +servient.addClientFactory(new HttpClientFactory()); +servient.addClientFactory(new CoapClientFactory()); + +const wotHelper = new Helpers(servient); function getFormIndexForDecrementWithCoAP(thing: WoT.ConsumedThing): number { - const forms = thing.getThingDescription().actions.decrement.forms; - for (let i = 0; i < forms.length; i++) { - if (/^coaps?:\/\/.*/.test(forms[i].href)) { - return i; + const forms = thing.getThingDescription().actions?.decrement.forms; + if (forms !== undefined) { + for (let i = 0; i < forms.length; i++) { + if (/^coaps?:\/\/.*/.test(forms[i].href)) { + return i; + } } } // return formIndex: 0 if no CoAP target IRI found return 0; } -WoTHelpers.fetch("coap://localhost:5683/counter") +wotHelper + .fetch("coap://localhost:5683/counter") .then(async (td) => { // using await for serial execution (note 'async' in then() of fetch()) try { diff --git a/packages/examples/src/scripts/counter.ts b/packages/examples/src/scripts/counter.ts index 4c6dda51b..c70545bdc 100644 --- a/packages/examples/src/scripts/counter.ts +++ b/packages/examples/src/scripts/counter.ts @@ -208,7 +208,7 @@ WoT.produce({ let fill = "black"; if (options && typeof options === "object" && "uriVariables" in options) { console.log("options = " + JSON.stringify(options)); - if ("fill" in options.uriVariables) { + if (options.uriVariables && "fill" in options.uriVariables) { const uriVariables = options.uriVariables as Record; fill = uriVariables.fill; } @@ -234,7 +234,7 @@ WoT.produce({ let step = 1; if (options && typeof options === "object" && "uriVariables" in options) { console.log("options = " + JSON.stringify(options)); - if ("step" in options.uriVariables) { + if (options.uriVariables && "step" in options.uriVariables) { const uriVariables = options.uriVariables as Record; step = uriVariables.step as number; } @@ -251,7 +251,7 @@ WoT.produce({ let step = 1; if (options && typeof options === "object" && "uriVariables" in options) { console.log("options = " + JSON.stringify(options)); - if ("step" in options.uriVariables) { + if (options.uriVariables && "step" in options.uriVariables) { const uriVariables = options.uriVariables as Record; step = uriVariables.step as number; } diff --git a/packages/examples/src/scripts/smart-coffee-machine-client.ts b/packages/examples/src/scripts/smart-coffee-machine-client.ts index b365146cc..9abbc0a9e 100644 --- a/packages/examples/src/scripts/smart-coffee-machine-client.ts +++ b/packages/examples/src/scripts/smart-coffee-machine-client.ts @@ -17,9 +17,17 @@ // It considers a fictional smart coffee machine in order to demonstrate the capabilities of Web of Things. // An accompanying tutorial is available at http://www.thingweb.io/smart-coffee-machine.html. +import { Servient, Helpers } from "@node-wot/core"; +import { HttpClientFactory } from "@node-wot/binding-http"; +import { CoapClientFactory } from "@node-wot/binding-coap"; import { ThingDescription } from "wot-typescript-definitions"; -import { Helpers } from "@node-wot/core"; -let WoTHelpers: Helpers; + +// create Servient and add HTTP/CoAP binding +const servient = new Servient(); +servient.addClientFactory(new HttpClientFactory()); +servient.addClientFactory(new CoapClientFactory()); + +const wotHelper = new Helpers(servient); // Print data and an accompanying message in a distinguishable way function log(msg: string, data: unknown) { @@ -29,7 +37,7 @@ function log(msg: string, data: unknown) { console.info("======================"); } -WoTHelpers.fetch("http://127.0.0.1:8080/smart-coffee-machine").then(async (td) => { +wotHelper.fetch("http://127.0.0.1:8080/smart-coffee-machine").then(async (td) => { try { const thing = await WoT.consume(td as ThingDescription); log("Thing Description:", td); @@ -60,7 +68,7 @@ WoTHelpers.fetch("http://127.0.0.1:8080/smart-coffee-machine").then(async (td) = const makeCoffee = await thing.invokeAction("makeDrink", undefined, { uriVariables: { drinkId: "latte", size: "l", quantity: 3 }, }); - const makeCoffeep = (await makeCoffee.value()) as Record; + const makeCoffeep = (await makeCoffee?.value()) as Record; if (makeCoffeep.result) { log("Enjoy your drink!", makeCoffeep); } else { @@ -79,7 +87,7 @@ WoTHelpers.fetch("http://127.0.0.1:8080/smart-coffee-machine").then(async (td) = time: "10:00", mode: "everyday", }); - const scheduledTaskp = (await scheduledTask.value()) as Record; + const scheduledTaskp = (await scheduledTask?.value()) as Record; log(scheduledTaskp.message, scheduledTaskp); // See how it has been added to the schedules property diff --git a/packages/examples/src/security/oauth/consumer.ts b/packages/examples/src/security/oauth/consumer.ts index 8288b6622..66ff3e37d 100644 --- a/packages/examples/src/security/oauth/consumer.ts +++ b/packages/examples/src/security/oauth/consumer.ts @@ -12,15 +12,24 @@ * * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ -import { Helpers } from "@node-wot/core"; + +import { Servient, Helpers } from "@node-wot/core"; +import { HttpClientFactory } from "@node-wot/binding-http"; +import { CoapClientFactory } from "@node-wot/binding-coap"; import { ThingDescription } from "wot-typescript-definitions"; -let WoTHelpers: Helpers; +// create Servient and add HTTP/CoAP binding +const servient = new Servient(); +servient.addClientFactory(new HttpClientFactory()); +servient.addClientFactory(new CoapClientFactory()); + +const wotHelper = new Helpers(servient); -WoTHelpers.fetch("https://localhost:8080/oauth").then((td) => { +wotHelper.fetch("https://localhost:8080/oauth").then((td) => { WoT.consume(td as ThingDescription).then(async (thing) => { try { - const result = await (await thing.invokeAction("sayOk")).value(); + const resp = await thing.invokeAction("sayOk"); + const result = resp?.value(); console.log("oAuth token was", result); } catch (error) { console.log("It seems that I couldn't access the resource"); diff --git a/packages/examples/src/testthing/testclient.ts b/packages/examples/src/testthing/testclient.ts index 3abab1967..26d3bd4bc 100644 --- a/packages/examples/src/testthing/testclient.ts +++ b/packages/examples/src/testthing/testclient.ts @@ -13,9 +13,17 @@ * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ -import { Helpers } from "@node-wot/core"; +import { Servient, Helpers } from "@node-wot/core"; +import { HttpClientFactory } from "@node-wot/binding-http"; +import { CoapClientFactory } from "@node-wot/binding-coap"; import { ThingDescription } from "wot-typescript-definitions"; -let WoTHelpers: Helpers; + +// create Servient and add HTTP/CoAP binding +const servient = new Servient(); +servient.addClientFactory(new HttpClientFactory()); +servient.addClientFactory(new CoapClientFactory()); + +const wotHelper = new Helpers(servient); console.log = () => { /* empty */ @@ -30,7 +38,11 @@ async function testPropertyRead(thing: WoT.ConsumedThing, name: string) { const value = await res.value(); console.info("PASS " + name + " READ:", value); } catch (err) { - console.error("FAIL " + name + " READ:", err.message); + if (err instanceof Error) { + console.error("FAIL " + name + " READ:", err.message); + } else { + console.error("FAIL " + name + " READ:", err); + } } } @@ -46,12 +58,24 @@ async function testPropertyWrite( if (!shouldFail) console.info("PASS " + name + " WRITE (" + displayValue + ")"); else console.error("FAIL " + name + " WRITE: (" + displayValue + ")"); } catch (err) { - if (!shouldFail) console.error("FAIL " + name + " WRITE (" + displayValue + "):", err.message); - else console.info("PASS " + name + " WRITE (" + displayValue + "):", err.message); + if (!shouldFail) { + if (err instanceof Error) { + console.error("FAIL " + name + " WRITE (" + displayValue + "):", err.message); + } else { + console.error("FAIL " + name + " WRITE (" + displayValue + "):", err); + } + } else { + if (err instanceof Error) { + console.info("PASS " + name + " WRITE (" + displayValue + "):", err.message); + } else { + console.info("PASS " + name + " WRITE (" + displayValue + "):", err); + } + } } } -WoTHelpers.fetch("http://localhost:8080/testthing") +wotHelper + .fetch("http://localhost:8080/testthing") .then(async (td) => { // using await for serial execution (note 'async' in then() of fetch()) try { diff --git a/packages/examples/tsconfig.json b/packages/examples/tsconfig.json index bfabb0e56..7a65a8bb5 100644 --- a/packages/examples/tsconfig.json +++ b/packages/examples/tsconfig.json @@ -1,11 +1,11 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strict": true, + "strictFunctionTypes": true, "outDir": "dist", "rootDir": "src", "target": "ES2018", - "alwaysStrict": false, - "noImplicitUseStrict": true, "sourceMap": false, "removeComments": false },