You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
1.9 KiB

import type { BrowserContext, Page } from "playwright";
import { ExecutionLayer } from "@/workers/rpa/kernel/execution-layer";
import { SelectorGraph } from "@/workers/rpa/kernel/selector-graph";
import { StateEngine } from "@/workers/rpa/kernel/state-engine";
import {
assertPlaywrightPage,
assertRPAContext,
isRPAContext,
type IRPAContext,
} from "@/workers/rpa/kernel/context-validator";
export type { IRPAContext } from "@/workers/rpa/kernel/context-validator";
/** RPA 运行期唯一状态容器(无模块级全局变量) */
export class RPAContext implements IRPAContext {
readonly selectors: SelectorGraph;
readonly exec: ExecutionLayer;
readonly runtime: ExecutionLayer;
readonly state: StateEngine;
private widgetScrollAtMs = 0;
constructor(
readonly page: Page,
readonly browserContext?: BrowserContext,
) {
assertPlaywrightPage(page, "RPAContext.constructor(page)");
this.selectors = new SelectorGraph();
this.exec = ExecutionLayer.forPage(page);
this.runtime = this.exec;
this.state = new StateEngine(this);
assertRPAContext(this, "RPAContext.constructor");
}
static fromSession(
pageOrCtx: Page | RPAContext,
browserContext?: BrowserContext,
): RPAContext {
return resolveRPAContext(pageOrCtx, browserContext);
}
getWidgetScrollAt(): number {
return this.widgetScrollAtMs;
}
setWidgetScrollAt(ms: number): void {
this.widgetScrollAtMs = ms;
}
}
/** Page | RPAContext 统一解析(禁止把 Context 再包一层导致 page.locator 断裂) */
export function resolveRPAContext(
pageOrCtx: Page | RPAContext,
browserContext?: BrowserContext,
): RPAContext {
if (isRPAContext(pageOrCtx)) {
assertRPAContext(pageOrCtx);
return pageOrCtx as RPAContext;
}
assertPlaywrightPage(pageOrCtx, "resolveRPAContext(page)");
const created = new RPAContext(pageOrCtx, browserContext);
assertRPAContext(created, "RPAContext.fromSession");
return created;
}