diff --git a/backend/src/constants.js b/backend/src/constants.js index 04d4030..dcb143b 100644 --- a/backend/src/constants.js +++ b/backend/src/constants.js @@ -9,3 +9,5 @@ export const GIST_BACKUP_FILE_NAME = 'Sub-Store'; export const ARTIFACT_REPOSITORY_KEY = 'Sub-Store Artifacts Repository'; export const RESOURCE_CACHE_KEY = '#sub-store-cached-resource'; export const CACHE_EXPIRATION_TIME_MS = 60 * 60 * 1000; // 1 hour +export const SCRIPT_RESOURCE_CACHE_KEY = '#sub-store-cached-script-resource'; // cached-script-resource CSR +export const CSR_EXPIRATION_TIME_KEY = '#sub-store-csr-expiration-time'; // Custom expiration time key; (Loon|Surge) Default write 48 hour diff --git a/backend/src/core/proxy-utils/processors/index.js b/backend/src/core/proxy-utils/processors/index.js index c35ff3a..c47d4f3 100644 --- a/backend/src/core/proxy-utils/processors/index.js +++ b/backend/src/core/proxy-utils/processors/index.js @@ -1,4 +1,5 @@ import resourceCache from '@/utils/resource-cache'; +import scriptResourceCache from '@/utils/script-resource-cache'; import { isIPv4, isIPv6 } from '@/utils'; import { FULL } from '@/utils/logical'; import { getFlag } from '@/utils/geo'; @@ -633,6 +634,7 @@ function createDynamicFunction(name, script, $arguments) { '$httpClient', '$notification', 'ProxyUtils', + 'scriptResourceCache', `${script}\n return ${name}`, )( $arguments, @@ -645,6 +647,7 @@ function createDynamicFunction(name, script, $arguments) { // eslint-disable-next-line no-undef $notification, ProxyUtils, + scriptResourceCache, ); } else { return new Function( @@ -652,7 +655,8 @@ function createDynamicFunction(name, script, $arguments) { '$substore', 'lodash', 'ProxyUtils', + 'scriptResourceCache', `${script}\n return ${name}`, - )($arguments, $, lodash, ProxyUtils); + )($arguments, $, lodash, ProxyUtils, scriptResourceCache); } } diff --git a/backend/src/utils/script-resource-cache.js b/backend/src/utils/script-resource-cache.js new file mode 100644 index 0000000..d497e3a --- /dev/null +++ b/backend/src/utils/script-resource-cache.js @@ -0,0 +1,105 @@ +import $ from '@/core/app'; +import { + SCRIPT_RESOURCE_CACHE_KEY, + CSR_EXPIRATION_TIME_KEY, +} from '@/constants'; + +class ResourceCache { + constructor() { + this.expires = getExpiredTime(); + if (!$.read(SCRIPT_RESOURCE_CACHE_KEY)) { + $.write('{}', SCRIPT_RESOURCE_CACHE_KEY); + } + this.resourceCache = JSON.parse($.read(SCRIPT_RESOURCE_CACHE_KEY)); + this._cleanup(); + } + + _cleanup() { + // clear obsolete cached resource + let clear = false; + Object.entries(this.resourceCache).forEach((entry) => { + const [id, updated] = entry; + if (!updated.time) { + // clear old version cache + delete this.resourceCache[id]; + $.delete(`#${id}`); + clear = true; + } + if (new Date().getTime() - updated.time > this.expires) { + delete this.resourceCache[id]; + clear = true; + } + }); + if (clear) this._persist(); + } + + revokeAll() { + this.resourceCache = {}; + this._persist(); + } + + _persist() { + $.write(JSON.stringify(this.resourceCache), SCRIPT_RESOURCE_CACHE_KEY); + } + + get(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].data; + } + return null; + } + + gettime(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].time; + } + return null; + } + + set(id, value) { + this.resourceCache[id] = { time: new Date().getTime(), data: value }; + this._persist(); + } +} + +function getExpiredTime() { + console.log($.read(CSR_EXPIRATION_TIME_KEY)); + if (!$.read(CSR_EXPIRATION_TIME_KEY)) { + $.write('1728e5', CSR_EXPIRATION_TIME_KEY); // 48 * 3600 * 1000 + } + let expiration = 1728e5; + if ($.env.isLoon) { + const loont = { + // Loon 插件自义定 + '1\u5206\u949f': 6e4, + '5\u5206\u949f': 3e5, + '10\u5206\u949f': 6e5, + '30\u5206\u949f': 18e5, // "30分钟" + '1\u5c0f\u65f6': 36e5, + '2\u5c0f\u65f6': 72e5, + '3\u5c0f\u65f6': 108e5, + '6\u5c0f\u65f6': 216e5, + '12\u5c0f\u65f6': 432e5, + '24\u5c0f\u65f6': 864e5, + '48\u5c0f\u65f6': 1728e5, + '72\u5c0f\u65f6': 2592e5, // "72小时" + '\u53c2\u6570\u4f20\u5165': 'readcachets', // "参数输入" + }; + let intimed = $.read('#\u8282\u70b9\u7f13\u5b58\u6709\u6548\u671f'); // Loon #节点缓存有效期 + console.log(intimed); + if (intimed in loont) { + expiration = loont[intimed]; + if (expiration === 'readcachets') { + expiration = intimed; + } + } + return expiration; + } else { + expiration = $.read(CSR_EXPIRATION_TIME_KEY); + return expiration; + } +} + +export default new ResourceCache(); diff --git a/config/Loon.plugin b/config/Loon.plugin index 343f41d..e1421ab 100644 --- a/config/Loon.plugin +++ b/config/Loon.plugin @@ -4,12 +4,16 @@ #!author=Peng-YM #!homepage=https://github.com/Peng-YM/Sub-Store #!icon=https://raw.githubusercontent.com/58xinian/icon/master/Sub-Store1.png +#!select = 节点缓存有效期,1分钟,5分钟,10分钟,30分钟,1小时,2小时,3小时,6小时,12小时,24小时,48小时,72小时,参数传入 + +[Rule] +DOMAIN,sub-store.vercel.app,PROXY [MITM] hostname=sub.store [Script] http-request ^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js, requires-body=true, timeout=120, tag=Sub-Store Core -http-request https?:\/\/sub\.store script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js, requires-body=true, timeout=120, tag=Sub-Store Simple +http-request ^https?:\/\/sub\.store script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js, requires-body=true, timeout=120, tag=Sub-Store Simple cron "0 0 * * *" script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js, tag=Sub-Store Sync \ No newline at end of file