@juzi/file-box 1.8.0 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cjs/src/config.d.ts +5 -4
- package/dist/cjs/src/config.d.ts.map +1 -1
- package/dist/cjs/src/config.js +7 -7
- package/dist/cjs/src/config.js.map +1 -1
- package/dist/cjs/src/file-box.js +1 -1
- package/dist/cjs/src/file-box.js.map +1 -1
- package/dist/cjs/src/misc.d.ts.map +1 -1
- package/dist/cjs/src/misc.js +100 -83
- package/dist/cjs/src/misc.js.map +1 -1
- package/dist/cjs/src/misc.spec.js +6 -0
- package/dist/cjs/src/misc.spec.js.map +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/tests/chunk-download.spec.js +12 -56
- package/dist/cjs/tests/chunk-download.spec.js.map +1 -1
- package/dist/cjs/tests/misc-error-handling.spec.js +36 -26
- package/dist/cjs/tests/misc-error-handling.spec.js.map +1 -1
- package/dist/cjs/tests/network-timeout.spec.js +101 -118
- package/dist/cjs/tests/network-timeout.spec.js.map +1 -1
- package/dist/esm/src/config.d.ts +5 -4
- package/dist/esm/src/config.d.ts.map +1 -1
- package/dist/esm/src/config.js +6 -6
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/file-box.js +2 -2
- package/dist/esm/src/file-box.js.map +1 -1
- package/dist/esm/src/misc.d.ts.map +1 -1
- package/dist/esm/src/misc.js +101 -84
- package/dist/esm/src/misc.js.map +1 -1
- package/dist/esm/src/misc.spec.js +6 -0
- package/dist/esm/src/misc.spec.js.map +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/esm/tests/chunk-download.spec.js +12 -56
- package/dist/esm/tests/chunk-download.spec.js.map +1 -1
- package/dist/esm/tests/misc-error-handling.spec.js +36 -26
- package/dist/esm/tests/misc-error-handling.spec.js.map +1 -1
- package/dist/esm/tests/network-timeout.spec.js +103 -120
- package/dist/esm/tests/network-timeout.spec.js.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +6 -9
- package/src/file-box.ts +2 -2
- package/src/misc.spec.ts +7 -0
- package/src/misc.ts +112 -88
- package/src/version.ts +1 -1
|
@@ -1,136 +1,119 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
2
|
import { createServer } from 'http';
|
|
3
3
|
import { setTimeout } from 'timers/promises';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { test } from 'tstest';
|
|
5
|
+
import { CONFIG } from '../src/config.js';
|
|
6
6
|
import { FileBox } from '../src/mod.js';
|
|
7
|
-
test('
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
test('HTTP timeout handling', async (t) => {
|
|
8
|
+
// 设置短超时用于快速测试
|
|
9
|
+
const originalRequestTimeout = CONFIG.HTTP_REQUEST_TIMEOUT;
|
|
10
|
+
const originalResponseTimeout = CONFIG.HTTP_RESPONSE_TIMEOUT;
|
|
11
|
+
CONFIG.HTTP_REQUEST_TIMEOUT = 200; // 200ms
|
|
12
|
+
CONFIG.HTTP_RESPONSE_TIMEOUT = 300; // 300ms
|
|
13
|
+
t.teardown(() => {
|
|
14
|
+
CONFIG.HTTP_REQUEST_TIMEOUT = originalRequestTimeout;
|
|
15
|
+
CONFIG.HTTP_RESPONSE_TIMEOUT = originalResponseTimeout;
|
|
14
16
|
});
|
|
15
|
-
t.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/* eslint @typescript-eslint/no-misused-promises:off */
|
|
23
|
-
const server = createServer(async (req, res) => {
|
|
24
|
-
if (req.method === 'HEAD') {
|
|
25
|
-
res.writeHead(200, {
|
|
26
|
-
'Content-Length': '100',
|
|
27
|
-
});
|
|
28
|
-
res.end();
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
res.write(Buffer.from('This is the first chunk of data.'));
|
|
32
|
-
if (req.url === URL.NOT_TIMEOUT) {
|
|
33
|
-
await setTimeout(HTTP_REQUEST_TIMEOUT * 0.5);
|
|
34
|
-
res.write(Buffer.from('This is the second chunk of data.'));
|
|
35
|
-
}
|
|
36
|
-
else if (req.url === URL.READY) {
|
|
37
|
-
await setTimeout(HTTP_REQUEST_TIMEOUT + 100);
|
|
38
|
-
}
|
|
39
|
-
else if (req.url === URL.TIMEOUT) {
|
|
40
|
-
if (req.method === 'GET') {
|
|
41
|
-
await setTimeout(HTTP_RESPONSE_TIMEOUT + 100);
|
|
17
|
+
await t.test('should complete download without timeout', async (t) => {
|
|
18
|
+
const testData = 'Test data for no timeout';
|
|
19
|
+
const server = createServer((req, res) => {
|
|
20
|
+
if (req.method === 'HEAD') {
|
|
21
|
+
res.writeHead(200, { 'Content-Length': String(testData.length) });
|
|
22
|
+
res.end();
|
|
23
|
+
return;
|
|
42
24
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const host = await new Promise((resolve) => {
|
|
48
|
-
server.listen(port, '127.0.0.1', () => {
|
|
49
|
-
const addr = server.address();
|
|
50
|
-
// console.debug(`Server is listening on port ${JSON.stringify(addr)}`)
|
|
51
|
-
resolve(`http://127.0.0.1:${addr.port}`);
|
|
25
|
+
// 服务器不支持 Range,直接返回 200
|
|
26
|
+
// 快速响应,不应该超时
|
|
27
|
+
res.writeHead(200, { 'Content-Length': String(testData.length) });
|
|
28
|
+
res.end(testData);
|
|
52
29
|
});
|
|
53
|
-
});
|
|
54
|
-
t.teardown(() => {
|
|
55
|
-
// console.debug('teardown')
|
|
56
|
-
server.close();
|
|
57
|
-
sandbox.restore();
|
|
58
|
-
});
|
|
59
|
-
/** eslint @typescript-eslint/no-floating-promises:off */
|
|
60
|
-
t.test('should not timeout', async (t) => {
|
|
61
|
-
const url = `${host}${URL.NOT_TIMEOUT}`;
|
|
62
|
-
const dataSpy = sandbox.spy();
|
|
63
|
-
const errorSpy = sandbox.spy();
|
|
64
|
-
// Disable chunked download for timeout tests
|
|
65
|
-
process.env['FILEBOX_NO_SLICE_DOWN'] = 'true';
|
|
66
|
-
// console.debug(`${new Date().toLocaleTimeString()} Start request "${url}" ...`)
|
|
67
|
-
const start = Date.now();
|
|
68
|
-
const stream = await FileBox.fromUrl(url).toStream();
|
|
69
|
-
stream.once('error', errorSpy).on('data', dataSpy);
|
|
70
|
-
await sandbox.clock.tickAsync(1);
|
|
71
|
-
t.ok(dataSpy.calledOnce, `should get chunk 1 (${Date.now() - start} passed)`);
|
|
72
|
-
t.ok(errorSpy.notCalled, `should not get error (${Date.now() - start} passed)`);
|
|
73
|
-
// FIXME: tickAsync does not work on socket timeout
|
|
74
30
|
await new Promise((resolve) => {
|
|
75
|
-
|
|
76
|
-
// resolve(setTimeout(HTTP_REQUEST_TIMEOUT))
|
|
31
|
+
server.listen(0, '127.0.0.1', resolve);
|
|
77
32
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
33
|
+
const port = server.address().port;
|
|
34
|
+
t.teardown(() => { server.close(); });
|
|
35
|
+
const url = `http://127.0.0.1:${port}/test`;
|
|
36
|
+
const fileBox = FileBox.fromUrl(url);
|
|
37
|
+
const stream = await fileBox.toStream();
|
|
38
|
+
const chunks = [];
|
|
39
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
40
|
+
await new Promise((resolve, reject) => {
|
|
41
|
+
stream.on('end', resolve);
|
|
42
|
+
stream.on('error', reject);
|
|
43
|
+
});
|
|
44
|
+
const result = Buffer.concat(chunks).toString();
|
|
45
|
+
t.equal(result, testData, 'should receive complete data');
|
|
84
46
|
t.end();
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// })
|
|
100
|
-
// .on('data', (d: Buffer) => {
|
|
101
|
-
// console.error(`on data for req "${url}":`, d.toString())
|
|
102
|
-
// })
|
|
103
|
-
await sandbox.clock.tickAsync(1);
|
|
104
|
-
// t.comment('recv data count:', dataSpy.callCount)
|
|
105
|
-
// t.comment('recv error count:', errorSpy.callCount)
|
|
106
|
-
t.ok(dataSpy.calledOnce, `should get chunk 1 (${Date.now() - start} passed)`);
|
|
107
|
-
t.ok(errorSpy.notCalled, `should not get error (${Date.now() - start} passed)`);
|
|
108
|
-
// FIXME: tickAsync does not work on socket timeout
|
|
47
|
+
});
|
|
48
|
+
await t.test('should handle response timeout', async (t) => {
|
|
49
|
+
const server = createServer((req, res) => {
|
|
50
|
+
if (req.method === 'HEAD') {
|
|
51
|
+
res.writeHead(200, { 'Content-Length': '100' });
|
|
52
|
+
res.end();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// 发送部分数据后停止,不调用 res.end()
|
|
56
|
+
// 让连接挂起,Socket 会在 HTTP_RESPONSE_TIMEOUT 后超时
|
|
57
|
+
res.writeHead(200, { 'Content-Length': '100' });
|
|
58
|
+
res.write('Partial data...');
|
|
59
|
+
// 不调用 res.end()
|
|
60
|
+
});
|
|
109
61
|
await new Promise((resolve) => {
|
|
110
|
-
|
|
111
|
-
// resolve(setTimeout(HTTP_RESPONSE_TIMEOUT))
|
|
62
|
+
server.listen(0, '127.0.0.1', resolve);
|
|
112
63
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
64
|
+
const port = server.address().port;
|
|
65
|
+
t.teardown(() => { server.close(); });
|
|
66
|
+
const url = `http://127.0.0.1:${port}/timeout`;
|
|
67
|
+
try {
|
|
68
|
+
const fileBox = FileBox.fromUrl(url);
|
|
69
|
+
const stream = await fileBox.toStream();
|
|
70
|
+
const chunks = [];
|
|
71
|
+
await new Promise((resolve, reject) => {
|
|
72
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
73
|
+
stream.on('end', resolve);
|
|
74
|
+
stream.on('error', reject);
|
|
75
|
+
});
|
|
76
|
+
t.fail('should have thrown timeout error');
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const err = error;
|
|
80
|
+
t.ok(err.message.includes('timeout'), `should timeout with error: ${err.message}`);
|
|
81
|
+
}
|
|
118
82
|
t.end();
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
83
|
+
});
|
|
84
|
+
await t.test('should handle request timeout', async (t) => {
|
|
85
|
+
let requestReceived = false;
|
|
86
|
+
/* eslint @typescript-eslint/no-misused-promises:off */
|
|
87
|
+
const server = createServer(async (req, res) => {
|
|
88
|
+
if (req.method === 'HEAD') {
|
|
89
|
+
res.writeHead(200, { 'Content-Length': '100' });
|
|
90
|
+
res.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
requestReceived = true;
|
|
94
|
+
// 延迟响应超过 HTTP_REQUEST_TIMEOUT
|
|
95
|
+
// 在发送任何数据之前延迟,触发 request timeout
|
|
96
|
+
await setTimeout(CONFIG.HTTP_REQUEST_TIMEOUT + 100);
|
|
97
|
+
res.writeHead(200, { 'Content-Length': '10' });
|
|
98
|
+
res.end('Too late');
|
|
99
|
+
});
|
|
100
|
+
await new Promise((resolve) => {
|
|
101
|
+
server.listen(0, '127.0.0.1', resolve);
|
|
102
|
+
});
|
|
103
|
+
const port = server.address().port;
|
|
104
|
+
t.teardown(() => { server.close(); });
|
|
105
|
+
const url = `http://127.0.0.1:${port}/request-timeout`;
|
|
106
|
+
try {
|
|
107
|
+
const fileBox = FileBox.fromUrl(url);
|
|
108
|
+
await fileBox.toStream();
|
|
109
|
+
t.fail('should have thrown timeout error');
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
const err = error;
|
|
113
|
+
t.ok(requestReceived, 'should have received request');
|
|
114
|
+
t.ok(err.message.includes('timeout'), `should timeout with error: ${err.message}`);
|
|
115
|
+
}
|
|
133
116
|
t.end();
|
|
134
|
-
})
|
|
117
|
+
});
|
|
135
118
|
});
|
|
136
119
|
//# sourceMappingURL=network-timeout.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-timeout.spec.js","sourceRoot":"","sources":["../../../tests/network-timeout.spec.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"network-timeout.spec.js","sourceRoot":"","sources":["../../../tests/network-timeout.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/// <reference path="./typings.d.ts" />
|
|
2
2
|
export { VERSION } from './version.js'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export const NO_SLICE_DOWN = process.env['FILEBOX_NO_SLICE_DOWN'] === 'true'
|
|
11
|
-
|
|
12
|
-
export const READY_RETRY = Number(process.env['FILE_BOX_READY_RETRY']) || 3
|
|
4
|
+
// 导出可变配置对象,支持测试时动态修改
|
|
5
|
+
export const CONFIG = {
|
|
6
|
+
HTTP_REQUEST_TIMEOUT: Number(process.env['FILEBOX_HTTP_REQUEST_TIMEOUT']) || 10 * 1000,
|
|
7
|
+
HTTP_RESPONSE_TIMEOUT: Number(process.env['FILEBOX_HTTP_RESPONSE_TIMEOUT'] ?? process.env['FILEBOX_HTTP_TIMEOUT']) || 60 * 1000,
|
|
8
|
+
READY_RETRY: Number(process.env['FILEBOX_READY_RETRY'] ?? process.env['FILE_BOX_READY_RETRY']) || 3,
|
|
9
|
+
}
|
package/src/file-box.ts
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
} from 'clone-class'
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
|
-
|
|
28
|
+
CONFIG,
|
|
29
29
|
VERSION,
|
|
30
30
|
} from './config.js'
|
|
31
31
|
import {
|
|
@@ -637,7 +637,7 @@ class FileBox implements Pipeable, FileBoxInterface {
|
|
|
637
637
|
break
|
|
638
638
|
} catch (e) {
|
|
639
639
|
tryCount++
|
|
640
|
-
if (tryCount >= READY_RETRY) {
|
|
640
|
+
if (tryCount >= CONFIG.READY_RETRY) {
|
|
641
641
|
throw e
|
|
642
642
|
}
|
|
643
643
|
}
|
package/src/misc.spec.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { createServer } from 'http'
|
|
|
5
5
|
import type { AddressInfo } from 'net'
|
|
6
6
|
import { test } from 'tstest'
|
|
7
7
|
|
|
8
|
+
import { CONFIG } from './config.js'
|
|
8
9
|
import {
|
|
9
10
|
dataUrlToBase64,
|
|
10
11
|
httpHeaderToFileName,
|
|
@@ -13,6 +14,10 @@ import {
|
|
|
13
14
|
streamToBuffer,
|
|
14
15
|
} from './misc.js'
|
|
15
16
|
|
|
17
|
+
// 设置短超时用于测试
|
|
18
|
+
CONFIG.HTTP_REQUEST_TIMEOUT = 1000
|
|
19
|
+
CONFIG.HTTP_RESPONSE_TIMEOUT = 1000
|
|
20
|
+
|
|
16
21
|
test('dataUrl to base64', async t => {
|
|
17
22
|
const base64 = [
|
|
18
23
|
'R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl',
|
|
@@ -97,6 +102,8 @@ test('httpStream', async t => {
|
|
|
97
102
|
return
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
// This server doesn't support Range, always return 200 with full content
|
|
106
|
+
// (ignoring any Range header)
|
|
100
107
|
res.writeHead(200, {
|
|
101
108
|
'Content-Length': String(content.length),
|
|
102
109
|
'Content-Type': 'application/json',
|