feat: add query and fix bugs
This commit is contained in:
134
src/query/query-upload/core/upload-chunk.ts
Normal file
134
src/query/query-upload/core/upload-chunk.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { randomId } from '../utils/random-id.ts';
|
||||
import { UploadProgress } from './upload-progress.ts';
|
||||
export type ConvertOpts = {
|
||||
appKey?: string;
|
||||
version?: string;
|
||||
username?: string;
|
||||
directory?: string;
|
||||
isPublic?: boolean;
|
||||
filename?: string;
|
||||
/**
|
||||
* 是否不检查应用文件, 默认 true,默认不检测
|
||||
*/
|
||||
noCheckAppFiles?: boolean;
|
||||
};
|
||||
|
||||
// createEventSource: (baseUrl: string, searchParams: URLSearchParams) => {
|
||||
// return new EventSource(baseUrl + '/api/s1/events?' + searchParams.toString());
|
||||
// },
|
||||
export type UploadOpts = {
|
||||
uploadProgress: UploadProgress;
|
||||
/**
|
||||
* 创建 EventSource 兼容 nodejs
|
||||
* @param baseUrl 基础 URL
|
||||
* @param searchParams 查询参数
|
||||
* @returns EventSource
|
||||
*/
|
||||
createEventSource: (baseUrl: string, searchParams: URLSearchParams) => EventSource;
|
||||
baseUrl?: string;
|
||||
token: string;
|
||||
FormDataFn: any;
|
||||
};
|
||||
export const uploadFileChunked = async (file: File, opts: ConvertOpts, opts2: UploadOpts) => {
|
||||
const { directory, appKey, version, username, isPublic, noCheckAppFiles = true } = opts;
|
||||
const { uploadProgress, createEventSource, baseUrl = '', token, FormDataFn } = opts2 || {};
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const taskId = randomId();
|
||||
const filename = opts.filename || file.name;
|
||||
uploadProgress?.start(`${filename} 上传中...`);
|
||||
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('taskId', taskId);
|
||||
if (isPublic) {
|
||||
searchParams.set('public', 'true');
|
||||
}
|
||||
if (noCheckAppFiles) {
|
||||
searchParams.set('noCheckAppFiles', '1');
|
||||
}
|
||||
const eventSource = createEventSource(baseUrl + '/api/s1/events', searchParams);
|
||||
let isError = false;
|
||||
// 监听服务器推送的进度更新
|
||||
eventSource.onmessage = function (event) {
|
||||
console.log('Progress update:', event.data);
|
||||
const parseIfJson = (data: string) => {
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch (e) {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
const receivedData = parseIfJson(event.data);
|
||||
if (typeof receivedData === 'string') return;
|
||||
const progress = Number(receivedData.progress);
|
||||
const progressFixed = progress.toFixed(2);
|
||||
uploadProgress?.set(progress, { ...receivedData, progressFixed, filename, taskId });
|
||||
};
|
||||
eventSource.onerror = function (event) {
|
||||
console.log('eventSource.onerror', event);
|
||||
isError = true;
|
||||
reject(event);
|
||||
};
|
||||
|
||||
const chunkSize = 1 * 1024 * 1024; // 1MB
|
||||
const totalChunks = Math.ceil(file.size / chunkSize);
|
||||
|
||||
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
|
||||
const start = currentChunk * chunkSize;
|
||||
const end = Math.min(start + chunkSize, file.size);
|
||||
const chunk = file.slice(start, end);
|
||||
|
||||
const formData = new FormDataFn();
|
||||
formData.append('file', chunk, filename);
|
||||
formData.append('chunkIndex', currentChunk.toString());
|
||||
formData.append('totalChunks', totalChunks.toString());
|
||||
const isLast = currentChunk === totalChunks - 1;
|
||||
if (directory) {
|
||||
formData.append('directory', directory);
|
||||
}
|
||||
if (appKey && version) {
|
||||
formData.append('appKey', appKey);
|
||||
formData.append('version', version);
|
||||
}
|
||||
if (username) {
|
||||
formData.append('username', username);
|
||||
}
|
||||
try {
|
||||
const res = await fetch(baseUrl + '/api/s1/resources/upload/chunk?taskId=' + taskId, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'task-id': taskId,
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}).then((response) => response.json());
|
||||
|
||||
if (res?.code !== 200) {
|
||||
console.log('uploadChunk error', res);
|
||||
uploadProgress?.error(res?.message || '上传失败');
|
||||
isError = true;
|
||||
eventSource.close();
|
||||
|
||||
uploadProgress?.done();
|
||||
reject(new Error(res?.message || '上传失败'));
|
||||
return;
|
||||
}
|
||||
if (isLast) {
|
||||
fetch(baseUrl + '/api/s1/events/close?taskId=' + taskId);
|
||||
eventSource.close();
|
||||
uploadProgress?.done();
|
||||
resolve(res);
|
||||
}
|
||||
// console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
|
||||
} catch (error) {
|
||||
console.log('Error uploading chunk', error);
|
||||
fetch(baseUrl + '/api/s1/events/close?taskId=' + taskId);
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 循环结束
|
||||
if (!uploadProgress?.end) {
|
||||
uploadProgress?.done();
|
||||
}
|
||||
});
|
||||
};
|
Reference in New Issue
Block a user