lupine.components 1.0.7 → 1.0.9
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/package.json +1 -1
- package/src/lib/download-file.ts +118 -0
- package/src/lib/index.ts +1 -0
- package/src/lib/upload-file.ts +47 -23
package/package.json
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { NotificationColor, NotificationMessage } from 'lupine.components';
|
|
2
|
+
import { getRenderPageProps } from 'lupine.web';
|
|
3
|
+
|
|
4
|
+
const _saveChunkSize = {
|
|
5
|
+
downloadSize: 1024 * 200,
|
|
6
|
+
};
|
|
7
|
+
export const setDownloadChunkSize = (chunkSize: number) => {
|
|
8
|
+
_saveChunkSize.downloadSize = chunkSize;
|
|
9
|
+
};
|
|
10
|
+
export const getDownloadChunkSize = () => {
|
|
11
|
+
return _saveChunkSize.downloadSize;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// should return { chunkNumber: number }
|
|
15
|
+
export const downloadFileChunk = async (
|
|
16
|
+
downloadUrl: string,
|
|
17
|
+
rangeStart: number,
|
|
18
|
+
rangeLength: number,
|
|
19
|
+
retryCount = 3,
|
|
20
|
+
retryMessage = '' // can have ${tryCount}
|
|
21
|
+
) => {
|
|
22
|
+
let url = downloadUrl + (downloadUrl.indexOf('?') === -1 ? '?' : '');
|
|
23
|
+
url += `&start=${rangeStart.toString()}`;
|
|
24
|
+
url += `&length=${rangeLength.toString()}`;
|
|
25
|
+
let tryCount = 0;
|
|
26
|
+
while (tryCount < retryCount) {
|
|
27
|
+
try {
|
|
28
|
+
const rawData = (await getRenderPageProps().renderPageFunctions.fetchData(
|
|
29
|
+
url,
|
|
30
|
+
undefined,
|
|
31
|
+
true,
|
|
32
|
+
true
|
|
33
|
+
)) as Response;
|
|
34
|
+
// console.log('downloadFileChunk', rawData);
|
|
35
|
+
const fileSize = rawData.headers.get('file-size');
|
|
36
|
+
const partSize = rawData.headers.get('part-size');
|
|
37
|
+
if (!fileSize || !partSize) {
|
|
38
|
+
console.log(`downloadFileChunk error`, rawData);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
fileSize: parseInt(fileSize, 10),
|
|
43
|
+
partSize: parseInt(partSize, 10),
|
|
44
|
+
arrayBuffer: await rawData.arrayBuffer(),
|
|
45
|
+
};
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.log(`downloadFileChunk error, try: ${tryCount}`, error);
|
|
48
|
+
}
|
|
49
|
+
tryCount++;
|
|
50
|
+
if (retryMessage) {
|
|
51
|
+
NotificationMessage.sendMessage(
|
|
52
|
+
retryMessage.replace('${tryCount}', tryCount.toString()),
|
|
53
|
+
NotificationColor.Warning
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export interface DownloadFileProps {
|
|
61
|
+
fileSize: number;
|
|
62
|
+
partSize: number;
|
|
63
|
+
arrayBuffer: ArrayBuffer;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
A sample for text result:
|
|
68
|
+
const decoder = new TextDecoder('utf-8');
|
|
69
|
+
const chunks: string[] = [];
|
|
70
|
+
let downloadSize = 0;
|
|
71
|
+
const processResponse = (result: DownloadFileProps) => {
|
|
72
|
+
if (!result || result.fileSize <= 0 || result.partSize < 0) {
|
|
73
|
+
NotificationMessage.sendMessage('加载数据失败', NotificationColor.Error);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const fileSize = result.fileSize;
|
|
77
|
+
downloadSize += result.partSize;
|
|
78
|
+
progressUpdate?.onProgress?.(Math.round((downloadSize / fileSize) * 100) / 100, downloadSize, fileSize);
|
|
79
|
+
chunks.push(decoder.decode(result.arrayBuffer));
|
|
80
|
+
return true;
|
|
81
|
+
};
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
export const downloadFile = async (
|
|
85
|
+
downloadUrl: string,
|
|
86
|
+
processResponse: (result: DownloadFileProps) => boolean | undefined, // true: success, false: failed, undefined: continue
|
|
87
|
+
chunkSize = 0,
|
|
88
|
+
retryCount = 3,
|
|
89
|
+
retryMessage = 'Downloading failed, try: ${tryCount}' // can have ${tryCount}
|
|
90
|
+
) => {
|
|
91
|
+
if (chunkSize < 1) {
|
|
92
|
+
chunkSize = _saveChunkSize.downloadSize;
|
|
93
|
+
}
|
|
94
|
+
let downloadSize = 0;
|
|
95
|
+
let expectedFileSize: number | null = null;
|
|
96
|
+
while (true) {
|
|
97
|
+
const start = downloadSize;
|
|
98
|
+
const length = chunkSize;
|
|
99
|
+
const downloadResult = await downloadFileChunk(downloadUrl, start, length, retryCount, retryMessage);
|
|
100
|
+
if (!downloadResult) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (expectedFileSize === null) {
|
|
104
|
+
expectedFileSize = downloadResult.fileSize;
|
|
105
|
+
}
|
|
106
|
+
downloadSize += downloadResult.partSize;
|
|
107
|
+
// console.log(`downloadSize: ${downloadSize}, downloadFileChunk:`, downloadResult);
|
|
108
|
+
const result = processResponse(downloadResult);
|
|
109
|
+
if (result !== undefined) {
|
|
110
|
+
// success or failed
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
if (downloadSize >= expectedFileSize) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
};
|
package/src/lib/index.ts
CHANGED
package/src/lib/upload-file.ts
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
import { getRenderPageProps } from
|
|
1
|
+
import { getRenderPageProps } from 'lupine.web';
|
|
2
|
+
import { NotificationColor, NotificationMessage } from '../components';
|
|
2
3
|
|
|
3
4
|
const _saveChunkSize = {
|
|
4
|
-
size: 1024 *
|
|
5
|
+
size: 1024 * 200,
|
|
5
6
|
};
|
|
6
|
-
export const
|
|
7
|
+
export const setUploadChunkSize = (chunkSize: number) => {
|
|
7
8
|
_saveChunkSize.size = chunkSize;
|
|
8
9
|
};
|
|
9
|
-
export const
|
|
10
|
+
export const getUploadChunkSize = () => {
|
|
10
11
|
return _saveChunkSize.size;
|
|
11
12
|
};
|
|
12
13
|
export const checkUploadedFileSize = async (uploadUrl: string) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// const json = await response.json();
|
|
17
|
-
const json = await getRenderPageProps().renderPageFunctions.fetchData(uploadUrl + '?check-size=1');
|
|
18
|
-
return json && json.size ? json.size : 0;
|
|
14
|
+
let url = uploadUrl + (uploadUrl.indexOf('?') === -1 ? '?' : '') + '&check-size=1';
|
|
15
|
+
const json = await getRenderPageProps().renderPageFunctions.fetchData(url);
|
|
16
|
+
return json && json.json.size ? json.json.size : 0;
|
|
19
17
|
};
|
|
20
18
|
|
|
21
19
|
// should return { chunkNumber: number }
|
|
@@ -24,22 +22,39 @@ export const uploadFileChunk = async (
|
|
|
24
22
|
chunkNumber: number,
|
|
25
23
|
totalChunks: number,
|
|
26
24
|
uploadUrl: string,
|
|
27
|
-
key: string
|
|
25
|
+
key: string,
|
|
26
|
+
retryCount = 3,
|
|
27
|
+
retryMessage = '' // can have ${tryCount}
|
|
28
28
|
) => {
|
|
29
|
-
// this must be the FE so we can use fetch
|
|
30
29
|
let url = uploadUrl + (uploadUrl.indexOf('?') === -1 ? '?' : '');
|
|
31
30
|
url += `&chunkNumber=${chunkNumber.toString()}`;
|
|
32
31
|
url += `&totalChunks=${totalChunks.toString()}`;
|
|
33
32
|
if (key) {
|
|
34
33
|
url += `&key=${key}`;
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
let tryCount = 0;
|
|
36
|
+
let json;
|
|
37
|
+
while (tryCount < retryCount) {
|
|
38
|
+
try {
|
|
39
|
+
json = await getRenderPageProps().renderPageFunctions.fetchData(url, chunk);
|
|
40
|
+
if (json && json.json) {
|
|
41
|
+
json = json.json;
|
|
42
|
+
}
|
|
43
|
+
if (json && json.status) {
|
|
44
|
+
// ok or error
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.log(`uploadFileChunk error, try: ${tryCount}`, error);
|
|
49
|
+
}
|
|
50
|
+
tryCount++;
|
|
51
|
+
if (retryMessage) {
|
|
52
|
+
NotificationMessage.sendMessage(
|
|
53
|
+
retryMessage.replace('${tryCount}', tryCount.toString()),
|
|
54
|
+
NotificationColor.Warning
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
43
58
|
return json;
|
|
44
59
|
};
|
|
45
60
|
|
|
@@ -47,13 +62,22 @@ export const uploadFile = async (
|
|
|
47
62
|
file: File | string,
|
|
48
63
|
uploadUrl: string,
|
|
49
64
|
progressFn?: (percentage: number, chunkNumber: number, totalChunks: number) => void,
|
|
50
|
-
chunkSize =
|
|
65
|
+
chunkSize = 0,
|
|
66
|
+
retryCount = 3,
|
|
67
|
+
retryMessage = '' // can have ${tryCount}
|
|
51
68
|
) => {
|
|
52
69
|
// const uploadedSize = await checkUploadedFileSize(uploadUrl);
|
|
53
70
|
let key = '';
|
|
54
71
|
const len = file instanceof File ? file.size : file.length;
|
|
72
|
+
if (!chunkSize) {
|
|
73
|
+
chunkSize = _saveChunkSize.size;
|
|
74
|
+
}
|
|
55
75
|
if (len <= chunkSize) {
|
|
56
|
-
|
|
76
|
+
const uploaded = await uploadFileChunk(file, 0, 1, uploadUrl, key, retryCount, retryMessage);
|
|
77
|
+
if (!uploaded || uploaded.status !== 'ok') {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
57
81
|
}
|
|
58
82
|
|
|
59
83
|
const totalChunks = Math.ceil(len / chunkSize);
|
|
@@ -61,8 +85,8 @@ export const uploadFile = async (
|
|
|
61
85
|
const start = i * chunkSize;
|
|
62
86
|
const end = Math.min((i + 1) * chunkSize, len);
|
|
63
87
|
const chunk = file.slice(start, end);
|
|
64
|
-
const uploaded = await uploadFileChunk(chunk, i, totalChunks, uploadUrl, key);
|
|
65
|
-
if (!uploaded || uploaded.
|
|
88
|
+
const uploaded = await uploadFileChunk(chunk, i, totalChunks, uploadUrl, key, retryCount, retryMessage);
|
|
89
|
+
if (!uploaded || uploaded.status !== 'ok') {
|
|
66
90
|
return false;
|
|
67
91
|
}
|
|
68
92
|
key = uploaded.key;
|