Skip to content

Commit 3910927

Browse files
committed
fix: Correct event handler ordering for dynamic printer connections
CRITICAL BUG FIX: The previous implementation had an ordering issue that prevented Spoolman deduction from working for dynamically connected printers (via API). PROBLEM: - 'connected' handler started polling but didn't create monitors - 'backend-initialized' handler tried to create monitors BEFORE polling started - Result: pollingService was null → monitors never created for dynamic connections EVENT ORDERING ISSUE: During dynamic connections (API reconnect/discovery): 1. Backend initializes → emits 'backend-initialized' 2. backend-initialized handler runs → pollingService is NULL (polling not started) 3. Handler returns early → NO MONITORS CREATED 4. Connection completes → emits 'connected' 5. connected handler starts polling → but monitors already skipped SOLUTION: Consolidated all initialization into the backend-initialized handler: STEP 1: Start polling (creates pollingService reference) STEP 2: Get pollingService from context (now available) STEP 3: Create PrintStateMonitor STEP 4: Create SpoolmanTracker This handler now fires for BOTH: - Startup connections (--last-used, --all-saved) - Dynamic connections (API reconnect, discovery) CHANGES: - Moved polling start INTO backend-initialized handler (before monitor creation) - Removed redundant startPolling() and initializeMonitors() functions - Simplified 'connected' handler to just log (no duplicate initialization) - Single initialization path for all connection types TESTING: ✅ Startup connections (--last-used) → monitors created via backend-initialized ✅ API connect (/api/printers/connect) → monitors created via backend-initialized ✅ API reconnect (/api/printers/reconnect) → monitors created via backend-initialized
1 parent 9f4f31a commit 3910927

1 file changed

Lines changed: 25 additions & 88 deletions

File tree

src/index.ts

Lines changed: 25 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -221,58 +221,6 @@ function setupEventForwarding(): void {
221221
console.log('[Events] Event forwarding configured for WebUI');
222222
}
223223

224-
/**
225-
* Start polling for all connected contexts
226-
*/
227-
function startPolling(): void {
228-
for (const contextId of connectedContexts) {
229-
try {
230-
pollingCoordinator.startPollingForContext(contextId);
231-
console.log(`[Polling] Started for context: ${contextId}`);
232-
} catch (error) {
233-
console.error(`[Polling] Failed to start for context ${contextId}:`, error);
234-
}
235-
}
236-
}
237-
238-
/**
239-
* Initialize monitors for all connected contexts
240-
* Creates PrintStateMonitor and SpoolmanTracker for each context
241-
*/
242-
function initializeMonitors(): void {
243-
const printStateMonitor = getMultiContextPrintStateMonitor();
244-
const spoolmanTracker = getMultiContextSpoolmanTracker();
245-
246-
for (const contextId of connectedContexts) {
247-
try {
248-
const context = contextManager.getContext(contextId);
249-
const pollingService = context?.pollingService;
250-
251-
if (!pollingService) {
252-
console.error(`[Monitors] Missing polling service for context ${contextId}`);
253-
continue;
254-
}
255-
256-
// Create PrintStateMonitor
257-
printStateMonitor.createMonitorForContext(contextId, pollingService);
258-
const stateMonitor = printStateMonitor.getMonitor(contextId);
259-
260-
if (!stateMonitor) {
261-
console.error(`[Monitors] Failed to create print state monitor for ${contextId}`);
262-
continue;
263-
}
264-
265-
console.log(`[Monitors] Created PrintStateMonitor for context ${contextId}`);
266-
267-
// Create SpoolmanTracker (depends on PrintStateMonitor)
268-
spoolmanTracker.createTrackerForContext(contextId, stateMonitor);
269-
console.log(`[Monitors] Created SpoolmanTracker for context ${contextId}`);
270-
} catch (error) {
271-
console.error(`[Monitors] Failed to initialize monitors for context ${contextId}:`, error);
272-
}
273-
}
274-
}
275-
276224
/**
277225
* Initialize camera proxies for all connected contexts
278226
*/
@@ -454,43 +402,37 @@ async function main(): Promise<void> {
454402
// This ensures listeners are ready when polling data starts flowing
455403
setupEventForwarding();
456404

457-
// 12b. Setup post-connection hook for dynamic printer connections
458-
// This handles printers connected after startup (via API reconnect/discovery)
405+
// 12b. Setup post-connection hook for logging
459406
connectionManager.on('connected', (printerDetails) => {
460-
const activeContextId = contextManager.getActiveContextId();
461-
if (activeContextId) {
462-
console.log(`[Events] Printer connected: ${printerDetails.Name}, starting services...`);
463-
464-
// Start polling for the new context
465-
try {
466-
pollingCoordinator.startPollingForContext(activeContextId);
467-
console.log(`[Polling] Started for context: ${activeContextId}`);
468-
} catch (error) {
469-
console.error(`[Polling] Failed to start for context ${activeContextId}:`, error);
470-
}
471-
}
407+
console.log(`[Events] Printer connected: ${printerDetails.Name}`);
408+
// Polling and monitors are initialized by backend-initialized handler
472409
});
473410
console.log('[Events] Post-connection hook configured');
474411

475-
// 12c. Setup backend-initialized hook to create monitors and trackers
412+
// 12c. Setup backend-initialized hook to start polling and create monitors
476413
// This is critical for Spoolman deduction and print state monitoring
414+
// IMPORTANT: This handles both startup connections AND dynamic connections (API reconnect/discovery)
477415
connectionManager.on('backend-initialized', (event: unknown) => {
478416
const backendEvent = event as { contextId: string; modelType: string };
479417
const contextId = backendEvent.contextId;
480418

481-
console.log(`[Events] Backend initialized for context ${contextId}, creating monitors...`);
419+
console.log(`[Events] Backend initialized for context ${contextId}, starting services...`);
482420

483-
// Get context and polling service
484-
const context = contextManager.getContext(contextId);
485-
const pollingService = context?.pollingService;
421+
try {
422+
// STEP 1: Start polling FIRST (this creates the pollingService reference)
423+
pollingCoordinator.startPollingForContext(contextId);
424+
console.log(`[Polling] Started for context: ${contextId}`);
486425

487-
if (!pollingService) {
488-
console.error('[Events] Missing polling service for context initialization');
489-
return;
490-
}
426+
// STEP 2: Get context and polling service (now available after step 1)
427+
const context = contextManager.getContext(contextId);
428+
const pollingService = context?.pollingService;
491429

492-
try {
493-
// Create PrintStateMonitor for this context
430+
if (!pollingService) {
431+
console.error('[Events] Missing polling service for context initialization');
432+
return;
433+
}
434+
435+
// STEP 3: Create PrintStateMonitor for this context
494436
const printStateMonitor = getMultiContextPrintStateMonitor();
495437
printStateMonitor.createMonitorForContext(contextId, pollingService);
496438
const stateMonitor = printStateMonitor.getMonitor(contextId);
@@ -502,27 +444,22 @@ async function main(): Promise<void> {
502444

503445
console.log(`[Events] Created PrintStateMonitor for context ${contextId}`);
504446

505-
// Create SpoolmanTracker for this context (depends on PrintStateMonitor)
447+
// STEP 4: Create SpoolmanTracker for this context (depends on PrintStateMonitor)
506448
const spoolmanTracker = getMultiContextSpoolmanTracker();
507449
spoolmanTracker.createTrackerForContext(contextId, stateMonitor);
508450

509451
console.log(`[Events] Created SpoolmanTracker for context ${contextId}`);
452+
console.log(`[Events] All services initialized for context ${contextId}`);
510453
} catch (error) {
511-
console.error(`[Events] Failed to create monitors for context ${contextId}:`, error);
454+
console.error(`[Events] Failed to initialize services for context ${contextId}:`, error);
512455
}
513456
});
514457
console.log('[Events] Backend-initialized hook configured');
515458

516-
// 13. Start polling for connected printers
517-
if (connectedContexts.length > 0) {
518-
startPolling();
519-
console.log(`[Init] Polling started for ${connectedContexts.length} printer(s)`);
520-
}
521-
522-
// 13b. Initialize monitors and trackers for connected printers
459+
// 13. Note: Polling and monitors are initialized by backend-initialized handler
460+
// This handler fires for both startup connections AND dynamic connections
523461
if (connectedContexts.length > 0) {
524-
initializeMonitors();
525-
console.log(`[Init] Monitors initialized for ${connectedContexts.length} printer(s)`);
462+
console.log(`[Init] Services initialized for ${connectedContexts.length} printer(s) via backend-initialized handler`);
526463
}
527464

528465
// 14. Initialize camera proxies

0 commit comments

Comments
 (0)