@fluidframework/azure-end-to-end-tests 2.70.0-361248 → 2.70.0-361788
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/lib/test/multiprocess/childClient.tool.js +218 -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 +79 -23
- package/lib/test/multiprocess/presenceTest.spec.js.map +1 -1
- package/package.json +23 -23
- package/src/test/multiprocess/childClient.tool.ts +268 -131
- package/src/test/multiprocess/messageTypes.ts +36 -0
- package/src/test/multiprocess/orchestratorUtils.ts +121 -23
- package/src/test/multiprocess/presenceTest.spec.ts +103 -23
|
@@ -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,58 @@ 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
|
+
const interest = telemetryEventInterestLevel(event.eventName);
|
|
154
|
+
if (interest === "none") {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.log.push({
|
|
158
|
+
timestamp: Date.now(),
|
|
159
|
+
agentId: process_id,
|
|
160
|
+
eventCategory: "telemetry",
|
|
161
|
+
eventName: event.eventName,
|
|
162
|
+
details: typeof event.details === "string" ? event.details : JSON.stringify(event.details),
|
|
163
|
+
});
|
|
164
|
+
if (verbosity.includes("telem")) {
|
|
165
|
+
selectiveVerboseLog(event, logLevel);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
this.onDisconnected = () => {
|
|
170
|
+
// Test state is a bit fragile and does not account for reconnections.
|
|
171
|
+
this.send({ event: "error", error: `${process_id}: Container disconnected` });
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
send(msg) {
|
|
175
|
+
this.log.push({
|
|
176
|
+
timestamp: Date.now(),
|
|
177
|
+
agentId: process_id,
|
|
178
|
+
eventCategory: "messageSent",
|
|
179
|
+
eventName: msg.event,
|
|
180
|
+
details: msg.event === "debugReportComplete" && msg.log
|
|
181
|
+
? JSON.stringify({ logLength: msg.log.length })
|
|
182
|
+
: JSON.stringify(msg),
|
|
183
|
+
});
|
|
184
|
+
send(msg);
|
|
149
185
|
}
|
|
150
186
|
registerWorkspace(workspaceId, options) {
|
|
151
187
|
if (!this.presence) {
|
|
152
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
188
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
153
189
|
return;
|
|
154
190
|
}
|
|
155
191
|
const { latest, latestMap } = options;
|
|
@@ -160,7 +196,7 @@ class MessageHandler {
|
|
|
160
196
|
// TODO: AB#47518
|
|
161
197
|
const latestState = workspace.states.latest;
|
|
162
198
|
latestState.events.on("remoteUpdated", (update) => {
|
|
163
|
-
send({
|
|
199
|
+
this.send({
|
|
164
200
|
event: "latestValueUpdated",
|
|
165
201
|
workspaceId,
|
|
166
202
|
attendeeId: update.attendee.attendeeId,
|
|
@@ -168,7 +204,7 @@ class MessageHandler {
|
|
|
168
204
|
});
|
|
169
205
|
});
|
|
170
206
|
for (const remote of latestState.getRemotes()) {
|
|
171
|
-
send({
|
|
207
|
+
this.send({
|
|
172
208
|
event: "latestValueUpdated",
|
|
173
209
|
workspaceId,
|
|
174
210
|
attendeeId: remote.attendee.attendeeId,
|
|
@@ -185,7 +221,7 @@ class MessageHandler {
|
|
|
185
221
|
const latestMapState = workspace.states.latestMap;
|
|
186
222
|
latestMapState.events.on("remoteUpdated", (update) => {
|
|
187
223
|
for (const [key, valueWithMetadata] of update.items) {
|
|
188
|
-
send({
|
|
224
|
+
this.send({
|
|
189
225
|
event: "latestMapValueUpdated",
|
|
190
226
|
workspaceId,
|
|
191
227
|
attendeeId: update.attendee.attendeeId,
|
|
@@ -196,7 +232,7 @@ class MessageHandler {
|
|
|
196
232
|
});
|
|
197
233
|
for (const remote of latestMapState.getRemotes()) {
|
|
198
234
|
for (const [key, valueWithMetadata] of remote.items) {
|
|
199
|
-
send({
|
|
235
|
+
this.send({
|
|
200
236
|
event: "latestMapValueUpdated",
|
|
201
237
|
workspaceId,
|
|
202
238
|
attendeeId: remote.attendee.attendeeId,
|
|
@@ -207,7 +243,7 @@ class MessageHandler {
|
|
|
207
243
|
}
|
|
208
244
|
}
|
|
209
245
|
this.workspaces.set(workspaceId, workspace);
|
|
210
|
-
send({
|
|
246
|
+
this.send({
|
|
211
247
|
event: "workspaceRegistered",
|
|
212
248
|
workspaceId,
|
|
213
249
|
latest: latest ?? false,
|
|
@@ -216,15 +252,33 @@ class MessageHandler {
|
|
|
216
252
|
}
|
|
217
253
|
async onMessage(msg) {
|
|
218
254
|
if (verbosity.includes("msgs")) {
|
|
255
|
+
this.log.push({
|
|
256
|
+
timestamp: Date.now(),
|
|
257
|
+
agentId: process_id,
|
|
258
|
+
eventCategory: "messageReceived",
|
|
259
|
+
eventName: msg.command,
|
|
260
|
+
});
|
|
219
261
|
console.log(`[${process_id}] Received`, msg);
|
|
220
262
|
}
|
|
263
|
+
if (msg.command === "ping") {
|
|
264
|
+
this.handlePing();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (msg.command === "connect") {
|
|
268
|
+
await this.handleConnect(msg);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// All other message must wait if connect is in progress
|
|
272
|
+
if (this.msgQueue !== undefined) {
|
|
273
|
+
this.msgQueue.push(msg);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
this.processMessage(msg);
|
|
277
|
+
}
|
|
278
|
+
processMessage(msg) {
|
|
221
279
|
switch (msg.command) {
|
|
222
|
-
case "
|
|
223
|
-
this.
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case "connect": {
|
|
227
|
-
await this.handleConnect(msg);
|
|
280
|
+
case "debugReport": {
|
|
281
|
+
this.handleDebugReport(msg);
|
|
228
282
|
break;
|
|
229
283
|
}
|
|
230
284
|
case "disconnectSelf": {
|
|
@@ -255,74 +309,125 @@ class MessageHandler {
|
|
|
255
309
|
break;
|
|
256
310
|
}
|
|
257
311
|
default: {
|
|
258
|
-
console.error(`${process_id}: Unknown command
|
|
259
|
-
send({
|
|
312
|
+
console.error(`${process_id}: Unknown command:`, msg);
|
|
313
|
+
this.send({
|
|
314
|
+
event: "error",
|
|
315
|
+
error: `${process_id} Unknown command: ${JSON.stringify(msg)}`,
|
|
316
|
+
});
|
|
260
317
|
}
|
|
261
318
|
}
|
|
262
319
|
}
|
|
263
320
|
handlePing() {
|
|
264
|
-
send({ event: "ack" });
|
|
321
|
+
this.send({ event: "ack" });
|
|
265
322
|
}
|
|
266
323
|
async handleConnect(msg) {
|
|
267
324
|
if (!msg.user) {
|
|
268
|
-
send({ event: "error", error: `${process_id}: No azure user information given` });
|
|
325
|
+
this.send({ event: "error", error: `${process_id}: No azure user information given` });
|
|
269
326
|
return;
|
|
270
327
|
}
|
|
271
|
-
if (
|
|
272
|
-
send({ event: "error", error: `${process_id}:
|
|
328
|
+
if (this.container) {
|
|
329
|
+
this.send({ event: "error", error: `${process_id}: Container already loaded` });
|
|
273
330
|
return;
|
|
274
331
|
}
|
|
275
|
-
|
|
276
|
-
this.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
332
|
+
// Prevent reentrance. Queue messages until after connect is fully processed.
|
|
333
|
+
this.msgQueue = [];
|
|
334
|
+
try {
|
|
335
|
+
const { container, containerId, connected } = await getOrCreateContainer({
|
|
336
|
+
...msg,
|
|
337
|
+
logger: this.logger,
|
|
338
|
+
onDisconnected: this.onDisconnected,
|
|
339
|
+
});
|
|
340
|
+
this.container = container;
|
|
341
|
+
const presence = getPresence(container);
|
|
342
|
+
this.presence = presence;
|
|
343
|
+
// wait for 'ConnectionState.Connected'
|
|
344
|
+
await connected;
|
|
345
|
+
// Acknowledge connection before sending current attendee information
|
|
346
|
+
this.send({
|
|
347
|
+
event: "connected",
|
|
348
|
+
containerId,
|
|
349
|
+
attendeeId: presence.attendees.getMyself().attendeeId,
|
|
350
|
+
});
|
|
351
|
+
// Send existing attendees excluding self to parent/orchestrator
|
|
352
|
+
const self = presence.attendees.getMyself();
|
|
353
|
+
for (const attendee of presence.attendees.getAttendees()) {
|
|
354
|
+
if (attendee !== self && attendee.getConnectionStatus() === "Connected") {
|
|
355
|
+
this.sendAttendeeConnected(attendee);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Listen for presence events to notify parent/orchestrator when a new attendee joins or leaves the session.
|
|
359
|
+
presence.attendees.events.on("attendeeConnected", this.sendAttendeeConnected);
|
|
360
|
+
presence.attendees.events.on("attendeeDisconnected", this.sendAttendeeDisconnected);
|
|
361
|
+
}
|
|
362
|
+
finally {
|
|
363
|
+
// Process any queued messages received while connecting
|
|
364
|
+
for (const queuedMsg of this.msgQueue) {
|
|
365
|
+
this.processMessage(queuedMsg);
|
|
366
|
+
}
|
|
367
|
+
this.msgQueue = undefined;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
handleDebugReport(msg) {
|
|
371
|
+
if (msg.reportAttendees) {
|
|
372
|
+
if (this.presence) {
|
|
373
|
+
const attendees = this.presence.attendees.getAttendees();
|
|
374
|
+
let connectedCount = 0;
|
|
375
|
+
for (const attendee of attendees) {
|
|
376
|
+
if (attendee.getConnectionStatus() === "Connected") {
|
|
377
|
+
connectedCount++;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
console.log(`[${process_id}] Report: ${attendees.size} attendees, ${connectedCount} connected`);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
290
384
|
}
|
|
291
385
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
386
|
+
const debugReport = {
|
|
387
|
+
event: "debugReportComplete",
|
|
388
|
+
};
|
|
389
|
+
if (msg.sendEventLog) {
|
|
390
|
+
debugReport.log = this.log;
|
|
391
|
+
}
|
|
392
|
+
this.send(debugReport);
|
|
295
393
|
}
|
|
296
394
|
handleDisconnectSelf() {
|
|
297
395
|
if (!this.container) {
|
|
298
|
-
send({ event: "error", error: `${process_id} is not connected to container` });
|
|
396
|
+
this.send({ event: "error", error: `${process_id} is not connected to container` });
|
|
299
397
|
return;
|
|
300
398
|
}
|
|
399
|
+
// There are no current scenarios where disconnect without presence is expected.
|
|
301
400
|
if (!this.presence) {
|
|
302
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
401
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
303
402
|
return;
|
|
304
403
|
}
|
|
404
|
+
// Disconnect event is treated as an error in normal handling.
|
|
405
|
+
// Remove listener as this disconnect is intentional.
|
|
406
|
+
this.container.off("disconnected", this.onDisconnected);
|
|
305
407
|
this.container.disconnect();
|
|
306
|
-
send({
|
|
408
|
+
this.send({
|
|
307
409
|
event: "disconnectedSelf",
|
|
308
410
|
attendeeId: this.presence.attendees.getMyself().attendeeId,
|
|
309
411
|
});
|
|
310
412
|
}
|
|
311
413
|
handleSetLatestValue(msg) {
|
|
312
414
|
if (!this.presence) {
|
|
313
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
415
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
314
416
|
return;
|
|
315
417
|
}
|
|
316
418
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
317
419
|
if (!workspace) {
|
|
318
|
-
send({
|
|
420
|
+
this.send({
|
|
421
|
+
event: "error",
|
|
422
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
423
|
+
});
|
|
319
424
|
return;
|
|
320
425
|
}
|
|
321
426
|
// Cast required due to optional keys in WorkspaceSchema
|
|
322
427
|
// TODO: AB#47518
|
|
323
428
|
const latestState = workspace.states.latest;
|
|
324
429
|
if (!latestState) {
|
|
325
|
-
send({
|
|
430
|
+
this.send({
|
|
326
431
|
event: "error",
|
|
327
432
|
error: `${process_id} latest state not registered for workspace ${msg.workspaceId}`,
|
|
328
433
|
});
|
|
@@ -335,23 +440,26 @@ class MessageHandler {
|
|
|
335
440
|
}
|
|
336
441
|
handleSetLatestMapValue(msg) {
|
|
337
442
|
if (!this.presence) {
|
|
338
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
443
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
339
444
|
return;
|
|
340
445
|
}
|
|
341
446
|
if (typeof msg.key !== "string") {
|
|
342
|
-
send({ event: "error", error: `${process_id} invalid key type` });
|
|
447
|
+
this.send({ event: "error", error: `${process_id} invalid key type` });
|
|
343
448
|
return;
|
|
344
449
|
}
|
|
345
450
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
346
451
|
if (!workspace) {
|
|
347
|
-
send({
|
|
452
|
+
this.send({
|
|
453
|
+
event: "error",
|
|
454
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
455
|
+
});
|
|
348
456
|
return;
|
|
349
457
|
}
|
|
350
458
|
// Cast required due to optional keys in WorkspaceSchema
|
|
351
459
|
// TODO: AB#47518
|
|
352
460
|
const latestMapState = workspace.states.latestMap;
|
|
353
461
|
if (!latestMapState) {
|
|
354
|
-
send({
|
|
462
|
+
this.send({
|
|
355
463
|
event: "error",
|
|
356
464
|
error: `${process_id} latestMap state not registered for workspace ${msg.workspaceId}`,
|
|
357
465
|
});
|
|
@@ -364,19 +472,22 @@ class MessageHandler {
|
|
|
364
472
|
}
|
|
365
473
|
handleGetLatestValue(msg) {
|
|
366
474
|
if (!this.presence) {
|
|
367
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
475
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
368
476
|
return;
|
|
369
477
|
}
|
|
370
478
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
371
479
|
if (!workspace) {
|
|
372
|
-
send({
|
|
480
|
+
this.send({
|
|
481
|
+
event: "error",
|
|
482
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
483
|
+
});
|
|
373
484
|
return;
|
|
374
485
|
}
|
|
375
486
|
// Cast required due to optional keys in WorkspaceSchema
|
|
376
487
|
// TODO: AB#47518
|
|
377
488
|
const latestState = workspace.states.latest;
|
|
378
489
|
if (!latestState) {
|
|
379
|
-
send({
|
|
490
|
+
this.send({
|
|
380
491
|
event: "error",
|
|
381
492
|
error: `${process_id} latest state not registered for workspace ${msg.workspaceId}`,
|
|
382
493
|
});
|
|
@@ -391,7 +502,7 @@ class MessageHandler {
|
|
|
391
502
|
else {
|
|
392
503
|
value = latestState.local;
|
|
393
504
|
}
|
|
394
|
-
send({
|
|
505
|
+
this.send({
|
|
395
506
|
event: "latestValueGetResponse",
|
|
396
507
|
workspaceId: msg.workspaceId,
|
|
397
508
|
attendeeId: msg.attendeeId,
|
|
@@ -400,23 +511,26 @@ class MessageHandler {
|
|
|
400
511
|
}
|
|
401
512
|
handleGetLatestMapValue(msg) {
|
|
402
513
|
if (!this.presence) {
|
|
403
|
-
send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
514
|
+
this.send({ event: "error", error: `${process_id} is not connected to presence` });
|
|
404
515
|
return;
|
|
405
516
|
}
|
|
406
517
|
if (typeof msg.key !== "string") {
|
|
407
|
-
send({ event: "error", error: `${process_id} invalid key type` });
|
|
518
|
+
this.send({ event: "error", error: `${process_id} invalid key type` });
|
|
408
519
|
return;
|
|
409
520
|
}
|
|
410
521
|
const workspace = this.workspaces.get(msg.workspaceId);
|
|
411
522
|
if (!workspace) {
|
|
412
|
-
send({
|
|
523
|
+
this.send({
|
|
524
|
+
event: "error",
|
|
525
|
+
error: `${process_id} workspace ${msg.workspaceId} not found`,
|
|
526
|
+
});
|
|
413
527
|
return;
|
|
414
528
|
}
|
|
415
529
|
// Cast required due to optional keys in WorkspaceSchema
|
|
416
530
|
// TODO: AB#47518
|
|
417
531
|
const latestMapState = workspace.states.latestMap;
|
|
418
532
|
if (!latestMapState) {
|
|
419
|
-
send({
|
|
533
|
+
this.send({
|
|
420
534
|
event: "error",
|
|
421
535
|
error: `${process_id} latestMap state not registered for workspace ${msg.workspaceId}`,
|
|
422
536
|
});
|
|
@@ -432,7 +546,7 @@ class MessageHandler {
|
|
|
432
546
|
else {
|
|
433
547
|
value = latestMapState.local.get(msg.key);
|
|
434
548
|
}
|
|
435
|
-
send({
|
|
549
|
+
this.send({
|
|
436
550
|
event: "latestMapValueGetResponse",
|
|
437
551
|
workspaceId: msg.workspaceId,
|
|
438
552
|
attendeeId: msg.attendeeId,
|