Skip to content

Commit

Permalink
feat: 在 Now 平台上开启文件缓存,加快启动速度
Browse files Browse the repository at this point in the history
  • Loading branch information
geekdada committed Nov 23, 2019
1 parent 88164af commit 4456d2e
Show file tree
Hide file tree
Showing 6 changed files with 435 additions and 15 deletions.
54 changes: 40 additions & 14 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import URLSafeBase64 from 'urlsafe-base64';
import YAML from 'yaml';
import os from 'os';
import Debug from 'debug';
import crypto from 'crypto';

import {
CommandConfig,
Expand All @@ -35,6 +36,7 @@ import {
import { validateFilter } from './filter';
import { parseSSRUri } from './ssr';
import { OBFS_UA, NETWORK_TIMEOUT, NETWORK_CONCURRENCY, PROXY_TEST_URL, PROXY_TEST_INTERVAL } from './constant';
import { createTmpFactory } from './tmp-helper';
import { formatVmessUri } from './v2ray';

const debug = Debug('surgio:utils');
Expand Down Expand Up @@ -1125,20 +1127,44 @@ export const loadRemoteSnippetList = (remoteSnippetList: ReadonlyArray<RemoteSni
}

return Bluebird.map(remoteSnippetList, item => {
const res = ConfigCache.has(item.url)
? Promise.resolve(ConfigCache.get(item.url)) :
load(item.url)
.then(str => {
ConfigCache.set(item.url, str);
return str;
});

return res.then(str => ({
main: (rule: string) => addProxyToSurgeRuleSet(str, rule),
name: item.name,
url: item.url,
text: str, // 原始内容
}));
const tmpFactory = createTmpFactory('remote-snippets');
const fileMd5 = crypto.createHash('md5').update(item.url).digest('hex');

return (async () => {
if (process.env.NOW_REGION) {
const tmp = tmpFactory(fileMd5, 1000 * 60 * 60);
let snippet;

if (await tmp.getContent()) {
snippet = await tmp.getContent();
} else {
snippet = await load(item.url);
await tmp.setContent(snippet);
}

return {
main: (rule: string) => addProxyToSurgeRuleSet(snippet, rule),
name: item.name,
url: item.url,
text: snippet, // 原始内容
};
} else {
const res = ConfigCache.has(item.url)
? ConfigCache.get(item.url) :
load(item.url)
.then(str => {
ConfigCache.set(item.url, str);
return str;
});

return res.then(str => ({
main: (rule: string) => addProxyToSurgeRuleSet(str, rule),
name: item.name,
url: item.url,
text: str, // 原始内容
}));
}
})();
}, {
concurrency: NETWORK_CONCURRENCY,
});
Expand Down
72 changes: 72 additions & 0 deletions lib/utils/tmp-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os from 'os';
import path from 'path';
import fs from 'fs-extra';
import Debug from 'debug';

const debug = Debug('surgio:utils:tmp-helper');
const tmpDir = path.join(os.tmpdir(), 'surgio-config');

debug('tmpDir: %s', tmpDir);

export class TmpFile {
public filename: string;
public extname: string;

constructor(public filePath: string, public maxAge?: number) {
this.filename = path.basename(filePath);
this.extname = path.extname(filePath);

fs.accessSync(path.dirname(this.filePath), fs.constants.W_OK);
}

public async setContent(content: string): Promise<this> {
const lastEditTime = new Date();
await fs.writeJson(this.filePath, {
content,
maxAge: this.maxAge,
lastEditTime: lastEditTime.getTime(),
});

return this;
}

public async getContent(): Promise<string> {
const tmpContent = await this.validateContent();
if (tmpContent) {
return tmpContent.content;
}
return undefined;
}

private async validateContent(): Promise<TmpContent> {
if (!fs.existsSync(this.filePath)) {
return undefined;
}

const tmpContent: TmpContent = await fs.readJson(this.filePath);
const now = Date.now();

if (!tmpContent.maxAge) {
return tmpContent;
} else if (this.maxAge && now - tmpContent.lastEditTime < this.maxAge) {
return tmpContent;
} else if (!this.maxAge && tmpContent.maxAge) {
this.maxAge = tmpContent.maxAge;
}

return undefined;
}
}

export interface TmpContent { readonly content: string, readonly lastEditTime: number, readonly maxAge?: number }

export const createTmpFactory = (baseDir: string): ((filePath: string, maxAge?: number) => TmpFile) => {
// tslint:disable-next-line:no-parameter-reassignment
baseDir = path.join(tmpDir, baseDir);

if (!fs.existsSync(baseDir)) {
fs.mkdirpSync(baseDir);
}

return (filePath: string, maxAge?: number) => new TmpFile(path.join(baseDir, filePath), maxAge);
};
32 changes: 31 additions & 1 deletion test/utils/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ test('getShadowsocksJSONConfig', async t => {
});
});

test('loadRemoteSnippetList', async t => {
test.serial('loadRemoteSnippetList', async t => {
const remoteSnippetList = await utils.loadRemoteSnippetList([
{
url: 'http://example.com/telegram.list',
Expand All @@ -480,6 +480,36 @@ test('loadRemoteSnippetList', async t => {
t.snapshot(remoteSnippetList[3].main('Proxy'));
});

test.serial('loadRemoteSnippetList in now', async t => {
process.env.NOW_REGION = 'dev_1';

const remoteSnippetList = await utils.loadRemoteSnippetList([
{
url: 'http://example.com/telegram.list',
name: 'telegram',
},
{
url: 'http://example.com/netflix.list',
name: 'netflix',
},
{
url: 'http://example.com/test-ruleset.list',
name: 'test',
},
{
url: 'http://example.com/ForeignMedia.list',
name: 'ForeignMedia',
},
]);

t.snapshot(remoteSnippetList[0].main('Proxy'));
t.snapshot(remoteSnippetList[1].main('Proxy'));
t.snapshot(remoteSnippetList[2].main('Proxy'));
t.snapshot(remoteSnippetList[3].main('Proxy'));

process.env.NOW_REGION = null;
});

test('loadRemoteSnippetList with error', async t => {
t.plan(1);
try {
Expand Down
Loading

0 comments on commit 4456d2e

Please sign in to comment.