From 07ad5668c53fb844ca25e124e1f79995c085e13b Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Wed, 9 Aug 2023 08:40:09 +0200 Subject: [PATCH] chore(binding-coap): use ts strict checking --- packages/binding-coap/src/coap-client.ts | 7 +- packages/binding-coap/src/coap-server.ts | 76 +++++++++++-------- packages/binding-coap/src/coaps-client.ts | 38 +++++----- .../binding-coap/test/coap-client-test.ts | 7 +- .../binding-coap/test/coap-server-test.ts | 48 ++++++------ packages/binding-coap/tsconfig.json | 1 + 6 files changed, 98 insertions(+), 79 deletions(-) diff --git a/packages/binding-coap/src/coap-client.ts b/packages/binding-coap/src/coap-client.ts index b6ea3ebcb..253afd349 100644 --- a/packages/binding-coap/src/coap-client.ts +++ b/packages/binding-coap/src/coap-client.ts @@ -68,8 +68,7 @@ export default class CoapClient implements ProtocolClient { debug(`CoapClient received Content-Format: ${res.headers["Content-Format"]}`); // FIXME does not work with blockwise because of node-coap - let contentType = res.headers["Content-Format"] as string; - if (!contentType) contentType = form.contentType; + const contentType = (res.headers["Content-Format"] as string) ?? form.contentType; resolve(new Content(contentType, Readable.from(res.payload))); }); @@ -226,8 +225,8 @@ export default class CoapClient implements ProtocolClient { try { const block2OptionValue = blockSizeToOptionValue(blockSize); req.setOption(optionName, block2OptionValue); - } catch (e) { - warn(e.toString()); + } catch (error) { + warn(`${error}`); } } diff --git a/packages/binding-coap/src/coap-server.ts b/packages/binding-coap/src/coap-server.ts index ab46c8f7d..04ecb5d3f 100644 --- a/packages/binding-coap/src/coap-server.ts +++ b/packages/binding-coap/src/coap-server.ts @@ -63,7 +63,7 @@ export default class CoapServer implements ProtocolServer { private readonly port: number; private readonly address?: string; - private mdnsIntroducer: MdnsIntroducer; + private mdnsIntroducer?: MdnsIntroducer; private readonly server: Server = createServer( { reuseAddr: false }, @@ -461,7 +461,7 @@ export default class CoapServer implements ProtocolServer { affordanceKey: string, req: IncomingMessage, res: OutgoingMessage, - contentType?: string + contentType: string ) { const property = thing.properties[affordanceKey]; @@ -475,7 +475,7 @@ export default class CoapServer implements ProtocolServer { if (req.headers.Observe == null) { this.handleReadProperty(property, req, contentType, thing, res, affordanceKey); } else { - this.handleObserveProperty(req, thing, res, affordanceKey); + this.handleObserveProperty(property, req, contentType, thing, res, affordanceKey); } break; case "PUT": @@ -502,31 +502,42 @@ export default class CoapServer implements ProtocolServer { try { const interactionOptions = this.createInteractionOptions( property.forms, - property.uriVariables, thing, req, - contentType + contentType, + property.uriVariables ); const content = await thing.handleReadProperty(affordanceKey, interactionOptions); this.streamContentResponse(res, content); } catch (err) { - error(`CoapServer on port ${this.getPort()} got internal error on read '${req.url}': ${err.message}`); - this.sendResponse(res, "5.00", err.message); + const errorMessage = `${err}`; + error(`CoapServer on port ${this.getPort()} got internal error on read '${req.url}': ${errorMessage}`); + this.sendResponse(res, "5.00", errorMessage); } } private async handleObserveProperty( + property: PropertyElement, req: IncomingMessage, + contentType: string, thing: ExposedThing, res: OutgoingMessage, affordanceKey: string ) { + const interactionOptions = this.createInteractionOptions( + property.forms, + thing, + req, + contentType, + property.uriVariables + ); + const listener = this.createContentListener(req, res, this.PROPERTY_DIR, affordanceKey); try { - await thing.handleObserveProperty(affordanceKey, listener, null); + await thing.handleObserveProperty(affordanceKey, listener, interactionOptions); } catch (error) { - warn(error.toString()); + warn(`${error}`); } res.end(); @@ -535,10 +546,10 @@ export default class CoapServer implements ProtocolServer { if (err) { error(`CoapServer on port ${this.port} failed on observe with: ${err.message}`); } - thing.handleUnobserveProperty(affordanceKey, listener, null); + thing.handleUnobserveProperty(affordanceKey, listener, interactionOptions); }); - setTimeout(() => thing.handleUnobserveProperty(affordanceKey, listener, null), 60 * 60 * 1000); + setTimeout(() => thing.handleUnobserveProperty(affordanceKey, listener, interactionOptions), 60 * 60 * 1000); } private createContentListener( @@ -562,12 +573,13 @@ export default class CoapServer implements ProtocolServer { debug(`CoapServer on port ${this.getPort()} failed '${affordanceKey}' subscription`); this.sendResponse(res, code, "Subscription to event failed"); } else { + const errorMessage = `${err}`; debug( - `CoapServer on port ${this.getPort()} got internal error on observe '${req.url}': ${ - err.message - }` + `CoapServer on port ${this.getPort()} got internal error on observe '${ + req.url + }': ${errorMessage}` ); - this.sendResponse(res, code, err.message); + this.sendResponse(res, code, errorMessage); } } }; @@ -584,10 +596,10 @@ export default class CoapServer implements ProtocolServer { try { const interactionOptions = this.createInteractionOptions( property.forms, - property.uriVariables, thing, req, - contentType + contentType, + property.uriVariables ); await thing.handleWriteProperty( affordanceKey, @@ -596,8 +608,9 @@ export default class CoapServer implements ProtocolServer { ); this.sendChangedResponse(res); } catch (err) { - error(`CoapServer on port ${this.getPort()} got internal error on write '${req.url}': ${err.message}`); - this.sendResponse(res, "5.00", err.message); + const errorMessage = `${err}`; + error(`CoapServer on port ${this.getPort()} got internal error on write '${req.url}': ${errorMessage}`); + this.sendResponse(res, "5.00", errorMessage); } } @@ -606,7 +619,7 @@ export default class CoapServer implements ProtocolServer { affordanceKey: string, req: IncomingMessage, res: OutgoingMessage, - contentType?: string + contentType: string ) { const action = thing.actions[affordanceKey]; @@ -622,10 +635,10 @@ export default class CoapServer implements ProtocolServer { const interactionOptions = this.createInteractionOptions( action.forms, - action.uriVariables, thing, req, - contentType + contentType, + action.uriVariables ); try { const output = await thing.handleInvokeAction( @@ -638,18 +651,19 @@ export default class CoapServer implements ProtocolServer { } else { this.sendChangedResponse(res); } - } catch (err) { - error(`CoapServer on port ${this.getPort()} got internal error on invoke '${req.url}': ${err.message}`); - this.sendResponse(res, "5.00", err.message); + } catch (errror) { + const errorMessage = `${error}`; + error(`CoapServer on port ${this.getPort()} got internal error on invoke '${req.url}': ${errorMessage}`); + this.sendResponse(res, "5.00", errorMessage); } } private createInteractionOptions( forms: TD.Form[], - affordanceUriVariables: { [k: string]: DataSchema }, thing: ExposedThing, req: IncomingMessage, - contentType: string + contentType: string, + affordanceUriVariables?: { [k: string]: DataSchema } ) { const options: AugmentedInteractionOptions = { formIndex: ProtocolHelpers.findRequestMatchingFormIndex(forms, this.scheme, req.url, contentType), @@ -667,7 +681,7 @@ export default class CoapServer implements ProtocolServer { affordanceKey: string, req: IncomingMessage, res: OutgoingMessage, - contentType?: string + contentType: string ) { const event = thing.events[affordanceKey]; @@ -698,10 +712,10 @@ export default class CoapServer implements ProtocolServer { const interactionOptions = this.createInteractionOptions( event.forms, - event.uriVariables, thing, req, - contentType + contentType, + event.uriVariables ); const listener = this.createContentListener(req, res, this.EVENT_DIR, affordanceKey); @@ -709,7 +723,7 @@ export default class CoapServer implements ProtocolServer { try { await thing.handleSubscribeEvent(affordanceKey, listener, interactionOptions); } catch (error) { - warn(error.toString()); + warn(`${error}`); } res.end(); diff --git a/packages/binding-coap/src/coaps-client.ts b/packages/binding-coap/src/coaps-client.ts index 941fbd9d4..e4c4eb191 100644 --- a/packages/binding-coap/src/coaps-client.ts +++ b/packages/binding-coap/src/coaps-client.ts @@ -21,7 +21,7 @@ import * as TD from "@node-wot/td-tools"; import { Subscription } from "rxjs/Subscription"; -import { ProtocolClient, Content, createLoggers } from "@node-wot/core"; +import { ProtocolClient, Content, createLoggers, ContentSerdes } from "@node-wot/core"; import { CoapForm, CoapMethodName, isValidCoapMethod, isSupportedCoapMethod } from "./coap"; import { CoapClient as coaps, CoapResponse, RequestMethod, SecurityParameters } from "node-coap-client"; import { Readable } from "stream"; @@ -34,7 +34,7 @@ declare interface pskSecurityParameters { export default class CoapsClient implements ProtocolClient { // FIXME coap Agent closes socket when no messages in flight -> new socket with every request - private authorization: SecurityParameters; + private authorization?: SecurityParameters; public toString(): string { return "[CoapsClient]"; @@ -46,11 +46,11 @@ export default class CoapsClient implements ProtocolClient { .then((res: CoapResponse) => { debug(`CoapsClient received ${res.code} from ${form.href}`); - // FIXME node-coap-client does not support options - let contentType; // = res.format[...] - if (!contentType) contentType = form.contentType; + // FIXME: Add toString conversion for response Content-Format + const contentType = form.contentType ?? ContentSerdes.DEFAULT; + const body = Readable.from(res.payload ?? Buffer.alloc(0)); - resolve(new Content(contentType, Readable.from(res.payload))); + resolve(new Content(contentType, body)); }) .catch((err: Error) => { reject(err); @@ -78,11 +78,11 @@ export default class CoapsClient implements ProtocolClient { .then((res: CoapResponse) => { debug(`CoapsClient received ${res.code} from ${form.href}`); - // FIXME node-coap-client does not support options - let contentType; // = res.format[...] - if (!contentType) contentType = form.contentType; + // FIXME: Add toString conversion for response Content-Format + const contentType = form.contentType ?? ContentSerdes.DEFAULT; + const body = Readable.from(res.payload ?? Buffer.alloc(0)); - resolve(new Content(contentType, Readable.from(res.payload))); + resolve(new Content(contentType, body)); }) .catch((err: Error) => { reject(err); @@ -112,11 +112,13 @@ export default class CoapsClient implements ProtocolClient { ): Promise { return new Promise((resolve, reject) => { const requestUri = new URL(form.href.replace(/$coaps/, "https")); - coaps.setSecurityParams(requestUri.hostname, this.authorization); + if (this.authorization != null) { + coaps.setSecurityParams(requestUri.hostname, this.authorization); + } const callback = (resp: CoapResponse) => { if (resp.payload != null) { - next(new Content(form?.contentType, Readable.from(resp.payload))); + next(new Content(form?.contentType ?? ContentSerdes.DEFAULT, Readable.from(resp.payload))); } }; @@ -126,12 +128,12 @@ export default class CoapsClient implements ProtocolClient { resolve( new Subscription(() => { coaps.stopObserving(form.href); - complete(); + complete?.(); }) ); }) .catch((err) => { - error(err); + error?.(err); reject(err); }); }); @@ -153,7 +155,7 @@ export default class CoapsClient implements ProtocolClient { const security: TD.SecurityScheme = metadata[0]; - if (security.scheme === "psk") { + if (security.scheme === "psk" && credentials != null) { this.authorization = { psk: {} }; this.authorization.psk[credentials.identity] = credentials.psk; } else if (security.scheme === "apikey") { @@ -207,7 +209,9 @@ export default class CoapsClient implements ProtocolClient { ): Promise { // url only works with http* const requestUri = new URL(form.href.replace(/$coaps/, "https")); - coaps.setSecurityParams(requestUri.hostname, this.authorization); + if (this.authorization != null) { + coaps.setSecurityParams(requestUri.hostname, this.authorization); + } let method; @@ -221,7 +225,7 @@ export default class CoapsClient implements ProtocolClient { debug(`CoapsClient sending ${method} to ${form.href}`); - const body = content.body ? await content.toBuffer() : undefined; + const body = await content?.toBuffer(); const req = coaps.request( form.href /* string */, diff --git a/packages/binding-coap/test/coap-client-test.ts b/packages/binding-coap/test/coap-client-test.ts index 1a5d87757..97fd8aa2b 100644 --- a/packages/binding-coap/test/coap-client-test.ts +++ b/packages/binding-coap/test/coap-client-test.ts @@ -23,6 +23,7 @@ import { expect } from "chai"; import CoapServer from "../src/coap-server"; import CoapClient from "../src/coap-client"; import { CoapForm } from "../src/coap"; +import Servient from "@node-wot/core"; const port1 = 31833; const port2 = 31834; @@ -56,7 +57,7 @@ class CoapClientTest { const coapServer = new CoapServer(port1); - await coapServer.start(null); + await coapServer.start(new Servient()); expect(coapServer.getPort()).to.equal(port1); /* @@ -102,7 +103,7 @@ class CoapClientTest { @test async "should re-use port"() { const coapServer = new CoapServer(port2, "localhost"); - await coapServer.start(null); + await coapServer.start(new Servient()); const coapClient = new CoapClient(coapServer); await coapClient.readResource({ href: `coap://localhost:${port2}/`, @@ -113,7 +114,7 @@ class CoapClientTest { @test(timeout(5000)) async "subscribe test"() { const coapServer = new CoapServer(port2, "localhost"); - await coapServer.start(null); + await coapServer.start(new Servient()); const coapClient = new CoapClient(coapServer); const form: CoapForm = { href: `coap://127.0.0.1:${port2}`, diff --git a/packages/binding-coap/test/coap-server-test.ts b/packages/binding-coap/test/coap-server-test.ts index f9402ada9..a7e0057e1 100644 --- a/packages/binding-coap/test/coap-server-test.ts +++ b/packages/binding-coap/test/coap-server-test.ts @@ -1,4 +1,4 @@ -import { ExposedThing, Content } from "@node-wot/core"; +import Servient, { ExposedThing, Content } from "@node-wot/core"; /******************************************************************************** * Copyright (c) 2023 Contributors to the Eclipse Foundation * @@ -36,7 +36,7 @@ class CoapServerTest { @test async "should start and stop a server"() { const coapServer = new CoapServer(PORT); - await coapServer.start(null); + await coapServer.start(new Servient()); expect(coapServer.getPort()).to.eq(PORT); // from test await coapServer.stop(); @@ -46,9 +46,9 @@ class CoapServerTest { @test async "should read property"() { const coapServer = new CoapServer(PORT); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", properties: { test: { @@ -77,9 +77,9 @@ class CoapServerTest { @test async "should write property"() { const coapServer = new CoapServer(PORT); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", properties: { test: { @@ -116,9 +116,9 @@ class CoapServerTest { @test async "should perform an action"() { const coapServer = new CoapServer(PORT); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", actions: { try: { @@ -153,9 +153,9 @@ class CoapServerTest { @test async "should subscribe to event"() { const coapServer = new CoapServer(PORT); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", events: { eventTest: { @@ -187,16 +187,16 @@ class CoapServerTest { @test async "should cause EADDRINUSE error when already running"() { const portNumber = 9000; const coapServer1 = new CoapServer(portNumber); - await coapServer1.start(null); + await coapServer1.start(new Servient()); expect(coapServer1.getPort()).to.eq(portNumber); const coapServer2 = new CoapServer(coapServer1.getPort()); try { - await coapServer2.start(null); + await coapServer2.start(new Servient()); } catch (err) { - expect(err.message).to.eql(`bind EADDRINUSE 0.0.0.0:${portNumber}`); + expect((err as Error).message).to.eql(`bind EADDRINUSE 0.0.0.0:${portNumber}`); } await coapServer1.stop(); @@ -204,9 +204,9 @@ class CoapServerTest { @test async "should support IPv6"() { const coapServer = new CoapServer(PORT, "::"); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", properties: { test: { @@ -235,9 +235,9 @@ class CoapServerTest { const portNumber = 9001; const coapServer = new CoapServer(portNumber); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", uriVariables: { globalVarTest: { @@ -263,7 +263,7 @@ class CoapServerTest { }); const test: DataSchemaValue = "testValue"; testThing.setPropertyReadHandler("test", (options) => { - expect(options.uriVariables).to.deep.equal({ id: "testId", globalVarTest: "test1" }); + expect(options?.uriVariables).to.deep.equal({ id: "testId", globalVarTest: "test1" }); return new Promise((resolve, reject) => { resolve(test); }); @@ -287,12 +287,12 @@ class CoapServerTest { const portNumber = 9001; const coapServer = new CoapServer(portNumber); - await coapServer.start(null); + await coapServer.start(new Servient()); const testTitles = ["Test1", "Test2"]; for (const title of testTitles) { - const thing = new ExposedThing(null, { + const thing = new ExposedThing(new Servient(), { title, }); @@ -314,9 +314,9 @@ class CoapServerTest { const portNumber = 5683; const coapServer = new CoapServer(portNumber); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", }); @@ -368,9 +368,9 @@ class CoapServerTest { const portNumber = 9002; const coapServer = new CoapServer(portNumber); - await coapServer.start(null); + await coapServer.start(new Servient()); - const testThing = new ExposedThing(null, { + const testThing = new ExposedThing(new Servient(), { title: "Test", description: "This is a test!".repeat(100), }); diff --git a/packages/binding-coap/tsconfig.json b/packages/binding-coap/tsconfig.json index f57566684..086c6a78f 100644 --- a/packages/binding-coap/tsconfig.json +++ b/packages/binding-coap/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "dist", "rootDir": "src", + "strict": true, "typeRoots": ["./node_modules/@types", "./typings"] }, "include": ["src/**/*"],