diff --git a/package.json b/package.json index dbf6446..5e6fef5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/api", - "version": "0.0.30", + "version": "0.0.34", "description": "", "main": "mod.ts", "scripts": { diff --git a/query/query-resources/index.ts b/query/query-resources/index.ts index da1ed0a..1ca49b5 100644 --- a/query/query-resources/index.ts +++ b/query/query-resources/index.ts @@ -62,23 +62,50 @@ export class QueryResources { const url = `${this.prefix}${filepath}`; return this.get({}, { url, method: 'GET', headers: this.header(opts?.headers, false), isText: true }); } - async uploadFile(filepath: string, content: string, opts?: DataOpts): Promise> { + async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts): Promise> { const pathname = `${this.prefix}${filepath}`; const filename = path.basename(pathname); const type = getContentType(filename); const url = new URL(pathname, window.location.origin); - const hash = hashContent(content); + const hashResult = hashContent(content); + // Blob 类型时 hashContent 返回 Promise + const hash = hashResult instanceof Promise ? await hashResult : hashResult; url.searchParams.set('hash', hash); const formData = new FormData(); - formData.append('file', new Blob([content], { type })); + if (content instanceof Blob) { + formData.append('file', content); + } else { + formData.append('file', new Blob([content], { type })); + } return adapter({ url: url.toString(), headers: { ...this.header(opts?.headers, false) }, + params: { + hash: hash, + }, isPostFile: true, method: 'POST', body: formData, }); } + async createFolder(folderpath: string, opts?: DataOpts): Promise> { + const filepath = folderpath.endsWith('/') ? `${folderpath}keep.txt` : `${folderpath}/keep.txt`; + return this.uploadFile(filepath, '文件夹占位,其他文件不存在,文件夹不存在,如果有其他文件夹,删除当前文件夹占位文件即可', opts); + } + async rename(oldpath: string, newpath: string, opts?: DataOpts): Promise> { + const pathname = `${this.prefix}${oldpath}`; + const newName = `${this.prefix}${newpath}`; + const params = { + newName: newName, + }; + const url = pathname + return adapter({ + url, + method: 'PUT' as any, + headers: this.header(opts?.headers), + params, + }); + } async deleteFile(filepath: string, opts?: DataOpts): Promise> { const url = `${this.prefix}${filepath}`; return adapter({ diff --git a/query/query-resources/utils.ts b/query/query-resources/utils.ts index 895734f..7cd1ce3 100644 --- a/query/query-resources/utils.ts +++ b/query/query-resources/utils.ts @@ -1,14 +1,40 @@ import MD5 from 'crypto-js/md5'; -export const hashContent = (str: string | Buffer): string => { +export const hashContent = (str: string | Blob | Buffer): Promise | string => { if (typeof str === 'string') { return MD5(str).toString(); + } else if (str instanceof Blob) { + return hashBlob(str); } else if (Buffer.isBuffer(str)) { return MD5(str.toString()).toString(); } - console.error('hashContent error: input must be a string or Buffer'); + console.error('hashContent error: input must be a string, Blob, or Buffer'); return ''; }; + +export const hashBlob = (blob: Blob): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = async () => { + try { + const content = reader.result; + if (typeof content === 'string') { + resolve(MD5(content).toString()); + } else if (content) { + const contentString = new TextDecoder().decode(content); + resolve(MD5(contentString).toString()); + } else { + reject(new Error('Empty content')); + } + } catch (error) { + console.error('hashBlob error', error); + reject(error); + } + }; + reader.onerror = (error) => reject(error); + reader.readAsArrayBuffer(blob); + }); +}; export const hashFile = (file: File): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader();