-
Notifications
You must be signed in to change notification settings - Fork 324
Expand file tree
/
Copy pathexec_script.ts
More file actions
118 lines (105 loc) · 3.91 KB
/
exec_script.ts
File metadata and controls
118 lines (105 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import LoggerCore from "@App/app/logger/core";
import type Logger from "@App/app/logger/logger";
import { createContext, createProxyContext } from "./create_context";
import type { GMInfoEnv, ScriptFunc } from "./types";
import { compileScript } from "./utils";
import type { Message } from "@Packages/message/types";
import type { ValueUpdateDataEncoded } from "./types";
import { evaluateGMInfo } from "./gm_api/gm_info";
import type { IGM_Base } from "./gm_api/gm_api";
import type { ScriptRunResource, TScriptInfo } from "@App/app/repo/scripts";
import { getStorageName } from "@App/pkg/utils/utils";
// 执行脚本,控制脚本执行与停止
export default class ExecScript {
scriptRes: TScriptInfo;
scriptFunc: ScriptFunc;
logger: Logger;
// proxyContext: typeof globalThis;
sandboxContext?: IGM_Base & { [key: string]: any };
named?: { [key: string]: any };
constructor(
scriptRes: TScriptInfo,
envPrefix: "content" | "offscreen",
message: Message,
code: string | ScriptFunc,
envInfo: GMInfoEnv,
globalInjection?: { [key: string]: any } // 主要是全域API. @grant none 时无效
) {
this.scriptRes = scriptRes;
this.logger = LoggerCore.getInstance().logger({
component: "exec",
uuid: scriptRes.uuid,
name: scriptRes.name,
});
const GM_info = evaluateGMInfo(envInfo, scriptRes);
// 构建脚本资源
if (typeof code === "string") {
this.scriptFunc = compileScript(code);
} else {
this.scriptFunc = code;
}
const grantSet = new Set(scriptRes.metadata.grant || []);
if (grantSet.has("none")) {
// 不注入任何GM api
// ScriptCat行为:GM.info 和 GM_info 同时注入
// 不改变Context情况下,以 named 传多於一个全域变量
this.named = { GM: { info: GM_info }, GM_info };
} else {
// 构建脚本GM上下文
this.sandboxContext = createContext(scriptRes, GM_info, envPrefix, message, grantSet);
if (globalInjection) {
Object.assign(this.sandboxContext, globalInjection);
}
}
}
emitEvent(event: string, eventId: string, data: any) {
this.logger.debug("emit event", { event, eventId, data });
this.sandboxContext?.emitEvent(event, eventId, data);
}
valueUpdate(storageName: string, uuid: string, responses: ValueUpdateDataEncoded[]) {
const scriptRes = this.scriptRes;
if (scriptRes.uuid === uuid || getStorageName(scriptRes) === storageName) {
const context = this.sandboxContext;
if (context) {
const contextScriptRes = context.scriptRes as ScriptRunResource | null | undefined;
if (contextScriptRes) {
if (uuid === contextScriptRes.uuid || storageName === getStorageName(contextScriptRes)) {
contextScriptRes.value = context.extValueStoreCopy || contextScriptRes.value;
const valueStore = contextScriptRes.value;
context.valueStoreUpdate(valueStore, responses);
context.extValueStoreCopy = { ...valueStore };
}
}
}
}
}
execContext: any;
/**
* @see {@link compileScriptCode}
* @returns
*/
exec() {
this.logger.debug("script start");
const sandboxContext = this.sandboxContext;
this.execContext = sandboxContext ? createProxyContext(sandboxContext) : global; // this.$ 只能执行一次
return this.scriptFunc.call(this.execContext, this.named, this.scriptRes.name);
}
// 早期启动的脚本,处理GM API
updateEarlyScriptGMInfo(envInfo: GMInfoEnv) {
let GM_info;
if (this.sandboxContext) {
// 触发loadScriptResolve
this.sandboxContext["loadScriptResolve"]?.();
GM_info = this.execContext["GM_info"];
} else {
GM_info = this.named?.GM_info;
}
GM_info.isIncognito = envInfo.isIncognito;
GM_info.sandboxMode = envInfo.sandboxMode;
GM_info.userAgentData = envInfo.userAgentData;
}
stop() {
this.logger.debug("script stop");
return true;
}
}