148 lines
3.8 KiB
TypeScript
148 lines
3.8 KiB
TypeScript
import { emit, listen } from "@tauri-apps/api/event";
|
|
import { CmdType } from "./types";
|
|
|
|
/**
|
|
* process the merge mode
|
|
*/
|
|
function toMerge(
|
|
merge: CmdType.ProfileMerge,
|
|
data: CmdType.ProfileData
|
|
): CmdType.ProfileData {
|
|
if (!merge) return data;
|
|
|
|
const newData = { ...data };
|
|
|
|
// rules
|
|
if (Array.isArray(merge["prepend-rules"])) {
|
|
if (!newData.rules) newData.rules = [];
|
|
newData.rules.unshift(...merge["prepend-rules"]);
|
|
}
|
|
if (Array.isArray(merge["append-rules"])) {
|
|
if (!newData.rules) newData.rules = [];
|
|
newData.rules.push(...merge["append-rules"]);
|
|
}
|
|
|
|
// proxies
|
|
if (Array.isArray(merge["prepend-proxies"])) {
|
|
if (!newData.proxies) newData.proxies = [];
|
|
newData.proxies.unshift(...merge["prepend-proxies"]);
|
|
}
|
|
if (Array.isArray(merge["append-proxies"])) {
|
|
if (!newData.proxies) newData.proxies = [];
|
|
newData.proxies.push(...merge["append-proxies"]);
|
|
}
|
|
|
|
// proxy-groups
|
|
if (Array.isArray(merge["prepend-proxy-groups"])) {
|
|
if (!newData["proxy-groups"]) newData["proxy-groups"] = [];
|
|
newData["proxy-groups"].unshift(...merge["prepend-proxy-groups"]);
|
|
}
|
|
if (Array.isArray(merge["append-proxy-groups"])) {
|
|
if (!newData["proxy-groups"]) newData["proxy-groups"] = [];
|
|
newData["proxy-groups"].push(...merge["append-proxy-groups"]);
|
|
}
|
|
|
|
return newData;
|
|
}
|
|
|
|
/**
|
|
* process the script mode
|
|
*/
|
|
function toScript(
|
|
script: string,
|
|
data: CmdType.ProfileData
|
|
): Promise<CmdType.ProfileData> {
|
|
if (!script) {
|
|
throw new Error("miss the main function");
|
|
}
|
|
|
|
const paramsName = `__verge${Math.floor(Math.random() * 1000)}`;
|
|
const code = `'use strict';${script};return main(${paramsName});`;
|
|
const func = new Function(paramsName, code);
|
|
return func(data);
|
|
}
|
|
|
|
export type EStatus = { status: "ok" | "error"; message?: string };
|
|
export type EListener = (status: EStatus) => void;
|
|
export type EUnlistener = () => void;
|
|
|
|
/**
|
|
* The service helps to
|
|
* implement enhanced profiles
|
|
*/
|
|
class Enhance {
|
|
private isSetup = false;
|
|
private listenMap: Map<string, EListener>;
|
|
private resultMap: Map<string, EStatus>;
|
|
|
|
constructor() {
|
|
this.listenMap = new Map();
|
|
this.resultMap = new Map();
|
|
}
|
|
|
|
// setup some listener
|
|
// for the enhanced running status
|
|
listen(uid: string, cb: EListener): EUnlistener {
|
|
this.listenMap.set(uid, cb);
|
|
return () => this.listenMap.delete(uid);
|
|
}
|
|
|
|
// get the running status
|
|
status(uid: string): EStatus | undefined {
|
|
return this.resultMap.get(uid);
|
|
}
|
|
|
|
// setup the handler
|
|
setup() {
|
|
if (this.isSetup) return;
|
|
this.isSetup = true;
|
|
|
|
listen("script-handler", async (event) => {
|
|
const payload = event.payload as CmdType.EnhancedPayload;
|
|
let pdata = payload.current || {};
|
|
|
|
for (const each of payload.chain) {
|
|
const { uid, type = "" } = each.item;
|
|
|
|
try {
|
|
// process script
|
|
if (type === "script") {
|
|
// support async main function
|
|
pdata = await toScript(each.script!, { ...pdata });
|
|
}
|
|
|
|
// process merge
|
|
else if (type === "merge") {
|
|
pdata = toMerge(each.merge!, { ...pdata });
|
|
}
|
|
|
|
// invalid type
|
|
else {
|
|
throw new Error(`invalid enhanced profile type "${type}"`);
|
|
}
|
|
|
|
this.exec(uid, { status: "ok" });
|
|
} catch (err: any) {
|
|
this.exec(uid, {
|
|
status: "error",
|
|
message: err.message || err.toString(),
|
|
});
|
|
|
|
console.error(err);
|
|
}
|
|
}
|
|
|
|
const result = { data: pdata, status: "ok" };
|
|
emit(payload.callback, JSON.stringify(result)).catch(console.error);
|
|
});
|
|
}
|
|
|
|
// exec the listener
|
|
private exec(uid: string, status: EStatus) {
|
|
this.resultMap.set(uid, status);
|
|
this.listenMap.get(uid)?.(status);
|
|
}
|
|
}
|
|
|
|
export default new Enhance();
|