2022-06-19 01:14:38 +08:00

183 lines
5.2 KiB
JavaScript

import download from '@/utils/download';
import PROXY_PROCESSORS, { ApplyProcessor } from './processors';
import PROXY_PREPROCESSORS from './preprocessors';
import PROXY_PRODUCERS from './producers';
import PROXY_PARSERS from './parsers';
import $ from '@/core/app';
function preprocess(raw) {
for (const processor of PROXY_PREPROCESSORS) {
try {
if (processor.test(raw)) {
$.info(`Pre-processor [${processor.name}] activated`);
return processor.parse(raw);
}
} catch (e) {
$.error(`Parser [${processor.name}] failed\n Reason: ${e}`);
}
}
return raw;
}
function parse(raw) {
raw = preprocess(raw);
// parse
const lines = raw.split('\n');
const proxies = [];
let lastParser;
for (let line of lines) {
line = line.trim();
if (line.length === 0) continue; // skip empty line
let success = false;
// try to parse with last used parser
if (lastParser) {
const [proxy, error] = tryParse(lastParser, line);
if (!error) {
proxies.push(proxy);
success = true;
}
}
if (!success) {
// search for a new parser
for (const parser of PROXY_PARSERS) {
const [proxy, error] = tryParse(parser, line);
if (!error) {
proxies.push(proxy);
lastParser = parser;
success = true;
}
}
}
if (!success) {
$.error(`Failed to parse line: ${line}`);
}
}
return proxies;
}
async function process(proxies, operators = [], targetPlatform) {
for (const item of operators) {
// process script
let script;
const $arguments = {};
if (item.type.indexOf('Script') !== -1) {
const { mode, content } = item.args;
if (mode === 'link') {
const url = content;
// extract link arguments
const rawArgs = url.split('#');
if (rawArgs.length > 1) {
for (const pair of rawArgs[1].split('&')) {
const key = pair.split('=')[0];
const value = pair.split('=')[1] || true;
$arguments[key] = value;
}
}
// if this is a remote script, download it
try {
script = await download(url.split('#')[0]);
$.info(`Script loaded: >>>\n ${script}`);
} catch (err) {
$.error(
`Error when downloading remote script: ${item.args.content}.\n Reason: ${err}`,
);
// skip the script if download failed.
continue;
}
} else {
script = content;
}
}
if (!PROXY_PROCESSORS[item.type]) {
$.error(`Unknown operator: "${item.type}"`);
continue;
}
$.info(
`Applying "${item.type}" with arguments:\n >>> ${
JSON.stringify(item.args, null, 2) || 'None'
}`,
);
let processor;
if (item.type.indexOf('Script') !== -1) {
processor = PROXY_PROCESSORS[item.type](
script,
targetPlatform,
$arguments,
);
} else {
processor = PROXY_PROCESSORS[item.type](item.args);
}
proxies = await ApplyProcessor(processor, proxies);
}
return proxies;
}
function produce(proxies, targetPlatform) {
const producer = PROXY_PRODUCERS[targetPlatform];
if (!producer) {
throw new Error(`Target platform: ${targetPlatform} is not supported!`);
}
// filter unsupported proxies
proxies = proxies.filter(
(proxy) =>
!(proxy.supported && proxy.supported[targetPlatform] === false),
);
$.info(`Producing proxies for target: ${targetPlatform}`);
if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') {
return proxies
.map((proxy) => {
try {
return producer.produce(proxy);
} catch (err) {
$.error(
`Cannot produce proxy: ${JSON.stringify(
proxy,
null,
2,
)}\nReason: ${err}`,
);
return '';
}
})
.filter((line) => line.length > 0)
.join('\n');
} else if (producer.type === 'ALL') {
return producer.produce(proxies);
}
}
export const ProxyUtils = {
parse,
process,
produce,
};
function tryParse(parser, line) {
if (!safeMatch(parser, line)) return [null, new Error('Parser mismatch')];
try {
const proxy = parser.parse(line);
return [proxy, null];
} catch (err) {
return [null, err];
}
}
function safeMatch(parser, line) {
try {
return parser.test(line);
} catch (err) {
return false;
}
}