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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lupine.components",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "license": "MIT",
5
5
  "author": "uuware.com",
6
6
  "homepage": "https://uuware.com/",
@@ -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
@@ -2,6 +2,7 @@ export * from './dom';
2
2
  export * from './date-utils';
3
3
  export * from './deep-merge';
4
4
  export * from './document-ready';
5
+ export * from './download-file';
5
6
  export * from './drag-util';
6
7
  export * from './dynamical-load';
7
8
  export * from './format-bytes';
@@ -1,21 +1,19 @@
1
- import { getRenderPageProps } from "lupine.web";
1
+ import { getRenderPageProps } from 'lupine.web';
2
+ import { NotificationColor, NotificationMessage } from '../components';
2
3
 
3
4
  const _saveChunkSize = {
4
- size: 1024 * 500,
5
+ size: 1024 * 200,
5
6
  };
6
- export const setChunkSize = (chunkSize: number) => {
7
+ export const setUploadChunkSize = (chunkSize: number) => {
7
8
  _saveChunkSize.size = chunkSize;
8
9
  };
9
- export const getChunkSize = () => {
10
+ export const getUploadChunkSize = () => {
10
11
  return _saveChunkSize.size;
11
12
  };
12
13
  export const checkUploadedFileSize = async (uploadUrl: string) => {
13
- // const response = await fetch(uploadUrl + '?check-size=1', {
14
- // method: 'POST',
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
- // const response = await fetch(url, {
37
- // method: 'POST',
38
- // body: chunk,
39
- // });
40
- // const json = await response.json();
41
- console.log(`uploadFileChunk, ${uploadUrl}, index: ${chunkNumber}, total: ${totalChunks}, len: ${chunk.length}`);
42
- const json = await getRenderPageProps().renderPageFunctions.fetchData(url, chunk);
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 = _saveChunkSize.size
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
- return await uploadFileChunk(file, 0, 1, uploadUrl, key);
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.chunkNumber === i.toString() || !uploaded.key) {
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;