@mindexec/cli 0.2.141 → 0.2.143
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/scripts/remote-fleet-render-smoke.mjs +62 -0
- package/scripts/remote-registry-follower-smoke.mjs +34 -0
- package/server.js +43 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +78 -10
- package/wwwroot/service-worker-assets.js +2 -2
- package/wwwroot/service-worker.js +1 -1
package/package.json
CHANGED
|
@@ -442,6 +442,7 @@ async function loadCss3DManager() {
|
|
|
442
442
|
this.readyState = MiniWebSocket.CONNECTING;
|
|
443
443
|
this.binaryType = '';
|
|
444
444
|
this.sent = [];
|
|
445
|
+
this.closeCount = 0;
|
|
445
446
|
webSocketConnections.push(this);
|
|
446
447
|
setTimeout(() => {
|
|
447
448
|
if (this.readyState !== MiniWebSocket.CONNECTING) return;
|
|
@@ -458,6 +459,7 @@ async function loadCss3DManager() {
|
|
|
458
459
|
|
|
459
460
|
close() {
|
|
460
461
|
if (this.readyState === MiniWebSocket.CLOSED) return;
|
|
462
|
+
this.closeCount += 1;
|
|
461
463
|
this.readyState = MiniWebSocket.CLOSED;
|
|
462
464
|
this.onclose?.({ type: 'close' });
|
|
463
465
|
}
|
|
@@ -490,6 +492,8 @@ async function loadCss3DManager() {
|
|
|
490
492
|
Set,
|
|
491
493
|
WeakMap,
|
|
492
494
|
Blob,
|
|
495
|
+
TextDecoder,
|
|
496
|
+
TextEncoder,
|
|
493
497
|
requestAnimationFrame: callback => setTimeout(() => callback(Date.now()), 0),
|
|
494
498
|
cancelAnimationFrame: id => clearTimeout(id),
|
|
495
499
|
createImageBitmap: async blob => {
|
|
@@ -546,6 +550,18 @@ function wait(ms = 0) {
|
|
|
546
550
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
547
551
|
}
|
|
548
552
|
|
|
553
|
+
function encodeRemoteBinaryFrame(metadata, payload = new Uint8Array([0xff, 0xd8, 0xff, 0xd9])) {
|
|
554
|
+
const metaBytes = new TextEncoder().encode(JSON.stringify(metadata));
|
|
555
|
+
const payloadBytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);
|
|
556
|
+
const buffer = new ArrayBuffer(4 + metaBytes.byteLength + payloadBytes.byteLength);
|
|
557
|
+
const view = new DataView(buffer);
|
|
558
|
+
view.setUint32(0, metaBytes.byteLength);
|
|
559
|
+
const bytes = new Uint8Array(buffer);
|
|
560
|
+
bytes.set(metaBytes, 4);
|
|
561
|
+
bytes.set(payloadBytes, 4 + metaBytes.byteLength);
|
|
562
|
+
return buffer;
|
|
563
|
+
}
|
|
564
|
+
|
|
549
565
|
function buildMonitorNode(devices, hubStatus, latestTaskBatch = null, recentTaskBatches = [], lastError = '') {
|
|
550
566
|
const connected = devices.filter(device => device.Connected).length;
|
|
551
567
|
const endpoint = hubStatus.agentEndpoint || '127.0.0.1:5197';
|
|
@@ -935,6 +951,52 @@ try {
|
|
|
935
951
|
binaryDrawCalls.some(call => call.op === 'clearRect' || call.op === 'fillRect'),
|
|
936
952
|
false,
|
|
937
953
|
'binary Blob frame paint must not clear/fill the canvas before drawing');
|
|
954
|
+
|
|
955
|
+
await wait(20);
|
|
956
|
+
const liveWs = diagnostics.webSocketConnections[0];
|
|
957
|
+
assert.ok(liveWs, 'expected MDM render to open the binary frame WebSocket');
|
|
958
|
+
assert.equal(liveWs.readyState, 1, 'binary frame WebSocket should be open before rerender');
|
|
959
|
+
const wsCountBeforeRerender = diagnostics.webSocketConnections.length;
|
|
960
|
+
const wsCloseCountBeforeRerender = liveWs.closeCount;
|
|
961
|
+
const websocketFrameSeq = 10001;
|
|
962
|
+
liveWs.onmessage?.({
|
|
963
|
+
data: new Blob([encodeRemoteBinaryFrame({
|
|
964
|
+
type: 'remote.frame.binary',
|
|
965
|
+
deviceId: patchTarget.DeviceId,
|
|
966
|
+
kind: 'live',
|
|
967
|
+
frameSeq: websocketFrameSeq,
|
|
968
|
+
streamId: 'render-smoke-ws-live',
|
|
969
|
+
contentHash: `render-smoke-ws-live-${websocketFrameSeq}`,
|
|
970
|
+
mimeType: 'image/jpeg',
|
|
971
|
+
width: 64,
|
|
972
|
+
height: 36,
|
|
973
|
+
capturedAt: new Date().toISOString(),
|
|
974
|
+
receivedAt: new Date().toISOString()
|
|
975
|
+
})])
|
|
976
|
+
});
|
|
977
|
+
await wait(30);
|
|
978
|
+
assert.equal(
|
|
979
|
+
patchPreview.dataset.remoteFleetFrameSeq,
|
|
980
|
+
String(websocketFrameSeq),
|
|
981
|
+
JSON.stringify(diagnostics.runtimeTrace.slice(-12)));
|
|
982
|
+
|
|
983
|
+
manager.renderRemoteFleetMonitorForTest(bodyView, buildMonitorNode(devices, hub.getStatus({ includeSecrets: true }), latestTaskBatch, recentTaskBatches));
|
|
984
|
+
await wait(30);
|
|
985
|
+
assert.equal(
|
|
986
|
+
liveWs.closeCount,
|
|
987
|
+
wsCloseCountBeforeRerender,
|
|
988
|
+
'MDM rerender must not close the active binary frame WebSocket');
|
|
989
|
+
assert.equal(
|
|
990
|
+
diagnostics.webSocketConnections.length,
|
|
991
|
+
wsCountBeforeRerender,
|
|
992
|
+
'MDM rerender must reuse the active binary frame WebSocket instead of opening a replacement');
|
|
993
|
+
const rerenderedPatchPreview = bodyView
|
|
994
|
+
.querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`)
|
|
995
|
+
?.querySelector('[data-remote-fleet-device-preview="tile"]');
|
|
996
|
+
assert.ok(rerenderedPatchPreview);
|
|
997
|
+
assert.equal(rerenderedPatchPreview.dataset.remoteFleetFrameSeq, String(websocketFrameSeq));
|
|
998
|
+
assert.equal(rerenderedPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]')?.style.display, 'block');
|
|
999
|
+
|
|
938
1000
|
const alternateDevice = devices.find(device =>
|
|
939
1001
|
device.Connected === true
|
|
940
1002
|
&& device.DeviceId !== focusedDevice.DeviceId);
|
|
@@ -317,6 +317,20 @@ async function waitForManagedAgent(bridge, managerEndpoint, label, timeoutMs = 2
|
|
|
317
317
|
}, timeoutMs, `${label} managed agent\n${bridge.details()}`);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
async function waitForManagedAgentRestart(bridge, managerEndpoint, previousPid, label, timeoutMs = 20000) {
|
|
321
|
+
return await waitFor(async () => {
|
|
322
|
+
const result = await fetchJson(`${bridge.baseUrl}/api/remote/agent/status`);
|
|
323
|
+
const agent = result.payload;
|
|
324
|
+
return agent?.running === true
|
|
325
|
+
&& agent?.ready === true
|
|
326
|
+
&& String(agent.manager || '') === managerEndpoint
|
|
327
|
+
&& Number(agent.pid || 0) > 0
|
|
328
|
+
&& Number(agent.pid || 0) !== Number(previousPid || 0)
|
|
329
|
+
? agent
|
|
330
|
+
: null;
|
|
331
|
+
}, timeoutMs, `${label} managed agent restart\n${bridge.details()}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
320
334
|
async function waitForConnectedDevice(bridge, label) {
|
|
321
335
|
return await waitFor(async () => {
|
|
322
336
|
const result = await fetchJson(`${bridge.baseUrl}/api/remote/devices`);
|
|
@@ -324,6 +338,18 @@ async function waitForConnectedDevice(bridge, label) {
|
|
|
324
338
|
}, 12000, `${label} connected device\n${bridge.details()}`);
|
|
325
339
|
}
|
|
326
340
|
|
|
341
|
+
function killProcess(pid) {
|
|
342
|
+
const value = Number(pid || 0);
|
|
343
|
+
assert.ok(value > 0, `expected positive pid, got ${pid}`);
|
|
344
|
+
try {
|
|
345
|
+
process.kill(value, 'SIGTERM');
|
|
346
|
+
} catch (error) {
|
|
347
|
+
if (error?.code !== 'ESRCH') {
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
327
353
|
async function main() {
|
|
328
354
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'mindexec-remote-registry-smoke-'));
|
|
329
355
|
let fakeSupabase = null;
|
|
@@ -407,6 +433,14 @@ async function main() {
|
|
|
407
433
|
assert.equal(secondAgent.leaseId, 'lease-b');
|
|
408
434
|
await waitForConnectedDevice(hostB, 'host-b');
|
|
409
435
|
|
|
436
|
+
const secondPid = Number(secondAgent.pid || 0);
|
|
437
|
+
killProcess(secondPid);
|
|
438
|
+
const restartedAgent = await waitForManagedAgentRestart(client, hostBEndpoint, secondPid, 'host-b', 12000);
|
|
439
|
+
assert.equal(restartedAgent.usingNpx, false, JSON.stringify(restartedAgent));
|
|
440
|
+
assert.match(String(restartedAgent.launcher || ''), /mindexec-remote-fast/i);
|
|
441
|
+
assert.equal(restartedAgent.leaseId, 'lease-b');
|
|
442
|
+
await waitForConnectedDevice(hostB, 'host-b after restart');
|
|
443
|
+
|
|
410
444
|
currentTarget = {
|
|
411
445
|
...currentTarget,
|
|
412
446
|
active: false,
|
package/server.js
CHANGED
|
@@ -3151,6 +3151,7 @@ let remoteAgentSyncReportState = null;
|
|
|
3151
3151
|
let remoteAgentSyncReportLogKey = '';
|
|
3152
3152
|
let remoteAgentSyncReportLogAt = 0;
|
|
3153
3153
|
let remoteAgentConnectPromise = null;
|
|
3154
|
+
const remoteAgentIntentionalStopKeys = new Set();
|
|
3154
3155
|
const remoteAgentRecentSuccessfulManagers = new Map();
|
|
3155
3156
|
let remoteAgentRecentSuccessfulManagersLoaded = false;
|
|
3156
3157
|
let remoteAgentRecentSuccessfulManagersSavePromise = null;
|
|
@@ -3656,6 +3657,36 @@ function isRemoteAgentRegistryOwned() {
|
|
|
3656
3657
|
&& /registry/i.test(String(remoteAgentState.source || ''));
|
|
3657
3658
|
}
|
|
3658
3659
|
|
|
3660
|
+
function isRemoteAgentRegistryState(state) {
|
|
3661
|
+
return /registry/i.test(String(state?.source || ''));
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
function suppressRemoteAgentAutoRetry(connectionKey) {
|
|
3665
|
+
const key = safeRemoteAgentField(connectionKey, 128);
|
|
3666
|
+
if (!key) {
|
|
3667
|
+
return;
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
remoteAgentIntentionalStopKeys.add(key);
|
|
3671
|
+
const timer = setTimeout(() => {
|
|
3672
|
+
remoteAgentIntentionalStopKeys.delete(key);
|
|
3673
|
+
}, 10000);
|
|
3674
|
+
timer?.unref?.();
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
function maybeRetryRemoteAgentAfterExit(state, reason = 'agent-exited') {
|
|
3678
|
+
if (!state
|
|
3679
|
+
|| !REMOTE_REGISTRY_FOLLOWER_ENABLED
|
|
3680
|
+
|| isShuttingDown
|
|
3681
|
+
|| !isRemoteAgentRegistryState(state)
|
|
3682
|
+
|| remoteAgentIntentionalStopKeys.has(String(state.connectionKey || ''))) {
|
|
3683
|
+
return;
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
logWarn('remote', `managed RemoteAgent registry process ended; waking registry follower ${formatKeyValue('reason', reason)} ${formatKeyValue('manager', state.manager || '-')}`);
|
|
3687
|
+
scheduleRemoteRegistryFollower(0, reason);
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3659
3690
|
function isLocalRemoteHostTargetActive() {
|
|
3660
3691
|
const status = remoteHub.getStatus({ includeSecrets: false });
|
|
3661
3692
|
return status?.hostTargetActive === true
|
|
@@ -3912,6 +3943,7 @@ function resolveNpxCliLauncher() {
|
|
|
3912
3943
|
|
|
3913
3944
|
async function stopRemoteAgentConnection(reason = 'stopped') {
|
|
3914
3945
|
const previous = remoteAgentState;
|
|
3946
|
+
suppressRemoteAgentAutoRetry(previous.connectionKey);
|
|
3915
3947
|
if (previous.proc) {
|
|
3916
3948
|
try {
|
|
3917
3949
|
await terminateProcessTree(previous.proc);
|
|
@@ -4143,6 +4175,17 @@ function createRemoteAgentAttempt(options = {}) {
|
|
|
4143
4175
|
state.lastError = signal ? `signal:${signal}` : `exit:${code}`;
|
|
4144
4176
|
}
|
|
4145
4177
|
attempt.error = attempt.error || state.lastError || `exit:${code ?? 'unknown'}`;
|
|
4178
|
+
if (remoteAgentState === state
|
|
4179
|
+
&& remoteAgentState.connectionKey === state.connectionKey) {
|
|
4180
|
+
const serialized = serializeRemoteAgentState();
|
|
4181
|
+
if (state.status === 'failed') {
|
|
4182
|
+
logWarn('remote', `managed RemoteAgent failed: ${formatRemoteAgentFailureSummary(state)}`);
|
|
4183
|
+
} else {
|
|
4184
|
+
logEvent('remote', `managed RemoteAgent exited ${formatKeyValue('code', code ?? 0)}`, 'remote');
|
|
4185
|
+
}
|
|
4186
|
+
emitBridgeEvent(state.status === 'exited' ? 'RemoteAgentExited' : 'RemoteAgentFailed', serialized);
|
|
4187
|
+
maybeRetryRemoteAgentAfterExit(state, state.status === 'exited' ? 'agent-exited' : 'agent-failed');
|
|
4188
|
+
}
|
|
4146
4189
|
});
|
|
4147
4190
|
} catch (err) {
|
|
4148
4191
|
attempt.failed = true;
|
|
@@ -13459,13 +13459,15 @@
|
|
|
13459
13459
|
const REMOTE_FLEET_FRAME_CANVAS_MAX_DPR = 2;
|
|
13460
13460
|
const REMOTE_FLEET_FRAME_BLOB_CACHE_MS = 10000;
|
|
13461
13461
|
const REMOTE_FLEET_FRAME_BLOB_CACHE_LIMIT = 96;
|
|
13462
|
-
const REMOTE_FLEET_LIVE_FRAME_DECODE_TIMEOUT_MS =
|
|
13462
|
+
const REMOTE_FLEET_LIVE_FRAME_DECODE_TIMEOUT_MS = 700;
|
|
13463
13463
|
const REMOTE_FLEET_THUMBNAIL_FRAME_DECODE_TIMEOUT_MS = 1200;
|
|
13464
13464
|
const REMOTE_FLEET_BINARY_FRAME_MAX_DECODE_IN_FLIGHT = 1;
|
|
13465
13465
|
const REMOTE_FLEET_BINARY_FRAME_WS_RECONNECT_MS = 1500;
|
|
13466
13466
|
const REMOTE_FLEET_BINARY_FRAME_SUBSCRIBE_MS = 1000;
|
|
13467
13467
|
const REMOTE_FLEET_BINARY_FRAME_STALE_FALLBACK_MS = 1400;
|
|
13468
13468
|
const REMOTE_FLEET_BINARY_FRAME_CONNECT_GRACE_MS = 1600;
|
|
13469
|
+
const REMOTE_FLEET_BINARY_FRAME_CACHE_MS = 10000;
|
|
13470
|
+
const REMOTE_FLEET_BINARY_FRAME_CACHE_LIMIT = 240;
|
|
13469
13471
|
const REMOTE_FLEET_AUTO_LIVE_START_MAX_PARALLEL = 8;
|
|
13470
13472
|
const REMOTE_FLEET_AUTO_LIVE_START_COOLDOWN_MS = 3000;
|
|
13471
13473
|
const REMOTE_FLEET_TASK_FOLLOW_INITIAL_MS = 250;
|
|
@@ -13639,9 +13641,11 @@
|
|
|
13639
13641
|
return nodeState;
|
|
13640
13642
|
}
|
|
13641
13643
|
|
|
13642
|
-
function clearRemoteFleetTimers(bodyView) {
|
|
13644
|
+
function clearRemoteFleetTimers(bodyView, options = {}) {
|
|
13643
13645
|
if (!bodyView) return;
|
|
13644
|
-
|
|
13646
|
+
if (options.keepBinaryFrameSocket !== true) {
|
|
13647
|
+
releaseRemoteFleetBinaryFrameSocket(bodyView);
|
|
13648
|
+
}
|
|
13645
13649
|
if (bodyView._remoteFleetLiveRefreshTimer) {
|
|
13646
13650
|
clearInterval(bodyView._remoteFleetLiveRefreshTimer);
|
|
13647
13651
|
bodyView._remoteFleetLiveRefreshTimer = null;
|
|
@@ -13822,6 +13826,57 @@
|
|
|
13822
13826
|
.slice(0, 240);
|
|
13823
13827
|
}
|
|
13824
13828
|
|
|
13829
|
+
function pruneRemoteFleetBinaryFrameCache(session) {
|
|
13830
|
+
if (!session?.latestBinaryFrames) {
|
|
13831
|
+
return;
|
|
13832
|
+
}
|
|
13833
|
+
|
|
13834
|
+
const now = getRemoteFleetFrameNow();
|
|
13835
|
+
for (const [deviceId, entry] of session.latestBinaryFrames) {
|
|
13836
|
+
if (!entry
|
|
13837
|
+
|| !entry.frame
|
|
13838
|
+
|| now - Number(entry.seenAt || 0) > REMOTE_FLEET_BINARY_FRAME_CACHE_MS
|
|
13839
|
+
|| session.latestBinaryFrames.size > REMOTE_FLEET_BINARY_FRAME_CACHE_LIMIT) {
|
|
13840
|
+
session.latestBinaryFrames.delete(deviceId);
|
|
13841
|
+
}
|
|
13842
|
+
}
|
|
13843
|
+
}
|
|
13844
|
+
|
|
13845
|
+
function rememberRemoteFleetBinaryFrame(session, frame) {
|
|
13846
|
+
const deviceId = String(frame?.deviceId || '').trim();
|
|
13847
|
+
if (!session || !deviceId || !frame?._remoteFleetPayloadBlob) {
|
|
13848
|
+
return;
|
|
13849
|
+
}
|
|
13850
|
+
|
|
13851
|
+
if (!(session.latestBinaryFrames instanceof Map)) {
|
|
13852
|
+
session.latestBinaryFrames = new Map();
|
|
13853
|
+
}
|
|
13854
|
+
|
|
13855
|
+
pruneRemoteFleetBinaryFrameCache(session);
|
|
13856
|
+
session.latestBinaryFrames.set(deviceId, {
|
|
13857
|
+
seenAt: getRemoteFleetFrameNow(),
|
|
13858
|
+
frame: cloneRemoteFleetFramePatch(frame)
|
|
13859
|
+
});
|
|
13860
|
+
}
|
|
13861
|
+
|
|
13862
|
+
function applyRemoteFleetBinaryFrameCacheToBody(bodyView, session) {
|
|
13863
|
+
if (!bodyView || !(session?.latestBinaryFrames instanceof Map) || session.latestBinaryFrames.size === 0) {
|
|
13864
|
+
return 0;
|
|
13865
|
+
}
|
|
13866
|
+
|
|
13867
|
+
pruneRemoteFleetBinaryFrameCache(session);
|
|
13868
|
+
const patches = [];
|
|
13869
|
+
for (const entry of session.latestBinaryFrames.values()) {
|
|
13870
|
+
if (entry?.frame) {
|
|
13871
|
+
patches.push(cloneRemoteFleetFramePatch(entry.frame));
|
|
13872
|
+
}
|
|
13873
|
+
}
|
|
13874
|
+
|
|
13875
|
+
return patches.length > 0
|
|
13876
|
+
? applyRemoteFleetFramePatches(bodyView, patches)
|
|
13877
|
+
: 0;
|
|
13878
|
+
}
|
|
13879
|
+
|
|
13825
13880
|
function refreshRemoteFleetBinaryFrameSubscription(session, force = false) {
|
|
13826
13881
|
if (!session?.ws || session.ws.readyState !== WebSocket.OPEN) {
|
|
13827
13882
|
return false;
|
|
@@ -13877,7 +13932,11 @@
|
|
|
13877
13932
|
refreshRemoteFleetBinaryFrameSubscription(session);
|
|
13878
13933
|
return true;
|
|
13879
13934
|
}
|
|
13935
|
+
if (session.wsOpening === true) {
|
|
13936
|
+
return true;
|
|
13937
|
+
}
|
|
13880
13938
|
|
|
13939
|
+
session.wsOpening = true;
|
|
13881
13940
|
try {
|
|
13882
13941
|
const status = await getRemoteFleetBridgeStatusForFrames();
|
|
13883
13942
|
const wsUrl = buildRemoteFleetBinaryFrameWsUrl(status);
|
|
@@ -13891,6 +13950,7 @@
|
|
|
13891
13950
|
session.subscriptionKey = '';
|
|
13892
13951
|
ws.binaryType = 'arraybuffer';
|
|
13893
13952
|
ws.onopen = () => {
|
|
13953
|
+
session.wsOpening = false;
|
|
13894
13954
|
session.wsOpenedAt = getRemoteFleetFrameNow();
|
|
13895
13955
|
window.RuntimeTrace?.emit?.('remote.frame.wsOpen', { nodeId: session.nodeId });
|
|
13896
13956
|
refreshRemoteFleetBinaryFrameSubscription(session, true);
|
|
@@ -13922,6 +13982,7 @@
|
|
|
13922
13982
|
let applied = 0;
|
|
13923
13983
|
const frameAt = getRemoteFleetFrameNow();
|
|
13924
13984
|
session.lastBinaryFrameAt = frameAt;
|
|
13985
|
+
rememberRemoteFleetBinaryFrame(session, frame);
|
|
13925
13986
|
session.bodies.forEach(body => {
|
|
13926
13987
|
if (document.body.contains(body)) {
|
|
13927
13988
|
const bodyApplied = applyRemoteFleetFramePatches(body, [frame]);
|
|
@@ -13975,6 +14036,7 @@
|
|
|
13975
14036
|
});
|
|
13976
14037
|
};
|
|
13977
14038
|
ws.onclose = () => {
|
|
14039
|
+
session.wsOpening = false;
|
|
13978
14040
|
if (session.ws === ws) {
|
|
13979
14041
|
session.ws = null;
|
|
13980
14042
|
}
|
|
@@ -13990,6 +14052,7 @@
|
|
|
13990
14052
|
};
|
|
13991
14053
|
return true;
|
|
13992
14054
|
} catch (error) {
|
|
14055
|
+
session.wsOpening = false;
|
|
13993
14056
|
window.RuntimeTrace?.emit?.('remote.frame.wsOpenFailed', {
|
|
13994
14057
|
nodeId: session.nodeId,
|
|
13995
14058
|
error: error?.message || String(error || '')
|
|
@@ -14014,6 +14077,7 @@
|
|
|
14014
14077
|
reconnectTimer: null,
|
|
14015
14078
|
subscriptionTimer: null,
|
|
14016
14079
|
subscriptionKey: '',
|
|
14080
|
+
latestBinaryFrames: new Map(),
|
|
14017
14081
|
controlSessions: new Set(),
|
|
14018
14082
|
getDeviceIds: null
|
|
14019
14083
|
};
|
|
@@ -14031,6 +14095,7 @@
|
|
|
14031
14095
|
mode: String(options.mode || 'remote-fast')
|
|
14032
14096
|
};
|
|
14033
14097
|
bodyView._remoteFleetBinaryFrameSession = session;
|
|
14098
|
+
applyRemoteFleetBinaryFrameCacheToBody(bodyView, session);
|
|
14034
14099
|
openRemoteFleetBinaryFrameSocket(session).catch(() => undefined);
|
|
14035
14100
|
return true;
|
|
14036
14101
|
}
|
|
@@ -16043,7 +16108,7 @@
|
|
|
16043
16108
|
|
|
16044
16109
|
function renderRemoteFleetDevice(bodyView, nodeModel) {
|
|
16045
16110
|
if (!bodyView) return;
|
|
16046
|
-
clearRemoteFleetTimers(bodyView);
|
|
16111
|
+
clearRemoteFleetTimers(bodyView, { keepBinaryFrameSocket: true });
|
|
16047
16112
|
|
|
16048
16113
|
const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
|
|
16049
16114
|
const device = parseRemoteFleetPinnedDevice(nodeModel);
|
|
@@ -16541,7 +16606,7 @@
|
|
|
16541
16606
|
|
|
16542
16607
|
function renderRemoteFleetMonitor(bodyView, nodeModel) {
|
|
16543
16608
|
if (!bodyView) return;
|
|
16544
|
-
clearRemoteFleetTimers(bodyView);
|
|
16609
|
+
clearRemoteFleetTimers(bodyView, { keepBinaryFrameSocket: true });
|
|
16545
16610
|
|
|
16546
16611
|
const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
|
|
16547
16612
|
const searchState = bodyView.dataset.remoteFleetSearch || '';
|
|
@@ -18038,11 +18103,14 @@
|
|
|
18038
18103
|
clearRemoteFleetTimers(bodyView);
|
|
18039
18104
|
}
|
|
18040
18105
|
}, REMOTE_FLEET_LIVE_REFRESH_MS);
|
|
18041
|
-
} else
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
|
|
18106
|
+
} else {
|
|
18107
|
+
releaseRemoteFleetBinaryFrameSocket(bodyView);
|
|
18108
|
+
if (autoMonitorState && hasMonitorTargets) {
|
|
18109
|
+
startRemoteFleetFrameLoop(bodyView, REMOTE_FLEET_THUMBNAIL_FRAME_REFRESH_MS, () => refreshRemoteFleetVisibleFrames(true));
|
|
18110
|
+
startRemoteFleetMonitorRefreshTimer(REMOTE_FLEET_MONITOR_REFRESH_MS, 'visible-devices');
|
|
18111
|
+
} else if (autoMonitorState) {
|
|
18112
|
+
startRemoteFleetMonitorRefreshTimer(REMOTE_FLEET_EMPTY_MONITOR_REFRESH_MS, 'empty-discovery');
|
|
18113
|
+
}
|
|
18046
18114
|
}
|
|
18047
18115
|
}
|
|
18048
18116
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "Q3LEcx0Y",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"url": "_content/MindExecution.Shared/js/mind-map-core.js.backup"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
"hash": "sha256-
|
|
89
|
+
"hash": "sha256-ct4yGB6E/ViQSpNNn3fHtt3v+usCW9LYQEbpOmzuRdk=",
|
|
90
90
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
91
91
|
},
|
|
92
92
|
{
|