livedesk 0.1.81 → 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 +122 -1
- package/package.json +2 -2
package/hub/src/remote-hub.js
CHANGED
|
@@ -1205,6 +1205,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1205
1205
|
const devices = new Map();
|
|
1206
1206
|
const taskBatches = new Map();
|
|
1207
1207
|
const sockets = new Map();
|
|
1208
|
+
const inputSockets = new Map();
|
|
1208
1209
|
const allSockets = new Set();
|
|
1209
1210
|
const duplicateDeviceLogAt = new Map();
|
|
1210
1211
|
let server = null;
|
|
@@ -1738,6 +1739,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1738
1739
|
|
|
1739
1740
|
function closeExistingDeviceSocket(deviceId, nextSessionId) {
|
|
1740
1741
|
const existing = devices.get(deviceId);
|
|
1742
|
+
closeInputSocket(existing, 'replaced-by-new-session');
|
|
1741
1743
|
if (!existing?.socket || existing.socket.destroyed) {
|
|
1742
1744
|
return;
|
|
1743
1745
|
}
|
|
@@ -1752,6 +1754,43 @@ export function createRemoteHub(options = {}) {
|
|
|
1752
1754
|
existing.socket.destroy();
|
|
1753
1755
|
}
|
|
1754
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
|
+
|
|
1755
1794
|
function getDeviceActivityMs(device) {
|
|
1756
1795
|
return Math.max(
|
|
1757
1796
|
Date.parse(device?.lastSeenAt || '') || 0,
|
|
@@ -2136,6 +2175,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2136
2175
|
|
|
2137
2176
|
const device = {
|
|
2138
2177
|
socket,
|
|
2178
|
+
inputSocket: null,
|
|
2139
2179
|
deviceId,
|
|
2140
2180
|
sessionId,
|
|
2141
2181
|
deviceName: safeString(hello.deviceName || hello.hostname || deviceId, 120),
|
|
@@ -2152,6 +2192,8 @@ export function createRemoteHub(options = {}) {
|
|
|
2152
2192
|
capabilities,
|
|
2153
2193
|
connected: true,
|
|
2154
2194
|
connectedAt: now,
|
|
2195
|
+
inputConnectedAt: '',
|
|
2196
|
+
inputLastSeenAt: '',
|
|
2155
2197
|
disconnectedAt: '',
|
|
2156
2198
|
lastSeenAt: now,
|
|
2157
2199
|
lastStatusAt: '',
|
|
@@ -2195,6 +2237,37 @@ export function createRemoteHub(options = {}) {
|
|
|
2195
2237
|
return device;
|
|
2196
2238
|
}
|
|
2197
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
|
+
|
|
2198
2271
|
function detachSocket(socket, reason = 'socket-closed') {
|
|
2199
2272
|
const deviceId = sockets.get(socket);
|
|
2200
2273
|
sockets.delete(socket);
|
|
@@ -2209,6 +2282,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2209
2282
|
|
|
2210
2283
|
device.connected = false;
|
|
2211
2284
|
device.socket = null;
|
|
2285
|
+
closeInputSocket(device, reason);
|
|
2212
2286
|
device.disconnectedAt = new Date().toISOString();
|
|
2213
2287
|
device.lastDisconnectReason = reason;
|
|
2214
2288
|
if (device.activeLiveStream) {
|
|
@@ -2973,6 +3047,12 @@ export function createRemoteHub(options = {}) {
|
|
|
2973
3047
|
}
|
|
2974
3048
|
|
|
2975
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
|
+
|
|
2976
3056
|
device.counters.messagesReceived += 1;
|
|
2977
3057
|
device.lastSeenAt = new Date().toISOString();
|
|
2978
3058
|
|
|
@@ -3016,6 +3096,19 @@ export function createRemoteHub(options = {}) {
|
|
|
3016
3096
|
return;
|
|
3017
3097
|
}
|
|
3018
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
|
+
|
|
3019
3112
|
const device = attachDevice(socket, message);
|
|
3020
3113
|
if (!device) {
|
|
3021
3114
|
return;
|
|
@@ -3032,6 +3125,11 @@ export function createRemoteHub(options = {}) {
|
|
|
3032
3125
|
return;
|
|
3033
3126
|
}
|
|
3034
3127
|
|
|
3128
|
+
if (state.inputOnly) {
|
|
3129
|
+
device.inputLastSeenAt = new Date().toISOString();
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3035
3133
|
device.counters.messagesReceived += 1;
|
|
3036
3134
|
device.lastSeenAt = new Date().toISOString();
|
|
3037
3135
|
|
|
@@ -3103,7 +3201,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3103
3201
|
|
|
3104
3202
|
const state = {
|
|
3105
3203
|
authenticated: false,
|
|
3106
|
-
device: null
|
|
3204
|
+
device: null,
|
|
3205
|
+
inputOnly: false
|
|
3107
3206
|
};
|
|
3108
3207
|
|
|
3109
3208
|
const helloTimer = setTimeout(() => {
|
|
@@ -3154,6 +3253,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3154
3253
|
const detach = reason => {
|
|
3155
3254
|
allSockets.delete(socket);
|
|
3156
3255
|
clearTimeout(helloTimer);
|
|
3256
|
+
detachInputSocket(socket, reason);
|
|
3157
3257
|
detachSocket(socket, reason);
|
|
3158
3258
|
};
|
|
3159
3259
|
|
|
@@ -3243,6 +3343,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3243
3343
|
const state = {
|
|
3244
3344
|
authenticated: false,
|
|
3245
3345
|
device: null,
|
|
3346
|
+
inputOnly: false,
|
|
3246
3347
|
buffer: Buffer.alloc(0),
|
|
3247
3348
|
pendingBinaryFrame: null
|
|
3248
3349
|
};
|
|
@@ -3323,11 +3424,13 @@ export function createRemoteHub(options = {}) {
|
|
|
3323
3424
|
socket.on('close', () => {
|
|
3324
3425
|
allSockets.delete(socket);
|
|
3325
3426
|
clearTimeout(helloTimer);
|
|
3427
|
+
detachInputSocket(socket);
|
|
3326
3428
|
detachSocket(socket);
|
|
3327
3429
|
});
|
|
3328
3430
|
socket.on('error', err => {
|
|
3329
3431
|
allSockets.delete(socket);
|
|
3330
3432
|
clearTimeout(helloTimer);
|
|
3433
|
+
detachInputSocket(socket, err?.message || 'socket-error');
|
|
3331
3434
|
detachSocket(socket, err?.message || 'socket-error');
|
|
3332
3435
|
});
|
|
3333
3436
|
}
|
|
@@ -3514,6 +3617,24 @@ export function createRemoteHub(options = {}) {
|
|
|
3514
3617
|
return { ok: false, error: 'missing-input-type' };
|
|
3515
3618
|
}
|
|
3516
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
|
+
|
|
3517
3638
|
return sendCommand(deviceId, {
|
|
3518
3639
|
command: 'input.control',
|
|
3519
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"
|