@kevisual/api 0.0.37 → 0.0.39
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/query/query-resources/index.ts +25 -17
package/package.json
CHANGED
|
@@ -62,7 +62,7 @@ export class QueryResources {
|
|
|
62
62
|
const url = `${this.prefix}${filepath}`;
|
|
63
63
|
return this.get({}, { url, method: 'GET', ...opts, headers: this.header(opts?.headers, false), isText: true });
|
|
64
64
|
}
|
|
65
|
-
async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts): Promise<Result<any>> {
|
|
65
|
+
async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts & { chunkSize?: number, maxSize?: number }): Promise<Result<any>> {
|
|
66
66
|
const pathname = `${this.prefix}${filepath}`;
|
|
67
67
|
const filename = path.basename(pathname);
|
|
68
68
|
const type = getContentType(filename);
|
|
@@ -71,15 +71,15 @@ export class QueryResources {
|
|
|
71
71
|
// Blob 类型时 hashContent 返回 Promise
|
|
72
72
|
const hash = hashResult instanceof Promise ? await hashResult : hashResult;
|
|
73
73
|
url.searchParams.set('hash', hash);
|
|
74
|
-
|
|
74
|
+
const { chunkSize, maxSize, ...restOpts } = opts || {};
|
|
75
75
|
// 判断是否需要分块上传(文件大于20MB)
|
|
76
76
|
const isBlob = content instanceof Blob;
|
|
77
77
|
const fileSize = isBlob ? content.size : new Blob([content]).size;
|
|
78
|
-
const CHUNK_THRESHOLD = 20 * 1024 * 1024; // 20MB
|
|
78
|
+
const CHUNK_THRESHOLD = maxSize ?? 20 * 1024 * 1024; // 20MB
|
|
79
79
|
|
|
80
80
|
if (fileSize > CHUNK_THRESHOLD && isBlob) {
|
|
81
81
|
// 使用分块上传
|
|
82
|
-
return this.uploadChunkedFile(filepath, content, hash,
|
|
82
|
+
return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts });
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
const formData = new FormData();
|
|
@@ -94,34 +94,36 @@ export class QueryResources {
|
|
|
94
94
|
method: 'POST',
|
|
95
95
|
body: formData,
|
|
96
96
|
timeout: 5 * 60 * 1000, // 5分钟超时
|
|
97
|
-
...
|
|
98
|
-
headers: { ...
|
|
97
|
+
...restOpts,
|
|
98
|
+
headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) },
|
|
99
99
|
params: {
|
|
100
100
|
hash: hash,
|
|
101
|
-
...
|
|
101
|
+
...restOpts?.params,
|
|
102
102
|
},
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
|
-
async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts): Promise<Result<any>> {
|
|
105
|
+
async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise<Result<any>> {
|
|
106
106
|
const pathname = `${this.prefix}${filepath}`;
|
|
107
107
|
const filename = path.basename(pathname);
|
|
108
108
|
const url = new URL(pathname, window.location.origin);
|
|
109
109
|
url.searchParams.set('hash', hash);
|
|
110
|
-
url.searchParams.set('
|
|
110
|
+
url.searchParams.set('chunk', '1');
|
|
111
111
|
console.log(`url,`, url, hash);
|
|
112
112
|
// 预留 eventSource 支持(暂不处理)
|
|
113
113
|
// const createEventSource = opts?.createEventSource;
|
|
114
|
-
|
|
115
|
-
const chunkSize = 5 * 1024 * 1024; // 5MB
|
|
114
|
+
const { chunkSize: _chunkSize, ...restOpts } = opts || {};
|
|
115
|
+
const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB
|
|
116
116
|
const totalChunks = Math.ceil(file.size / chunkSize);
|
|
117
117
|
|
|
118
118
|
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
|
|
119
119
|
const start = currentChunk * chunkSize;
|
|
120
120
|
const end = Math.min(start + chunkSize, file.size);
|
|
121
|
-
const
|
|
121
|
+
const chunkBlob = file.slice(start, end);
|
|
122
|
+
// 转换为 File 类型
|
|
123
|
+
const chunkFile = new File([chunkBlob], filename, { type: file.type || 'application/octet-stream' });
|
|
122
124
|
|
|
123
125
|
const formData = new FormData();
|
|
124
|
-
formData.append('file',
|
|
126
|
+
formData.append('file', chunkFile, filename);
|
|
125
127
|
formData.append('chunkIndex', currentChunk.toString());
|
|
126
128
|
formData.append('totalChunks', totalChunks.toString());
|
|
127
129
|
console.log(`Uploading chunk ${currentChunk + 1}/${totalChunks}`, url.toString());
|
|
@@ -132,17 +134,23 @@ export class QueryResources {
|
|
|
132
134
|
method: 'POST',
|
|
133
135
|
body: formData,
|
|
134
136
|
timeout: 5 * 60 * 1000, // 5分钟超时
|
|
135
|
-
...
|
|
136
|
-
headers: { ...
|
|
137
|
+
...restOpts,
|
|
138
|
+
headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) },
|
|
137
139
|
params: {
|
|
138
140
|
hash: hash,
|
|
139
|
-
|
|
141
|
+
chunk: '1',
|
|
142
|
+
chunkIndex: currentChunk,
|
|
143
|
+
totalChunks,
|
|
144
|
+
...restOpts?.params,
|
|
140
145
|
},
|
|
141
146
|
});
|
|
147
|
+
if (res.code !== 200) {
|
|
148
|
+
throw new Error(`Chunk upload failed with code ${res!.code}, message: ${res!.message}`);
|
|
149
|
+
}
|
|
142
150
|
console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
|
|
143
151
|
} catch (error) {
|
|
144
152
|
console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error);
|
|
145
|
-
|
|
153
|
+
return { code: 500, message: `分块上传失败: ${(error as Error).message}` };
|
|
146
154
|
}
|
|
147
155
|
}
|
|
148
156
|
|