From 9e5a1adb1292621632f679e4eb3efd38e48f922c Mon Sep 17 00:00:00 2001 From: xream Date: Wed, 13 Sep 2023 23:45:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E9=AA=8C=E6=80=A7=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9C=AC=E5=9C=B0=E8=84=9A=E6=9C=AC=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package.json | 2 +- backend/src/constants.js | 1 + backend/src/core/proxy-utils/index.js | 25 ++++++- backend/src/restful/file.js | 103 ++++++++++++++++++++++++++ backend/src/restful/index.js | 2 + 5 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 backend/src/restful/file.js diff --git a/backend/package.json b/backend/package.json index 3dbbaf4..81fbaa3 100644 --- a/backend/package.json +++ b/backend/package.json @@ -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": { diff --git a/backend/src/constants.js b/backend/src/constants.js index dcb143b..492305a 100644 --- a/backend/src/constants.js +++ b/backend/src/constants.js @@ -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'; diff --git a/backend/src/core/proxy-utils/index.js b/backend/src/core/proxy-utils/index.js index e27367b..bbd841e 100644 --- a/backend/src/core/proxy-utils/index.js +++ b/backend/src/core/proxy-utils/index.js @@ -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( diff --git a/backend/src/restful/file.js b/backend/src/restful/file.js new file mode 100644 index 0000000..92f5d66 --- /dev/null +++ b/backend/src/restful/file.js @@ -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); +} diff --git a/backend/src/restful/index.js b/backend/src/restful/index.js index 88fdabf..7d9de34 100644 --- a/backend/src/restful/index.js +++ b/backend/src/restful/index.js @@ -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);