Skip to content

Commit f589a83

Browse files
committed
feat(gateway): 支持批量转换 rewrite-remote 中的 URL
1 parent 680b209 commit f589a83

File tree

7 files changed

+367
-201
lines changed

7 files changed

+367
-201
lines changed

lib/gateway/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const createKoaApp = (surgioServer: SurgioServer): SurgioKoaApplication =
5353
router.get('/get-artifact/:name', authMiddleware(), prepareArtifact(), surgioServer.koaGetArtifact.bind(surgioServer));
5454
router.get('/list-artifact', authMiddleware(), surgioServer.koaListArtifact.bind(surgioServer));
5555
router.get('/qx-script', surgioServer.processQuanXScript.bind(surgioServer));
56+
router.get('/qx-rewrite-remote', surgioServer.processQuanXRewriteRemote.bind(surgioServer));
5657
router.get('/robot.txt', ctx => {
5758
ctx.body = 'User-agent: *\n' +
5859
'Disallow: /';

lib/gateway/server.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import path from "path";
88
import { PackageJson } from 'type-fest';
99
import legacyUrl from 'url';
1010
import axios from 'axios';
11+
import { transformQxRewriteRemote } from '../utils/qx-helper';
1112
import TransfromScript from './utils/transform-script';
1213

1314
import getEngine from '../template';
@@ -161,17 +162,60 @@ export class Server {
161162
responseType: 'stream',
162163
})
163164
.catch(err => {
164-
throw createError(400, `请求文件时出错: ${err.message}`);
165+
throw createError(500, `请求文件时出错: ${err.message}`);
165166
});
167+
const contentType: string = content.headers['content-type'];
168+
169+
if (
170+
!contentType.includes('text/plain') ||
171+
!contentType.includes('application/javascript')
172+
) {
173+
ctx.throw(400, '该文件不是一个可转换的脚本文件');
174+
return;
175+
}
166176

167177
const body = new TransfromScript(deviceIds);
168178

169179
content.data.pipe(body);
170180

171-
ctx.set('cache-control', 'max-age=3600');
181+
ctx.set('content-disposition', 'attachment;filename=script.js');
182+
ctx.set('cache-control', 'max-age=3600, s-maxage=3600');
172183
ctx.body = body;
173184
}
174185

186+
public async processQuanXRewriteRemote(ctx: Context): Promise<void> {
187+
const { url, id: idFromUrl } = ctx.query;
188+
const deviceIds = idFromUrl ? idFromUrl.split(',') : undefined;
189+
const publicUrl = this.config.publicUrl;
190+
191+
if (!url) {
192+
ctx.throw(400, 'invalid url');
193+
return;
194+
}
195+
196+
const content = await axios.request<string>({
197+
url,
198+
method: 'get',
199+
responseType: 'text',
200+
})
201+
.catch(err => {
202+
throw createError(500, `请求文件时出错: ${err.message}`);
203+
});
204+
const contentType: string = content.headers['content-type'];
205+
206+
if (
207+
!contentType.includes('text/plain')
208+
) {
209+
ctx.throw(400, '该文件不是一个可转换的文件');
210+
return;
211+
}
212+
213+
ctx.set('content-type', contentType);
214+
ctx.set('cache-control', 'max-age=3600, s-maxage=3600');
215+
ctx.set('content-disposition', 'attachment;filename=rewrite-remote.conf');
216+
ctx.body = transformQxRewriteRemote(content.data, publicUrl, deviceIds);
217+
}
218+
175219
// istanbul ignore next
176220
public fcErrorHandler(response: FcResponse, err: Error): void {
177221
response.setStatusCode(500);

lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export interface CommandConfig {
4949
};
5050
readonly gateway?: {
5151
readonly accessToken?: string;
52-
readonly auth?: boolean;
52+
auth?: boolean; // tslint:disable-line:readonly-keyword
5353
},
5454
readonly proxyTestUrl?: string;
5555
readonly proxyTestInterval?: number;

lib/utils/qx-helper.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { URL } from 'url';
2+
3+
export const transformQxRewriteRemote = (str: string, publicUrl: string, deviceIds?: ReadonlyArray<string>): string => {
4+
return str.split('\n')
5+
.map(item => {
6+
if (
7+
item.startsWith('#') ||
8+
item.startsWith('//') ||
9+
item.trim() === ''
10+
) {
11+
return item;
12+
}
13+
14+
const rule = item.split(' ');
15+
16+
if (rule.indexOf('script-response-body') > -1) {
17+
const scriptPath = rule[3];
18+
const apiEndpoint = new URL(publicUrl);
19+
apiEndpoint.pathname = '/qx-script';
20+
apiEndpoint.searchParams.set('url', `${scriptPath}`);
21+
22+
if (deviceIds) {
23+
apiEndpoint.searchParams.set('id', deviceIds.join(','));
24+
}
25+
26+
rule[3] = apiEndpoint.toString();
27+
28+
return rule.join(' ');
29+
}
30+
31+
return item;
32+
})
33+
.join('\n')
34+
};

test/gateway/index.test.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ test('auth', async t => {
150150
const surgioServer = gateway.createSurgioServer(fixture);
151151
const app = gateway.createKoaApp(surgioServer);
152152

153-
// @ts-ignore
154153
app.surgioConfig.gateway.auth = true;
155154

156155
await request(app.callback())
@@ -171,13 +170,17 @@ test('qx-script', async t => {
171170
const app = gateway.createKoaApp(surgioServer);
172171

173172
const res1 = await request(app.callback())
174-
.get('/qx-script?url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js');
173+
.get('/qx-script?url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js')
174+
.expect(200);
175175
const res2 = await request(app.callback())
176-
.get('/qx-script?id=abcdef&url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js');
176+
.get('/qx-script?id=abcdef&url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js')
177+
.expect(200);
177178
const res3 = await request(app.callback())
178-
.get('/qx-script?id=abcdef,bcdefg&url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js');
179+
.get('/qx-script?id=abcdef,bcdefg&url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js')
180+
.expect(200);
179181
const res4 = await request(app.callback())
180-
.get('/qx-script?id=abcdef&url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js');
182+
.get('/qx-script?id=abcdef&url=https%3A%2F%2Fraw.githubusercontent.com%2Fcrossutility%2FQuantumult-X%2Fmaster%2Fsample-rewrite-with-script.js')
183+
.expect(200);
181184

182185
t.snapshot(res1.body.toString());
183186
t.snapshot(res2.body.toString());
@@ -192,11 +195,37 @@ test('qx-script error', async t => {
192195

193196
await request(app.callback())
194197
.get('/qx-script?url=http://example.com/error')
195-
.expect(400);
198+
.expect(500);
196199

197200
await request(app.callback())
198201
.get('/qx-script')
199202
.expect(400);
200203

201204
t.pass();
202205
});
206+
207+
test.only('qx-rewrite-remote', async t => {
208+
const fixture = path.join(__dirname, '../fixture/gateway');
209+
const surgioServer = gateway.createSurgioServer(fixture);
210+
const app = gateway.createKoaApp(surgioServer);
211+
212+
const res = await request(app.callback())
213+
.get('/qx-rewrite-remote?url=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js.conf')
214+
.expect(200)
215+
.expect('content-type', 'text/plain; charset=utf-8')
216+
.expect('cache-control', 'max-age=3600, s-maxage=3600');
217+
218+
t.snapshot(res.text);
219+
});
220+
221+
test.only('qx-rewrite-remote with id', async t => {
222+
const fixture = path.join(__dirname, '../fixture/gateway');
223+
const surgioServer = gateway.createSurgioServer(fixture);
224+
const app = gateway.createKoaApp(surgioServer);
225+
226+
const res = await request(app.callback())
227+
.get('/qx-rewrite-remote?id=abcde,fghijk&url=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js.conf')
228+
.expect(200);
229+
230+
t.snapshot(res.text);
231+
});

0 commit comments

Comments
 (0)