@reactoo/watchtogether-sdk-js 2.8.59 → 2.8.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/watchtogether-sdk.min.js +2 -2
- package/package.json +1 -1
- package/src/modules/wt-iot2.js +3 -1
- package/src/modules/wt-iot.js +0 -362
package/package.json
CHANGED
package/src/modules/wt-iot2.js
CHANGED
|
@@ -311,7 +311,9 @@ class Iot {
|
|
|
311
311
|
event === 'handsCleared' ||
|
|
312
312
|
event === 'volume_set' ||
|
|
313
313
|
event === 'asset_created' ||
|
|
314
|
-
event === 'attribute_updated'
|
|
314
|
+
event === 'attribute_updated' ||
|
|
315
|
+
event === 'session_terminating' ||
|
|
316
|
+
event === 'session_terminated'
|
|
315
317
|
) {
|
|
316
318
|
this.emit('message', {event, ...message, roomId})
|
|
317
319
|
}
|
package/src/modules/wt-iot.js
DELETED
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
import emitter from './wt-emitter';
|
|
2
|
-
import { decodeJanusDisplay } from "../models/utils";
|
|
3
|
-
import { mqtt, iot } from 'aws-iot-device-sdk-v2';
|
|
4
|
-
|
|
5
|
-
class Iot {
|
|
6
|
-
constructor(enableDebugFlag) {
|
|
7
|
-
Object.assign(this, emitter());
|
|
8
|
-
this.decoder = new TextDecoder('utf-8');
|
|
9
|
-
this.log = Iot.noop;
|
|
10
|
-
this.credentialsExpirationCheckIntervalId = null;
|
|
11
|
-
this.currentCredentialsExpirationStamp = null;
|
|
12
|
-
this.lastConnectParams = null;
|
|
13
|
-
this.connection = null;
|
|
14
|
-
this.subscribedTopics = new Set();
|
|
15
|
-
|
|
16
|
-
if (enableDebugFlag) {
|
|
17
|
-
this.enableDebug();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
static noop() {}
|
|
22
|
-
|
|
23
|
-
enableDebug() {
|
|
24
|
-
this.log = console.log.bind(console);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
connect(apiMqttUrl, apiMqttClientId, region, accessKeyId, secretAccessKey, sessionToken, expiration) {
|
|
28
|
-
this.log('iot connect called, we disconnect first just to be sure');
|
|
29
|
-
return this.disconnect()
|
|
30
|
-
.catch(() => {
|
|
31
|
-
// we dont care if disconnect fails
|
|
32
|
-
return Promise.resolve();
|
|
33
|
-
})
|
|
34
|
-
.then(() => {
|
|
35
|
-
this.log('iot connect');
|
|
36
|
-
this.startCredentialsExpirationCheck(expiration);
|
|
37
|
-
this.lastConnectParams = { apiMqttUrl, apiMqttClientId, region, accessKeyId, secretAccessKey, sessionToken, expiration };
|
|
38
|
-
|
|
39
|
-
const configBuilder = iot.AwsIotMqttConnectionConfigBuilder.new_with_websockets();
|
|
40
|
-
|
|
41
|
-
configBuilder.with_clean_session(true);
|
|
42
|
-
configBuilder.with_client_id(apiMqttClientId);
|
|
43
|
-
configBuilder.with_endpoint(apiMqttUrl);
|
|
44
|
-
configBuilder.with_credentials(region, accessKeyId, secretAccessKey, sessionToken);
|
|
45
|
-
configBuilder.with_keep_alive_seconds(30);
|
|
46
|
-
configBuilder.with_ping_timeout_ms(3000);
|
|
47
|
-
configBuilder.with_reconnect_max_sec(5);
|
|
48
|
-
configBuilder.with_reconnect_min_sec(1);
|
|
49
|
-
|
|
50
|
-
const config = configBuilder.build();
|
|
51
|
-
|
|
52
|
-
const client = new mqtt.MqttClient();
|
|
53
|
-
this.connection = client.new_connection(config);
|
|
54
|
-
|
|
55
|
-
this.connection.on('connect', () => {
|
|
56
|
-
this.emit('connect');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
this.connection.on('closed', (error) => {
|
|
60
|
-
this.emit('closed', error);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
this.connection.on('disconnect', () => {
|
|
64
|
-
this.emit('disconnect');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
this.connection.on('error', (error) => {
|
|
68
|
-
this.emit('error', error);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
this.connection.on('interrupt', (error) => {
|
|
72
|
-
this.emit('interrupt', error);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
this.connection.on('resume', (error) => {
|
|
76
|
-
this.emit('resume', error);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
this.connection.on('message', (topic, payload) => {
|
|
80
|
-
this.handleMessage(topic, new Uint8Array(payload));
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
this.connection.on('connection_success', (error) => {
|
|
84
|
-
this.emit('connection_success', error);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
this.connection.on('connection_failure', (error) => {
|
|
88
|
-
this.emit('connection_failure', error);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
const timeoutId = setTimeout(() => {
|
|
93
|
-
reject(new Error('Connection timeout'));
|
|
94
|
-
}, 5000); // 5 seconds timeout is enough
|
|
95
|
-
this.connection.connect()
|
|
96
|
-
.then((r) => {
|
|
97
|
-
clearTimeout(timeoutId);
|
|
98
|
-
resolve(r);
|
|
99
|
-
})
|
|
100
|
-
.catch((error) => {
|
|
101
|
-
clearTimeout(timeoutId);
|
|
102
|
-
reject(error);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
disconnect() {
|
|
110
|
-
this.log('iot disconnect');
|
|
111
|
-
this.stopCredentialsExpirationCheck();
|
|
112
|
-
if (this.connection) {
|
|
113
|
-
return new Promise((resolve, reject) => {
|
|
114
|
-
const timeoutId = setTimeout(() => {
|
|
115
|
-
reject(new Error('Disconnect timeout'));
|
|
116
|
-
}, 5000); // 5 seconds timeout is enough
|
|
117
|
-
this.connection.disconnect()
|
|
118
|
-
.then((r) => {
|
|
119
|
-
clearTimeout(timeoutId);
|
|
120
|
-
resolve(r);
|
|
121
|
-
})
|
|
122
|
-
.catch((error) => {
|
|
123
|
-
clearTimeout(timeoutId);
|
|
124
|
-
reject(error);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
} else return Promise.resolve();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
isConnected() {
|
|
131
|
-
return this.connection && this.connection.currentState === 0 && this.connection.desiredState === 0;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
clearTopics() {
|
|
135
|
-
this.subscribedTopics.clear();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
subscribe(topic) {
|
|
139
|
-
this.log('iot subscribe', topic);
|
|
140
|
-
if (this.connection && this.connection.currentState === 0 && this.connection.desiredState === 0 && typeof topic === 'string' && topic.trim() !== '') {
|
|
141
|
-
this.subscribedTopics.add(topic);
|
|
142
|
-
return this.connection.subscribe(topic, mqtt.QoS.AtLeastOnce)
|
|
143
|
-
.catch(err => {
|
|
144
|
-
this.log('Error subscribing to topic:', err);
|
|
145
|
-
this.subscribedTopics.delete(topic);
|
|
146
|
-
return Promise.reject(err);
|
|
147
|
-
});
|
|
148
|
-
} else {
|
|
149
|
-
this.log('Invalid topic or not connected:', topic);
|
|
150
|
-
return Promise.reject(new Error('Invalid topic or not connected'));
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
unsubscribe(topic) {
|
|
155
|
-
this.log('iot unsubscribe', topic);
|
|
156
|
-
if (this.connection && this.connection.currentState === 0 && this.connection.desiredState === 0 && typeof topic === 'string' && topic.trim() !== '') {
|
|
157
|
-
this.subscribedTopics.delete(topic);
|
|
158
|
-
return this.connection.unsubscribe(topic)
|
|
159
|
-
.catch(err => {
|
|
160
|
-
this.log('Error unsubscribing from topic:', err);
|
|
161
|
-
this.subscribedTopics.add(topic);
|
|
162
|
-
return Promise.reject(err);
|
|
163
|
-
});
|
|
164
|
-
} else {
|
|
165
|
-
this.log('Invalid topic or not connected:', topic);
|
|
166
|
-
return Promise.reject(new Error('Invalid topic or not connected'));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
send(topic, message) {
|
|
171
|
-
this.log('iot send', topic, message);
|
|
172
|
-
let msg = typeof message === 'object' ? JSON.stringify(message) : message;
|
|
173
|
-
if (this.connection && this.connection.currentState === 0 && this.connection.desiredState === 0) {
|
|
174
|
-
this.connection.publish(topic, msg, mqtt.QoS.AtLeastOnce, false);
|
|
175
|
-
} else {
|
|
176
|
-
throw new Error('Invalid topic or not connected:', topic);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
handleMessage(topic, payload) {
|
|
181
|
-
const topicParts = topic.split('/');
|
|
182
|
-
let message;
|
|
183
|
-
try {
|
|
184
|
-
message = JSON.parse(this.decoder.decode(payload));
|
|
185
|
-
} catch (error) {
|
|
186
|
-
this.log('Error parsing message:', error);
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if(message.display) {
|
|
191
|
-
const decodedDisplay = decodeJanusDisplay(message.display);
|
|
192
|
-
if(decodedDisplay.userId) {
|
|
193
|
-
message = {...message, userId: decodedDisplay.userId, role: decodedDisplay.role, start: decodedDisplay.start};
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if(topicParts[0] === 'user') { // user
|
|
198
|
-
const userId = topicParts[1].replace("_", ':');
|
|
199
|
-
this.emit('message', {userId, ...message, event: message.event ? `user:${message.event}` : 'user'});
|
|
200
|
-
} else if(topicParts[0] === 'wt') {
|
|
201
|
-
const event = message.event;
|
|
202
|
-
const roomId = topicParts[2];
|
|
203
|
-
if(topicParts[1] === 'room') { // room
|
|
204
|
-
if(
|
|
205
|
-
event === 'message' ||
|
|
206
|
-
event === 'template_updated' ||
|
|
207
|
-
event === 'record_start' ||
|
|
208
|
-
event === 'record_stop' ||
|
|
209
|
-
event === 'record_configured' ||
|
|
210
|
-
event === 'record_livestream_available' ||
|
|
211
|
-
event === 'record_livestream_kick' ||
|
|
212
|
-
event === 'user_update_displayname' ||
|
|
213
|
-
event === 'user_update_avatar' ||
|
|
214
|
-
event === 'user_update_bio' ||
|
|
215
|
-
event === 'user_update_customattributes' ||
|
|
216
|
-
event === 'user_update_privateattributes' ||
|
|
217
|
-
event === 'channel_changed' ||
|
|
218
|
-
event === "instance_homepage_changed" ||
|
|
219
|
-
event === "instance_settings_changed" ||
|
|
220
|
-
event === "externalmix_changed" ||
|
|
221
|
-
event === "video_uploaded" ||
|
|
222
|
-
event === "change_user_devices" ||
|
|
223
|
-
event === "queue" ||
|
|
224
|
-
event === "title_changed" ||
|
|
225
|
-
event === "videowall_changed" ||
|
|
226
|
-
event === 'left' || //user removed room a.k.a. left the room
|
|
227
|
-
event === 'kicked' ||
|
|
228
|
-
event === 'banned' ||
|
|
229
|
-
event === 'unbanned' ||
|
|
230
|
-
event === 'approved' ||
|
|
231
|
-
event === 'muted' ||
|
|
232
|
-
event === 'unmuted' ||
|
|
233
|
-
event === 'messageRemoved' ||
|
|
234
|
-
event === 'messageReported' ||
|
|
235
|
-
event === 'chatClear' ||
|
|
236
|
-
event === 'handRaised' ||
|
|
237
|
-
event === 'handLowered' ||
|
|
238
|
-
event === 'handsCleared' ||
|
|
239
|
-
event === 'volume_set' ||
|
|
240
|
-
event === 'asset_created'
|
|
241
|
-
) {
|
|
242
|
-
this.emit('message', {event, ...message, roomId})
|
|
243
|
-
}
|
|
244
|
-
else if(event === 'joined' || event === 'leaving') {
|
|
245
|
-
this.emit('message', {event, ...message, isObserver:!!message.isObserver, roomId});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
else if(topicParts[1] === 'instanceroom') { // instance
|
|
249
|
-
if(event === 'add_room' || event === 'remove_room' || event === 'set_room' || event === "instance_homepage_changed" || event === 'instance_settings_changed') {
|
|
250
|
-
this.emit('message', {event, ...message});
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else if(topicParts[1] === 'externalmix') {
|
|
254
|
-
const event = message.event;
|
|
255
|
-
this.emit('message', {event, ...message});
|
|
256
|
-
}
|
|
257
|
-
else if(topicParts[1] === 'asset') {
|
|
258
|
-
this.emit('message', {event: 'asset', assetId: topicParts[2], ...message});
|
|
259
|
-
}
|
|
260
|
-
} else if(topicParts[0] === 'wtr' || topicParts[0] === 'gwtr') {
|
|
261
|
-
const recorderId = topicParts[1];
|
|
262
|
-
const sessionId = topicParts[2];
|
|
263
|
-
if(topicParts[3] === 'control') {
|
|
264
|
-
this.emit('message', {event: 'recorder_control', ...message, recorderId, sessionId});
|
|
265
|
-
} // recorder control
|
|
266
|
-
else if(topicParts[3] === 'monitor') {
|
|
267
|
-
this.emit('message', {event: 'recorder_monitor', ...message, recorderId, sessionId});
|
|
268
|
-
} // recorder monitor
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
startCredentialsExpirationCheck(expiration) {
|
|
273
|
-
this.stopCredentialsExpirationCheck();
|
|
274
|
-
this.currentCredentialsExpirationStamp = new Date(expiration).getTime();
|
|
275
|
-
this.credentialsExpirationCheckIntervalId = setInterval(() => {
|
|
276
|
-
const currentTimeStamp = new Date().getTime();
|
|
277
|
-
// update 15 minutes before expiration
|
|
278
|
-
if(this.currentCredentialsExpirationStamp - currentTimeStamp <= 900000) {
|
|
279
|
-
this.log('iot credentials expired, updating');
|
|
280
|
-
this.emit('updateCredentials');
|
|
281
|
-
}
|
|
282
|
-
}, 5000);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
stopCredentialsExpirationCheck() {
|
|
286
|
-
clearInterval(this.credentialsExpirationCheckIntervalId);
|
|
287
|
-
this.credentialsExpirationCheckIntervalId = null;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken, expiration) {
|
|
291
|
-
this.log('iot updateWebSocketCredentials');
|
|
292
|
-
this.lastConnectParams = {...this.lastConnectParams, accessKeyId, secretAccessKey, sessionToken, expiration };
|
|
293
|
-
const currentTopics = new Set(this.subscribedTopics);
|
|
294
|
-
// disconnect is part of connect process
|
|
295
|
-
return this.connect(
|
|
296
|
-
this.lastConnectParams.apiMqttUrl,
|
|
297
|
-
this.lastConnectParams.apiMqttClientId,
|
|
298
|
-
this.lastConnectParams.region,
|
|
299
|
-
accessKeyId,
|
|
300
|
-
secretAccessKey,
|
|
301
|
-
sessionToken,
|
|
302
|
-
expiration
|
|
303
|
-
).then(() => {
|
|
304
|
-
// Resubscribe to topics
|
|
305
|
-
currentTopics.forEach(topic => this.subscribe(topic));
|
|
306
|
-
return true;
|
|
307
|
-
})
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
checkConnection() {
|
|
311
|
-
return new Promise((resolve, reject) => {
|
|
312
|
-
if (!this.connection || !(this.connection.currentState === 0 && this.connection.desiredState === 0)) {
|
|
313
|
-
reject(new Error('Not connected'));
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (this.subscribedTopics.size === 0) {
|
|
318
|
-
reject(new Error('No subscribed topics available for connection check', {cause: -1}));
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Find a suitable topic for the connection check
|
|
323
|
-
let suitableTopic = Array.from(this.subscribedTopics).find(topic => topic.indexOf('user') > -1);
|
|
324
|
-
|
|
325
|
-
if (!suitableTopic) {
|
|
326
|
-
reject(new Error('No suitable topic found for connection check', {cause: -1}));
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const testMessage = {
|
|
331
|
-
type: 'keep_alive',
|
|
332
|
-
timestamp: Date.now()
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
const timeoutId = setTimeout(() => {
|
|
336
|
-
this.off('message', checkMessageHandler);
|
|
337
|
-
reject(new Error('Connection check timeout'));
|
|
338
|
-
}, 5000); // 5 seconds timeout
|
|
339
|
-
|
|
340
|
-
const checkMessageHandler = (message) => {
|
|
341
|
-
if (message.type === 'keep_alive' && message.timestamp === testMessage.timestamp) {
|
|
342
|
-
clearTimeout(timeoutId);
|
|
343
|
-
this.off('message', checkMessageHandler);
|
|
344
|
-
resolve();
|
|
345
|
-
}
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
this.on('message', checkMessageHandler);
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
this.send(suitableTopic, testMessage);
|
|
352
|
-
} catch (error) {
|
|
353
|
-
clearTimeout(timeoutId);
|
|
354
|
-
this.off('message', checkMessageHandler);
|
|
355
|
-
reject(new Error(`Publish error: ${error.message}`));
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export default Iot;
|
|
362
|
-
|