livedesk 0.1.125 → 0.1.127
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/README.md +10 -0
- package/bin/livedesk.js +2 -2
- package/hub/src/remote-hub.js +62 -19
- package/hub/src/server.js +291 -20
- package/package.json +2 -2
- package/web/dist/assets/index-BW_cOjlW.js +38 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-SKaOSr0A.js +0 -38
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ npx -y livedesk hub
|
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
This starts the LiveDesk Hub, opens the local screen wall, and accepts clients.
|
|
13
|
+
The Hub UI/API listens on `127.0.0.1` by default while the client endpoint
|
|
14
|
+
continues to listen on the LAN.
|
|
13
15
|
|
|
14
16
|
## Client
|
|
15
17
|
|
|
@@ -22,6 +24,14 @@ The client signs in with Google, discovers the active Hub, and connects to the w
|
|
|
22
24
|
On Windows, enable **Start with Windows** on the connection page to reconnect
|
|
23
25
|
automatically after reboot.
|
|
24
26
|
|
|
27
|
+
## Plans
|
|
28
|
+
|
|
29
|
+
- Free: 5 personal devices with a standard wall banner ad.
|
|
30
|
+
- Plus LTD launch: 30 personal devices, no ads, USD 79 one-time.
|
|
31
|
+
- Pro LTD launch: commercial use and larger walls, no ads, USD 199 one-time.
|
|
32
|
+
|
|
33
|
+
Monthly and yearly subscriptions are planned after the LTD launch.
|
|
34
|
+
|
|
25
35
|
## Free ad slot
|
|
26
36
|
|
|
27
37
|
Free accounts show a standard bottom ad slot. Set these Vite build variables
|
package/bin/livedesk.js
CHANGED
|
@@ -34,7 +34,7 @@ Commands:
|
|
|
34
34
|
Hub options:
|
|
35
35
|
--no-open Do not open the browser automatically.
|
|
36
36
|
--url <url> Browser URL to open. Default: ${DEFAULT_MANAGER_URL}
|
|
37
|
-
--host <host> Hub HTTP host. Default:
|
|
37
|
+
--host <host> Hub HTTP host. Default: 127.0.0.1
|
|
38
38
|
--port <port> Hub HTTP port. Default: 5179
|
|
39
39
|
--remote-port <port>
|
|
40
40
|
Client connection port. Default: 5197
|
|
@@ -304,7 +304,7 @@ async function runManager(args) {
|
|
|
304
304
|
const packagedWebDist = resolve(packageRoot, 'web', 'dist');
|
|
305
305
|
const env = {
|
|
306
306
|
...process.env,
|
|
307
|
-
LIVEDESK_HUB_HTTP_HOST: options.host || process.env.LIVEDESK_HUB_HTTP_HOST || '
|
|
307
|
+
LIVEDESK_HUB_HTTP_HOST: options.host || process.env.LIVEDESK_HUB_HTTP_HOST || '127.0.0.1',
|
|
308
308
|
LIVEDESK_HUB_HTTP_PORT: String(httpPort),
|
|
309
309
|
REMOTE_HUB_PORT: String(remotePort),
|
|
310
310
|
REMOTE_HUB_PAIR_TOKEN: pairToken,
|
package/hub/src/remote-hub.js
CHANGED
|
@@ -17,11 +17,11 @@ const MAX_AGENT_TASK_CHARS = 4000;
|
|
|
17
17
|
const MAX_AGENT_TASK_RESULT_CHARS = 3000;
|
|
18
18
|
const RECENT_TASK_LIMIT = 12;
|
|
19
19
|
const RECENT_TASK_BATCH_LIMIT = 16;
|
|
20
|
-
const RECENT_FRAME_CACHE_TTL_MS =
|
|
21
|
-
const RECENT_THUMBNAIL_FRAME_CACHE_LIMIT =
|
|
22
|
-
const RECENT_LIVE_FRAME_CACHE_LIMIT =
|
|
23
|
-
const RECENT_THUMBNAIL_FRAME_CACHE_MAX_BYTES =
|
|
24
|
-
const RECENT_LIVE_FRAME_CACHE_MAX_BYTES =
|
|
20
|
+
const RECENT_FRAME_CACHE_TTL_MS = 4000;
|
|
21
|
+
const RECENT_THUMBNAIL_FRAME_CACHE_LIMIT = 2;
|
|
22
|
+
const RECENT_LIVE_FRAME_CACHE_LIMIT = 1;
|
|
23
|
+
const RECENT_THUMBNAIL_FRAME_CACHE_MAX_BYTES = 2 * 1024 * 1024;
|
|
24
|
+
const RECENT_LIVE_FRAME_CACHE_MAX_BYTES = 3 * 1024 * 1024;
|
|
25
25
|
const LIVE_STREAM_PENDING_REUSE_MS = 5000;
|
|
26
26
|
const LIVE_STREAM_MIN_FRESH_MS = 3000;
|
|
27
27
|
const LIVE_STREAM_MAX_FRESH_MS = 12000;
|
|
@@ -1339,7 +1339,9 @@ export function createRemoteHub(options = {}) {
|
|
|
1339
1339
|
const inputSockets = new Map();
|
|
1340
1340
|
const frameSockets = new Map();
|
|
1341
1341
|
const allSockets = new Set();
|
|
1342
|
+
const agentBinaryIngressLanes = [];
|
|
1342
1343
|
const duplicateDeviceLogAt = new Map();
|
|
1344
|
+
let agentBinaryIngressDraining = false;
|
|
1343
1345
|
let server = null;
|
|
1344
1346
|
let started = false;
|
|
1345
1347
|
let boundPort = requestedPort;
|
|
@@ -2838,7 +2840,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2838
2840
|
|
|
2839
2841
|
function buildFramePayloadBuffer(framePayload, frameData) {
|
|
2840
2842
|
if (Buffer.isBuffer(framePayload)) {
|
|
2841
|
-
return
|
|
2843
|
+
return framePayload;
|
|
2842
2844
|
}
|
|
2843
2845
|
|
|
2844
2846
|
const raw = String(frameData || '');
|
|
@@ -2929,6 +2931,8 @@ export function createRemoteHub(options = {}) {
|
|
|
2929
2931
|
durationUs: Number.isFinite(Number(message.durationUs)) ? Number(message.durationUs) : 0,
|
|
2930
2932
|
sourceGapMs: Number.isFinite(Number(message.sourceGapMs)) ? Number(message.sourceGapMs) : 0,
|
|
2931
2933
|
agentSendGapMs: Number.isFinite(Number(message.agentSendGapMs)) ? Number(message.agentSendGapMs) : 0,
|
|
2934
|
+
agentSendDurationMs: Number.isFinite(Number(message.agentSendDurationMs)) ? Number(message.agentSendDurationMs) : 0,
|
|
2935
|
+
agentSendDurationFrameSeq: Number.isFinite(Number(message.agentSendDurationFrameSeq)) ? Number(message.agentSendDurationFrameSeq) : 0,
|
|
2932
2936
|
agentPaceMs: Number.isFinite(Number(message.agentPaceMs)) ? Number(message.agentPaceMs) : 0,
|
|
2933
2937
|
droppedByAgent: Number.isFinite(Number(message.droppedByAgent)) ? Number(message.droppedByAgent) : 0,
|
|
2934
2938
|
hardwareEncoder: safeString(message.hardwareEncoder, 80),
|
|
@@ -3111,6 +3115,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3111
3115
|
durationUs: Number.isFinite(Number(message.durationUs)) ? Number(message.durationUs) : 0,
|
|
3112
3116
|
sourceGapMs: Number.isFinite(Number(message.sourceGapMs)) ? Number(message.sourceGapMs) : 0,
|
|
3113
3117
|
agentSendGapMs: Number.isFinite(Number(message.agentSendGapMs)) ? Number(message.agentSendGapMs) : 0,
|
|
3118
|
+
agentSendDurationMs: Number.isFinite(Number(message.agentSendDurationMs)) ? Number(message.agentSendDurationMs) : 0,
|
|
3119
|
+
agentSendDurationFrameSeq: Number.isFinite(Number(message.agentSendDurationFrameSeq)) ? Number(message.agentSendDurationFrameSeq) : 0,
|
|
3114
3120
|
agentPaceMs: Number.isFinite(Number(message.agentPaceMs)) ? Number(message.agentPaceMs) : 0,
|
|
3115
3121
|
droppedByAgent: Number.isFinite(Number(message.droppedByAgent)) ? Number(message.droppedByAgent) : 0,
|
|
3116
3122
|
hardwareEncoder: safeString(message.hardwareEncoder, 80),
|
|
@@ -3305,29 +3311,56 @@ export function createRemoteHub(options = {}) {
|
|
|
3305
3311
|
state.binaryQueueDrops = Number(state.binaryQueueDrops || 0) + 1;
|
|
3306
3312
|
}
|
|
3307
3313
|
|
|
3308
|
-
function
|
|
3309
|
-
if (state
|
|
3314
|
+
function scheduleAgentBinaryIngress(socket, state) {
|
|
3315
|
+
if (!state || state.closed || !socket || socket.destroyed) {
|
|
3310
3316
|
return;
|
|
3311
3317
|
}
|
|
3312
|
-
state.binaryQueueDraining = true;
|
|
3313
|
-
setImmediate(() => {
|
|
3314
|
-
state.binaryQueueDraining = false;
|
|
3315
|
-
if (state.closed || socket.destroyed) {
|
|
3316
|
-
state.binaryQueue.length = 0;
|
|
3317
|
-
return;
|
|
3318
|
-
}
|
|
3319
3318
|
|
|
3319
|
+
state.binaryQueueSocket = socket;
|
|
3320
|
+
if (state.binaryQueueScheduled !== true) {
|
|
3321
|
+
state.binaryQueueScheduled = true;
|
|
3322
|
+
agentBinaryIngressLanes.push(state);
|
|
3323
|
+
}
|
|
3324
|
+
drainAgentBinaryIngressRoundRobin();
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
function drainAgentBinaryIngressRoundRobin() {
|
|
3328
|
+
if (agentBinaryIngressDraining) {
|
|
3329
|
+
return;
|
|
3330
|
+
}
|
|
3331
|
+
agentBinaryIngressDraining = true;
|
|
3332
|
+
setImmediate(() => {
|
|
3333
|
+
agentBinaryIngressDraining = false;
|
|
3320
3334
|
let processed = 0;
|
|
3321
|
-
while (
|
|
3335
|
+
while (agentBinaryIngressLanes.length > 0 && processed < AGENT_BINARY_INGRESS_DRAIN_BUDGET_PACKETS) {
|
|
3336
|
+
const state = agentBinaryIngressLanes.shift();
|
|
3337
|
+
if (!state) {
|
|
3338
|
+
continue;
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
state.binaryQueueScheduled = false;
|
|
3342
|
+
const socket = state.binaryQueueSocket;
|
|
3343
|
+
if (state.closed || !socket || socket.destroyed) {
|
|
3344
|
+
if (Array.isArray(state.binaryQueue)) {
|
|
3345
|
+
state.binaryQueue.length = 0;
|
|
3346
|
+
}
|
|
3347
|
+
continue;
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3322
3350
|
const item = state.binaryQueue.shift();
|
|
3323
3351
|
if (item) {
|
|
3324
3352
|
handleAgentBinaryFrame(socket, state, item.header, item.payload);
|
|
3325
3353
|
processed += 1;
|
|
3326
3354
|
}
|
|
3355
|
+
|
|
3356
|
+
if (state.binaryQueue.length > 0 && !state.closed && !socket.destroyed) {
|
|
3357
|
+
state.binaryQueueScheduled = true;
|
|
3358
|
+
agentBinaryIngressLanes.push(state);
|
|
3359
|
+
}
|
|
3327
3360
|
}
|
|
3328
3361
|
|
|
3329
|
-
if (
|
|
3330
|
-
|
|
3362
|
+
if (agentBinaryIngressLanes.length > 0) {
|
|
3363
|
+
drainAgentBinaryIngressRoundRobin();
|
|
3331
3364
|
}
|
|
3332
3365
|
});
|
|
3333
3366
|
}
|
|
@@ -3343,7 +3376,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3343
3376
|
dropQueuedAgentBinaryFrame(state);
|
|
3344
3377
|
}
|
|
3345
3378
|
state.binaryQueue.push({ header, payload });
|
|
3346
|
-
|
|
3379
|
+
scheduleAgentBinaryIngress(socket, state);
|
|
3347
3380
|
}
|
|
3348
3381
|
|
|
3349
3382
|
function handleAgentMessage(socket, state, message) {
|
|
@@ -3489,6 +3522,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3489
3522
|
frameOnly: false,
|
|
3490
3523
|
binaryQueue: [],
|
|
3491
3524
|
binaryQueueDraining: false,
|
|
3525
|
+
binaryQueueScheduled: false,
|
|
3526
|
+
binaryQueueSocket: null,
|
|
3492
3527
|
binaryQueueDrops: 0,
|
|
3493
3528
|
closed: false
|
|
3494
3529
|
};
|
|
@@ -3541,6 +3576,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3541
3576
|
const detach = reason => {
|
|
3542
3577
|
state.closed = true;
|
|
3543
3578
|
state.binaryQueue.length = 0;
|
|
3579
|
+
state.binaryQueueScheduled = false;
|
|
3580
|
+
state.binaryQueueSocket = null;
|
|
3544
3581
|
allSockets.delete(socket);
|
|
3545
3582
|
clearTimeout(helloTimer);
|
|
3546
3583
|
detachInputSocket(socket, reason);
|
|
@@ -3640,6 +3677,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3640
3677
|
pendingBinaryFrame: null,
|
|
3641
3678
|
binaryQueue: [],
|
|
3642
3679
|
binaryQueueDraining: false,
|
|
3680
|
+
binaryQueueScheduled: false,
|
|
3681
|
+
binaryQueueSocket: null,
|
|
3643
3682
|
binaryQueueDrops: 0,
|
|
3644
3683
|
closed: false
|
|
3645
3684
|
};
|
|
@@ -3770,6 +3809,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3770
3809
|
socket.on('close', () => {
|
|
3771
3810
|
state.closed = true;
|
|
3772
3811
|
state.binaryQueue.length = 0;
|
|
3812
|
+
state.binaryQueueScheduled = false;
|
|
3813
|
+
state.binaryQueueSocket = null;
|
|
3773
3814
|
allSockets.delete(socket);
|
|
3774
3815
|
clearTimeout(helloTimer);
|
|
3775
3816
|
detachInputSocket(socket);
|
|
@@ -3779,6 +3820,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3779
3820
|
socket.on('error', err => {
|
|
3780
3821
|
state.closed = true;
|
|
3781
3822
|
state.binaryQueue.length = 0;
|
|
3823
|
+
state.binaryQueueScheduled = false;
|
|
3824
|
+
state.binaryQueueSocket = null;
|
|
3782
3825
|
allSockets.delete(socket);
|
|
3783
3826
|
clearTimeout(helloTimer);
|
|
3784
3827
|
detachInputSocket(socket, err?.message || 'socket-error');
|