livedesk 0.1.124 → 0.1.126
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 +135 -16
- package/hub/src/server.js +1 -1
- package/package.json +1 -1
package/hub/src/remote-hub.js
CHANGED
|
@@ -1024,6 +1024,59 @@ function startsWithTcpBinaryFrameMagic(buffer) {
|
|
|
1024
1024
|
&& buffer.subarray(0, TCP_BINARY_FRAME_MAGIC.length).equals(TCP_BINARY_FRAME_MAGIC);
|
|
1025
1025
|
}
|
|
1026
1026
|
|
|
1027
|
+
function isJsonObjectStartByte(value) {
|
|
1028
|
+
return value === 0x7b;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
function isWhitespaceByte(value) {
|
|
1032
|
+
return value === 0x20 || value === 0x09 || value === 0x0d || value === 0x0a;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function findFirstNonWhitespaceByte(buffer) {
|
|
1036
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
1037
|
+
return -1;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
for (let index = 0; index < buffer.length; index += 1) {
|
|
1041
|
+
if (!isWhitespaceByte(buffer[index])) {
|
|
1042
|
+
return index;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
return -1;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function findTcpFrameOnlySyncIndex(buffer, startIndex = 0) {
|
|
1049
|
+
if (!Buffer.isBuffer(buffer) || buffer.length <= 0) {
|
|
1050
|
+
return -1;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
const safeStart = Math.max(0, Math.min(buffer.length, Math.floor(Number(startIndex) || 0)));
|
|
1054
|
+
const magicIndex = buffer.indexOf(TCP_BINARY_FRAME_MAGIC, safeStart);
|
|
1055
|
+
const jsonIndex = buffer.indexOf(0x7b, safeStart);
|
|
1056
|
+
if (magicIndex < 0) {
|
|
1057
|
+
return jsonIndex;
|
|
1058
|
+
}
|
|
1059
|
+
if (jsonIndex < 0) {
|
|
1060
|
+
return magicIndex;
|
|
1061
|
+
}
|
|
1062
|
+
return Math.min(magicIndex, jsonIndex);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
function keepTcpFrameOnlySyncTail(buffer) {
|
|
1066
|
+
if (!Buffer.isBuffer(buffer) || buffer.length <= 0) {
|
|
1067
|
+
return Buffer.alloc(0);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const maxTailLength = Math.min(buffer.length, TCP_BINARY_FRAME_MAGIC.length - 1);
|
|
1071
|
+
for (let tailLength = maxTailLength; tailLength > 0; tailLength -= 1) {
|
|
1072
|
+
const tail = buffer.subarray(buffer.length - tailLength);
|
|
1073
|
+
if (hasTcpBinaryFrameMagicPrefix(tail)) {
|
|
1074
|
+
return tail;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return Buffer.alloc(0);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1027
1080
|
function parseTcpBinaryFramePacket(buffer) {
|
|
1028
1081
|
if (!Buffer.isBuffer(buffer) || buffer.length < TCP_BINARY_FRAME_HEADER_BYTES) {
|
|
1029
1082
|
return { incomplete: true };
|
|
@@ -1286,7 +1339,9 @@ export function createRemoteHub(options = {}) {
|
|
|
1286
1339
|
const inputSockets = new Map();
|
|
1287
1340
|
const frameSockets = new Map();
|
|
1288
1341
|
const allSockets = new Set();
|
|
1342
|
+
const agentBinaryIngressLanes = [];
|
|
1289
1343
|
const duplicateDeviceLogAt = new Map();
|
|
1344
|
+
let agentBinaryIngressDraining = false;
|
|
1290
1345
|
let server = null;
|
|
1291
1346
|
let started = false;
|
|
1292
1347
|
let boundPort = requestedPort;
|
|
@@ -3252,29 +3307,56 @@ export function createRemoteHub(options = {}) {
|
|
|
3252
3307
|
state.binaryQueueDrops = Number(state.binaryQueueDrops || 0) + 1;
|
|
3253
3308
|
}
|
|
3254
3309
|
|
|
3255
|
-
function
|
|
3256
|
-
if (state
|
|
3310
|
+
function scheduleAgentBinaryIngress(socket, state) {
|
|
3311
|
+
if (!state || state.closed || !socket || socket.destroyed) {
|
|
3257
3312
|
return;
|
|
3258
3313
|
}
|
|
3259
|
-
state.binaryQueueDraining = true;
|
|
3260
|
-
setImmediate(() => {
|
|
3261
|
-
state.binaryQueueDraining = false;
|
|
3262
|
-
if (state.closed || socket.destroyed) {
|
|
3263
|
-
state.binaryQueue.length = 0;
|
|
3264
|
-
return;
|
|
3265
|
-
}
|
|
3266
3314
|
|
|
3315
|
+
state.binaryQueueSocket = socket;
|
|
3316
|
+
if (state.binaryQueueScheduled !== true) {
|
|
3317
|
+
state.binaryQueueScheduled = true;
|
|
3318
|
+
agentBinaryIngressLanes.push(state);
|
|
3319
|
+
}
|
|
3320
|
+
drainAgentBinaryIngressRoundRobin();
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
function drainAgentBinaryIngressRoundRobin() {
|
|
3324
|
+
if (agentBinaryIngressDraining) {
|
|
3325
|
+
return;
|
|
3326
|
+
}
|
|
3327
|
+
agentBinaryIngressDraining = true;
|
|
3328
|
+
setImmediate(() => {
|
|
3329
|
+
agentBinaryIngressDraining = false;
|
|
3267
3330
|
let processed = 0;
|
|
3268
|
-
while (
|
|
3331
|
+
while (agentBinaryIngressLanes.length > 0 && processed < AGENT_BINARY_INGRESS_DRAIN_BUDGET_PACKETS) {
|
|
3332
|
+
const state = agentBinaryIngressLanes.shift();
|
|
3333
|
+
if (!state) {
|
|
3334
|
+
continue;
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
state.binaryQueueScheduled = false;
|
|
3338
|
+
const socket = state.binaryQueueSocket;
|
|
3339
|
+
if (state.closed || !socket || socket.destroyed) {
|
|
3340
|
+
if (Array.isArray(state.binaryQueue)) {
|
|
3341
|
+
state.binaryQueue.length = 0;
|
|
3342
|
+
}
|
|
3343
|
+
continue;
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3269
3346
|
const item = state.binaryQueue.shift();
|
|
3270
3347
|
if (item) {
|
|
3271
3348
|
handleAgentBinaryFrame(socket, state, item.header, item.payload);
|
|
3272
3349
|
processed += 1;
|
|
3273
3350
|
}
|
|
3351
|
+
|
|
3352
|
+
if (state.binaryQueue.length > 0 && !state.closed && !socket.destroyed) {
|
|
3353
|
+
state.binaryQueueScheduled = true;
|
|
3354
|
+
agentBinaryIngressLanes.push(state);
|
|
3355
|
+
}
|
|
3274
3356
|
}
|
|
3275
3357
|
|
|
3276
|
-
if (
|
|
3277
|
-
|
|
3358
|
+
if (agentBinaryIngressLanes.length > 0) {
|
|
3359
|
+
drainAgentBinaryIngressRoundRobin();
|
|
3278
3360
|
}
|
|
3279
3361
|
});
|
|
3280
3362
|
}
|
|
@@ -3290,7 +3372,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3290
3372
|
dropQueuedAgentBinaryFrame(state);
|
|
3291
3373
|
}
|
|
3292
3374
|
state.binaryQueue.push({ header, payload });
|
|
3293
|
-
|
|
3375
|
+
scheduleAgentBinaryIngress(socket, state);
|
|
3294
3376
|
}
|
|
3295
3377
|
|
|
3296
3378
|
function handleAgentMessage(socket, state, message) {
|
|
@@ -3436,6 +3518,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3436
3518
|
frameOnly: false,
|
|
3437
3519
|
binaryQueue: [],
|
|
3438
3520
|
binaryQueueDraining: false,
|
|
3521
|
+
binaryQueueScheduled: false,
|
|
3522
|
+
binaryQueueSocket: null,
|
|
3439
3523
|
binaryQueueDrops: 0,
|
|
3440
3524
|
closed: false
|
|
3441
3525
|
};
|
|
@@ -3488,6 +3572,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3488
3572
|
const detach = reason => {
|
|
3489
3573
|
state.closed = true;
|
|
3490
3574
|
state.binaryQueue.length = 0;
|
|
3575
|
+
state.binaryQueueScheduled = false;
|
|
3576
|
+
state.binaryQueueSocket = null;
|
|
3491
3577
|
allSockets.delete(socket);
|
|
3492
3578
|
clearTimeout(helloTimer);
|
|
3493
3579
|
detachInputSocket(socket, reason);
|
|
@@ -3587,6 +3673,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3587
3673
|
pendingBinaryFrame: null,
|
|
3588
3674
|
binaryQueue: [],
|
|
3589
3675
|
binaryQueueDraining: false,
|
|
3676
|
+
binaryQueueScheduled: false,
|
|
3677
|
+
binaryQueueSocket: null,
|
|
3590
3678
|
binaryQueueDrops: 0,
|
|
3591
3679
|
closed: false
|
|
3592
3680
|
};
|
|
@@ -3619,6 +3707,15 @@ export function createRemoteHub(options = {}) {
|
|
|
3619
3707
|
}
|
|
3620
3708
|
|
|
3621
3709
|
if (state.authenticated && state.frameOnly && state.buffer.length > 0) {
|
|
3710
|
+
const firstNonWhitespaceIndex = findFirstNonWhitespaceByte(state.buffer);
|
|
3711
|
+
if (firstNonWhitespaceIndex < 0) {
|
|
3712
|
+
state.buffer = Buffer.alloc(0);
|
|
3713
|
+
return;
|
|
3714
|
+
}
|
|
3715
|
+
if (firstNonWhitespaceIndex > 0) {
|
|
3716
|
+
state.buffer = state.buffer.subarray(firstNonWhitespaceIndex);
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3622
3719
|
if (state.buffer.length < TCP_BINARY_FRAME_MAGIC.length && hasTcpBinaryFrameMagicPrefix(state.buffer)) {
|
|
3623
3720
|
return;
|
|
3624
3721
|
}
|
|
@@ -3629,9 +3726,13 @@ export function createRemoteHub(options = {}) {
|
|
|
3629
3726
|
return;
|
|
3630
3727
|
}
|
|
3631
3728
|
if (!packet || packet.invalid) {
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3729
|
+
const syncIndex = findTcpFrameOnlySyncIndex(state.buffer, 1);
|
|
3730
|
+
if (syncIndex > 0) {
|
|
3731
|
+
state.buffer = state.buffer.subarray(syncIndex);
|
|
3732
|
+
continue;
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
state.buffer = keepTcpFrameOnlySyncTail(state.buffer);
|
|
3635
3736
|
return;
|
|
3636
3737
|
}
|
|
3637
3738
|
|
|
@@ -3639,6 +3740,17 @@ export function createRemoteHub(options = {}) {
|
|
|
3639
3740
|
enqueueAgentBinaryFrame(socket, state, packet.header, packet.payload);
|
|
3640
3741
|
continue;
|
|
3641
3742
|
}
|
|
3743
|
+
|
|
3744
|
+
if (!isJsonObjectStartByte(state.buffer[0])) {
|
|
3745
|
+
const syncIndex = findTcpFrameOnlySyncIndex(state.buffer, 1);
|
|
3746
|
+
if (syncIndex > 0) {
|
|
3747
|
+
state.buffer = state.buffer.subarray(syncIndex);
|
|
3748
|
+
continue;
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3751
|
+
state.buffer = keepTcpFrameOnlySyncTail(state.buffer);
|
|
3752
|
+
return;
|
|
3753
|
+
}
|
|
3642
3754
|
}
|
|
3643
3755
|
|
|
3644
3756
|
const newlineIndex = state.buffer.indexOf(0x0a);
|
|
@@ -3676,6 +3788,9 @@ export function createRemoteHub(options = {}) {
|
|
|
3676
3788
|
|
|
3677
3789
|
handleAgentMessage(socket, state, message);
|
|
3678
3790
|
} catch (err) {
|
|
3791
|
+
if (state.authenticated && state.frameOnly) {
|
|
3792
|
+
continue;
|
|
3793
|
+
}
|
|
3679
3794
|
writeJsonLine(socket, { type: 'error', error: 'invalid-json' });
|
|
3680
3795
|
logWarn('remote', `invalid agent message: ${err?.message || err}`);
|
|
3681
3796
|
}
|
|
@@ -3690,6 +3805,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3690
3805
|
socket.on('close', () => {
|
|
3691
3806
|
state.closed = true;
|
|
3692
3807
|
state.binaryQueue.length = 0;
|
|
3808
|
+
state.binaryQueueScheduled = false;
|
|
3809
|
+
state.binaryQueueSocket = null;
|
|
3693
3810
|
allSockets.delete(socket);
|
|
3694
3811
|
clearTimeout(helloTimer);
|
|
3695
3812
|
detachInputSocket(socket);
|
|
@@ -3699,6 +3816,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3699
3816
|
socket.on('error', err => {
|
|
3700
3817
|
state.closed = true;
|
|
3701
3818
|
state.binaryQueue.length = 0;
|
|
3819
|
+
state.binaryQueueScheduled = false;
|
|
3820
|
+
state.binaryQueueSocket = null;
|
|
3702
3821
|
allSockets.delete(socket);
|
|
3703
3822
|
clearTimeout(helloTimer);
|
|
3704
3823
|
detachInputSocket(socket, err?.message || 'socket-error');
|
package/hub/src/server.js
CHANGED
|
@@ -23,7 +23,7 @@ const httpHost = process.env.LIVEDESK_HUB_HTTP_HOST || '0.0.0.0';
|
|
|
23
23
|
const httpPort = Number(process.env.LIVEDESK_HUB_HTTP_PORT || process.env.PORT || 5179);
|
|
24
24
|
const frameBackpressureBytes = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_BACKPRESSURE_BYTES', 16 * 1024 * 1024);
|
|
25
25
|
const frameClientQueuePackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_QUEUE_PACKETS', 12);
|
|
26
|
-
const frameClientDrainBudgetPackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_DRAIN_BUDGET_PACKETS',
|
|
26
|
+
const frameClientDrainBudgetPackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_DRAIN_BUDGET_PACKETS', 8);
|
|
27
27
|
const frameClients = new Set();
|
|
28
28
|
const frameClientsByDeviceId = new Map();
|
|
29
29
|
const frameWildcardClients = new Set();
|