fix(automation): add stopAutomation to IAutomationEngine interface and fix interval cleanup
This commit is contained in:
@@ -3,35 +3,53 @@ import type { BrowserWindow, IpcMainInvokeEvent } from 'electron';
|
|||||||
import { DIContainer } from './di-container';
|
import { DIContainer } from './di-container';
|
||||||
import type { HostedSessionConfig } from '@/packages/domain/entities/HostedSessionConfig';
|
import type { HostedSessionConfig } from '@/packages/domain/entities/HostedSessionConfig';
|
||||||
import { StepId } from '@/packages/domain/value-objects/StepId';
|
import { StepId } from '@/packages/domain/value-objects/StepId';
|
||||||
import { MockAutomationEngineAdapter } from '@/packages/infrastructure/adapters/automation/MockAutomationEngineAdapter';
|
|
||||||
|
let progressMonitorInterval: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
export function setupIpcHandlers(mainWindow: BrowserWindow): void {
|
export function setupIpcHandlers(mainWindow: BrowserWindow): void {
|
||||||
const container = DIContainer.getInstance();
|
const container = DIContainer.getInstance();
|
||||||
const startAutomationUseCase = container.getStartAutomationUseCase();
|
const startAutomationUseCase = container.getStartAutomationUseCase();
|
||||||
const sessionRepository = container.getSessionRepository();
|
const sessionRepository = container.getSessionRepository();
|
||||||
const automationEngine = container.getAutomationEngine();
|
const automationEngine = container.getAutomationEngine();
|
||||||
|
const logger = container.getLogger();
|
||||||
|
|
||||||
ipcMain.handle('start-automation', async (_event: IpcMainInvokeEvent, config: HostedSessionConfig) => {
|
ipcMain.handle('start-automation', async (_event: IpcMainInvokeEvent, config: HostedSessionConfig) => {
|
||||||
try {
|
try {
|
||||||
|
logger.info('Starting automation', { sessionName: config.sessionName });
|
||||||
|
|
||||||
|
// Clear any existing progress interval
|
||||||
|
if (progressMonitorInterval) {
|
||||||
|
clearInterval(progressMonitorInterval);
|
||||||
|
progressMonitorInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Connect to browser first (required for dev mode)
|
// Connect to browser first (required for dev mode)
|
||||||
const connectionResult = await container.initializeBrowserConnection();
|
const connectionResult = await container.initializeBrowserConnection();
|
||||||
if (!connectionResult.success) {
|
if (!connectionResult.success) {
|
||||||
|
logger.error('Browser connection failed', undefined, { errorMessage: connectionResult.error });
|
||||||
return { success: false, error: connectionResult.error };
|
return { success: false, error: connectionResult.error };
|
||||||
}
|
}
|
||||||
|
logger.info('Browser connection established');
|
||||||
|
|
||||||
const result = await startAutomationUseCase.execute(config);
|
const result = await startAutomationUseCase.execute(config);
|
||||||
|
logger.info('Automation session created', { sessionId: result.sessionId });
|
||||||
|
|
||||||
const session = await sessionRepository.findById(result.sessionId);
|
const session = await sessionRepository.findById(result.sessionId);
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
// Start the automation by executing step 1
|
// Start the automation by executing step 1
|
||||||
|
logger.info('Executing step 1');
|
||||||
await automationEngine.executeStep(StepId.create(1), config);
|
await automationEngine.executeStep(StepId.create(1), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up progress monitoring
|
// Set up progress monitoring
|
||||||
const checkInterval = setInterval(async () => {
|
progressMonitorInterval = setInterval(async () => {
|
||||||
const updatedSession = await sessionRepository.findById(result.sessionId);
|
const updatedSession = await sessionRepository.findById(result.sessionId);
|
||||||
if (!updatedSession) {
|
if (!updatedSession) {
|
||||||
clearInterval(checkInterval);
|
if (progressMonitorInterval) {
|
||||||
|
clearInterval(progressMonitorInterval);
|
||||||
|
progressMonitorInterval = null;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +65,11 @@ export function setupIpcHandlers(mainWindow: BrowserWindow): void {
|
|||||||
if (updatedSession.state.value === 'COMPLETED' ||
|
if (updatedSession.state.value === 'COMPLETED' ||
|
||||||
updatedSession.state.value === 'FAILED' ||
|
updatedSession.state.value === 'FAILED' ||
|
||||||
updatedSession.state.value === 'STOPPED_AT_STEP_18') {
|
updatedSession.state.value === 'STOPPED_AT_STEP_18') {
|
||||||
clearInterval(checkInterval);
|
logger.info('Automation ended', { state: updatedSession.state.value });
|
||||||
|
if (progressMonitorInterval) {
|
||||||
|
clearInterval(progressMonitorInterval);
|
||||||
|
progressMonitorInterval = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
@@ -56,9 +78,11 @@ export function setupIpcHandlers(mainWindow: BrowserWindow): void {
|
|||||||
sessionId: result.sessionId
|
sessionId: result.sessionId
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const err = error instanceof Error ? error : new Error('Unknown error');
|
||||||
|
logger.error('Automation failed', err);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error instanceof Error ? error.message : 'Unknown error'
|
error: err.message
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -89,22 +113,34 @@ export function setupIpcHandlers(mainWindow: BrowserWindow): void {
|
|||||||
|
|
||||||
ipcMain.handle('stop-automation', async (_event: IpcMainInvokeEvent, sessionId: string) => {
|
ipcMain.handle('stop-automation', async (_event: IpcMainInvokeEvent, sessionId: string) => {
|
||||||
try {
|
try {
|
||||||
|
logger.info('Stopping automation', { sessionId });
|
||||||
|
|
||||||
|
// Clear progress monitoring interval
|
||||||
|
if (progressMonitorInterval) {
|
||||||
|
clearInterval(progressMonitorInterval);
|
||||||
|
progressMonitorInterval = null;
|
||||||
|
logger.info('Progress monitor cleared');
|
||||||
|
}
|
||||||
|
|
||||||
// Stop the automation engine interval
|
// Stop the automation engine interval
|
||||||
const engine = automationEngine as MockAutomationEngineAdapter;
|
automationEngine.stopAutomation();
|
||||||
engine.stopAutomation();
|
logger.info('Automation engine stopped');
|
||||||
|
|
||||||
// Update session state to failed with user stop reason
|
// Update session state to failed with user stop reason
|
||||||
const session = await sessionRepository.findById(sessionId);
|
const session = await sessionRepository.findById(sessionId);
|
||||||
if (session) {
|
if (session) {
|
||||||
session.fail('User stopped automation');
|
session.fail('User stopped automation');
|
||||||
await sessionRepository.update(session);
|
await sessionRepository.update(session);
|
||||||
|
logger.info('Session marked as failed', { sessionId });
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const err = error instanceof Error ? error : new Error('Unknown error');
|
||||||
|
logger.error('Stop automation failed', err);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error instanceof Error ? error.message : 'Unknown error'
|
error: err.message
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ export interface ValidationResult {
|
|||||||
export interface IAutomationEngine {
|
export interface IAutomationEngine {
|
||||||
validateConfiguration(config: HostedSessionConfig): Promise<ValidationResult>;
|
validateConfiguration(config: HostedSessionConfig): Promise<ValidationResult>;
|
||||||
executeStep(stepId: StepId, config: HostedSessionConfig): Promise<void>;
|
executeStep(stepId: StepId, config: HostedSessionConfig): Promise<void>;
|
||||||
|
stopAutomation(): void;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user