Compare commits

..

1 Commits

Author SHA1 Message Date
QuentinHsu
bac04587b8 🐞 fix(subscriptions): negative usage flow 2022-10-23 13:36:01 +08:00
22 changed files with 4316 additions and 4662 deletions

View File

@@ -21,7 +21,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: "16"
node-version: "14"
- name: Install dependencies
run: |
npm install -g pnpm

View File

@@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.14.9",
"version": "2.13.5",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {
@@ -30,7 +30,7 @@
"@babel/preset-env": "^7.18.0",
"@babel/register": "^7.17.7",
"@types/gulp": "^4.0.9",
"axios": "^0.21.2",
"axios": "^0.20.0",
"babel-plugin-relative-path-import": "^2.0.1",
"babelify": "^10.0.0",
"browser-pack-flat": "^3.4.2",
@@ -51,4 +51,4 @@
"prettier-plugin-sort-imports": "^1.6.1",
"tinyify": "^3.0.0"
}
}
}

8544
backend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,5 +9,3 @@ 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

View File

@@ -23,19 +23,12 @@ function URI_SS() {
};
content = content.split('#')[0]; // strip proxy name
// handle IPV4 and IPV6
let serverAndPortArray = content.match(/@([^/]*)(\/|$)/);
let userInfoStr = Base64.decode(content.split('@')[0]);
if (!serverAndPortArray) {
content = Base64.decode(content);
userInfoStr = content.split('@')[0];
serverAndPortArray = content.match(/@([^/]*)(\/|$)/);
}
const serverAndPort = serverAndPortArray[1];
const serverAndPort = content.match(/@([^/]*)(\/|$)/)[1];
const portIdx = serverAndPort.lastIndexOf(':');
proxy.server = serverAndPort.substring(0, portIdx);
proxy.port = serverAndPort.substring(portIdx + 1);
const userInfo = userInfoStr.split(':');
const userInfo = Base64.decode(content.split('@')[0]).split(':');
proxy.cipher = userInfo[0];
proxy.password = userInfo[1];
@@ -277,7 +270,6 @@ function Clash_All() {
'http',
'snell',
'trojan',
'tuic',
].includes(proxy.type)
) {
throw new Error(
@@ -482,15 +474,6 @@ function Surge_Snell() {
return { name, test, parse };
}
function Surge_Tuic() {
const name = 'Surge Tuic Parser';
const test = (line) => {
return /^.*=\s*tuic(-v5)??/.test(line.split(',')[0]);
};
const parse = (line) => getSurgeParser().parse(line);
return { name, test, parse };
}
export default [
URI_SS(),
URI_SSR(),
@@ -502,7 +485,6 @@ export default [
Surge_Trojan(),
Surge_Http(),
Surge_Snell(),
Surge_Tuic(),
Surge_Socks5(),
Loon_SS(),
Loon_SSR(),

View File

@@ -29,7 +29,7 @@ const grammars = String.raw`
}
}
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5) {
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls) {
return proxy;
}
@@ -73,13 +73,6 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
$set(proxy, "obfs-opts.path", obfs.path);
}
}
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
}
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
proxy.version = 5;
}
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
proxy.type = "socks5";
}
@@ -182,11 +175,6 @@ uri = $[^,]+
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
tfo = comma "tfo" equals flag:bool { proxy.tfo = flag; }
ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); }
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
comma = _ "," _

View File

@@ -27,7 +27,7 @@
}
}
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5) {
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls) {
return proxy;
}
@@ -71,13 +71,6 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
$set(proxy, "obfs-opts.path", obfs.path);
}
}
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
}
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
proxy.version = 5;
}
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
proxy.type = "socks5";
}
@@ -180,11 +173,6 @@ uri = $[^,]+
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
tfo = comma "tfo" equals flag:bool { proxy.tfo = flag; }
ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); }
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
comma = _ "," _

View File

@@ -95,10 +95,22 @@ function FullConfig() {
return /^(\[server_local\]|\[Proxy\])/gm.test(raw);
};
const parse = function (raw) {
const match = raw.match(
/^\[server_local|Proxy\]([\s\S]+?)^\[.+?\](\r?\n|$)/im,
)?.[1];
return match || raw;
const regex = /^\[server_local]|\[Proxy]/gm;
const match = regex.exec(raw);
const results = [];
let first = true;
if (match) {
raw = raw.substring(match.index);
for (const line of raw.split('\n')) {
if (!first && !line.test(/^\s*\[/)) {
results.push(line);
}
// skip the first line
first = false;
}
return results.join('\n');
}
};
return { name, test, parse };
}

View File

@@ -1,5 +1,4 @@
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';
@@ -634,7 +633,6 @@ function createDynamicFunction(name, script, $arguments) {
'$httpClient',
'$notification',
'ProxyUtils',
'scriptResourceCache',
`${script}\n return ${name}`,
)(
$arguments,
@@ -647,7 +645,6 @@ function createDynamicFunction(name, script, $arguments) {
// eslint-disable-next-line no-undef
$notification,
ProxyUtils,
scriptResourceCache,
);
} else {
return new Function(
@@ -655,8 +652,7 @@ function createDynamicFunction(name, script, $arguments) {
'$substore',
'lodash',
'ProxyUtils',
'scriptResourceCache',
`${script}\n return ${name}`,
)($arguments, $, lodash, ProxyUtils, scriptResourceCache);
)($arguments, $, lodash, ProxyUtils);
}
}

View File

@@ -4,27 +4,11 @@ export default function Clash_Producer() {
const type = 'ALL';
const produce = (proxies) => {
// filter unsupported proxies
proxies = proxies.filter((proxy) => {
if (
![
'ss',
'ssr',
'vmess',
'socks',
'http',
'snell',
'trojan',
].includes(proxy.type)
) {
return false;
} else if (
proxy.type === 'snell' &&
String(proxy.version) === '4'
) {
return false;
}
return true;
});
proxies = proxies.filter((proxy) =>
['ss', 'ssr', 'vmess', 'socks', 'http', 'snell', 'trojan'].includes(
proxy.type,
),
);
return (
'proxies:\n' +
proxies
@@ -41,18 +25,6 @@ export default function Clash_Producer() {
proxy.servername = proxy.sni;
delete proxy.sni;
}
// https://dreamacro.github.io/clash/configuration/outbound.html#vmess
if (
isPresent(proxy, 'cipher') &&
![
'auto',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(proxy.cipher)
) {
proxy.cipher = 'auto';
}
}
delete proxy['tls-fingerprint'];

View File

@@ -3,7 +3,6 @@ import Clash_Producer from './clash';
import Stash_Producer from './stash';
import Loon_Producer from './loon';
import URI_Producer from './uri';
import V2Ray_Producer from './v2ray';
import QX_Producer from './qx';
function JSON_Producer() {
@@ -18,7 +17,6 @@ export default {
Loon: Loon_Producer(),
Clash: Clash_Producer(),
URI: URI_Producer(),
V2Ray: V2Ray_Producer(),
JSON: JSON_Producer(),
Stash: Stash_Producer(),
};

View File

@@ -6,15 +6,6 @@ export default function Stash_Producer() {
return (
'proxies:\n' +
proxies
.filter((proxy) => {
if (
proxy.type === 'snell' &&
String(proxy.version) === '4'
) {
return false;
}
return true;
})
.map((proxy) => {
if (proxy.type === 'vmess') {
// handle vmess aead
@@ -28,34 +19,6 @@ export default function Stash_Producer() {
proxy.servername = proxy.sni;
delete proxy.sni;
}
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400
// https://stash.wiki/proxy-protocols/proxy-types#vmess
if (
isPresent(proxy, 'cipher') &&
![
'auto',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(proxy.cipher)
) {
proxy.cipher = 'auto';
}
} else if (proxy.type === 'tuic') {
if (isPresent(proxy, 'alpn')) {
proxy.alpn = Array.isArray(proxy.alpn)
? proxy.alpn
: [proxy.alpn];
} else {
proxy.alpn = ['h3'];
}
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
if (
(!proxy.token || proxy.token.length === 0) &&
!isPresent(proxy, 'version')
) {
proxy.version = 5;
}
}
delete proxy['tls-fingerprint'];

View File

@@ -4,14 +4,6 @@ import $ from '@/core/app';
const targetPlatform = 'Surge';
const ipVersions = {
dual: 'dual',
ipv4: 'v4-only',
ipv6: 'v6-only',
'ipv4-prefer': 'prefer-v4',
'ipv6-prefer': 'prefer-v6',
};
export default function Surge_Producer() {
const produce = (proxy) => {
switch (proxy.type) {
@@ -27,8 +19,6 @@ export default function Surge_Producer() {
return socks5(proxy);
case 'snell':
return snell(proxy);
case 'tuic':
return tuic(proxy);
}
throw new Error(
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
@@ -65,10 +55,6 @@ function shadowsocks(proxy) {
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}
@@ -101,10 +87,6 @@ function trojan(proxy) {
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}
@@ -145,9 +127,6 @@ function vmess(proxy) {
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}
@@ -176,10 +155,6 @@ function http(proxy) {
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}
@@ -210,10 +185,6 @@ function socks5(proxy) {
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}
@@ -225,67 +196,20 @@ function snell(proxy) {
// obfs
result.appendIfPresent(
`,obfs=${proxy['obfs-opts']?.mode}`,
`,obfs=${proxy['obfs-opts'].mode}`,
'obfs-opts.mode',
);
result.appendIfPresent(
`,obfs-host=${proxy['obfs-opts']?.host}`,
`,obfs-host=${proxy['obfs-opts'].host}`,
'obfs-opts.host',
);
result.appendIfPresent(
`,obfs-uri=${proxy['obfs-opts']?.path}`,
`,obfs-uri=${proxy['obfs-opts'].path}`,
'obfs-opts.path',
);
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
// reuse
result.appendIfPresent(`,reuse=${proxy['reuse']}`, 'reuse');
return result.toString();
}
function tuic(proxy) {
const result = new Result(proxy);
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
let type = proxy.type;
if (!proxy.token || proxy.token.length === 0) {
type = 'tuic-v5';
}
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,uuid=${proxy.uuid}`, 'uuid');
result.appendIfPresent(`,password=${proxy.password}`, 'password');
result.appendIfPresent(`,token=${proxy.token}`, 'token');
result.appendIfPresent(
`,alpn=${Array.isArray(proxy.alpn) ? proxy.alpn[0] : proxy.alpn}`,
'alpn',
);
result.appendIfPresent(
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
'ip-version',
);
// tls verification
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
result.appendIfPresent(
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
'skip-cert-verify',
);
// tfo
result.appendIfPresent(`,tfo=${proxy['fast-open']}`, 'fast-open');
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}

View File

@@ -1,12 +0,0 @@
/* eslint-disable no-case-declarations */
import { Base64 } from 'js-base64';
import URI_Producer from './uri';
const URI = URI_Producer();
export default function V2Ray_Producer() {
const type = 'ALL';
const produce = (proxies) =>
Base64.encode(proxies.map((proxy) => URI.produce(proxy)).join('\n'));
return { type, produce };
}

View File

@@ -131,12 +131,7 @@ async function deleteArtifact(req, res) {
files[encodeURIComponent(artifact.name)] = {
content: '',
};
// 当别的Sub 删了同步订阅 或 gist里面删了 当前设备没有删除 时 无法删除的bug
try {
await syncToGist(files);
} catch (i) {
$.error(`Function syncToGist: ${name} : ${i}`);
}
await syncToGist(files);
}
// delete local cache
deleteByName(allArtifacts, name);

View File

@@ -1,14 +1,13 @@
import { HTTP, ENV } from '@/vendor/open-api';
import { HTTP } from '@/vendor/open-api';
import { hex_md5 } from '@/vendor/md5';
import resourceCache from '@/utils/resource-cache';
const tasks = new Map();
export default async function download(url, ua) {
const { isNode } = ENV();
ua = ua || 'Quantumult%20X/1.0.29 (iPhone14,5; iOS 15.4.1)';
const id = hex_md5(ua + url);
if (!isNode && tasks.has(id)) {
if (tasks.has(id)) {
return tasks.get(id);
}
@@ -40,8 +39,6 @@ export default async function download(url, ua) {
}
});
if (!isNode) {
tasks.set(id, result);
}
tasks.set(id, result);
return result;
}

View File

@@ -40,10 +40,6 @@ export default class Gist {
}
async upload(files) {
if (Object.keys(files).length === 0) {
return Promise.reject('未提供需上传的文件');
}
const id = await this.locate();
if (id === -1) {

View File

@@ -16,13 +16,8 @@ class ResourceCache {
let clear = false;
Object.entries(this.resourceCache).forEach((entry) => {
const [id, updated] = entry;
if (!updated.time) {
// clear old version cache
delete this.resourceCache[id];
if (new Date().getTime() - updated > this.expires) {
$.delete(`#${id}`);
clear = true;
}
if (new Date().getTime() - updated.time > this.expires) {
delete this.resourceCache[id];
clear = true;
}
@@ -31,6 +26,9 @@ class ResourceCache {
}
revokeAll() {
Object.keys(this.resourceCache).forEach((id) => {
$.delete(`#${id}`);
});
this.resourceCache = {};
this._persist();
}
@@ -40,16 +38,17 @@ class ResourceCache {
}
get(id) {
const updated = this.resourceCache[id] && this.resourceCache[id].time;
const updated = this.resourceCache[id];
if (updated && new Date().getTime() - updated <= this.expires) {
return this.resourceCache[id].data;
return $.read(`#${id}`);
}
return null;
}
set(id, value) {
this.resourceCache[id] = { time: new Date().getTime(), data: value }
this.resourceCache[id] = new Date().getTime();
this._persist();
$.write(value, `#${id}`);
}
}

View File

@@ -1,105 +0,0 @@
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();

View File

@@ -4,16 +4,12 @@
#!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

View File

@@ -1,12 +0,0 @@
#!name=Sub-Store
#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用原版
[MITM]
hostname = %APPEND% sub.store
[Script]
# 主程序 已经去掉 Sub-Store Core 的参数 [,ability=http-client-policy] 不会爆内存,这个参数在 Surge 非常占用内存; 如果不需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 则可以使用此脚本
Sub-Store Core=type=http-request,pattern=^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
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js

View File

@@ -17,13 +17,8 @@ class ResourceCache {
let clear = false;
Object.entries(this.resourceCache).forEach((entry) => {
const [id, updated] = entry;
if (!updated.time) {
// clear old version cache
delete this.resourceCache[id];
if (new Date().getTime() - updated > this.expires) {
$.delete(`#${id}`);
clear = true;
}
if (new Date().getTime() - updated.time > this.expires) {
delete this.resourceCache[id];
clear = true;
}
@@ -32,6 +27,9 @@ class ResourceCache {
}
revokeAll() {
Object.keys(this.resourceCache).forEach((id) => {
$.delete(`#${id}`);
});
this.resourceCache = {};
this._persist();
}
@@ -41,16 +39,17 @@ class ResourceCache {
}
get(id) {
const updated = this.resourceCache[id] && this.resourceCache[id].time;
const updated = this.resourceCache[id];
if (updated && new Date().getTime() - updated <= this.expires) {
return this.resourceCache[id].data;
return $.read(`#${id}`);
}
return null;
}
set(id, value) {
this.resourceCache[id] = { time: new Date().getTime(), data: value }
this.resourceCache[id] = new Date().getTime();
this._persist();
$.write(value, `#${id}`);
}
}