livedesk 0.1.80 → 0.1.82
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/hub/src/remote-hub.js
CHANGED
|
@@ -535,6 +535,8 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
535
535
|
const normalizedY = Number(input.normalizedY ?? input.NormalizedY);
|
|
536
536
|
const deltaX = Number(input.deltaX ?? input.DeltaX);
|
|
537
537
|
const deltaY = Number(input.deltaY ?? input.DeltaY);
|
|
538
|
+
const keyCode = Number(input.keyCode ?? input.KeyCode);
|
|
539
|
+
const location = Number(input.location ?? input.Location);
|
|
538
540
|
return {
|
|
539
541
|
type,
|
|
540
542
|
normalizedX: Number.isFinite(normalizedX) ? Math.max(0, Math.min(1, normalizedX)) : undefined,
|
|
@@ -544,6 +546,8 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
544
546
|
deltaY: Number.isFinite(deltaY) ? Math.max(-4096, Math.min(4096, deltaY)) : 0,
|
|
545
547
|
key: safeString(input.key || input.Key, 80),
|
|
546
548
|
code: safeString(input.code || input.Code, 80),
|
|
549
|
+
keyCode: Number.isFinite(keyCode) ? Math.max(0, Math.min(65535, Math.trunc(keyCode))) : 0,
|
|
550
|
+
location: Number.isFinite(location) ? Math.max(0, Math.min(255, Math.trunc(location))) : 0,
|
|
547
551
|
text: safeText(input.text || input.Text, 256),
|
|
548
552
|
repeat: input.repeat === true || input.Repeat === true,
|
|
549
553
|
controlLeaseId: safeString(input.controlLeaseId || input.ControlLeaseId, 128),
|
|
@@ -1201,6 +1205,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1201
1205
|
const devices = new Map();
|
|
1202
1206
|
const taskBatches = new Map();
|
|
1203
1207
|
const sockets = new Map();
|
|
1208
|
+
const inputSockets = new Map();
|
|
1204
1209
|
const allSockets = new Set();
|
|
1205
1210
|
const duplicateDeviceLogAt = new Map();
|
|
1206
1211
|
let server = null;
|
|
@@ -1734,6 +1739,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1734
1739
|
|
|
1735
1740
|
function closeExistingDeviceSocket(deviceId, nextSessionId) {
|
|
1736
1741
|
const existing = devices.get(deviceId);
|
|
1742
|
+
closeInputSocket(existing, 'replaced-by-new-session');
|
|
1737
1743
|
if (!existing?.socket || existing.socket.destroyed) {
|
|
1738
1744
|
return;
|
|
1739
1745
|
}
|
|
@@ -1748,6 +1754,43 @@ export function createRemoteHub(options = {}) {
|
|
|
1748
1754
|
existing.socket.destroy();
|
|
1749
1755
|
}
|
|
1750
1756
|
|
|
1757
|
+
function closeInputSocket(device, reason = 'input-socket-closed') {
|
|
1758
|
+
const socket = device?.inputSocket;
|
|
1759
|
+
if (!socket) {
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
device.inputSocket = null;
|
|
1764
|
+
inputSockets.delete(socket);
|
|
1765
|
+
try {
|
|
1766
|
+
writeJsonLine(socket, { type: 'disconnect', reason });
|
|
1767
|
+
} catch {
|
|
1768
|
+
// Best-effort notice before closing the side channel.
|
|
1769
|
+
}
|
|
1770
|
+
try {
|
|
1771
|
+
socket.destroy?.();
|
|
1772
|
+
} catch {
|
|
1773
|
+
// Ignore close failures.
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
function detachInputSocket(socket, reason = 'input-socket-closed') {
|
|
1778
|
+
const deviceId = inputSockets.get(socket);
|
|
1779
|
+
inputSockets.delete(socket);
|
|
1780
|
+
if (!deviceId) {
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
const device = devices.get(deviceId);
|
|
1785
|
+
if (!device || device.inputSocket !== socket) {
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
device.inputSocket = null;
|
|
1790
|
+
device.inputLastSeenAt = new Date().toISOString();
|
|
1791
|
+
emitRemoteEvent('RemoteInputSocketDisconnected', device, { reason });
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1751
1794
|
function getDeviceActivityMs(device) {
|
|
1752
1795
|
return Math.max(
|
|
1753
1796
|
Date.parse(device?.lastSeenAt || '') || 0,
|
|
@@ -2132,6 +2175,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2132
2175
|
|
|
2133
2176
|
const device = {
|
|
2134
2177
|
socket,
|
|
2178
|
+
inputSocket: null,
|
|
2135
2179
|
deviceId,
|
|
2136
2180
|
sessionId,
|
|
2137
2181
|
deviceName: safeString(hello.deviceName || hello.hostname || deviceId, 120),
|
|
@@ -2148,6 +2192,8 @@ export function createRemoteHub(options = {}) {
|
|
|
2148
2192
|
capabilities,
|
|
2149
2193
|
connected: true,
|
|
2150
2194
|
connectedAt: now,
|
|
2195
|
+
inputConnectedAt: '',
|
|
2196
|
+
inputLastSeenAt: '',
|
|
2151
2197
|
disconnectedAt: '',
|
|
2152
2198
|
lastSeenAt: now,
|
|
2153
2199
|
lastStatusAt: '',
|
|
@@ -2191,6 +2237,37 @@ export function createRemoteHub(options = {}) {
|
|
|
2191
2237
|
return device;
|
|
2192
2238
|
}
|
|
2193
2239
|
|
|
2240
|
+
function attachInputSocket(socket, hello) {
|
|
2241
|
+
const deviceId = normalizeDeviceId(hello.deviceId);
|
|
2242
|
+
const device = devices.get(deviceId);
|
|
2243
|
+
if (!device || !device.connected || !device.socket || device.socket.destroyed) {
|
|
2244
|
+
writeJsonLine(socket, { type: 'error', error: 'device-not-connected' });
|
|
2245
|
+
socket.destroy();
|
|
2246
|
+
return null;
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
closeInputSocket(device, 'replaced-by-new-input-socket');
|
|
2250
|
+
|
|
2251
|
+
const now = new Date().toISOString();
|
|
2252
|
+
device.inputSocket = socket;
|
|
2253
|
+
device.inputConnectedAt = now;
|
|
2254
|
+
device.inputLastSeenAt = now;
|
|
2255
|
+
inputSockets.set(socket, deviceId);
|
|
2256
|
+
|
|
2257
|
+
writeJsonLine(socket, {
|
|
2258
|
+
type: 'welcome',
|
|
2259
|
+
channel: 'input',
|
|
2260
|
+
protocol: REMOTE_AGENT_PROTOCOL,
|
|
2261
|
+
protocolVersion: REMOTE_PROTOCOL_VERSION,
|
|
2262
|
+
sessionId: device.sessionId,
|
|
2263
|
+
deviceId,
|
|
2264
|
+
serverTime: now
|
|
2265
|
+
});
|
|
2266
|
+
|
|
2267
|
+
emitRemoteEvent('RemoteInputSocketConnected', device);
|
|
2268
|
+
return device;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2194
2271
|
function detachSocket(socket, reason = 'socket-closed') {
|
|
2195
2272
|
const deviceId = sockets.get(socket);
|
|
2196
2273
|
sockets.delete(socket);
|
|
@@ -2205,6 +2282,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2205
2282
|
|
|
2206
2283
|
device.connected = false;
|
|
2207
2284
|
device.socket = null;
|
|
2285
|
+
closeInputSocket(device, reason);
|
|
2208
2286
|
device.disconnectedAt = new Date().toISOString();
|
|
2209
2287
|
device.lastDisconnectReason = reason;
|
|
2210
2288
|
if (device.activeLiveStream) {
|
|
@@ -2969,6 +3047,12 @@ export function createRemoteHub(options = {}) {
|
|
|
2969
3047
|
}
|
|
2970
3048
|
|
|
2971
3049
|
const device = state.device;
|
|
3050
|
+
if (state.inputOnly) {
|
|
3051
|
+
writeJsonLine(socket, { type: 'error', error: 'input-channel-binary-not-supported' });
|
|
3052
|
+
socket.destroy();
|
|
3053
|
+
return;
|
|
3054
|
+
}
|
|
3055
|
+
|
|
2972
3056
|
device.counters.messagesReceived += 1;
|
|
2973
3057
|
device.lastSeenAt = new Date().toISOString();
|
|
2974
3058
|
|
|
@@ -3012,6 +3096,19 @@ export function createRemoteHub(options = {}) {
|
|
|
3012
3096
|
return;
|
|
3013
3097
|
}
|
|
3014
3098
|
|
|
3099
|
+
const channel = safeString(message.channel || message.Channel, 40).toLowerCase();
|
|
3100
|
+
if (channel === 'input') {
|
|
3101
|
+
const device = attachInputSocket(socket, message);
|
|
3102
|
+
if (!device) {
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
state.authenticated = true;
|
|
3107
|
+
state.device = device;
|
|
3108
|
+
state.inputOnly = true;
|
|
3109
|
+
return;
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3015
3112
|
const device = attachDevice(socket, message);
|
|
3016
3113
|
if (!device) {
|
|
3017
3114
|
return;
|
|
@@ -3028,6 +3125,11 @@ export function createRemoteHub(options = {}) {
|
|
|
3028
3125
|
return;
|
|
3029
3126
|
}
|
|
3030
3127
|
|
|
3128
|
+
if (state.inputOnly) {
|
|
3129
|
+
device.inputLastSeenAt = new Date().toISOString();
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3031
3133
|
device.counters.messagesReceived += 1;
|
|
3032
3134
|
device.lastSeenAt = new Date().toISOString();
|
|
3033
3135
|
|
|
@@ -3099,7 +3201,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3099
3201
|
|
|
3100
3202
|
const state = {
|
|
3101
3203
|
authenticated: false,
|
|
3102
|
-
device: null
|
|
3204
|
+
device: null,
|
|
3205
|
+
inputOnly: false
|
|
3103
3206
|
};
|
|
3104
3207
|
|
|
3105
3208
|
const helloTimer = setTimeout(() => {
|
|
@@ -3150,6 +3253,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3150
3253
|
const detach = reason => {
|
|
3151
3254
|
allSockets.delete(socket);
|
|
3152
3255
|
clearTimeout(helloTimer);
|
|
3256
|
+
detachInputSocket(socket, reason);
|
|
3153
3257
|
detachSocket(socket, reason);
|
|
3154
3258
|
};
|
|
3155
3259
|
|
|
@@ -3239,6 +3343,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3239
3343
|
const state = {
|
|
3240
3344
|
authenticated: false,
|
|
3241
3345
|
device: null,
|
|
3346
|
+
inputOnly: false,
|
|
3242
3347
|
buffer: Buffer.alloc(0),
|
|
3243
3348
|
pendingBinaryFrame: null
|
|
3244
3349
|
};
|
|
@@ -3319,11 +3424,13 @@ export function createRemoteHub(options = {}) {
|
|
|
3319
3424
|
socket.on('close', () => {
|
|
3320
3425
|
allSockets.delete(socket);
|
|
3321
3426
|
clearTimeout(helloTimer);
|
|
3427
|
+
detachInputSocket(socket);
|
|
3322
3428
|
detachSocket(socket);
|
|
3323
3429
|
});
|
|
3324
3430
|
socket.on('error', err => {
|
|
3325
3431
|
allSockets.delete(socket);
|
|
3326
3432
|
clearTimeout(helloTimer);
|
|
3433
|
+
detachInputSocket(socket, err?.message || 'socket-error');
|
|
3327
3434
|
detachSocket(socket, err?.message || 'socket-error');
|
|
3328
3435
|
});
|
|
3329
3436
|
}
|
|
@@ -3510,6 +3617,24 @@ export function createRemoteHub(options = {}) {
|
|
|
3510
3617
|
return { ok: false, error: 'missing-input-type' };
|
|
3511
3618
|
}
|
|
3512
3619
|
|
|
3620
|
+
const inputSocket = device.inputSocket;
|
|
3621
|
+
if (inputSocket && !inputSocket.destroyed) {
|
|
3622
|
+
const sent = writeJsonLine(inputSocket, {
|
|
3623
|
+
type: 'input.control',
|
|
3624
|
+
payload: {
|
|
3625
|
+
...normalized,
|
|
3626
|
+
issuedAt: normalized.issuedAt || new Date().toISOString()
|
|
3627
|
+
}
|
|
3628
|
+
});
|
|
3629
|
+
if (sent) {
|
|
3630
|
+
device.counters.commandsSent += 1;
|
|
3631
|
+
device.inputLastSeenAt = new Date().toISOString();
|
|
3632
|
+
return { ok: true, inputSocket: true };
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
detachInputSocket(inputSocket, 'input-socket-write-failed');
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3513
3638
|
return sendCommand(deviceId, {
|
|
3514
3639
|
command: 'input.control',
|
|
3515
3640
|
payload: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livedesk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.82",
|
|
4
4
|
"description": "LiveDesk Hub and client launcher",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"node": ">=20"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@livedesk/client": "0.1.
|
|
33
|
+
"@livedesk/client": "0.1.62",
|
|
34
34
|
"cors": "^2.8.5",
|
|
35
35
|
"express": "^4.21.2",
|
|
36
36
|
"ws": "^8.18.3"
|