@livedesk/hub 0.1.37 → 0.1.39
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/package.json +1 -1
- package/src/live-desk-update.js +88 -39
- package/src/remote-hub.js +87 -20
- package/src/server.js +43 -8
package/package.json
CHANGED
package/src/live-desk-update.js
CHANGED
|
@@ -8,10 +8,11 @@ export const LIVE_DESK_UPDATE_COMMAND = 'livedesk.client-update';
|
|
|
8
8
|
// same device returned, so the Hub-owned compatibility bridge upgrades them.
|
|
9
9
|
export const LIVE_DESK_DEDICATED_CLIENT_UPDATE_MIN_VERSION = '0.1.172';
|
|
10
10
|
export const LIVE_DESK_UPDATE_CLIENT_BATCH_SIZE = 5;
|
|
11
|
-
export const LIVE_DESK_UPDATE_TARGET_TIMEOUT_MS = 480_000;
|
|
12
|
-
export const LIVE_DESK_UPDATE_TIMEOUT_MS = 90 * 60_000;
|
|
13
|
-
export const LIVE_DESK_UPDATE_CLIENT_RESTART_STABILITY_MS = 60_000;
|
|
14
|
-
export const
|
|
11
|
+
export const LIVE_DESK_UPDATE_TARGET_TIMEOUT_MS = 480_000;
|
|
12
|
+
export const LIVE_DESK_UPDATE_TIMEOUT_MS = 90 * 60_000;
|
|
13
|
+
export const LIVE_DESK_UPDATE_CLIENT_RESTART_STABILITY_MS = 60_000;
|
|
14
|
+
export const LIVE_DESK_UPDATE_VERIFIED_CLIENT_STABILITY_MS = 10_000;
|
|
15
|
+
export const LIVE_DESK_UPDATE_CHECK_INTERVAL_MS = 60_000;
|
|
15
16
|
export const LIVE_DESK_LEGACY_COMMAND_MAX_LENGTH = 3900;
|
|
16
17
|
|
|
17
18
|
function cleanVersion(value) {
|
|
@@ -194,9 +195,10 @@ function statusForRun(run) {
|
|
|
194
195
|
activeCount,
|
|
195
196
|
queuedCount,
|
|
196
197
|
pendingOfflineCount,
|
|
197
|
-
failedCount,
|
|
198
|
-
batchSize: run.batchSize,
|
|
199
|
-
clientRestartStabilityMs: run.clientRestartStabilityMs,
|
|
198
|
+
failedCount,
|
|
199
|
+
batchSize: run.batchSize,
|
|
200
|
+
clientRestartStabilityMs: run.clientRestartStabilityMs,
|
|
201
|
+
verifiedClientRestartStabilityMs: run.verifiedClientRestartStabilityMs,
|
|
200
202
|
latestManagerVersion: run.latestManagerVersion,
|
|
201
203
|
latestClientVersion: run.latestClientVersion,
|
|
202
204
|
error: run.error || '',
|
|
@@ -226,10 +228,14 @@ function resetReconnectCandidate(target) {
|
|
|
226
228
|
target.candidatePid = 0;
|
|
227
229
|
target.candidateConnectedAt = '';
|
|
228
230
|
target.candidateProductVersion = '';
|
|
229
|
-
target.candidateAgentVersion = '';
|
|
230
|
-
target.
|
|
231
|
-
target.
|
|
232
|
-
|
|
231
|
+
target.candidateAgentVersion = '';
|
|
232
|
+
target.candidateSupervisorProofId = '';
|
|
233
|
+
target.verificationSource = '';
|
|
234
|
+
target.requiredStabilityMs = 0;
|
|
235
|
+
target.supervisorProofAt = '';
|
|
236
|
+
target.candidateSince = '';
|
|
237
|
+
target.stabilityDeadlineAt = '';
|
|
238
|
+
}
|
|
233
239
|
|
|
234
240
|
export function createLiveDeskUpdateManager({
|
|
235
241
|
remoteHub,
|
|
@@ -240,10 +246,11 @@ export function createLiveDeskUpdateManager({
|
|
|
240
246
|
fetchImpl = globalThis.fetch,
|
|
241
247
|
now = () => Date.now(),
|
|
242
248
|
clientBatchSize = LIVE_DESK_UPDATE_CLIENT_BATCH_SIZE,
|
|
243
|
-
targetTimeoutMs = LIVE_DESK_UPDATE_TARGET_TIMEOUT_MS,
|
|
244
|
-
operationTimeoutMs = LIVE_DESK_UPDATE_TIMEOUT_MS,
|
|
245
|
-
clientRestartStabilityMs = LIVE_DESK_UPDATE_CLIENT_RESTART_STABILITY_MS
|
|
246
|
-
|
|
249
|
+
targetTimeoutMs = LIVE_DESK_UPDATE_TARGET_TIMEOUT_MS,
|
|
250
|
+
operationTimeoutMs = LIVE_DESK_UPDATE_TIMEOUT_MS,
|
|
251
|
+
clientRestartStabilityMs = LIVE_DESK_UPDATE_CLIENT_RESTART_STABILITY_MS,
|
|
252
|
+
verifiedClientRestartStabilityMs = LIVE_DESK_UPDATE_VERIFIED_CLIENT_STABILITY_MS
|
|
253
|
+
}) {
|
|
247
254
|
let latestRelease = null;
|
|
248
255
|
let checkError = '';
|
|
249
256
|
let checkPromise = null;
|
|
@@ -262,12 +269,18 @@ export function createLiveDeskUpdateManager({
|
|
|
262
269
|
effectiveTargetTimeoutMs,
|
|
263
270
|
Number(operationTimeoutMs) || LIVE_DESK_UPDATE_TIMEOUT_MS
|
|
264
271
|
);
|
|
265
|
-
const effectiveClientRestartStabilityMs = Math.max(
|
|
272
|
+
const effectiveClientRestartStabilityMs = Math.max(
|
|
266
273
|
0,
|
|
267
274
|
Number.isFinite(Number(clientRestartStabilityMs))
|
|
268
275
|
? Number(clientRestartStabilityMs)
|
|
269
|
-
: LIVE_DESK_UPDATE_CLIENT_RESTART_STABILITY_MS
|
|
270
|
-
);
|
|
276
|
+
: LIVE_DESK_UPDATE_CLIENT_RESTART_STABILITY_MS
|
|
277
|
+
);
|
|
278
|
+
const effectiveVerifiedClientRestartStabilityMs = Math.max(
|
|
279
|
+
5_000,
|
|
280
|
+
Number.isFinite(Number(verifiedClientRestartStabilityMs))
|
|
281
|
+
? Number(verifiedClientRestartStabilityMs)
|
|
282
|
+
: LIVE_DESK_UPDATE_VERIFIED_CLIENT_STABILITY_MS
|
|
283
|
+
);
|
|
271
284
|
|
|
272
285
|
const touch = () => {
|
|
273
286
|
if (run) run.updatedAt = new Date(now()).toISOString();
|
|
@@ -341,9 +354,10 @@ export function createLiveDeskUpdateManager({
|
|
|
341
354
|
queuedCount: 0,
|
|
342
355
|
pendingOfflineCount: 0,
|
|
343
356
|
failedCount: 0,
|
|
344
|
-
batchSize: effectiveClientBatchSize,
|
|
345
|
-
clientRestartStabilityMs: effectiveClientRestartStabilityMs,
|
|
346
|
-
|
|
357
|
+
batchSize: effectiveClientBatchSize,
|
|
358
|
+
clientRestartStabilityMs: effectiveClientRestartStabilityMs,
|
|
359
|
+
verifiedClientRestartStabilityMs: effectiveVerifiedClientRestartStabilityMs,
|
|
360
|
+
targets: []
|
|
347
361
|
})
|
|
348
362
|
};
|
|
349
363
|
};
|
|
@@ -535,9 +549,30 @@ export function createLiveDeskUpdateManager({
|
|
|
535
549
|
const connectedAtEpochMs = Date.parse(connectedAt);
|
|
536
550
|
const dispatchedAtEpochMs = Date.parse(target.dispatchedAt || '');
|
|
537
551
|
const candidatePid = Math.max(0, Math.floor(Number(device?.pid) || 0));
|
|
538
|
-
const candidateProductVersion = String(device?.productVersion || '');
|
|
539
|
-
const candidateAgentVersion = String(device?.agentVersion || '');
|
|
540
|
-
const
|
|
552
|
+
const candidateProductVersion = String(device?.productVersion || '');
|
|
553
|
+
const candidateAgentVersion = String(device?.agentVersion || '');
|
|
554
|
+
const supervisorProof = device?.clientUpdateProof;
|
|
555
|
+
const supervisorProofId = [
|
|
556
|
+
String(supervisorProof?.operationId || ''),
|
|
557
|
+
String(supervisorProof?.attemptId || ''),
|
|
558
|
+
String(supervisorProof?.sessionId || ''),
|
|
559
|
+
String(supervisorProof?.agentPid || ''),
|
|
560
|
+
String(supervisorProof?.launcherPid || ''),
|
|
561
|
+
String(supervisorProof?.completedAt || '')
|
|
562
|
+
].join(':');
|
|
563
|
+
const hasSupervisorProof = !!supervisorProof
|
|
564
|
+
&& String(supervisorProof.operationId || '') === run.operationId
|
|
565
|
+
&& !!String(supervisorProof.attemptId || '')
|
|
566
|
+
&& String(supervisorProof.sessionId || '') === sessionId
|
|
567
|
+
&& Number(supervisorProof.agentPid || 0) === candidatePid
|
|
568
|
+
&& Number(supervisorProof.launcherPid || 0) > 1
|
|
569
|
+
&& cleanVersion(supervisorProof.productVersion) === cleanVersion(candidateProductVersion)
|
|
570
|
+
&& cleanVersion(supervisorProof.agentVersion) === cleanVersion(candidateAgentVersion)
|
|
571
|
+
&& Date.parse(String(supervisorProof.receivedAt || '')) >= connectedAtEpochMs;
|
|
572
|
+
const requiredStabilityMs = hasSupervisorProof
|
|
573
|
+
? run.verifiedClientRestartStabilityMs
|
|
574
|
+
: run.clientRestartStabilityMs;
|
|
575
|
+
const qualifiesForStability = device?.connected === true
|
|
541
576
|
&& !!sessionId
|
|
542
577
|
&& candidatePid > 1
|
|
543
578
|
&& sessionId !== target.dispatchedSessionId
|
|
@@ -546,9 +581,10 @@ export function createLiveDeskUpdateManager({
|
|
|
546
581
|
const sameCandidate = qualifiesForStability
|
|
547
582
|
&& target.candidateSessionId === sessionId
|
|
548
583
|
&& target.candidatePid === candidatePid
|
|
549
|
-
&& target.candidateConnectedAt === connectedAt
|
|
550
|
-
&& target.candidateProductVersion === candidateProductVersion
|
|
551
|
-
&& target.candidateAgentVersion === candidateAgentVersion
|
|
584
|
+
&& target.candidateConnectedAt === connectedAt
|
|
585
|
+
&& target.candidateProductVersion === candidateProductVersion
|
|
586
|
+
&& target.candidateAgentVersion === candidateAgentVersion
|
|
587
|
+
&& target.candidateSupervisorProofId === (hasSupervisorProof ? supervisorProofId : '');
|
|
552
588
|
|
|
553
589
|
if (!qualifiesForStability) {
|
|
554
590
|
resetReconnectCandidate(target);
|
|
@@ -556,12 +592,18 @@ export function createLiveDeskUpdateManager({
|
|
|
556
592
|
target.candidateSessionId = sessionId;
|
|
557
593
|
target.candidatePid = candidatePid;
|
|
558
594
|
target.candidateConnectedAt = connectedAt;
|
|
559
|
-
target.candidateProductVersion = candidateProductVersion;
|
|
560
|
-
target.candidateAgentVersion = candidateAgentVersion;
|
|
561
|
-
target.
|
|
562
|
-
target.
|
|
563
|
-
|
|
564
|
-
|
|
595
|
+
target.candidateProductVersion = candidateProductVersion;
|
|
596
|
+
target.candidateAgentVersion = candidateAgentVersion;
|
|
597
|
+
target.candidateSupervisorProofId = hasSupervisorProof ? supervisorProofId : '';
|
|
598
|
+
target.verificationSource = hasSupervisorProof ? 'supervisor-proof' : 'hub-session';
|
|
599
|
+
target.requiredStabilityMs = requiredStabilityMs;
|
|
600
|
+
target.supervisorProofAt = hasSupervisorProof
|
|
601
|
+
? String(supervisorProof.receivedAt || supervisorProof.completedAt || '')
|
|
602
|
+
: '';
|
|
603
|
+
target.candidateSince = new Date(currentTime).toISOString();
|
|
604
|
+
target.stabilityDeadlineAt = new Date(
|
|
605
|
+
currentTime + requiredStabilityMs
|
|
606
|
+
).toISOString();
|
|
565
607
|
}
|
|
566
608
|
|
|
567
609
|
if (qualifiesForStability
|
|
@@ -646,8 +688,9 @@ export function createLiveDeskUpdateManager({
|
|
|
646
688
|
latestManagerVersion: release.latestManagerVersion,
|
|
647
689
|
latestClientVersion: release.latestClientVersion,
|
|
648
690
|
needsHubRestart,
|
|
649
|
-
batchSize: effectiveClientBatchSize,
|
|
650
|
-
clientRestartStabilityMs: effectiveClientRestartStabilityMs,
|
|
691
|
+
batchSize: effectiveClientBatchSize,
|
|
692
|
+
clientRestartStabilityMs: effectiveClientRestartStabilityMs,
|
|
693
|
+
verifiedClientRestartStabilityMs: effectiveVerifiedClientRestartStabilityMs,
|
|
651
694
|
error: '',
|
|
652
695
|
targets: targets.map(device => ({
|
|
653
696
|
deviceId: String(device.deviceId || ''),
|
|
@@ -666,9 +709,13 @@ export function createLiveDeskUpdateManager({
|
|
|
666
709
|
candidateSessionId: '',
|
|
667
710
|
candidatePid: 0,
|
|
668
711
|
candidateConnectedAt: '',
|
|
669
|
-
candidateProductVersion: '',
|
|
670
|
-
candidateAgentVersion: '',
|
|
671
|
-
|
|
712
|
+
candidateProductVersion: '',
|
|
713
|
+
candidateAgentVersion: '',
|
|
714
|
+
candidateSupervisorProofId: '',
|
|
715
|
+
verificationSource: '',
|
|
716
|
+
requiredStabilityMs: 0,
|
|
717
|
+
supervisorProofAt: '',
|
|
718
|
+
candidateSince: '',
|
|
672
719
|
stabilityDeadlineAt: '',
|
|
673
720
|
completedAt: '',
|
|
674
721
|
error: ''
|
|
@@ -698,7 +745,9 @@ export function createLiveDeskUpdateManager({
|
|
|
698
745
|
|
|
699
746
|
const handleRemoteEvent = (type, event) => {
|
|
700
747
|
if (!run || run.state !== 'waiting-for-clients') return;
|
|
701
|
-
if (type === 'RemoteDeviceConnected'
|
|
748
|
+
if (type === 'RemoteDeviceConnected'
|
|
749
|
+
|| type === 'RemoteDeviceDisconnected'
|
|
750
|
+
|| type === 'RemoteClientUpdateVerified') {
|
|
702
751
|
verifyTargets();
|
|
703
752
|
return;
|
|
704
753
|
}
|
package/src/remote-hub.js
CHANGED
|
@@ -286,7 +286,7 @@ function normalizePort(value) {
|
|
|
286
286
|
return clampNumber(value, 0, 65535, DEFAULT_REMOTE_HUB_PORT);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
function safeString(value, maxLength = 200) {
|
|
289
|
+
function safeString(value, maxLength = 200) {
|
|
290
290
|
return String(value ?? '').replace(/[\r\n\t]/g, ' ').trim().slice(0, maxLength);
|
|
291
291
|
}
|
|
292
292
|
|
|
@@ -1119,9 +1119,55 @@ function getAccountRouteEndpointReason(endpoint, context = {}) {
|
|
|
1119
1119
|
return 'ok';
|
|
1120
1120
|
}
|
|
1121
1121
|
|
|
1122
|
-
function safeText(value, maxLength = 1000) {
|
|
1123
|
-
return String(value ?? '').replace(/\0/g, '').trim().slice(0, maxLength);
|
|
1124
|
-
}
|
|
1122
|
+
function safeText(value, maxLength = 1000) {
|
|
1123
|
+
return String(value ?? '').replace(/\0/g, '').trim().slice(0, maxLength);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
function normalizeClientUpdateVerifiedProof(device, message, receivedAt) {
|
|
1127
|
+
const operationId = safeString(message?.operationId, 180);
|
|
1128
|
+
const attemptId = safeString(message?.attemptId, 180);
|
|
1129
|
+
const productVersion = safeString(message?.productVersion, 40);
|
|
1130
|
+
const agentVersion = safeString(message?.agentVersion, 40);
|
|
1131
|
+
const completedAt = safeString(message?.completedAt, 64);
|
|
1132
|
+
const launcherPid = Math.max(0, Math.floor(Number(message?.launcherPid) || 0));
|
|
1133
|
+
const agentPid = Math.max(0, Math.floor(Number(message?.agentPid) || 0));
|
|
1134
|
+
const supervisorPid = Math.max(0, Math.floor(Number(message?.supervisorPid) || 0));
|
|
1135
|
+
if (!operationId
|
|
1136
|
+
|| !attemptId
|
|
1137
|
+
|| !productVersion
|
|
1138
|
+
|| !agentVersion
|
|
1139
|
+
|| !Number.isFinite(Date.parse(completedAt))
|
|
1140
|
+
|| launcherPid <= 1
|
|
1141
|
+
|| agentPid <= 1
|
|
1142
|
+
|| supervisorPid <= 1
|
|
1143
|
+
|| agentPid !== Number(device?.pid || 0)
|
|
1144
|
+
|| productVersion !== String(device?.productVersion || '')
|
|
1145
|
+
|| agentVersion !== String(device?.agentVersion || '')) {
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
return {
|
|
1149
|
+
operationId,
|
|
1150
|
+
attemptId,
|
|
1151
|
+
sessionId: String(device.sessionId || ''),
|
|
1152
|
+
launcherPid,
|
|
1153
|
+
agentPid,
|
|
1154
|
+
supervisorPid,
|
|
1155
|
+
productVersion,
|
|
1156
|
+
agentVersion,
|
|
1157
|
+
completedAt,
|
|
1158
|
+
receivedAt
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
function normalizeRemoteKeyboardKey(value) {
|
|
1163
|
+
const raw = String(value ?? '').replace(/\0/g, '');
|
|
1164
|
+
return raw === ' ' ? ' ' : safeString(raw, 80);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function normalizeRemoteKeyboardText(value) {
|
|
1168
|
+
const raw = String(value ?? '').replace(/\0/g, '');
|
|
1169
|
+
return raw === ' ' ? ' ' : safeText(raw, 256);
|
|
1170
|
+
}
|
|
1125
1171
|
|
|
1126
1172
|
function safeTaskData(value) {
|
|
1127
1173
|
if (value === undefined || value === null) return undefined;
|
|
@@ -1202,14 +1248,14 @@ function readRawRemoteInputMonitorIndex(input) {
|
|
|
1202
1248
|
return undefined;
|
|
1203
1249
|
}
|
|
1204
1250
|
|
|
1205
|
-
function normalizeRemoteInputEvent(value = {}) {
|
|
1251
|
+
function normalizeRemoteInputEvent(value = {}) {
|
|
1206
1252
|
const input = value && typeof value === 'object' ? value : {};
|
|
1207
1253
|
const type = safeString(input.type || input.Type, 48);
|
|
1208
1254
|
const normalizedX = Number(input.normalizedX ?? input.NormalizedX);
|
|
1209
1255
|
const normalizedY = Number(input.normalizedY ?? input.NormalizedY);
|
|
1210
1256
|
const deltaX = Number(input.deltaX ?? input.DeltaX);
|
|
1211
1257
|
const deltaY = Number(input.deltaY ?? input.DeltaY);
|
|
1212
|
-
const keyCode = Number(input.keyCode ?? input.KeyCode);
|
|
1258
|
+
const keyCode = Number(input.keyCode ?? input.KeyCode);
|
|
1213
1259
|
const location = Number(input.location ?? input.Location);
|
|
1214
1260
|
const monitorIndex = parseExactLiveStreamMonitorIndex(readRawRemoteInputMonitorIndex(input));
|
|
1215
1261
|
const inputSeq = Number(input.inputSeq ?? input.InputSeq);
|
|
@@ -1217,13 +1263,18 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
1217
1263
|
const hubReceivedAtEpochMs = Number(input.hubReceivedAtEpochMs ?? input.HubReceivedAtEpochMs);
|
|
1218
1264
|
const captureGeneration = Number(input.captureGeneration ?? input.CaptureGeneration);
|
|
1219
1265
|
const rawPressedCodes = input.pressedCodes ?? input.PressedCodes;
|
|
1220
|
-
const pressedCodes = Array.isArray(rawPressedCodes)
|
|
1266
|
+
const pressedCodes = Array.isArray(rawPressedCodes)
|
|
1221
1267
|
? [...new Set(rawPressedCodes
|
|
1222
1268
|
.map(code => safeString(code, 80))
|
|
1223
1269
|
.filter(Boolean))]
|
|
1224
1270
|
.slice(0, 64)
|
|
1225
|
-
: null;
|
|
1226
|
-
|
|
1271
|
+
: null;
|
|
1272
|
+
const key = normalizeRemoteKeyboardKey(input.key ?? input.Key);
|
|
1273
|
+
let code = safeString(input.code ?? input.Code, 80);
|
|
1274
|
+
if ((!code || code === 'Unidentified') && (key === ' ' || key === 'Spacebar' || keyCode === 32)) {
|
|
1275
|
+
code = 'Space';
|
|
1276
|
+
}
|
|
1277
|
+
return {
|
|
1227
1278
|
type,
|
|
1228
1279
|
// A missing monitor is not equivalent to the primary display. Control
|
|
1229
1280
|
// input must prove the exact monitor owned by its capture generation.
|
|
@@ -1233,11 +1284,11 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
1233
1284
|
button: safeString(input.button || input.Button, 24),
|
|
1234
1285
|
deltaX: Number.isFinite(deltaX) ? Math.max(-4096, Math.min(4096, deltaX)) : 0,
|
|
1235
1286
|
deltaY: Number.isFinite(deltaY) ? Math.max(-4096, Math.min(4096, deltaY)) : 0,
|
|
1236
|
-
key
|
|
1237
|
-
code
|
|
1287
|
+
key,
|
|
1288
|
+
code,
|
|
1238
1289
|
keyCode: Number.isFinite(keyCode) ? Math.max(0, Math.min(65535, Math.trunc(keyCode))) : 0,
|
|
1239
1290
|
location: Number.isFinite(location) ? Math.max(0, Math.min(255, Math.trunc(location))) : 0,
|
|
1240
|
-
text:
|
|
1291
|
+
text: normalizeRemoteKeyboardText(input.text ?? input.Text),
|
|
1241
1292
|
repeat: input.repeat === true || input.Repeat === true,
|
|
1242
1293
|
pressedCodes,
|
|
1243
1294
|
shiftKey: input.shiftKey === true || input.ShiftKey === true,
|
|
@@ -1611,8 +1662,9 @@ function serializeDevice(device, options = {}) {
|
|
|
1611
1662
|
byteLength: device.latestAudioFrame.byteLength
|
|
1612
1663
|
}
|
|
1613
1664
|
: null,
|
|
1614
|
-
latestAudioStatus: device.latestAudioStatus ? { ...device.latestAudioStatus } : null,
|
|
1615
|
-
|
|
1665
|
+
latestAudioStatus: device.latestAudioStatus ? { ...device.latestAudioStatus } : null,
|
|
1666
|
+
clientUpdateProof: device.clientUpdateProof ? { ...device.clientUpdateProof } : null,
|
|
1667
|
+
udp: device.udp ? { ...device.udp } : { enabled: false, state: 'tcp-only', ready: false },
|
|
1616
1668
|
latestTask: device.latestTask ? { ...device.latestTask } : null,
|
|
1617
1669
|
synthetic: device.synthetic === true,
|
|
1618
1670
|
recentTasks: Array.isArray(device.recentTasks)
|
|
@@ -4412,8 +4464,9 @@ export function createRemoteHub(options = {}) {
|
|
|
4412
4464
|
liveCapturePause: existing?.liveCapturePause || null,
|
|
4413
4465
|
activeAudioStream: null,
|
|
4414
4466
|
latestAudioFrame: null,
|
|
4415
|
-
latestAudioStatus: null,
|
|
4416
|
-
|
|
4467
|
+
latestAudioStatus: null,
|
|
4468
|
+
clientUpdateProof: null,
|
|
4469
|
+
udp: {
|
|
4417
4470
|
enabled: capabilities.udpP2p === true,
|
|
4418
4471
|
state: 'tcp-only',
|
|
4419
4472
|
ready: false,
|
|
@@ -7426,7 +7479,7 @@ export function createRemoteHub(options = {}) {
|
|
|
7426
7479
|
device.counters.statusReceived += 1;
|
|
7427
7480
|
emitRemoteEvent('RemoteDeviceStatus', device);
|
|
7428
7481
|
break;
|
|
7429
|
-
case 'command.result':
|
|
7482
|
+
case 'command.result':
|
|
7430
7483
|
case 'command.error':
|
|
7431
7484
|
device.counters.commandResultsReceived += 1;
|
|
7432
7485
|
{
|
|
@@ -7454,9 +7507,23 @@ export function createRemoteHub(options = {}) {
|
|
|
7454
7507
|
commandId: safeString(message.commandId, 128),
|
|
7455
7508
|
result: message.result ?? null,
|
|
7456
7509
|
error: safeString(message.error, 500)
|
|
7457
|
-
});
|
|
7458
|
-
break;
|
|
7459
|
-
case '
|
|
7510
|
+
});
|
|
7511
|
+
break;
|
|
7512
|
+
case 'client.update.verified': {
|
|
7513
|
+
const receivedAt = new Date().toISOString();
|
|
7514
|
+
const proof = normalizeClientUpdateVerifiedProof(device, message, receivedAt);
|
|
7515
|
+
if (!proof) {
|
|
7516
|
+
logWarn(
|
|
7517
|
+
'remote',
|
|
7518
|
+
`ignored invalid Client update supervisor proof from ${device.deviceName} (${device.deviceId})`
|
|
7519
|
+
);
|
|
7520
|
+
break;
|
|
7521
|
+
}
|
|
7522
|
+
device.clientUpdateProof = proof;
|
|
7523
|
+
emitRemoteEvent('RemoteClientUpdateVerified', device, { proof });
|
|
7524
|
+
break;
|
|
7525
|
+
}
|
|
7526
|
+
case 'input.applied':
|
|
7460
7527
|
case 'input.error':
|
|
7461
7528
|
handleRemoteInputOutcome(device, message, 'main');
|
|
7462
7529
|
break;
|
package/src/server.js
CHANGED
|
@@ -2710,7 +2710,7 @@ function enqueueFramePacketForClient(ws, packetOwner, meta) {
|
|
|
2710
2710
|
}
|
|
2711
2711
|
// FRAME_LANE_GENERATION_CONTRACT_END
|
|
2712
2712
|
|
|
2713
|
-
function updateFrameSubscription(ws, payload = {}) {
|
|
2713
|
+
function updateFrameSubscription(ws, payload = {}) {
|
|
2714
2714
|
const previousDeviceIds = ws.liveDeskDeviceIds instanceof Set
|
|
2715
2715
|
? new Set(ws.liveDeskDeviceIds)
|
|
2716
2716
|
: new Set();
|
|
@@ -2743,10 +2743,43 @@ function updateFrameSubscription(ws, payload = {}) {
|
|
|
2743
2743
|
const targetIds = newlySubscribedIds.length > 0 ? newlySubscribedIds : deviceIds;
|
|
2744
2744
|
for (const deviceId of targetIds.slice(0, 80)) {
|
|
2745
2745
|
startFrameSubscriptionLive(ws, 'subscribe', deviceId, { reuseExisting: true });
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
|
-
|
|
2749
|
-
function
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
function refreshFrameSubscriptionLive(ws, payload = {}) {
|
|
2750
|
+
if (!ws || ws.readyState !== 1) {
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
const requestedIds = normalizeDeviceIds(payload.deviceIds ?? payload.devices ?? payload.deviceId);
|
|
2754
|
+
const subscribedIds = [...(ws.liveDeskDeviceIds || [])];
|
|
2755
|
+
const targetIds = requestedIds.length > 0
|
|
2756
|
+
? requestedIds.filter(deviceId => ws.liveDeskDeviceIds?.has?.(deviceId))
|
|
2757
|
+
: subscribedIds;
|
|
2758
|
+
if (targetIds.length === 0) {
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
ws.liveDeskAutoStart = /^(1|true|yes|on|live)$/i.test(String(
|
|
2762
|
+
payload.autoStartLive ?? payload.startLive ?? ws.liveDeskAutoStart ?? ''
|
|
2763
|
+
));
|
|
2764
|
+
ws.liveDeskLiveOptions = normalizeLiveOptions({
|
|
2765
|
+
...(ws.liveDeskLiveOptions || {}),
|
|
2766
|
+
...payload,
|
|
2767
|
+
forceRestart: false,
|
|
2768
|
+
reuseExisting: true,
|
|
2769
|
+
monitorSelections: {
|
|
2770
|
+
...(ws.liveDeskLiveOptions?.monitorSelections || {}),
|
|
2771
|
+
...(payload.monitorSelections || {})
|
|
2772
|
+
}
|
|
2773
|
+
});
|
|
2774
|
+
for (const deviceId of targetIds.slice(0, 80)) {
|
|
2775
|
+
startFrameSubscriptionLive(ws, 'watchdog', deviceId, {
|
|
2776
|
+
...ws.liveDeskLiveOptions,
|
|
2777
|
+
reuseExisting: true
|
|
2778
|
+
});
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
function startFrameSubscriptionLive(
|
|
2750
2783
|
ws,
|
|
2751
2784
|
reason = 'subscribe',
|
|
2752
2785
|
onlyDeviceId = '',
|
|
@@ -5494,9 +5527,11 @@ frameWss.on('connection', (ws, req) => {
|
|
|
5494
5527
|
ws.on('message', data => {
|
|
5495
5528
|
try {
|
|
5496
5529
|
const payload = JSON.parse(Buffer.isBuffer(data) ? data.toString('utf8') : String(data || ''));
|
|
5497
|
-
if (payload?.type === 'subscribe') {
|
|
5498
|
-
updateFrameSubscription(ws, payload);
|
|
5499
|
-
} else if (payload?.type === '
|
|
5530
|
+
if (payload?.type === 'subscribe') {
|
|
5531
|
+
updateFrameSubscription(ws, payload);
|
|
5532
|
+
} else if (payload?.type === 'refresh-live') {
|
|
5533
|
+
refreshFrameSubscriptionLive(ws, payload);
|
|
5534
|
+
} else if (payload?.type === 'restart-live') {
|
|
5500
5535
|
restartFrameSubscriptionLive(ws, payload);
|
|
5501
5536
|
}
|
|
5502
5537
|
} catch {
|