@fluidframework/azure-end-to-end-tests 2.70.0-361248 → 2.70.0
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/CHANGELOG.md +4 -0
- package/lib/test/multiprocess/childClient.tool.js +226 -104
- package/lib/test/multiprocess/childClient.tool.js.map +1 -1
- package/lib/test/multiprocess/messageTypes.js.map +1 -1
- package/lib/test/multiprocess/orchestratorUtils.js +72 -17
- package/lib/test/multiprocess/orchestratorUtils.js.map +1 -1
- package/lib/test/multiprocess/presenceTest.spec.js +151 -100
- package/lib/test/multiprocess/presenceTest.spec.js.map +1 -1
- package/package.json +24 -23
- package/src/test/multiprocess/childClient.tool.ts +277 -131
- package/src/test/multiprocess/messageTypes.ts +36 -0
- package/src/test/multiprocess/orchestratorUtils.ts +121 -23
- package/src/test/multiprocess/presenceTest.spec.ts +202 -125
package/CHANGELOG.md
CHANGED
|
@@ -24,28 +24,42 @@ const endPoint = process.env.azure__fluid__relay__service__endpoint;
|
|
|
24
24
|
if (useAzure && endPoint === undefined) {
|
|
25
25
|
throw new Error("Azure Fluid Relay service endpoint is missing");
|
|
26
26
|
}
|
|
27
|
+
const containerSchema = {
|
|
28
|
+
initialObjects: {
|
|
29
|
+
// A DataObject is added as otherwise fluid-static complains "Container cannot be initialized without any DataTypes"
|
|
30
|
+
_unused: TestDataObject,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
function telemetryEventInterestLevel(eventName) {
|
|
34
|
+
if (eventName.includes(":Signal") || eventName.includes(":Join")) {
|
|
35
|
+
return "details";
|
|
36
|
+
}
|
|
37
|
+
else if (eventName.includes(":Container:") || eventName.includes(":Presence:")) {
|
|
38
|
+
return "basic";
|
|
39
|
+
}
|
|
40
|
+
return "none";
|
|
41
|
+
}
|
|
27
42
|
function selectiveVerboseLog(event, logLevel) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
details: event.details,
|
|
32
|
-
containerConnectionState: event.containerConnectionState,
|
|
33
|
-
});
|
|
43
|
+
const interest = telemetryEventInterestLevel(event.eventName);
|
|
44
|
+
if (interest === "none") {
|
|
45
|
+
return;
|
|
34
46
|
}
|
|
35
|
-
|
|
36
|
-
event.eventName
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
const content = {
|
|
48
|
+
eventName: event.eventName,
|
|
49
|
+
containerConnectionState: event.containerConnectionState,
|
|
50
|
+
};
|
|
51
|
+
if (interest === "details") {
|
|
52
|
+
content.details = event.details;
|
|
41
53
|
}
|
|
54
|
+
console.log(`[${process_id}] [${logLevel ?? LogLevel.default}]`, content);
|
|
42
55
|
}
|
|
43
56
|
/**
|
|
44
|
-
* Get or create a Fluid container
|
|
57
|
+
* Get or create a Fluid container.
|
|
45
58
|
*/
|
|
46
|
-
const
|
|
59
|
+
const getOrCreateContainer = async (params) => {
|
|
47
60
|
let container;
|
|
48
|
-
let containerId;
|
|
61
|
+
let { containerId } = params;
|
|
62
|
+
const { logger, onDisconnected, user, scopes, createScopes } = params;
|
|
49
63
|
const connectionProps = useAzure
|
|
50
64
|
? {
|
|
51
65
|
tenantId,
|
|
@@ -60,40 +74,30 @@ const getOrCreatePresenceContainer = async (id, user, scopes, createScopes) => {
|
|
|
60
74
|
};
|
|
61
75
|
const client = new AzureClient({
|
|
62
76
|
connection: connectionProps,
|
|
63
|
-
logger
|
|
64
|
-
send: verbosity.includes("telem") ? selectiveVerboseLog : () => { },
|
|
65
|
-
},
|
|
77
|
+
logger,
|
|
66
78
|
});
|
|
67
|
-
const schema = {
|
|
68
|
-
initialObjects: {
|
|
69
|
-
// A DataObject is added as otherwise fluid-static complains "Container cannot be initialized without any DataTypes"
|
|
70
|
-
_unused: TestDataObject,
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
79
|
let services;
|
|
74
|
-
if (
|
|
75
|
-
({ container, services } = await client.createContainer(
|
|
80
|
+
if (containerId === undefined) {
|
|
81
|
+
({ container, services } = await client.createContainer(containerSchema, "2"));
|
|
76
82
|
containerId = await container.attach();
|
|
77
83
|
}
|
|
78
84
|
else {
|
|
79
|
-
|
|
80
|
-
({ container, services } = await client.getContainer(containerId, schema, "2"));
|
|
85
|
+
({ container, services } = await client.getContainer(containerId, containerSchema, "2"));
|
|
81
86
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
container.on("disconnected", onDisconnected);
|
|
88
|
+
const connected = container.connectionState === ConnectionState.Connected
|
|
89
|
+
? Promise.resolve()
|
|
90
|
+
: timeoutPromise((resolve) => container.once("connected", () => resolve()), {
|
|
85
91
|
durationMs: connectTimeoutMs,
|
|
86
92
|
errorMsg: "container connect() timeout",
|
|
87
93
|
});
|
|
88
|
-
}
|
|
89
94
|
assert.strictEqual(container.attachState, AttachState.Attached, "Container is not attached after attach is called");
|
|
90
|
-
const presence = getPresence(container);
|
|
91
95
|
return {
|
|
92
96
|
client,
|
|
93
97
|
container,
|
|
94
|
-
presence,
|
|
95
98
|
services,
|
|
96
99
|
containerId,
|
|
100
|
+
connected,
|
|
97
101
|
};
|
|
98
102
|
};
|
|
99
103
|
function createSendFunction() {
|
|
@@ -110,21 +114,6 @@ function createSendFunction() {
|
|
|
110
114
|
throw new Error("process.send is not defined");
|
|
111
115
|
}
|
|
112
116
|
const send = createSendFunction();
|
|
113
|
-
function sendAttendeeConnected(attendee) {
|
|
114
|
-
send({
|
|
115
|
-
event: "attendeeConnected",
|
|
116
|
-
attendeeId: attendee.attendeeId,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
function sendAttendeeDisconnected(attendee) {
|
|
120
|
-
send({
|
|
121
|
-
event: "attendeeDisconnected",
|
|
122
|
-
attendeeId: attendee.attendeeId,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
function isConnected(container) {
|
|
126
|
-
return container !== undefined && container.connectionState === ConnectionState.Connected;
|
|
127
|
-
}
|
|
128
117
|
function isStringOrNumberRecord(value) {
|
|
129
118
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
130
119
|
return false;
|
|
@@ -145,11 +134,66 @@ function isStringOrNumberRecord(value) {
|
|
|
145
134
|
const WorkspaceSchema = {};
|
|
146
135
|
class MessageHandler {
|
|
147
136
|
constructor() {
|
|
137
|
+
this.log = [];
|
|
148
138
|
this.workspaces = new Map();
|
|
139
|
+
this.sendAttendeeConnected = (attendee) => {
|
|
140
|
+
this.send({
|
|
141
|
+
event: "attendeeConnected",
|
|
142
|
+
attendeeId: attendee.attendeeId,
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
this.sendAttendeeDisconnected = (attendee) => {
|
|
146
|
+
this.send({
|
|
147
|
+
event: "attendeeDisconnected",
|
|
148
|
+
attendeeId: attendee.attendeeId,
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
this.logger = {
|
|
152
|
+
send: (event, logLevel) => {
|
|
153
|
+
// Special case unexpected telemetry event
|
|
154
|
+
if (event.eventName.endsWith(":JoinResponseWhenAlone")) {
|
|
155
|
+
this.send({
|
|
156
|
+
event: "error",
|
|
157
|
+
error: `Unexpected ClientJoin response. Details: ${JSON.stringify(event.details)}`,
|
|
158
|
+
});
|
|
159
|
+
// Keep going
|
|
160
|
+
}
|
|
161
|
+
const interest = telemetryEventInterestLevel(event.eventName);
|
|
162
|
+
if (interest === "none") {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.log.push({
|
|
166
|
+
timestamp: Date.now(),
|
|
167
|
+
agentId: process_id,
|
|
168
|
+
eventCategory: "telemetry",
|
|
169
|
+
eventName: event.eventName,
|
|
170
|
+
details: typeof event.details === "string" ? event.details : JSON.stringify(event.details),
|
|
171
|
+
});
|
|
172
|
+
if (verbosity.includes("telem")) {
|
|
173
|
+
selectiveVerboseLog(event, logLevel);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
this.onDisconnected = () => {
|
|
178
|
+
// Test state is a bit fragile and does not account for reconnections.
|
|
179
|
+
this.send({ event: "error", error: `${process_id}: Container disconnected` });
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
send(msg) {
|
|
183
|
+
this.log.push({
|
|
184
|
+
timestamp: Date.now(),
|
|
185
|
+
agentId: process_id,
|
|
186
|
+
eventCategory: "messageSent",
|
|
187
|
+
eventName: msg.event,
|
|
188
|
+
details: msg.event === "debugReportComplete" && msg.log
|
|
189
|
+
? JSON.stringify({ logLength: msg.log.length })
|
|
190
|
+
: JSON.stringify(msg),
|
|
191
|
+
});
|
|
192
|
+
send(msg);
|
|
149
193
|
}
|
|
150
194
|
registerWorkspace(workspaceId, options) {
|
|
151
195
|
if (!this.presence) {
|
|
152
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
196
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
153
197
|
return;
|
|
154
198
|
}
|
|
155
199
|
const { latest, latestMap } = options;
|
|
@@ -160,7 +204,7 @@ class MessageHandler {
|
|
|
160
204
|
// TODO: AB#47518
|
|
161
205
|
const latestState = workspace.states.latest;
|
|
162
206
|
latestState.events.on("remoteUpdated", (update) => {
|
|
163
|
-
send({
|
|
207
|
+
this.send({
|
|
164
208
|
event: "latestValueUpdated",
|
|
165
209
|
workspaceId,
|
|
166
210
|
attendeeId: update.attendee.attendeeId,
|
|
@@ -168,7 +212,7 @@ class MessageHandler {
|
|
|
168
212
|
});
|
|
169
213
|
});
|
|
170
214
|
for (const remote of latestState.getRemotes()) {
|
|
171
|
-
send({
|
|
215
|
+
this.send({
|
|
172
216
|
event: "latestValueUpdated",
|
|
173
217
|
workspaceId,
|
|
174
218
|
attendeeId: remote.attendee.attendeeId,
|
|
@@ -185,7 +229,7 @@ class MessageHandler {
|
|
|
185
229
|
const latestMapState = workspace.states.latestMap;
|
|
186
230
|
latestMapState.events.on("remoteUpdated", (update) => {
|
|
187
231
|
for (const [key, valueWithMetadata] of update.items) {
|
|
188
|
-
send({
|
|
232
|
+
this.send({
|
|
189
233
|
event: "latestMapValueUpdated",
|
|
190
234
|
workspaceId,
|
|
191
235
|
attendeeId: update.attendee.attendeeId,
|
|
@@ -196,7 +240,7 @@ class MessageHandler {
|
|
|
196
240
|
});
|
|
197
241
|
for (const remote of latestMapState.getRemotes()) {
|
|
198
242
|
for (const [key, valueWithMetadata] of remote.items) {
|
|
199
|
-
send({
|
|
243
|
+
this.send({
|
|
200
244
|
event: "latestMapValueUpdated",
|
|
201
245
|
workspaceId,
|
|
202
246
|
attendeeId: remote.attendee.attendeeId,
|
|
@@ -207,7 +251,7 @@ class MessageHandler {
|
|
|
207
251
|
}
|
|
208
252
|
}
|
|
209
253
|
this.workspaces.set(workspaceId, workspace);
|
|
210
|
-
send({
|
|
254
|
+
this.send({
|
|
211
255
|
event: "workspaceRegistered",
|
|
212
256
|
workspaceId,
|
|
213
257
|
latest: latest ?? false,
|
|
@@ -216,15 +260,33 @@ class MessageHandler {
|
|
|
216
260
|
}
|
|
217
261
|
async onMessage(msg) {
|
|
218
262
|
if (verbosity.includes("msgs")) {
|
|
263
|
+
this.log.push({
|
|
264
|
+
timestamp: Date.now(),
|
|
265
|
+
agentId: process_id,
|
|
266
|
+
eventCategory: "messageReceived",
|
|
267
|
+
eventName: msg.command,
|
|
268
|
+
});
|
|
219
269
|
console.log(`[${process_id}] Received`, msg);
|
|
220
270
|
}
|
|
271
|
+
if (msg.command === "ping") {
|
|
272
|
+
this.handlePing();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (msg.command === "connect") {
|
|
276
|
+
await this.handleConnect(msg);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// All other message must wait if connect is in progress
|
|
280
|
+
if (this.msgQueue !== undefined) {
|
|
281
|
+
this.msgQueue.push(msg);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
this.processMessage(msg);
|
|
285
|
+
}
|
|
286
|
+
processMessage(msg) {
|
|
221
287
|
switch (msg.command) {
|
|
222
|
-
case "
|
|
223
|
-
this.
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case "connect": {
|
|
227
|
-
await this.handleConnect(msg);
|
|
288
|
+
case "debugReport": {
|
|
289
|
+
this.handleDebugReport(msg);
|
|
228
290
|
break;
|
|
229
291
|
}
|
|
230
292
|
case "disconnectSelf": {
|
|
@@ -255,74 +317,125 @@ class MessageHandler {
|
|
|
255
317
|
break;
|
|
256
318
|
}
|
|
257
319
|
default: {
|
|
258
|
-
console.error(`${process_id}: Unknown command
|
|
259
|
-
send({
|
|
320
|
+
console.error(`${process_id}: Unknown command:`, msg);
|
|
321
|
+
this.send({
|
|
322
|
+
event: "error",
|
|
323
|
+
error: `${process_id} Unknown command: ${JSON.stringify(msg)}`,
|
|
324
|
+
});
|
|
260
325
|
}
|
|
261
326
|
}
|
|
262
327
|
}
|
|
263
328
|
handlePing() {
|
|
264
|
-
send({ event: "ack" });
|
|
329
|
+
this.send({ event: "ack" });
|
|
265
330
|
}
|
|
266
331
|
async handleConnect(msg) {
|
|
267
332
|
if (!msg.user) {
|
|
268
|
-
send({ event: "error", error: `${process_id}: No azure user information given` });
|
|
333
|
+
this.send({ event: "error", error: `${process_id}: No azure user information given` });
|
|
269
334
|
return;
|
|
270
335
|
}
|
|
271
|
-
if (
|
|
272
|
-
send({ event: "error", error: `${process_id}:
|
|
336
|
+
if (this.container) {
|
|
337
|
+
this.send({ event: "error", error: `${process_id}: Container already loaded` });
|
|
273
338
|
return;
|
|
274
339
|
}
|
|
275
|
-
|
|
276
|
-
this.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
340
|
+
// Prevent reentrance. Queue messages until after connect is fully processed.
|
|
341
|
+
this.msgQueue = [];
|
|
342
|
+
try {
|
|
343
|
+
const { container, containerId, connected } = await getOrCreateContainer({
|
|
344
|
+
...msg,
|
|
345
|
+
logger: this.logger,
|
|
346
|
+
onDisconnected: this.onDisconnected,
|
|
347
|
+
});
|
|
348
|
+
this.container = container;
|
|
349
|
+
const presence = getPresence(container);
|
|
350
|
+
this.presence = presence;
|
|
351
|
+
// wait for 'ConnectionState.Connected'
|
|
352
|
+
await connected;
|
|
353
|
+
// Acknowledge connection before sending current attendee information
|
|
354
|
+
this.send({
|
|
355
|
+
event: "connected",
|
|
356
|
+
containerId,
|
|
357
|
+
attendeeId: presence.attendees.getMyself().attendeeId,
|
|
358
|
+
});
|
|
359
|
+
// Send existing attendees excluding self to parent/orchestrator
|
|
360
|
+
const self = presence.attendees.getMyself();
|
|
361
|
+
for (const attendee of presence.attendees.getAttendees()) {
|
|
362
|
+
if (attendee !== self && attendee.getConnectionStatus() === "Connected") {
|
|
363
|
+
this.sendAttendeeConnected(attendee);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Listen for presence events to notify parent/orchestrator when a new attendee joins or leaves the session.
|
|
367
|
+
presence.attendees.events.on("attendeeConnected", this.sendAttendeeConnected);
|
|
368
|
+
presence.attendees.events.on("attendeeDisconnected", this.sendAttendeeDisconnected);
|
|
369
|
+
}
|
|
370
|
+
finally {
|
|
371
|
+
// Process any queued messages received while connecting
|
|
372
|
+
for (const queuedMsg of this.msgQueue) {
|
|
373
|
+
this.processMessage(queuedMsg);
|
|
290
374
|
}
|
|
375
|
+
this.msgQueue = undefined;
|
|
291
376
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
377
|
+
}
|
|
378
|
+
handleDebugReport(msg) {
|
|
379
|
+
if (msg.reportAttendees) {
|
|
380
|
+
if (this.presence) {
|
|
381
|
+
const attendees = this.presence.attendees.getAttendees();
|
|
382
|
+
let connectedCount = 0;
|
|
383
|
+
for (const attendee of attendees) {
|
|
384
|
+
if (attendee.getConnectionStatus() === "Connected") {
|
|
385
|
+
connectedCount++;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
console.log(`[${process_id}] Report: ${attendees.size} attendees, ${connectedCount} connected`);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const debugReport = {
|
|
395
|
+
event: "debugReportComplete",
|
|
396
|
+
};
|
|
397
|
+
if (msg.sendEventLog) {
|
|
398
|
+
debugReport.log = this.log;
|
|
399
|
+
}
|
|
400
|
+
this.send(debugReport);
|
|
295
401
|
}
|
|
296
402
|
handleDisconnectSelf() {
|
|
297
403
|
if (!this.container) {
|
|
298
|
-
send({ event: "error", error: `${process_id} is not connected to container` });
|
|
404
|
+
this.send({ event: "error", error: `${process_id} is not connected to container` });
|
|
299
405
|
return;
|
|
300
406
|
}
|
|
407
|
+
// There are no current scenarios where disconnect without presence is expected.
|
|
301
408
|
if (!this.presence) {
|
|
302
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
409
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
303
410
|
return;
|
|
304
411
|
}
|
|
412
|
+
// Disconnect event is treated as an error in normal handling.
|
|
413
|
+
// Remove listener as this disconnect is intentional.
|
|
414
|
+
this.container.off("disconnected", this.onDisconnected);
|
|
305
415
|
this.container.disconnect();
|
|
306
|
-
send({
|
|
416
|
+
this.send({
|
|
307
417
|
event: "disconnectedSelf",
|
|
308
418
|
attendeeId: this.presence.attendees.getMyself().attendeeId,
|
|
309
419
|
});
|
|
310
420
|
}
|
|
311
421
|
handleSetLatestValue(msg) {
|
|
312
422
|
if (!this.presence) {
|
|
313
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
423
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
314
424
|
return;
|
|
315
425
|
}
|
|
316
426
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
317
427
|
if (!workspace) {
|
|
318
|
-
send({
|
|
428
|
+
this.send({
|
|
429
|
+
event: "error",
|
|
430
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
431
|
+
});
|
|
319
432
|
return;
|
|
320
433
|
}
|
|
321
434
|
// Cast required due to optional keys in WorkspaceSchema
|
|
322
435
|
// TODO: AB#47518
|
|
323
436
|
const latestState = workspace.states.latest;
|
|
324
437
|
if (!latestState) {
|
|
325
|
-
send({
|
|
438
|
+
this.send({
|
|
326
439
|
event: "error",
|
|
327
440
|
error: `${process_id} latest state not registered for workspace ${msg.workspaceId}`,
|
|
328
441
|
});
|
|
@@ -335,23 +448,26 @@ class MessageHandler {
|
|
|
335
448
|
}
|
|
336
449
|
handleSetLatestMapValue(msg) {
|
|
337
450
|
if (!this.presence) {
|
|
338
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
451
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
339
452
|
return;
|
|
340
453
|
}
|
|
341
454
|
if (typeof msg.key !== "string") {
|
|
342
|
-
send({ event: "error", error: `${process_id} invalid key type` });
|
|
455
|
+
this.send({ event: "error", error: `${process_id} invalid key type` });
|
|
343
456
|
return;
|
|
344
457
|
}
|
|
345
458
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
346
459
|
if (!workspace) {
|
|
347
|
-
send({
|
|
460
|
+
this.send({
|
|
461
|
+
event: "error",
|
|
462
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
463
|
+
});
|
|
348
464
|
return;
|
|
349
465
|
}
|
|
350
466
|
// Cast required due to optional keys in WorkspaceSchema
|
|
351
467
|
// TODO: AB#47518
|
|
352
468
|
const latestMapState = workspace.states.latestMap;
|
|
353
469
|
if (!latestMapState) {
|
|
354
|
-
send({
|
|
470
|
+
this.send({
|
|
355
471
|
event: "error",
|
|
356
472
|
error: `${process_id} latestMap state not registered for workspace ${msg.workspaceId}`,
|
|
357
473
|
});
|
|
@@ -364,19 +480,22 @@ class MessageHandler {
|
|
|
364
480
|
}
|
|
365
481
|
handleGetLatestValue(msg) {
|
|
366
482
|
if (!this.presence) {
|
|
367
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
483
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
368
484
|
return;
|
|
369
485
|
}
|
|
370
486
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
371
487
|
if (!workspace) {
|
|
372
|
-
send({
|
|
488
|
+
this.send({
|
|
489
|
+
event: "error",
|
|
490
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
491
|
+
});
|
|
373
492
|
return;
|
|
374
493
|
}
|
|
375
494
|
// Cast required due to optional keys in WorkspaceSchema
|
|
376
495
|
// TODO: AB#47518
|
|
377
496
|
const latestState = workspace.states.latest;
|
|
378
497
|
if (!latestState) {
|
|
379
|
-
send({
|
|
498
|
+
this.send({
|
|
380
499
|
event: "error",
|
|
381
500
|
error: `${process_id} latest state not registered for workspace ${msg.workspaceId}`,
|
|
382
501
|
});
|
|
@@ -391,7 +510,7 @@ class MessageHandler {
|
|
|
391
510
|
else {
|
|
392
511
|
value = latestState.local;
|
|
393
512
|
}
|
|
394
|
-
send({
|
|
513
|
+
this.send({
|
|
395
514
|
event: "latestValueGetResponse",
|
|
396
515
|
workspaceId: msg.workspaceId,
|
|
397
516
|
attendeeId: msg.attendeeId,
|
|
@@ -400,23 +519,26 @@ class MessageHandler {
|
|
|
400
519
|
}
|
|
401
520
|
handleGetLatestMapValue(msg) {
|
|
402
521
|
if (!this.presence) {
|
|
403
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
522
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
404
523
|
return;
|
|
405
524
|
}
|
|
406
525
|
if (typeof msg.key !== "string") {
|
|
407
|
-
send({ event: "error", error: `${process_id} invalid key type` });
|
|
526
|
+
this.send({ event: "error", error: `${process_id} invalid key type` });
|
|
408
527
|
return;
|
|
409
528
|
}
|
|
410
529
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
411
530
|
if (!workspace) {
|
|
412
|
-
send({
|
|
531
|
+
this.send({
|
|
532
|
+
event: "error",
|
|
533
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
534
|
+
});
|
|
413
535
|
return;
|
|
414
536
|
}
|
|
415
537
|
// Cast required due to optional keys in WorkspaceSchema
|
|
416
538
|
// TODO: AB#47518
|
|
417
539
|
const latestMapState = workspace.states.latestMap;
|
|
418
540
|
if (!latestMapState) {
|
|
419
|
-
send({
|
|
541
|
+
this.send({
|
|
420
542
|
event: "error",
|
|
421
543
|
error: `${process_id} latestMap state not registered for workspace ${msg.workspaceId}`,
|
|
422
544
|
});
|
|
@@ -432,7 +554,7 @@ class MessageHandler {
|
|
|
432
554
|
else {
|
|
433
555
|
value = latestMapState.local.get(msg.key);
|
|
434
556
|
}
|
|
435
|
-
send({
|
|
557
|
+
this.send({
|
|
436
558
|
event: "latestMapValueGetResponse",
|
|
437
559
|
workspaceId: msg.workspaceId,
|
|
438
560
|
attendeeId: msg.attendeeId,
|