Skip to content

Commit 3325e12

Browse files
authored
Merge pull request eclipse-thingweb#1397 from danielpeintner/scripting-SNAPSHOT.31
Add skeleton for query and cancel action
2 parents 78e4fca + 80ec074 commit 3325e12

8 files changed

Lines changed: 78 additions & 29 deletions

File tree

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"tslint": "5.12.1",
8080
"typescript": "^5.7.3",
8181
"typescript-standard": "^0.3.36",
82-
"wot-typescript-definitions": "0.8.0-SNAPSHOT.30"
82+
"wot-typescript-definitions": "0.8.0-SNAPSHOT.31"
8383
},
8484
"version": ""
8585
}

packages/binding-coap/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"node-coap-client": "1.0.8",
2222
"rxjs": "5.5.11",
2323
"slugify": "^1.4.5",
24-
"wot-typescript-definitions": "0.8.0-SNAPSHOT.30"
24+
"wot-typescript-definitions": "0.8.0-SNAPSHOT.31"
2525
},
2626
"scripts": {
2727
"build": "tsc -b",

packages/binding-modbus/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"@node-wot/core": "0.9.2",
2121
"modbus-serial": "8.0.17",
2222
"rxjs": "5.5.11",
23-
"wot-typescript-definitions": "0.8.0-SNAPSHOT.30"
23+
"wot-typescript-definitions": "0.8.0-SNAPSHOT.31"
2424
},
2525
"scripts": {
2626
"build": "tsc -b",

packages/core/src/consumed-thing.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import ContentType from "content-type";
3838
import ContentManager from "./content-serdes";
3939

4040
import UriTemplate = require("uritemplate");
41-
import { InteractionOutput } from "./interaction-output";
41+
import { InteractionOutput, ActionInteractionOutput } from "./interaction-output";
4242
import {
4343
ActionElement,
4444
EventElement,
@@ -564,7 +564,7 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
564564

565565
const content = await client.readResource(form);
566566
try {
567-
return this.handleInteractionOutput(content, form, tp, false);
567+
return this.handleInteractionOutput(content, form, tp);
568568
} catch (e) {
569569
const error = e instanceof Error ? e : new Error(JSON.stringify(e));
570570
throw new Error(`Error while processing property for ${tp.title}. ${error.message}`);
@@ -574,13 +574,17 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
574574
private handleInteractionOutput(
575575
content: Content,
576576
form: Form,
577-
outputDataSchema: WoT.DataSchema | undefined,
578-
ignoreValidation: boolean
577+
outputDataSchema: WoT.DataSchema | undefined
579578
): InteractionOutput {
580579
// infer media type from form if not in response metadata
581580
content.type ??= form.contentType ?? "application/json";
582-
583581
// check if returned media type is the same as expected media type (from TD)
582+
this.checkMediaTypeOrThrow(content, form);
583+
return new InteractionOutput(content, form, outputDataSchema);
584+
}
585+
586+
// check if returned media type is the same as expected media type (from TD)
587+
private checkMediaTypeOrThrow(content: Content, form: Form) {
584588
if (form.response != null) {
585589
const parsedMediaTypeContent = ContentType.parse(content.type);
586590
const parsedMediaTypeForm = ContentType.parse(form.response.contentType);
@@ -590,7 +594,19 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
590594
);
591595
}
592596
}
593-
return new InteractionOutput(content, form, outputDataSchema, { ignoreValidation });
597+
}
598+
599+
private handleActionInteractionOutput(
600+
content: Content,
601+
form: Form,
602+
outputDataSchema: WoT.DataSchema | undefined,
603+
synchronous?: boolean
604+
): ActionInteractionOutput {
605+
// infer media type from form if not in response metadata
606+
content.type ??= form.contentType ?? "application/json";
607+
// check if returned media type is the same as expected media type (from TD)
608+
this.checkMediaTypeOrThrow(content, form);
609+
return new ActionInteractionOutput(content, form, outputDataSchema, synchronous);
594610
}
595611

596612
async _readProperties(propertyNames: string[]): Promise<WoT.PropertyReadMap> {
@@ -680,7 +696,7 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
680696
actionName: string,
681697
parameter?: InteractionInput,
682698
options?: WoT.InteractionOptions
683-
): Promise<WoT.InteractionOutput> {
699+
): Promise<WoT.ActionInteractionOutput> {
684700
const ta = this.actions[actionName];
685701
if (ta == null) {
686702
throw new Error(`ConsumedThing '${this.title}' does not have action ${actionName}`);
@@ -709,8 +725,7 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
709725

710726
const content = await client.invokeResource(form, input);
711727
try {
712-
const ignoreValidation = ta.synchronous === undefined ? true : !ta.synchronous;
713-
return this.handleInteractionOutput(content, form, ta.output, ignoreValidation);
728+
return this.handleActionInteractionOutput(content, form, ta.output, ta.synchronous);
714729
} catch (e) {
715730
const error = e instanceof Error ? e : new Error(JSON.stringify(e));
716731
throw new Error(`Error while processing action for ${ta.title}. ${error.message}`);
@@ -753,7 +768,7 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
753768
// next
754769
(content) => {
755770
try {
756-
listener(this.handleInteractionOutput(content, form, tp, false));
771+
listener(this.handleInteractionOutput(content, form, tp));
757772
} catch (e) {
758773
const error = e instanceof Error ? e : new Error(JSON.stringify(e));
759774
warn(`Error while processing observe property for ${tp.title}. ${error.message}`);
@@ -809,7 +824,7 @@ export default class ConsumedThing extends Thing implements IConsumedThing {
809824
formWithoutURITemplates,
810825
(content) => {
811826
try {
812-
listener(this.handleInteractionOutput(content, form, te.data, false));
827+
listener(this.handleInteractionOutput(content, form, te.data));
813828
} catch (e) {
814829
const error = e instanceof Error ? e : new Error(JSON.stringify(e));
815830
warn(`Error while processing event for ${te.title}. ${error.message}`);

packages/core/src/interaction-output.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ export class InteractionOutput implements WoT.InteractionOutput {
4242
dataUsed: boolean;
4343
form?: WoT.Form;
4444
schema?: WoT.DataSchema;
45-
ignoreValidation: boolean; // by default set to false
4645

4746
public get data(): ReadableStream {
4847
if (this.#stream) {
@@ -58,11 +57,10 @@ export class InteractionOutput implements WoT.InteractionOutput {
5857
return (this.#stream = ProtocolHelpers.toWoTStream(this.#content.body) as ReadableStream);
5958
}
6059

61-
constructor(content: Content, form?: WoT.Form, schema?: WoT.DataSchema, options = { ignoreValidation: false }) {
60+
constructor(content: Content, form?: WoT.Form, schema?: WoT.DataSchema) {
6261
this.#content = content;
6362
this.form = form;
6463
this.schema = schema;
65-
this.ignoreValidation = options.ignoreValidation ?? false;
6664
this.dataUsed = false;
6765
}
6866

@@ -129,7 +127,7 @@ export class InteractionOutput implements WoT.InteractionOutput {
129127
// validate the schema
130128
const validate = ajv.compile<T>(this.schema);
131129

132-
if (!this.ignoreValidation && !validate(json)) {
130+
if (!this.ignoreValidation() && !validate(json)) {
133131
debug(`schema = ${util.inspect(this.schema, { depth: 10, colors: true })}`);
134132
debug(`value: ${json}`);
135133
debug(`Error: ${validate.errors}`);
@@ -139,4 +137,32 @@ export class InteractionOutput implements WoT.InteractionOutput {
139137
this.#value = json;
140138
return json as T;
141139
}
140+
141+
protected ignoreValidation(): boolean {
142+
return false; // by default set to false
143+
}
144+
}
145+
146+
export class ActionInteractionOutput extends InteractionOutput implements WoT.ActionInteractionOutput {
147+
synchronous?: boolean;
148+
149+
constructor(content: Content, form?: WoT.Form, schema?: WoT.DataSchema, synchronous?: boolean) {
150+
super(content, form, schema);
151+
this.synchronous = synchronous;
152+
}
153+
154+
protected ignoreValidation(): boolean {
155+
return this.synchronous === undefined ? true : !this.synchronous; // validate data for synchronous action only
156+
}
157+
158+
async query<T extends WoT.InteractionOutput>(
159+
params?: WoT.InteractionInput,
160+
options?: WoT.InteractionOptions
161+
): Promise<T> {
162+
throw new Error("Not yet implemented");
163+
}
164+
165+
async cancel(params?: WoT.InteractionInput, options?: WoT.InteractionOptions): Promise<void> {
166+
throw new Error("Not yet implemented");
167+
}
142168
}

packages/core/test/InteractionOutputTest.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { suite, test } from "@testdeck/mocha";
1818
import promised from "chai-as-promised";
1919
import { expect, use } from "chai";
2020
import { Readable } from "stream";
21-
import { InteractionOutput } from "../src/interaction-output";
21+
import { InteractionOutput, ActionInteractionOutput } from "../src/interaction-output";
2222
import { Content } from "..";
2323
import { fail } from "assert";
2424

@@ -121,12 +121,20 @@ class InteractionOutputTests {
121121
}
122122
}
123123

124-
@test async "should accept returning unexpected value with no validation"() {
125-
// type boolean should not throw since we set ignoreValidation to true
124+
@test async "should accept returning unexpected value with no validation (synchronous==false)"() {
126125
const stream = Readable.from(Buffer.from("not boolean", "utf-8"));
127126
const content = new Content("application/json", stream);
128127

129-
const out = new InteractionOutput(content, {}, { type: "boolean" }, { ignoreValidation: true });
128+
const out = new ActionInteractionOutput(content, {}, { type: "boolean" }, false);
129+
const result = await out.value();
130+
expect(result).to.eql("not boolean");
131+
}
132+
133+
@test async "should accept returning unexpected value with no validation (synchronous===undefined)"() {
134+
const stream = Readable.from(Buffer.from("not boolean", "utf-8"));
135+
const content = new Content("application/json", stream);
136+
137+
const out = new ActionInteractionOutput(content, {}, { type: "boolean" });
130138
const result = await out.value();
131139
expect(result).to.eql("not boolean");
132140
}

packages/examples/src/security/oauth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
"ts-node": "10.9.1",
2020
"typescript": "4.7.4",
2121
"typescript-standard": "^0.3.36",
22-
"wot-typescript-definitions": "0.8.0-SNAPSHOT.30"
22+
"wot-typescript-definitions": "0.8.0-SNAPSHOT.31"
2323
}
2424
}

0 commit comments

Comments
 (0)