forked from WebThingsIO/webthing-node-2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy paththing.js
More file actions
172 lines (155 loc) · 4.37 KB
/
thing.js
File metadata and controls
172 lines (155 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import ValidationError from './validation-error.js';
/**
* Thing.
*
* Represents a W3C WoT Web Thing.
*/
class Thing {
DEFAULT_CONTEXT = 'https://www.w3.org/2022/wot/td/v1.1';
propertyReadHandlers = new Map();
/**
* Construct Thing from partial Thing Description.
*
* @param {Record<string, any>} partialTD A partial Thing Description
* to which Forms will be added.
*/
constructor(partialTD) {
// Create an empty validation error to collect errors during parsing.
let validationError = new ValidationError([]);
// Parse @context member
try {
this.parseContextMember(partialTD['@context']);
} catch (error) {
if (error instanceof ValidationError) {
validationError.validationErrors.push(...error.validationErrors);
} else {
throw error;
}
}
// Parse title member
try {
this.parseTitleMember(partialTD.title);
} catch (error) {
if (error instanceof ValidationError) {
validationError.validationErrors.push(...error.validationErrors);
} else {
throw error;
}
}
// Hard code the nosec security scheme for now
this.securityDefinitions = {
nosec_sc: {
scheme: 'nosec',
},
};
this.security = 'nosec_sc';
}
/**
* Parse the @context member of a Thing Description.
*
* @param {any} context The @context, if any, provided in the partialTD.
* @throws {ValidationError} A validation error.
*/
parseContextMember(context) {
// If no @context provided then set it to the default
if (context === undefined) {
this.context = this.DEFAULT_CONTEXT;
return;
}
// If @context is a string but not the default then turn it into an Array
// and add the default as well
if (typeof context === 'string') {
if (context == this.DEFAULT_CONTEXT) {
this.context = context;
return;
} else {
this.context = new Array();
this.context.push(context);
this.context.push(this.DEFAULT_CONTEXT);
}
return;
}
// If @context is provided and it's an array but doesn't contain the default,
// then add the default
if (Array.isArray(context)) {
// TODO: Check that members of the Array are valid
this.context = context;
if (!this.context.includes(this.DEFAULT_CONTEXT)) {
this.context.push(this.DEFAULT_CONTEXT);
}
return;
}
// If @context is set but it's not a string or Array then it's invalid
throw new ValidationError([
{
field: 'title',
description: 'context member is set but is not a string or Array',
},
]);
}
/**
* Parse the title member of a Thing Description.
*
* @param {string} title The title provided in the partialTD.
* @throws {ValidationError} A validation error.
*/
parseTitleMember(title) {
// Require the user to provide a title
if (!title) {
throw new ValidationError([
{
field: '(root)',
description: 'Mandatory title member not provided',
},
]);
}
if (typeof title !== 'string') {
throw new ValidationError([
{
field: 'title',
description: 'title member is not a string',
},
]);
}
this.title = title;
}
/**
* Get Thing Description.
*
* @returns {Object} A complete Thing Description for the Thing.
*/
getThingDescription() {
const thingDescription = {
'@context': this.context,
title: this.title,
securityDefinitions: this.securityDefinitions,
security: this.security,
};
return thingDescription;
}
/**
* Set Property Read Handler.
*
* @param {string} name The name of the property to handle.
* @param {function} handler A function to handle property reads.
*/
setPropertyReadHandler(name, handler) {
this.propertyReadHandlers.set(name, handler);
}
/**
* Read Property.
*
* @param {string} name The name of the property to read.
* @returns {any} The current value of the property, with a format conforming
* to its data schema in the Thing Description.
*/
readProperty(name) {
if (!this.propertyReadHandlers.has(name)) {
console.error('No property read handler for the property ' + name);
throw new Error();
} else {
return this.propertyReadHandlers.get(name)();
}
}
}
export default Thing;