feat: 实验性支持本地脚本复用

This commit is contained in:
xream 2023-09-13 23:45:00 +08:00
parent 2c89a0ddbd
commit 9e5a1adb12
No known key found for this signature in database
GPG Key ID: 1D2C5225471789F9
5 changed files with 131 additions and 2 deletions

View File

@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.14.52",
"version": "2.14.53",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {

View File

@ -2,6 +2,7 @@ export const SCHEMA_VERSION_KEY = 'schemaVersion';
export const SETTINGS_KEY = 'settings';
export const SUBS_KEY = 'subs';
export const COLLECTIONS_KEY = 'collections';
export const FILES_KEY = 'files';
export const ARTIFACTS_KEY = 'artifacts';
export const RULES_KEY = 'rules';
export const GIST_BACKUP_KEY = 'Auto Generated Sub-Store Backup';

View File

@ -1,5 +1,6 @@
import download from '@/utils/download';
import { isIPv4, isIPv6 } from '@/utils';
import { FILES_KEY } from '@/constants';
import PROXY_PROCESSORS, { ApplyProcessor } from './processors';
import PROXY_PREPROCESSORS from './preprocessors';
import PROXY_PRODUCERS from './producers';
@ -84,7 +85,29 @@ async function process(proxies, operators = [], targetPlatform) {
// if this is a remote script, download it
try {
script = await download(url.split('#')[0]);
const downloadUrl = url.split('#')[0];
const downloadUrlMatch =
downloadUrl.match(/^\/api\/file\/(.+)/);
if (downloadUrlMatch) {
let fileName = downloadUrlMatch?.[1];
if (fileName == null) {
throw new Error(`本地脚本 URL 无效: ${url}`);
}
fileName = decodeURIComponent(fileName);
const allFiles = $.read(FILES_KEY);
const file = allFiles.find(
(i) => i.name === fileName && i.type === item.type,
);
if (!file) {
throw new Error(
`找不到类型为 ${item.type} 的本地脚本: ${fileName}`,
);
}
script = file.content;
} else {
script = await download(downloadUrl);
}
// $.info(`Script loaded: >>>\n ${script}`);
} catch (err) {
$.error(

103
backend/src/restful/file.js Normal file
View File

@ -0,0 +1,103 @@
import { deleteByName, findByName, updateByName } from '@/utils/database';
import { FILES_KEY } from '@/constants';
import { failed, success } from '@/restful/response';
import $ from '@/core/app';
import { RequestInvalidError, ResourceNotFoundError } from '@/restful/errors';
export default function register($app) {
if (!$.read(FILES_KEY)) $.write([], FILES_KEY);
$app.route('/api/file/:name')
.get(getFile)
.patch(updateFile)
.delete(deleteFile);
$app.route('/api/files').get(getAllFiles).post(createFile).put(replaceFile);
}
// file API
function createFile(req, res) {
const file = req.body;
$.info(`正在创建文件:${file.name}`);
const allFiles = $.read(FILES_KEY);
if (findByName(allFiles, file.name)) {
failed(
res,
new RequestInvalidError(
'DUPLICATE_KEY',
`File ${file.name} already exists.`,
),
);
}
allFiles.push(file);
$.write(allFiles, FILES_KEY);
success(res, file, 201);
}
function getFile(req, res) {
let { name } = req.params;
name = decodeURIComponent(name);
const allFiles = $.read(FILES_KEY);
const file = findByName(allFiles, name);
if (file) {
success(res, file);
} else {
failed(
res,
new ResourceNotFoundError(
`FILE_NOT_FOUND`,
`File ${name} does not exist`,
404,
),
);
}
}
function updateFile(req, res) {
let { name } = req.params;
name = decodeURIComponent(name);
let file = req.body;
const allFiles = $.read(FILES_KEY);
const oldFile = findByName(allFiles, name);
if (oldFile) {
const newFile = {
...oldFile,
...file,
};
$.info(`正在更新文件:${name}...`);
updateByName(allFiles, name, newFile);
$.write(allFiles, FILES_KEY);
success(res, newFile);
} else {
failed(
res,
new ResourceNotFoundError(
'RESOURCE_NOT_FOUND',
`File ${name} does not exist!`,
),
404,
);
}
}
function deleteFile(req, res) {
let { name } = req.params;
name = decodeURIComponent(name);
$.info(`正在删除文件:${name}`);
let allFiles = $.read(FILES_KEY);
deleteByName(allFiles, name);
$.write(allFiles, FILES_KEY);
success(res);
}
function getAllFiles(req, res) {
const allFiles = $.read(FILES_KEY);
success(res, allFiles);
}
function replaceFile(req, res) {
const allFiles = req.body;
$.write(allFiles, FILES_KEY);
success(res);
}

View File

@ -4,6 +4,7 @@ import $ from '@/core/app';
import registerSubscriptionRoutes from './subscriptions';
import registerCollectionRoutes from './collections';
import registerArtifactRoutes from './artifacts';
import registerFileRoutes from './file';
import registerSyncRoutes from './sync';
import registerDownloadRoutes from './download';
import registerSettingRoutes from './settings';
@ -23,6 +24,7 @@ export default function serve() {
registerSortingRoutes($app);
registerSettingRoutes($app);
registerArtifactRoutes($app);
registerFileRoutes($app);
registerSyncRoutes($app);
registerNodeInfoRoutes($app);
registerMiscRoutes($app);