@juzi/file-box 1.7.3 → 1.7.5
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 +5 -1
- package/dist/cjs/src/config.d.ts +3 -1
- package/dist/cjs/src/config.d.ts.map +1 -1
- package/dist/cjs/src/config.js +5 -2
- package/dist/cjs/src/config.js.map +1 -1
- package/dist/cjs/src/file-box.spec.js +2 -1
- package/dist/cjs/src/file-box.spec.js.map +1 -1
- package/dist/cjs/src/misc.d.ts +1 -1
- package/dist/cjs/src/misc.d.ts.map +1 -1
- package/dist/cjs/src/misc.js +103 -189
- package/dist/cjs/src/misc.js.map +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/tests/network-timeout.spec.js +14 -14
- package/dist/cjs/tests/network-timeout.spec.js.map +1 -1
- package/dist/esm/src/config.d.ts +3 -1
- package/dist/esm/src/config.d.ts.map +1 -1
- package/dist/esm/src/config.js +4 -1
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/file-box.spec.js +2 -1
- package/dist/esm/src/file-box.spec.js.map +1 -1
- package/dist/esm/src/misc.d.ts +1 -1
- package/dist/esm/src/misc.d.ts.map +1 -1
- package/dist/esm/src/misc.js +104 -190
- package/dist/esm/src/misc.js.map +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/esm/tests/network-timeout.spec.js +14 -14
- package/dist/esm/tests/network-timeout.spec.js.map +1 -1
- package/package.json +5 -2
- package/src/config.ts +6 -1
- package/src/misc.ts +113 -227
- package/src/version.ts +1 -1
package/dist/esm/src/misc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../src/misc.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../src/misc.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/src/version.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createServer } from 'http';
|
|
3
3
|
import { setTimeout } from 'timers/promises';
|
|
4
4
|
import { sinon, test } from 'tstest';
|
|
5
|
+
import { HTTP_REQUEST_TIMEOUT, HTTP_RESPONSE_TIMEOUT } from '../src/config.js';
|
|
5
6
|
import { FileBox } from '../src/mod.js';
|
|
6
|
-
import { HTTP_TIMEOUT } from '../src/config.js';
|
|
7
7
|
test('slow network stall HTTP_TIMEOUT', async (t) => {
|
|
8
8
|
const sandbox = sinon.createSandbox();
|
|
9
9
|
sandbox.useFakeTimers({
|
|
@@ -23,15 +23,15 @@ test('slow network stall HTTP_TIMEOUT', async (t) => {
|
|
|
23
23
|
const server = createServer(async (req, res) => {
|
|
24
24
|
res.write(Buffer.from('This is the first chunk of data.'));
|
|
25
25
|
if (req.url === URL.NOT_TIMEOUT) {
|
|
26
|
-
await setTimeout(
|
|
26
|
+
await setTimeout(HTTP_REQUEST_TIMEOUT * 0.5);
|
|
27
27
|
res.write(Buffer.from('This is the second chunk of data.'));
|
|
28
28
|
}
|
|
29
29
|
else if (req.url === URL.READY) {
|
|
30
|
-
await setTimeout(
|
|
30
|
+
await setTimeout(HTTP_REQUEST_TIMEOUT + 100);
|
|
31
31
|
}
|
|
32
32
|
else if (req.url === URL.TIMEOUT) {
|
|
33
33
|
if (req.method === 'GET') {
|
|
34
|
-
await setTimeout(
|
|
34
|
+
await setTimeout(HTTP_RESPONSE_TIMEOUT + 100);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
// console.debug(`${new Date().toLocaleTimeString()} call res.end "${req.url}"`)
|
|
@@ -64,14 +64,14 @@ test('slow network stall HTTP_TIMEOUT', async (t) => {
|
|
|
64
64
|
// FIXME: tickAsync does not work on socket timeout
|
|
65
65
|
await new Promise((resolve) => {
|
|
66
66
|
stream.once('error', resolve).on('close', resolve);
|
|
67
|
-
// resolve(setTimeout(
|
|
67
|
+
// resolve(setTimeout(HTTP_REQUEST_TIMEOUT))
|
|
68
68
|
});
|
|
69
69
|
await sandbox.clock.tickAsync(1);
|
|
70
|
-
// await sandbox.clock.tickAsync(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
t.ok(dataSpy.calledThrice, `should get chunk 3 after TIMEOUT ${
|
|
74
|
-
t.ok(errorSpy.notCalled, `should not get error after TIMEOUT ${
|
|
70
|
+
// await sandbox.clock.tickAsync(HTTP_RESPONSE_TIMEOUT)
|
|
71
|
+
t.comment('recv data count:', dataSpy.callCount);
|
|
72
|
+
t.comment('recv error count:', errorSpy.callCount);
|
|
73
|
+
t.ok(dataSpy.calledThrice, `should get chunk 3 after TIMEOUT ${HTTP_REQUEST_TIMEOUT} (${Date.now() - start} passed)`);
|
|
74
|
+
t.ok(errorSpy.notCalled, `should not get error after TIMEOUT ${HTTP_REQUEST_TIMEOUT} (${Date.now() - start} passed)`);
|
|
75
75
|
t.end();
|
|
76
76
|
}).catch(t.threw);
|
|
77
77
|
/** eslint @typescript-eslint/no-floating-promises:off */
|
|
@@ -97,13 +97,13 @@ test('slow network stall HTTP_TIMEOUT', async (t) => {
|
|
|
97
97
|
// FIXME: tickAsync does not work on socket timeout
|
|
98
98
|
await new Promise((resolve) => {
|
|
99
99
|
stream.once('error', resolve).on('close', resolve);
|
|
100
|
-
// resolve(setTimeout(
|
|
100
|
+
// resolve(setTimeout(HTTP_RESPONSE_TIMEOUT))
|
|
101
101
|
});
|
|
102
102
|
await sandbox.clock.tickAsync(1);
|
|
103
|
-
// await sandbox.clock.tickAsync(
|
|
103
|
+
// await sandbox.clock.tickAsync(HTTP_RESPONSE_TIMEOUT)
|
|
104
104
|
// t.comment('recv data count:', dataSpy.callCount)
|
|
105
105
|
// t.comment('recv error count:', errorSpy.callCount)
|
|
106
|
-
t.ok(errorSpy.calledOnce, `should get error after TIMEOUT ${
|
|
106
|
+
t.ok(errorSpy.calledOnce, `should get error after TIMEOUT ${HTTP_RESPONSE_TIMEOUT} (${Date.now() - start} passed)`);
|
|
107
107
|
t.end();
|
|
108
108
|
}).catch(t.threw);
|
|
109
109
|
/** eslint @typescript-eslint/no-floating-promises:off */
|
|
@@ -116,7 +116,7 @@ test('slow network stall HTTP_TIMEOUT', async (t) => {
|
|
|
116
116
|
await fileBox.ready().catch(errorSpy);
|
|
117
117
|
await sandbox.clock.tickAsync(1);
|
|
118
118
|
// t.comment('recv error count:', errorSpy.callCount)
|
|
119
|
-
t.ok(errorSpy.calledOnce, `should get error after TIMEOUT ${
|
|
119
|
+
t.ok(errorSpy.calledOnce, `should get error after TIMEOUT ${HTTP_REQUEST_TIMEOUT} (${Date.now() - start} passed)`);
|
|
120
120
|
t.end();
|
|
121
121
|
}).catch(t.threw);
|
|
122
122
|
});
|
|
@@ -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,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAEpC,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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juzi/file-box",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.5",
|
|
4
4
|
"description": "Pack a File into Box for easy move/transfer between servers no matter of where it is.(local path, remote url, or cloud storage)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -52,12 +52,15 @@
|
|
|
52
52
|
"@chatie/tsconfig": "^4.6.2",
|
|
53
53
|
"@types/isomorphic-fetch": "0.0.35",
|
|
54
54
|
"@types/mime": "^2.0.3",
|
|
55
|
+
"@types/node": "^18.18.7",
|
|
55
56
|
"@types/qrcode": "^1.4.1",
|
|
56
57
|
"@types/uuid": "^8.3.3",
|
|
58
|
+
"eslint-plugin-n": "^16.2.0",
|
|
57
59
|
"gts": "^3.1.0",
|
|
58
60
|
"pkg-jq": "^0.2.11",
|
|
59
61
|
"read-pkg-up": "^8.0.0",
|
|
60
|
-
"reflect-metadata": "^0.1.13"
|
|
62
|
+
"reflect-metadata": "^0.1.13",
|
|
63
|
+
"tap": "^16.3.9"
|
|
61
64
|
},
|
|
62
65
|
"dependencies": {
|
|
63
66
|
"brolog": "^1.14.2",
|
package/src/config.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/// <reference path="./typings.d.ts" />
|
|
2
2
|
export { VERSION } from './version.js'
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const HTTP_REQUEST_TIMEOUT = Number(process.env['FILEBOX_HTTP_REQUEST_TIMEOUT'])
|
|
5
|
+
|| 10 * 1000
|
|
6
|
+
|
|
7
|
+
export const HTTP_RESPONSE_TIMEOUT = Number(process.env['FILEBOX_HTTP_RESPONSE_TIMEOUT'] ?? process.env['FILEBOX_HTTP_TIMEOUT'])
|
|
5
8
|
|| 60 * 1000
|
|
6
9
|
|
|
10
|
+
export const NO_SLICE_DOWN = process.env['FILEBOX_NO_SLICE_DOWN'] === 'true'
|
|
11
|
+
|
|
7
12
|
export const HTTP_CHUNK_SIZE = Number(process.env['FILEBOX_HTTP_CHUNK_SIZE'])
|
|
8
13
|
|| 1024 * 512
|
package/src/misc.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import { randomUUID } from 'crypto'
|
|
3
|
+
import { once } from 'events'
|
|
4
|
+
import { createReadStream, createWriteStream } from 'fs'
|
|
5
|
+
import { rm } from 'fs/promises'
|
|
6
|
+
import http from 'http'
|
|
7
|
+
import https from 'https'
|
|
8
|
+
import { tmpdir } from 'os'
|
|
9
|
+
import { join } from 'path'
|
|
10
|
+
import type { Readable } from 'stream'
|
|
3
11
|
import { URL } from 'url'
|
|
4
12
|
|
|
5
|
-
import {
|
|
13
|
+
import { HTTP_CHUNK_SIZE, HTTP_REQUEST_TIMEOUT, HTTP_RESPONSE_TIMEOUT, NO_SLICE_DOWN } from './config.js'
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
const protocolMap: {
|
|
16
|
+
[key: string]: { agent: http.Agent; request: typeof http.request }
|
|
17
|
+
} = {
|
|
18
|
+
'http:': { agent: http.globalAgent, request: http.request },
|
|
19
|
+
'https:': { agent: https.globalAgent, request: https.request },
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getProtocol (protocol: string) {
|
|
23
|
+
assert(protocolMap[protocol], new Error('unknown protocol: ' + protocol))
|
|
24
|
+
return protocolMap[protocol]!
|
|
25
|
+
}
|
|
8
26
|
|
|
9
27
|
export function dataUrlToBase64 (dataUrl: string): string {
|
|
10
28
|
const dataList = dataUrl.split(',')
|
|
@@ -18,7 +36,7 @@ export function dataUrlToBase64 (dataUrl: string): string {
|
|
|
18
36
|
* @credit https://stackoverflow.com/a/43632171/1123955
|
|
19
37
|
*/
|
|
20
38
|
export async function httpHeadHeader (url: string): Promise<http.IncomingHttpHeaders> {
|
|
21
|
-
|
|
39
|
+
const originUrl = url
|
|
22
40
|
let REDIRECT_TTL = 7
|
|
23
41
|
|
|
24
42
|
while (true) {
|
|
@@ -26,9 +44,15 @@ export async function httpHeadHeader (url: string): Promise<http.IncomingHttpHea
|
|
|
26
44
|
throw new Error(`ttl expired! too many(>${REDIRECT_TTL}) 302 redirection.`)
|
|
27
45
|
}
|
|
28
46
|
|
|
29
|
-
const res = await
|
|
47
|
+
const res = await fetch(url, {
|
|
48
|
+
method: 'HEAD',
|
|
49
|
+
})
|
|
50
|
+
res.destroy()
|
|
30
51
|
|
|
31
52
|
if (!/^3/.test(String(res.statusCode))) {
|
|
53
|
+
if (originUrl !== url) {
|
|
54
|
+
res.headers.location = url
|
|
55
|
+
}
|
|
32
56
|
return res.headers
|
|
33
57
|
}
|
|
34
58
|
|
|
@@ -40,44 +64,9 @@ export async function httpHeadHeader (url: string): Promise<http.IncomingHttpHea
|
|
|
40
64
|
|
|
41
65
|
url = res.headers.location
|
|
42
66
|
}
|
|
43
|
-
|
|
44
|
-
async function _headHeader (destUrl: string): Promise<http.IncomingMessage> {
|
|
45
|
-
const parsedUrl = new URL(destUrl)
|
|
46
|
-
const options = {
|
|
47
|
-
method : 'HEAD',
|
|
48
|
-
// method : 'GET',
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
let request: typeof http.request
|
|
52
|
-
|
|
53
|
-
if (parsedUrl.protocol === 'https:') {
|
|
54
|
-
request = https.request
|
|
55
|
-
} else if (parsedUrl.protocol === 'http:') {
|
|
56
|
-
request = http.request
|
|
57
|
-
} else {
|
|
58
|
-
throw new Error('unknown protocol: ' + parsedUrl.protocol)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return new Promise<http.IncomingMessage>((resolve, reject) => {
|
|
62
|
-
let res: undefined | http.IncomingMessage
|
|
63
|
-
const req = request(parsedUrl, options, (response) => {
|
|
64
|
-
res = response
|
|
65
|
-
resolve(res)
|
|
66
|
-
})
|
|
67
|
-
.on('error', reject)
|
|
68
|
-
.setTimeout(HTTP_TIMEOUT, () => {
|
|
69
|
-
const e = new Error(`FileBox: Http request timeout (${HTTP_TIMEOUT})!`)
|
|
70
|
-
req.emit('error', e)
|
|
71
|
-
req.destroy()
|
|
72
|
-
})
|
|
73
|
-
.end()
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
67
|
}
|
|
77
68
|
|
|
78
|
-
export function httpHeaderToFileName (
|
|
79
|
-
headers: http.IncomingHttpHeaders,
|
|
80
|
-
): null | string {
|
|
69
|
+
export function httpHeaderToFileName (headers: http.IncomingHttpHeaders): null | string {
|
|
81
70
|
const contentDisposition = headers['content-disposition']
|
|
82
71
|
|
|
83
72
|
if (!contentDisposition) {
|
|
@@ -94,220 +83,117 @@ export function httpHeaderToFileName (
|
|
|
94
83
|
return null
|
|
95
84
|
}
|
|
96
85
|
|
|
97
|
-
export async function httpStream (
|
|
98
|
-
url
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const protocol = parsedUrl.protocol
|
|
104
|
-
|
|
105
|
-
const options: http.RequestOptions = {}
|
|
106
|
-
|
|
107
|
-
let get: typeof https.get
|
|
108
|
-
|
|
109
|
-
if (!protocol) {
|
|
110
|
-
throw new Error('protocol is empty')
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (protocol.match(/^https:/i)) {
|
|
114
|
-
get = https.get
|
|
115
|
-
options.agent = https.globalAgent
|
|
116
|
-
} else if (protocol.match(/^http:/i)) {
|
|
117
|
-
get = http.get
|
|
118
|
-
options.agent = http.globalAgent
|
|
119
|
-
} else {
|
|
120
|
-
throw new Error('protocol unknown: ' + protocol)
|
|
86
|
+
export async function httpStream (url: string, headers: http.OutgoingHttpHeaders = {}): Promise<Readable> {
|
|
87
|
+
const headHeaders = await httpHeadHeader(url)
|
|
88
|
+
if (headHeaders.location) {
|
|
89
|
+
url = headHeaders.location
|
|
90
|
+
const { protocol } = new URL(url)
|
|
91
|
+
getProtocol(protocol)
|
|
121
92
|
}
|
|
122
93
|
|
|
123
|
-
options.
|
|
124
|
-
...headers,
|
|
94
|
+
const options: http.RequestOptions = {
|
|
95
|
+
headers: { ...headers },
|
|
96
|
+
method: 'GET',
|
|
125
97
|
}
|
|
126
98
|
|
|
127
|
-
const
|
|
128
|
-
const fileSize = Number(headHeaders['content-length'])
|
|
99
|
+
const fileSize = Number(headHeaders['content-length'])
|
|
129
100
|
|
|
130
|
-
if (headHeaders['accept-ranges'] === 'bytes' && fileSize > HTTP_CHUNK_SIZE) {
|
|
131
|
-
return await downloadFileInChunks(
|
|
101
|
+
if (!NO_SLICE_DOWN && headHeaders['accept-ranges'] === 'bytes' && fileSize > HTTP_CHUNK_SIZE) {
|
|
102
|
+
return await downloadFileInChunks(url, options, fileSize, HTTP_CHUNK_SIZE)
|
|
132
103
|
} else {
|
|
133
|
-
return await
|
|
104
|
+
return await fetch(url, options)
|
|
134
105
|
}
|
|
135
106
|
}
|
|
136
107
|
|
|
137
|
-
async function
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
108
|
+
async function fetch (url: string, options: http.RequestOptions): Promise<http.IncomingMessage> {
|
|
109
|
+
const { protocol } = new URL(url)
|
|
110
|
+
const { request, agent } = getProtocol(protocol)
|
|
111
|
+
const opts: http.RequestOptions = {
|
|
112
|
+
agent,
|
|
113
|
+
...options,
|
|
114
|
+
}
|
|
115
|
+
const req = request(url, opts).end()
|
|
116
|
+
req
|
|
117
|
+
.on('error', () => {
|
|
118
|
+
req.destroy()
|
|
147
119
|
})
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
|
|
120
|
+
.setTimeout(HTTP_REQUEST_TIMEOUT, () => {
|
|
121
|
+
req.emit('error', new Error(`FileBox: Http request timeout (${HTTP_REQUEST_TIMEOUT})!`))
|
|
122
|
+
})
|
|
123
|
+
const responseEvents = await once(req, 'response')
|
|
124
|
+
const res = responseEvents[0] as http.IncomingMessage
|
|
125
|
+
res
|
|
126
|
+
.on('error', () => {
|
|
127
|
+
res.destroy()
|
|
128
|
+
})
|
|
129
|
+
.setTimeout(HTTP_RESPONSE_TIMEOUT, () => {
|
|
130
|
+
res.emit('error', new Error(`FileBox: Http response timeout (${HTTP_RESPONSE_TIMEOUT})!`))
|
|
131
|
+
})
|
|
132
|
+
return res
|
|
161
133
|
}
|
|
162
134
|
|
|
163
135
|
async function downloadFileInChunks (
|
|
164
|
-
get: typeof https.get,
|
|
165
136
|
url: string,
|
|
166
137
|
options: http.RequestOptions,
|
|
167
138
|
fileSize: number,
|
|
168
139
|
chunkSize = HTTP_CHUNK_SIZE,
|
|
169
140
|
): Promise<Readable> {
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
141
|
+
const tmpFile = join(tmpdir(), `filebox-${randomUUID()}`)
|
|
142
|
+
const writeStream = createWriteStream(tmpFile)
|
|
143
|
+
const allowStatusCode = [ 200, 206 ]
|
|
144
|
+
const requestBaseOptions: http.RequestOptions = {
|
|
145
|
+
headers: {},
|
|
146
|
+
...options,
|
|
177
147
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const doDownloadChunk = async function (i: number, retries: number) {
|
|
188
|
-
const start = i * chunkSize
|
|
189
|
-
const end = Math.min((i + 1) * chunkSize - 1, fileSize - 1)
|
|
148
|
+
let chunkSeq = 0
|
|
149
|
+
let start = 0
|
|
150
|
+
let end = 0
|
|
151
|
+
let downSize = 0
|
|
152
|
+
let retries = 3
|
|
153
|
+
|
|
154
|
+
while (downSize < fileSize) {
|
|
155
|
+
end = Math.min(start + chunkSize, fileSize - 1)
|
|
190
156
|
const range = `bytes=${start}-${end}`
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (ac.signal.aborted) {
|
|
195
|
-
stream.destroy(new Error('Signal aborted.'))
|
|
196
|
-
return
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const requestOptions: http.RequestOptions = {
|
|
200
|
-
...options,
|
|
201
|
-
signal: ac.signal,
|
|
202
|
-
timeout: HTTP_TIMEOUT,
|
|
203
|
-
}
|
|
204
|
-
if (!requestOptions.headers) {
|
|
205
|
-
requestOptions.headers = {}
|
|
206
|
-
}
|
|
157
|
+
const requestOptions = Object.assign({}, requestBaseOptions)
|
|
158
|
+
assert(requestOptions.headers, 'Errors that should not happen: Invalid headers')
|
|
207
159
|
requestOptions.headers['Range'] = range
|
|
208
160
|
|
|
209
161
|
try {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
162
|
+
const res = await fetch(url, requestOptions)
|
|
163
|
+
assert(allowStatusCode.includes(res.statusCode ?? 0), `Request failed with status code ${res.statusCode}`)
|
|
164
|
+
assert(Number(res.headers['content-length']) > 0, 'Server returned 0 bytes of data')
|
|
165
|
+
for await (const chunk of res) {
|
|
166
|
+
assert(Buffer.isBuffer(chunk))
|
|
167
|
+
downSize += chunk.length
|
|
168
|
+
writeStream.write(chunk)
|
|
216
169
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (chunksDownloaded === chunksCount || dataTotalSize >= fileSize) {
|
|
226
|
-
stream.push(null)
|
|
227
|
-
}
|
|
228
|
-
} catch (err) {
|
|
229
|
-
if (retries === 0) {
|
|
230
|
-
stream.emit('error', err)
|
|
231
|
-
} else {
|
|
232
|
-
await doDownloadChunk(i, retries - 1)
|
|
170
|
+
res.destroy()
|
|
171
|
+
} catch (error) {
|
|
172
|
+
const err = error as Error
|
|
173
|
+
if (--retries <= 0) {
|
|
174
|
+
void rm(tmpFile, { force: true })
|
|
175
|
+
writeStream.close()
|
|
176
|
+
throw new Error(`Download file with chunk failed! ${err.message}`, { cause: err })
|
|
233
177
|
}
|
|
234
178
|
}
|
|
179
|
+
chunkSeq++
|
|
180
|
+
start = downSize
|
|
235
181
|
}
|
|
182
|
+
writeStream.close()
|
|
236
183
|
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
void doDownloadAllChunks().catch((e) => {
|
|
247
|
-
stream.emit('error', e)
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
return stream
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
async function downloadChunk (
|
|
254
|
-
get: typeof https.get,
|
|
255
|
-
url: string,
|
|
256
|
-
requestOptions: http.RequestOptions,
|
|
257
|
-
retries: number,
|
|
258
|
-
): Promise<Readable> {
|
|
259
|
-
return new Promise<Readable>((resolve, reject) => {
|
|
260
|
-
const doRequest = (attempt: number) => {
|
|
261
|
-
let resolved = false
|
|
262
|
-
const req = get(url, requestOptions, (res) => {
|
|
263
|
-
const statusCode = res.statusCode ?? 0
|
|
264
|
-
// console.info('downloadChunk(%d) statusCode: %d rsp.headers: %o', attempt, statusCode, res.headers)
|
|
265
|
-
|
|
266
|
-
if (statusCode < 200 || statusCode >= 300) {
|
|
267
|
-
if (attempt < retries) {
|
|
268
|
-
void doRequest(attempt + 1)
|
|
269
|
-
} else {
|
|
270
|
-
reject(new Error(`Request failed with status code ${res.statusCode}`))
|
|
271
|
-
}
|
|
272
|
-
return
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const stream = pipeline(res, new PassThrough(), () => {})
|
|
276
|
-
resolve(stream)
|
|
277
|
-
resolved = true
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
req
|
|
281
|
-
.once('error', (err) => {
|
|
282
|
-
if (resolved) {
|
|
283
|
-
return
|
|
284
|
-
}
|
|
285
|
-
// console.error('downloadChunk(%d) req error:', attempt, err)
|
|
286
|
-
if (attempt < retries) {
|
|
287
|
-
void doRequest(attempt + 1)
|
|
288
|
-
} else {
|
|
289
|
-
reject(err)
|
|
290
|
-
}
|
|
291
|
-
})
|
|
292
|
-
.setTimeout(HTTP_TIMEOUT, () => {
|
|
293
|
-
const e = new Error(`FileBox: Http request timeout (${HTTP_TIMEOUT})!`)
|
|
294
|
-
req.emit('error', e)
|
|
295
|
-
req.destroy()
|
|
296
|
-
})
|
|
297
|
-
.end()
|
|
298
|
-
}
|
|
299
|
-
void doRequest(0)
|
|
300
|
-
})
|
|
184
|
+
const readStream = createReadStream(tmpFile)
|
|
185
|
+
readStream
|
|
186
|
+
.once('end', () => readStream.close())
|
|
187
|
+
.once('close', () => {
|
|
188
|
+
void rm(tmpFile, { force: true })
|
|
189
|
+
})
|
|
190
|
+
return readStream
|
|
301
191
|
}
|
|
302
192
|
|
|
303
193
|
export async function streamToBuffer (stream: Readable): Promise<Buffer> {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
resolve(fullBuffer)
|
|
310
|
-
})
|
|
311
|
-
stream.on('data', (buffer) => bufferList.push(buffer))
|
|
312
|
-
})
|
|
194
|
+
const chunks: Buffer[] = []
|
|
195
|
+
for await (const chunk of stream) {
|
|
196
|
+
chunks.push(chunk)
|
|
197
|
+
}
|
|
198
|
+
return Buffer.concat(chunks)
|
|
313
199
|
}
|
package/src/version.ts
CHANGED