lightman-agent 1.0.23 → 1.0.24
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/src/index.ts +122 -64
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -111,10 +111,26 @@ async function main(): Promise<void> {
|
|
|
111
111
|
serverUrl: config.serverUrl,
|
|
112
112
|
identity,
|
|
113
113
|
logger,
|
|
114
|
-
onMessage: (msg: WsMessage) => {
|
|
115
|
-
handleServerMessage(
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
onMessage: (msg: WsMessage) => {
|
|
115
|
+
handleServerMessage(
|
|
116
|
+
msg,
|
|
117
|
+
commandExecutor,
|
|
118
|
+
logger,
|
|
119
|
+
powerScheduler,
|
|
120
|
+
startSerialBridge,
|
|
121
|
+
stopSerialBridge,
|
|
122
|
+
startOscBridge,
|
|
123
|
+
stopOscBridge,
|
|
124
|
+
multiScreenKiosk,
|
|
125
|
+
getIdentity,
|
|
126
|
+
kioskManager,
|
|
127
|
+
watchdog,
|
|
128
|
+
startPresenceSensor,
|
|
129
|
+
stopPresenceSensor,
|
|
130
|
+
() => lastKnownTotalScreens
|
|
131
|
+
);
|
|
132
|
+
},
|
|
133
|
+
});
|
|
118
134
|
|
|
119
135
|
// 4. Start health monitor
|
|
120
136
|
const healthMonitor = new HealthMonitor(
|
|
@@ -163,14 +179,15 @@ async function main(): Promise<void> {
|
|
|
163
179
|
const kioskManager = new KioskManager(kioskConfig, logger);
|
|
164
180
|
registerKioskCommands(commandExecutor.register.bind(commandExecutor), kioskManager, logger);
|
|
165
181
|
|
|
166
|
-
// Multi-screen kiosk manager — handles multiple Chrome instances on multi-display devices
|
|
167
|
-
const multiScreenKiosk = new MultiScreenKioskManager(kioskConfig, logger);
|
|
168
|
-
const getIdentity = () => identity!;
|
|
169
|
-
registerMultiScreenKioskCommands(commandExecutor.register.bind(commandExecutor), multiScreenKiosk, getIdentity, logger);
|
|
170
|
-
|
|
171
|
-
// Detect physical screens and keep them fresh (multi-display setups can change after boot).
|
|
172
|
-
let
|
|
173
|
-
|
|
182
|
+
// Multi-screen kiosk manager — handles multiple Chrome instances on multi-display devices
|
|
183
|
+
const multiScreenKiosk = new MultiScreenKioskManager(kioskConfig, logger);
|
|
184
|
+
const getIdentity = () => identity!;
|
|
185
|
+
registerMultiScreenKioskCommands(commandExecutor.register.bind(commandExecutor), multiScreenKiosk, getIdentity, logger);
|
|
186
|
+
|
|
187
|
+
// Detect physical screens and keep them fresh (multi-display setups can change after boot).
|
|
188
|
+
let lastKnownTotalScreens = 0;
|
|
189
|
+
let detectedScreens = detectScreens(logger);
|
|
190
|
+
multiScreenKiosk.setDetectedScreens(detectedScreens);
|
|
174
191
|
|
|
175
192
|
const toScreenPayload = (screens: DetectedScreen[]) => (
|
|
176
193
|
screens.map((s) => ({
|
|
@@ -502,24 +519,23 @@ async function main(): Promise<void> {
|
|
|
502
519
|
// Multi-screen handling:
|
|
503
520
|
// 1) Use explicit screenMap when present.
|
|
504
521
|
// 2) For multi-screen apps without a saved map, auto-create placeholders.
|
|
505
|
-
const requestedScreenMap = deviceCfg?.screenMap || [];
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
);
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
logger.error('[MultiKiosk] Failed to apply effective screenMap from config:', err);
|
|
522
|
+
const requestedScreenMap = deviceCfg?.screenMap || [];
|
|
523
|
+
const totalScreens = Math.max(deviceCfg?.totalScreens || 0, requestedScreenMap.length);
|
|
524
|
+
lastKnownTotalScreens = totalScreens;
|
|
525
|
+
const effectiveRequestedMap = normalizeScreenMapForTotalScreens(requestedScreenMap, totalScreens);
|
|
526
|
+
|
|
527
|
+
if (effectiveRequestedMap.length > 0) {
|
|
528
|
+
const resolved = resolveScreenMap({
|
|
529
|
+
requestedScreenMap: effectiveRequestedMap,
|
|
530
|
+
detectedScreens,
|
|
531
|
+
totalScreens,
|
|
532
|
+
});
|
|
533
|
+
logger.info(
|
|
534
|
+
`[MultiKiosk] Effective map ready: requested=${requestedScreenMap.length}, effective=${effectiveRequestedMap.length}, mode=${resolved.mode}, totalScreens=${totalScreens}`
|
|
535
|
+
);
|
|
536
|
+
watchdog.setMultiScreenActive(true);
|
|
537
|
+
multiScreenKiosk.applyScreenMap(effectiveRequestedMap, identity).catch((err) => {
|
|
538
|
+
logger.error('[MultiKiosk] Failed to apply effective screenMap from config:', err);
|
|
523
539
|
});
|
|
524
540
|
return;
|
|
525
541
|
}
|
|
@@ -606,10 +622,33 @@ async function main(): Promise<void> {
|
|
|
606
622
|
logger.info('LIGHTMAN Agent running.');
|
|
607
623
|
}
|
|
608
624
|
|
|
609
|
-
function createPlaceholderScreenMap(totalScreens: number): ScreenMapping[] {
|
|
610
|
-
const count = Math.max(0, Math.floor(totalScreens || 0));
|
|
611
|
-
return Array.from({ length: count }, () => ({ hardwareId: '', url: '' }));
|
|
612
|
-
}
|
|
625
|
+
function createPlaceholderScreenMap(totalScreens: number): ScreenMapping[] {
|
|
626
|
+
const count = Math.max(0, Math.floor(totalScreens || 0));
|
|
627
|
+
return Array.from({ length: count }, () => ({ hardwareId: '', url: '' }));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function normalizeScreenMapForTotalScreens(
|
|
631
|
+
screenMap: ScreenMapping[] | undefined,
|
|
632
|
+
totalScreens: number
|
|
633
|
+
): ScreenMapping[] {
|
|
634
|
+
const requested = Array.isArray(screenMap)
|
|
635
|
+
? screenMap.map((m) => ({
|
|
636
|
+
hardwareId: String(m.hardwareId || ''),
|
|
637
|
+
url: String(m.url || ''),
|
|
638
|
+
...(m.label ? { label: String(m.label) } : {}),
|
|
639
|
+
}))
|
|
640
|
+
: [];
|
|
641
|
+
|
|
642
|
+
const targetCount = Math.max(requested.length, Math.max(0, Math.floor(totalScreens || 0)));
|
|
643
|
+
if (targetCount === 0) return [];
|
|
644
|
+
|
|
645
|
+
if (requested.length >= targetCount) return requested;
|
|
646
|
+
|
|
647
|
+
return [
|
|
648
|
+
...requested,
|
|
649
|
+
...createPlaceholderScreenMap(targetCount - requested.length),
|
|
650
|
+
];
|
|
651
|
+
}
|
|
613
652
|
|
|
614
653
|
function haveScreensChanged(prev: DetectedScreen[], next: DetectedScreen[]): boolean {
|
|
615
654
|
if (prev.length !== next.length) return true;
|
|
@@ -631,22 +670,23 @@ function haveScreensChanged(prev: DetectedScreen[], next: DetectedScreen[]): boo
|
|
|
631
670
|
return false;
|
|
632
671
|
}
|
|
633
672
|
|
|
634
|
-
function handleServerMessage(
|
|
635
|
-
msg: WsMessage,
|
|
636
|
-
commandExecutor: CommandExecutor,
|
|
673
|
+
function handleServerMessage(
|
|
674
|
+
msg: WsMessage,
|
|
675
|
+
commandExecutor: CommandExecutor,
|
|
637
676
|
logger: Logger,
|
|
638
677
|
powerScheduler?: PowerScheduler,
|
|
639
678
|
startSerialBridge?: (comPort: string, controllerId: string, baudRate?: number) => void,
|
|
640
679
|
stopSerialBridge?: () => void,
|
|
641
680
|
startOscBridgeFn?: (oscPort: number, oscAddress: string, oscHost?: string) => void,
|
|
642
681
|
stopOscBridgeFn?: () => void,
|
|
643
|
-
multiScreenKiosk?: MultiScreenKioskManager,
|
|
644
|
-
getIdentity?: () => Identity,
|
|
645
|
-
kioskManager?: KioskManager,
|
|
646
|
-
watchdog?: Watchdog,
|
|
647
|
-
startPresenceSensorFn?: (port?: string) => void,
|
|
648
|
-
stopPresenceSensorFn?: () => void
|
|
649
|
-
)
|
|
682
|
+
multiScreenKiosk?: MultiScreenKioskManager,
|
|
683
|
+
getIdentity?: () => Identity,
|
|
684
|
+
kioskManager?: KioskManager,
|
|
685
|
+
watchdog?: Watchdog,
|
|
686
|
+
startPresenceSensorFn?: (port?: string) => void,
|
|
687
|
+
stopPresenceSensorFn?: () => void,
|
|
688
|
+
getTotalScreensHint?: () => number
|
|
689
|
+
): void {
|
|
650
690
|
switch (msg.type) {
|
|
651
691
|
case 'connected':
|
|
652
692
|
logger.info('Server acknowledged connection');
|
|
@@ -698,16 +738,25 @@ function handleServerMessage(
|
|
|
698
738
|
}
|
|
699
739
|
|
|
700
740
|
// Admin pushed updated screenMap via device config save
|
|
701
|
-
const screenMap = msg.payload.screenMap as ScreenMapping[] | undefined;
|
|
702
|
-
if (screenMap && Array.isArray(screenMap) && multiScreenKiosk && getIdentity) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
741
|
+
const screenMap = msg.payload.screenMap as ScreenMapping[] | undefined;
|
|
742
|
+
if (screenMap && Array.isArray(screenMap) && multiScreenKiosk && getIdentity) {
|
|
743
|
+
const payloadTotalScreens = Number(msg.payload.totalScreens || 0);
|
|
744
|
+
const hintTotalScreens = Math.max(
|
|
745
|
+
Number.isFinite(payloadTotalScreens) ? payloadTotalScreens : 0,
|
|
746
|
+
getTotalScreensHint ? getTotalScreensHint() : 0
|
|
747
|
+
);
|
|
748
|
+
const effectiveScreenMap = screenMap.length > 0
|
|
749
|
+
? normalizeScreenMapForTotalScreens(screenMap, hintTotalScreens)
|
|
750
|
+
: screenMap;
|
|
751
|
+
|
|
752
|
+
if (screenMap.length > 0) {
|
|
753
|
+
logger.info(`[MultiKiosk] Received screenMap update: requested=${screenMap.length}, effective=${effectiveScreenMap.length}, totalScreens=${hintTotalScreens} — killing single kiosk`);
|
|
754
|
+
if (kioskManager) kioskManager.kill().catch(() => {});
|
|
755
|
+
if (watchdog) watchdog.setMultiScreenActive(true);
|
|
756
|
+
multiScreenKiosk.applyScreenMap(effectiveScreenMap, getIdentity()).catch((err) => {
|
|
757
|
+
logger.error('[MultiKiosk] Failed to apply screenMap:', err);
|
|
758
|
+
});
|
|
759
|
+
} else {
|
|
711
760
|
// Empty screenMap — deactivate multi-screen, resume single kiosk
|
|
712
761
|
logger.info('[MultiKiosk] Empty screenMap received — deactivating multi-screen');
|
|
713
762
|
multiScreenKiosk.killAll().catch(() => {});
|
|
@@ -719,16 +768,25 @@ function handleServerMessage(
|
|
|
719
768
|
case 'agent:screenMap':
|
|
720
769
|
// Direct screenMap push from server
|
|
721
770
|
if (msg.payload && multiScreenKiosk && getIdentity) {
|
|
722
|
-
const screenMap = msg.payload.screenMap as ScreenMapping[] | undefined;
|
|
723
|
-
if (screenMap && Array.isArray(screenMap)) {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
771
|
+
const screenMap = msg.payload.screenMap as ScreenMapping[] | undefined;
|
|
772
|
+
if (screenMap && Array.isArray(screenMap)) {
|
|
773
|
+
const payloadTotalScreens = Number(msg.payload.totalScreens || 0);
|
|
774
|
+
const hintTotalScreens = Math.max(
|
|
775
|
+
Number.isFinite(payloadTotalScreens) ? payloadTotalScreens : 0,
|
|
776
|
+
getTotalScreensHint ? getTotalScreensHint() : 0
|
|
777
|
+
);
|
|
778
|
+
const effectiveScreenMap = screenMap.length > 0
|
|
779
|
+
? normalizeScreenMapForTotalScreens(screenMap, hintTotalScreens)
|
|
780
|
+
: screenMap;
|
|
781
|
+
|
|
782
|
+
if (screenMap.length > 0) {
|
|
783
|
+
logger.info(`[MultiKiosk] Received agent:screenMap: requested=${screenMap.length}, effective=${effectiveScreenMap.length}, totalScreens=${hintTotalScreens} — killing single kiosk`);
|
|
784
|
+
if (kioskManager) kioskManager.kill().catch(() => {});
|
|
785
|
+
if (watchdog) watchdog.setMultiScreenActive(true);
|
|
786
|
+
multiScreenKiosk.applyScreenMap(effectiveScreenMap, getIdentity()).catch((err) => {
|
|
787
|
+
logger.error('[MultiKiosk] Failed to apply screenMap:', err);
|
|
788
|
+
});
|
|
789
|
+
} else {
|
|
732
790
|
logger.info('[MultiKiosk] Empty agent:screenMap — deactivating multi-screen');
|
|
733
791
|
multiScreenKiosk.killAll().catch(() => {});
|
|
734
792
|
if (watchdog) watchdog.setMultiScreenActive(false);
|