refactor to adapters
This commit is contained in:
@@ -1,211 +0,0 @@
|
||||
/**
|
||||
* Automation configuration module for environment-based adapter selection.
|
||||
*
|
||||
* This module provides configuration types and loaders for the automation system,
|
||||
* allowing switching between different adapters based on NODE_ENV.
|
||||
*
|
||||
* Mapping:
|
||||
* - NODE_ENV=production → real browser automation → iRacing Window → Image Templates
|
||||
* - NODE_ENV=development → real browser automation → iRacing Window → Image Templates
|
||||
* - NODE_ENV=test → MockBrowserAutomation → N/A → N/A
|
||||
*/
|
||||
|
||||
export type AutomationMode = 'production' | 'development' | 'test';
|
||||
|
||||
/**
|
||||
* @deprecated Use AutomationMode instead. Will be removed in future version.
|
||||
*/
|
||||
export type LegacyAutomationMode = 'dev' | 'production' | 'mock';
|
||||
|
||||
/**
|
||||
* Retry configuration for element finding operations.
|
||||
*/
|
||||
export interface RetryConfig {
|
||||
/** Maximum number of retry attempts (default: 3) */
|
||||
maxRetries: number;
|
||||
/** Initial delay in milliseconds before first retry (default: 500) */
|
||||
baseDelayMs: number;
|
||||
/** Maximum delay in milliseconds between retries (default: 5000) */
|
||||
maxDelayMs: number;
|
||||
/** Multiplier for exponential backoff (default: 2.0) */
|
||||
backoffMultiplier: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timing configuration for automation operations.
|
||||
*/
|
||||
export interface TimingConfig {
|
||||
/** Wait time for page to load after opening browser (default: 5000) */
|
||||
pageLoadWaitMs: number;
|
||||
/** Delay between sequential actions (default: 200) */
|
||||
interActionDelayMs: number;
|
||||
/** Delay after clicking an element (default: 300) */
|
||||
postClickDelayMs: number;
|
||||
/** Delay before starting step execution (default: 100) */
|
||||
preStepDelayMs: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default retry configuration values.
|
||||
*/
|
||||
export const DEFAULT_RETRY_CONFIG: RetryConfig = {
|
||||
maxRetries: 3,
|
||||
baseDelayMs: 500,
|
||||
maxDelayMs: 5000,
|
||||
backoffMultiplier: 2.0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Default timing configuration values.
|
||||
*/
|
||||
export const DEFAULT_TIMING_CONFIG: TimingConfig = {
|
||||
pageLoadWaitMs: 5000,
|
||||
interActionDelayMs: 200,
|
||||
postClickDelayMs: 300,
|
||||
preStepDelayMs: 100,
|
||||
};
|
||||
|
||||
export interface AutomationEnvironmentConfig {
|
||||
mode: AutomationMode;
|
||||
|
||||
/** Production/development configuration for native automation */
|
||||
nutJs?: {
|
||||
mouseSpeed?: number;
|
||||
keyboardDelay?: number;
|
||||
windowTitle?: string;
|
||||
templatePath?: string;
|
||||
confidence?: number;
|
||||
/** Retry configuration for element finding */
|
||||
retry?: Partial<RetryConfig>;
|
||||
/** Timing configuration for waits */
|
||||
timing?: Partial<TimingConfig>;
|
||||
};
|
||||
|
||||
/** Default timeout for automation operations in milliseconds */
|
||||
defaultTimeout?: number;
|
||||
/** Number of retry attempts for failed operations */
|
||||
retryAttempts?: number;
|
||||
/** Whether to capture screenshots on error */
|
||||
screenshotOnError?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the automation mode based on NODE_ENV.
|
||||
*
|
||||
* Mapping:
|
||||
* - NODE_ENV=production → 'production'
|
||||
* - All other values → 'test' (default)
|
||||
*
|
||||
* For backward compatibility, if AUTOMATION_MODE is explicitly set,
|
||||
* it will be used with a deprecation warning logged to console.
|
||||
*
|
||||
* @returns AutomationMode derived from NODE_ENV
|
||||
*/
|
||||
export function getAutomationMode(): AutomationMode {
|
||||
const legacyMode = process.env.AUTOMATION_MODE;
|
||||
if (legacyMode && isValidLegacyAutomationMode(legacyMode)) {
|
||||
console.warn(
|
||||
`[DEPRECATED] AUTOMATION_MODE environment variable is deprecated. ` +
|
||||
`Use NODE_ENV instead. Mapping: dev→test, mock→test, production→production`
|
||||
);
|
||||
return mapLegacyMode(legacyMode);
|
||||
}
|
||||
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
// Map NODE_ENV to AutomationMode
|
||||
if (nodeEnv === 'production') return 'production';
|
||||
if (nodeEnv === 'development') return 'development';
|
||||
return 'test';
|
||||
}
|
||||
|
||||
/**
|
||||
* Load automation configuration from environment variables.
|
||||
*
|
||||
* Environment variables:
|
||||
* - NODE_ENV: 'production' | 'test' (default: 'test')
|
||||
* - AUTOMATION_MODE: (deprecated) 'dev' | 'production' | 'mock'
|
||||
* - IRACING_WINDOW_TITLE: Window title for native automation (default: 'iRacing')
|
||||
* - TEMPLATE_PATH: Path to template images (default: './resources/templates')
|
||||
* - OCR_CONFIDENCE: OCR confidence threshold (default: 0.9)
|
||||
* - AUTOMATION_TIMEOUT: Default timeout in ms (default: 30000)
|
||||
* - RETRY_ATTEMPTS: Number of retry attempts (default: 3)
|
||||
* - SCREENSHOT_ON_ERROR: Capture screenshots on error (default: true)
|
||||
*
|
||||
* @returns AutomationEnvironmentConfig with parsed environment values
|
||||
*/
|
||||
export function loadAutomationConfig(): AutomationEnvironmentConfig {
|
||||
const mode = getAutomationMode();
|
||||
|
||||
return {
|
||||
mode,
|
||||
nutJs: {
|
||||
mouseSpeed: parseIntSafe(process.env.NUTJS_MOUSE_SPEED, 1000),
|
||||
keyboardDelay: parseIntSafe(process.env.NUTJS_KEYBOARD_DELAY, 50),
|
||||
windowTitle: process.env.IRACING_WINDOW_TITLE || 'iRacing',
|
||||
templatePath: process.env.TEMPLATE_PATH || './resources/templates/iracing',
|
||||
confidence: parseFloatSafe(process.env.OCR_CONFIDENCE, 0.9),
|
||||
retry: {
|
||||
maxRetries: parseIntSafe(process.env.AUTOMATION_MAX_RETRIES, DEFAULT_RETRY_CONFIG.maxRetries),
|
||||
baseDelayMs: parseIntSafe(process.env.AUTOMATION_BASE_DELAY_MS, DEFAULT_RETRY_CONFIG.baseDelayMs),
|
||||
maxDelayMs: parseIntSafe(process.env.AUTOMATION_MAX_DELAY_MS, DEFAULT_RETRY_CONFIG.maxDelayMs),
|
||||
backoffMultiplier: parseFloatSafe(process.env.AUTOMATION_BACKOFF_MULTIPLIER, DEFAULT_RETRY_CONFIG.backoffMultiplier),
|
||||
},
|
||||
timing: {
|
||||
pageLoadWaitMs: parseIntSafe(process.env.AUTOMATION_PAGE_LOAD_WAIT_MS, DEFAULT_TIMING_CONFIG.pageLoadWaitMs),
|
||||
interActionDelayMs: parseIntSafe(process.env.AUTOMATION_INTER_ACTION_DELAY_MS, DEFAULT_TIMING_CONFIG.interActionDelayMs),
|
||||
postClickDelayMs: parseIntSafe(process.env.AUTOMATION_POST_CLICK_DELAY_MS, DEFAULT_TIMING_CONFIG.postClickDelayMs),
|
||||
preStepDelayMs: parseIntSafe(process.env.AUTOMATION_PRE_STEP_DELAY_MS, DEFAULT_TIMING_CONFIG.preStepDelayMs),
|
||||
},
|
||||
},
|
||||
defaultTimeout: parseIntSafe(process.env.AUTOMATION_TIMEOUT, 30000),
|
||||
retryAttempts: parseIntSafe(process.env.RETRY_ATTEMPTS, 3),
|
||||
screenshotOnError: process.env.SCREENSHOT_ON_ERROR !== 'false',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to validate automation mode string.
|
||||
*/
|
||||
function isValidAutomationMode(value: string | undefined): value is AutomationMode {
|
||||
return value === 'production' || value === 'development' || value === 'test';
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to validate legacy automation mode string.
|
||||
*/
|
||||
function isValidLegacyAutomationMode(value: string | undefined): value is LegacyAutomationMode {
|
||||
return value === 'dev' || value === 'production' || value === 'mock';
|
||||
}
|
||||
|
||||
/**
|
||||
* Map legacy automation mode to new mode.
|
||||
*/
|
||||
function mapLegacyMode(legacy: LegacyAutomationMode): AutomationMode {
|
||||
switch (legacy) {
|
||||
case 'dev': return 'test';
|
||||
case 'mock': return 'test';
|
||||
case 'production': return 'production';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely parse an integer with a default fallback.
|
||||
*/
|
||||
function parseIntSafe(value: string | undefined, defaultValue: number): number {
|
||||
if (value === undefined || value === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
const parsed = parseInt(value, 10);
|
||||
return isNaN(parsed) ? defaultValue : parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely parse a float with a default fallback.
|
||||
*/
|
||||
function parseFloatSafe(value: string | undefined, defaultValue: number): number {
|
||||
if (value === undefined || value === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
const parsed = parseFloat(value);
|
||||
return isNaN(parsed) ? defaultValue : parsed;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* Browser mode configuration module for headed/headless browser toggle.
|
||||
*
|
||||
* Determines browser mode based on NODE_ENV:
|
||||
* - development: default headed, but configurable via runtime setter
|
||||
* - production: always headless
|
||||
* - test: always headless
|
||||
* - default: headless (for safety)
|
||||
*/
|
||||
|
||||
export type BrowserMode = 'headed' | 'headless';
|
||||
|
||||
export interface BrowserModeConfig {
|
||||
mode: BrowserMode;
|
||||
source: 'GUI' | 'NODE_ENV';
|
||||
}
|
||||
|
||||
/**
|
||||
* Loader for browser mode configuration.
|
||||
* Determines whether browser should run in headed or headless mode based on NODE_ENV.
|
||||
* In development mode, provides runtime control via setter method.
|
||||
*/
|
||||
export class BrowserModeConfigLoader {
|
||||
private developmentMode: BrowserMode = 'headless'; // Default to headless in development
|
||||
|
||||
/**
|
||||
* Load browser mode configuration based on NODE_ENV.
|
||||
* - NODE_ENV=development: returns current developmentMode (default: headed)
|
||||
* - NODE_ENV=production: always headless
|
||||
* - NODE_ENV=test: always headless
|
||||
* - default: headless (for safety)
|
||||
*/
|
||||
load(): BrowserModeConfig {
|
||||
const nodeEnv = process.env.NODE_ENV || 'production';
|
||||
|
||||
if (nodeEnv === 'development') {
|
||||
return { mode: this.developmentMode, source: 'GUI' };
|
||||
}
|
||||
|
||||
return { mode: 'headless', source: 'NODE_ENV' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Set browser mode for development environment.
|
||||
* Only affects behavior when NODE_ENV=development.
|
||||
* @param mode - The browser mode to use in development
|
||||
*/
|
||||
setDevelopmentMode(mode: BrowserMode): void {
|
||||
this.developmentMode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current development browser mode setting.
|
||||
* @returns The current browser mode for development
|
||||
*/
|
||||
getDevelopmentMode(): BrowserMode {
|
||||
return this.developmentMode;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import type { LogLevel } from '@gridpilot/automation/application/ports/LoggerLogLevel';
|
||||
|
||||
export type LogEnvironment = 'development' | 'production' | 'test';
|
||||
|
||||
export interface LoggingEnvironmentConfig {
|
||||
level: LogLevel;
|
||||
prettyPrint: boolean;
|
||||
fileOutput: boolean;
|
||||
filePath?: string;
|
||||
maxFiles?: number;
|
||||
maxFileSize?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load logging configuration from environment variables.
|
||||
*
|
||||
* Environment variables:
|
||||
* - NODE_ENV: 'development' | 'production' | 'test' (default: 'development')
|
||||
* - LOG_LEVEL: Override log level (optional)
|
||||
* - LOG_FILE_PATH: Path for log files in production (default: './logs/gridpilot')
|
||||
* - LOG_MAX_FILES: Max rotated files to keep (default: 7)
|
||||
* - LOG_MAX_SIZE: Max file size before rotation (default: '10m')
|
||||
*
|
||||
* @returns LoggingEnvironmentConfig with parsed environment values
|
||||
*/
|
||||
export function loadLoggingConfig(): LoggingEnvironmentConfig {
|
||||
const envValue = process.env.NODE_ENV;
|
||||
const environment = isValidLogEnvironment(envValue) ? envValue : 'development';
|
||||
|
||||
const defaults = getDefaultsForEnvironment(environment);
|
||||
|
||||
const levelOverride = process.env.LOG_LEVEL;
|
||||
const level = isValidLogLevel(levelOverride) ? levelOverride : defaults.level;
|
||||
|
||||
return {
|
||||
level,
|
||||
prettyPrint: defaults.prettyPrint,
|
||||
fileOutput: defaults.fileOutput,
|
||||
filePath: process.env.LOG_FILE_PATH || './logs/gridpilot',
|
||||
maxFiles: parseIntSafe(process.env.LOG_MAX_FILES, 7),
|
||||
maxFileSize: process.env.LOG_MAX_SIZE || '10m',
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultsForEnvironment(env: LogEnvironment): LoggingEnvironmentConfig {
|
||||
switch (env) {
|
||||
case 'development':
|
||||
return {
|
||||
level: 'debug',
|
||||
prettyPrint: true,
|
||||
fileOutput: false,
|
||||
};
|
||||
case 'production':
|
||||
return {
|
||||
level: 'info',
|
||||
prettyPrint: false,
|
||||
fileOutput: true,
|
||||
};
|
||||
case 'test':
|
||||
return {
|
||||
level: 'warn',
|
||||
prettyPrint: false,
|
||||
fileOutput: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function isValidLogEnvironment(value: string | undefined): value is LogEnvironment {
|
||||
return value === 'development' || value === 'production' || value === 'test';
|
||||
}
|
||||
|
||||
function isValidLogLevel(value: string | undefined): value is LogLevel {
|
||||
return value === 'debug' || value === 'info' || value === 'warn' || value === 'error' || value === 'fatal';
|
||||
}
|
||||
|
||||
function parseIntSafe(value: string | undefined, defaultValue: number): number {
|
||||
if (value === undefined || value === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
const parsed = parseInt(value, 10);
|
||||
return isNaN(parsed) ? defaultValue : parsed;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Infrastructure configuration barrel export.
|
||||
* Exports all configuration modules for easy imports.
|
||||
*/
|
||||
|
||||
export * from './AutomationConfig';
|
||||
export * from './LoggingConfig';
|
||||
export * from './BrowserModeConfig';
|
||||
Reference in New Issue
Block a user