Files
PRA-only-demo/packages/rpa-core/src/engine/engine.ts
T

102 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Client } from "basic-ftp";
import type { Workbook as ExcelJSWorkbook } from "exceljs";
import { WindowsDriver } from "../driver/windows/windows-driver";
import type { AutomationDriver } from "../driver/types";
import type { CatalogComponent, FlowNode } from "../types";
import { getHandler } from "./registry";
import { RuntimeError, type RunContext } from "./types";
/** 人为拟真操作的开关与随机参数(desktop 能力的进程级设置)。 */
export interface ManualOperationSettings {
enabled: boolean;
randomMove: boolean;
randomClick: boolean;
randomSleep: boolean;
minMs: number;
maxMs: number;
}
/**
* 引擎实例状态容器(任务 1.3,R4:模块级全局状态收拢)。
*
* 折中方案(决策记录 2026-11-04):能力文件的 register() 调用与全局注册表保持不变,
* 但 Excel 缓存、数据库连接、FTP 客户端等进程级可变状态统一挂到引擎实例上。
* 包内各能力模块通过 defaultEngine 访问;宿主/CLI 可用 createEngine() 产生隔离实例,
* 或拿到 defaultEngine 做测试间重置。
*/
export class RpaEngine {
/** excel-store:路径 → ExcelJS 工作簿共享缓存 */
readonly excelCache = new Map<string, ExcelJSWorkbook>();
/** office.ts:Excel 句柄 id → 工作簿 */
readonly excelHandles = new Map<string, ExcelJSWorkbook>();
/** remaining-core:连接 id → 数据库连接(mysql2/pg/mssql) */
readonly dbConnections = new Map<string, unknown>();
/** ftp.ts:当前 FTP 连接 */
ftpClient?: Client;
/** ocr-caps.ts:懒加载的 OCR 实例 */
ocrInstance?: unknown;
/** desktop.ts:人为拟真操作设置 */
manualOperation: ManualOperationSettings = {
enabled: false,
randomMove: true,
randomClick: true,
randomSleep: true,
minMs: 1000,
maxMs: 3000
};
/** 桌面自动化驱动:按系统自动选(迁移指南五件小事 #2)。win32 用 PowerShell 版 WindowsDriver;
* 其他平台尚未实现,访问时抛 platform_unsupported 明确报错(惰性创建,避免 import 即炸) */
private _driver?: AutomationDriver;
get driver(): AutomationDriver {
if (!this._driver) {
if (process.platform === "win32") {
this._driver = new WindowsDriver();
} else {
throw new RuntimeError(
"platform_unsupported",
`该平台暂不支持桌面自动化驱动(当前:${process.platform})`,
{ recommendation: "桌面/键鼠/窗口能力目前仅支持 Windows;macOS/Linux 驱动在迁移指南三端计划中规划" }
);
}
}
return this._driver;
}
/** 注入驱动实现(测试替身或宿主适配器);注入后不再走平台自动选择 */
setDriver(driver: AutomationDriver): void {
this._driver = driver;
}
/**
* 单能力直接调用(ADR-R1 语义真实化):CLI/宿主脚本不再裸摸全局 getHandler,
* 而是经引擎入口调用。注意 handler 仍解析自进程注册表(ADR-R1 短期形态)。
*/
async execute(
componentId: string,
args: Record<string, unknown>,
ctx: RunContext,
node?: FlowNode,
component?: CatalogComponent
): Promise<unknown> {
const handler = getHandler(componentId);
if (!handler) {
throw new RuntimeError("capability_not_implemented", `能力 ${componentId} 未注册`, { componentId });
}
const resolvedNode: FlowNode = node ?? { id: "direct", componentId, position: { x: 0, y: 0 }, values: {}, options: {} };
return handler(ctx, resolvedNode, args, component as CatalogComponent);
}
}
export interface EngineOptions {
/** 注入桌面自动化驱动(测试替身或宿主适配器);缺省按 process.platform 自动选择 */
driver?: AutomationDriver;
}
export function createEngine(options?: EngineOptions): RpaEngine {
const engine = new RpaEngine();
if (options?.driver) engine.setDriver(options.driver);
return engine;
}
/** 能力模块内部使用的默认引擎实例(与全局注册表配套的进程级单例)。 */
export const defaultEngine = createEngine();