1 | import { CallbackManager } from '../../utils/handler.js';
|
2 | import { setHeader, XHR_STATS, NETWORK_TIMEOUT, convertObjectUrlToBlob } from './utils.js';
|
3 |
|
4 | const createUploadTask = ({ url, filePath, formData = {}, name, header, timeout, fileName, withCredentials = true, success, error }) => {
|
5 | let timeoutInter;
|
6 | let formKey;
|
7 | const apiName = 'uploadFile';
|
8 | const xhr = new XMLHttpRequest();
|
9 | const form = new FormData();
|
10 | const callbackManager = {
|
11 | headersReceived: new CallbackManager(),
|
12 | progressUpdate: new CallbackManager()
|
13 | };
|
14 | xhr.open('POST', url);
|
15 | xhr.withCredentials = !!withCredentials;
|
16 | setHeader(xhr, header);
|
17 | for (formKey in formData) {
|
18 | form.append(formKey, formData[formKey]);
|
19 | }
|
20 | xhr.upload.onprogress = e => {
|
21 | const { loaded, total } = e;
|
22 | callbackManager.progressUpdate.trigger({
|
23 | progress: Math.round(loaded / total * 100),
|
24 | totalBytesSent: loaded,
|
25 | totalBytesExpectedToSend: total
|
26 | });
|
27 | };
|
28 | xhr.onreadystatechange = () => {
|
29 | if (xhr.readyState !== XHR_STATS.HEADERS_RECEIVED)
|
30 | return;
|
31 | callbackManager.headersReceived.trigger({
|
32 | header: xhr.getAllResponseHeaders()
|
33 | });
|
34 | };
|
35 | xhr.onload = () => {
|
36 | const status = xhr.status;
|
37 | clearTimeout(timeoutInter);
|
38 | success({
|
39 | errMsg: `${apiName}:ok`,
|
40 | statusCode: status,
|
41 | data: xhr.responseText || xhr.response
|
42 | });
|
43 | };
|
44 | xhr.onabort = () => {
|
45 | clearTimeout(timeoutInter);
|
46 | error({
|
47 | errMsg: `${apiName}:fail abort`
|
48 | });
|
49 | };
|
50 | xhr.onerror = (e) => {
|
51 | clearTimeout(timeoutInter);
|
52 | error({
|
53 | errMsg: `${apiName}:fail ${e.message}`
|
54 | });
|
55 | };
|
56 | |
57 |
|
58 |
|
59 | const abort = () => {
|
60 | clearTimeout(timeoutInter);
|
61 | xhr.abort();
|
62 | };
|
63 | const send = () => {
|
64 | xhr.send(form);
|
65 | timeoutInter = setTimeout(() => {
|
66 | xhr.onabort = null;
|
67 | xhr.onload = null;
|
68 | xhr.upload.onprogress = null;
|
69 | xhr.onreadystatechange = null;
|
70 | xhr.onerror = null;
|
71 | abort();
|
72 | error({
|
73 | errMsg: `${apiName}:fail timeout`
|
74 | });
|
75 | }, timeout || NETWORK_TIMEOUT);
|
76 | };
|
77 | convertObjectUrlToBlob(filePath)
|
78 | .then((fileObj) => {
|
79 | if (!fileName) {
|
80 | fileName = typeof fileObj !== 'string' && fileObj.name;
|
81 | }
|
82 | form.append(name, fileObj, fileName || `file-${Date.now()}`);
|
83 | send();
|
84 | })
|
85 | .catch(e => {
|
86 | error({
|
87 | errMsg: `${apiName}:fail ${e.message}`
|
88 | });
|
89 | });
|
90 | |
91 |
|
92 |
|
93 |
|
94 | const onHeadersReceived = callbackManager.headersReceived.add;
|
95 | |
96 |
|
97 |
|
98 |
|
99 | const offHeadersReceived = callbackManager.headersReceived.remove;
|
100 | |
101 |
|
102 |
|
103 |
|
104 | const onProgressUpdate = callbackManager.progressUpdate.add;
|
105 | |
106 |
|
107 |
|
108 |
|
109 | const offProgressUpdate = callbackManager.progressUpdate.remove;
|
110 | return {
|
111 | abort,
|
112 | onHeadersReceived,
|
113 | offHeadersReceived,
|
114 | onProgressUpdate,
|
115 | offProgressUpdate
|
116 | };
|
117 | };
|
118 |
|
119 |
|
120 |
|
121 | const uploadFile = ({ url, filePath, name, header, formData, timeout, fileName, withCredentials, success, fail, complete }) => {
|
122 | let task;
|
123 | const result = new Promise((resolve, reject) => {
|
124 | task = createUploadTask({
|
125 | url,
|
126 | header,
|
127 | name,
|
128 | filePath,
|
129 | formData,
|
130 | timeout,
|
131 | fileName,
|
132 | withCredentials,
|
133 | success: res => {
|
134 | success && success(res);
|
135 | complete && complete(res);
|
136 | resolve(res);
|
137 | },
|
138 | error: res => {
|
139 | fail && fail(res);
|
140 | complete && complete(res);
|
141 | reject(res);
|
142 | }
|
143 | });
|
144 | });
|
145 | result.headersReceive = task.onHeadersReceived;
|
146 | result.progress = task.onProgressUpdate;
|
147 | return new Proxy(result, {
|
148 | get(target, prop) {
|
149 | const object = prop in task ? task : target;
|
150 | const value = object[prop];
|
151 | return typeof value === 'function' ? value.bind(object) : value;
|
152 | },
|
153 | });
|
154 | };
|
155 |
|
156 | export { uploadFile };
|
157 |
|