diff --git a/package.json b/package.json index 3946165..c00d4ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/api", - "version": "0.0.38", + "version": "0.0.39", "description": "", "main": "mod.ts", "scripts": { diff --git a/query/query-resources/index.ts b/query/query-resources/index.ts index c140c6b..2283326 100644 --- a/query/query-resources/index.ts +++ b/query/query-resources/index.ts @@ -62,7 +62,7 @@ export class QueryResources { const url = `${this.prefix}${filepath}`; return this.get({}, { url, method: 'GET', ...opts, headers: this.header(opts?.headers, false), isText: true }); } - async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts): Promise> { + async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts & { chunkSize?: number, maxSize?: number }): Promise> { const pathname = `${this.prefix}${filepath}`; const filename = path.basename(pathname); const type = getContentType(filename); @@ -71,15 +71,15 @@ export class QueryResources { // Blob 类型时 hashContent 返回 Promise const hash = hashResult instanceof Promise ? await hashResult : hashResult; url.searchParams.set('hash', hash); - + const { chunkSize, maxSize, ...restOpts } = opts || {}; // 判断是否需要分块上传(文件大于20MB) const isBlob = content instanceof Blob; const fileSize = isBlob ? content.size : new Blob([content]).size; - const CHUNK_THRESHOLD = 20 * 1024 * 1024; // 20MB + const CHUNK_THRESHOLD = maxSize ?? 20 * 1024 * 1024; // 20MB if (fileSize > CHUNK_THRESHOLD && isBlob) { // 使用分块上传 - return this.uploadChunkedFile(filepath, content, hash, opts); + return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts }); } const formData = new FormData(); @@ -94,15 +94,15 @@ export class QueryResources { method: 'POST', body: formData, timeout: 5 * 60 * 1000, // 5分钟超时 - ...opts, - headers: { ...opts?.headers, ...this.header(opts?.headers, false) }, + ...restOpts, + headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) }, params: { hash: hash, - ...opts?.params, + ...restOpts?.params, }, }); } - async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts): Promise> { + async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise> { const pathname = `${this.prefix}${filepath}`; const filename = path.basename(pathname); const url = new URL(pathname, window.location.origin); @@ -111,8 +111,8 @@ export class QueryResources { console.log(`url,`, url, hash); // 预留 eventSource 支持(暂不处理) // const createEventSource = opts?.createEventSource; - - const chunkSize = 5 * 1024 * 1024; // 5MB + const { chunkSize: _chunkSize, ...restOpts } = opts || {}; + const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB const totalChunks = Math.ceil(file.size / chunkSize); for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) { @@ -134,18 +134,23 @@ export class QueryResources { method: 'POST', body: formData, timeout: 5 * 60 * 1000, // 5分钟超时 - ...opts, - headers: { ...opts?.headers, ...this.header(opts?.headers, false) }, + ...restOpts, + headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) }, params: { hash: hash, chunk: '1', - ...opts?.params, + chunkIndex: currentChunk, + totalChunks, + ...restOpts?.params, }, }); + if (res.code !== 200) { + throw new Error(`Chunk upload failed with code ${res!.code}, message: ${res!.message}`); + } console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res); } catch (error) { console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error); - throw error; + return { code: 500, message: `分块上传失败: ${(error as Error).message}` }; } }