新增: 云OSS存储集成(七牛云+阿里云)+多桶导航+GBK编码自动转换

This commit is contained in:
lxy
2026-05-05 03:18:47 +08:00
parent eb5b85e007
commit b4f4b4627d
34 changed files with 5225 additions and 48 deletions
+194
View File
@@ -0,0 +1,194 @@
/**
* OSS Transport — 通过 Wails IPC 调用 Go 后端 OSS 客户端
*/
import type {
FsTransport, FileItem, FileOperationResult, DetectTypeResult,
} from './transport'
import type { ConnectionProfile } from './connection-manager'
import {
OssConnect, OssDisconnect, OssListDir, OssReadFile,
OssWriteFile, OssGetFileInfo, OssCreateDir, OssCreateFile,
OssDeletePath, OssRenamePath, OssDownloadToTemp, OssGetCommonPaths,
OssWriteBase64File, OssGetSignedURL,
} from '@bindings/u-desk/app'
function transformFile(file: any): FileItem {
return { ...file, is_dir: file.is_dir, mod_time: file.mod_time }
}
function transformFileList(files: any[]): FileItem[] {
return files.map(transformFile)
}
const PREVIEW_CACHE_MAX = 50
export class OssTransport implements FsTransport {
private profile: ConnectionProfile
private connID: string | null = null
private previewCache = new Map<string, string>()
private previewOrder: string[] = []
constructor(profile: ConnectionProfile) {
this.profile = profile
}
async connect(): Promise<string> {
const result = await OssConnect({
provider: this.profile.type,
access_key: this.profile.accessKey || '',
secret_key: this.profile.secretKey || '',
endpoint: this.profile.endpoint || '',
})
this.connID = result
return result
}
get sessionId(): string | null { return this.connID }
async disconnect(): Promise<void> {
if (this.connID) {
try { await OssDisconnect(this.connID) } catch (e) {
console.warn('[OSS] disconnect error:', e)
}
this.connID = null
}
this.previewCache.clear()
this.previewOrder = []
}
private requireConn(): string {
if (!this.connID) throw new Error('OSS 未连接')
return this.connID
}
// ====== 文件列表与信息 ======
async listDir(path: string): Promise<FileItem[]> {
return transformFileList(await OssListDir(this.requireConn(), path))
}
async getFileInfo(path: string): Promise<Record<string, any>> {
return OssGetFileInfo(this.requireConn(), path)
}
// ====== 文件读写 ======
async readFile(path: string): Promise<string> {
return OssReadFile(this.requireConn(), path)
}
async writeFile(path: string, content: string): Promise<void> {
await OssWriteFile(this.requireConn(), path, content)
}
async saveBase64File(path: string, content: string): Promise<void> {
if (!content) throw new Error('无效的 base64 内容')
await OssWriteBase64File(this.requireConn(), path, content)
}
// ====== 文件操作 ======
async createFile(dirPath: string, filename: string): Promise<FileOperationResult> {
const fullPath = dirPath.replace(/\/$/, '') + '/' + filename
return OssCreateFile(this.requireConn(), fullPath)
}
async createDir(parentPath: string, dirname: string): Promise<FileOperationResult> {
const fullPath = parentPath.replace(/\/$/, '') + '/' + dirname
return OssCreateDir(this.requireConn(), fullPath)
}
async deletePath(path: string): Promise<FileOperationResult> {
return OssDeletePath(this.requireConn(), path)
}
async renamePath(oldPath: string, newPath: string): Promise<FileOperationResult> {
return OssRenamePath({
conn_id: this.requireConn(),
old_path: oldPath,
new_path: newPath,
})
}
// ====== ZIP 操作(不支持)======
async listZipContents(_zipPath: string): Promise<FileItem[]> {
throw new Error('ZIP 操作在 OSS 模式暂未实现')
}
async extractFileFromZip(_zipPath: string, _filePath: string): Promise<string> {
throw new Error('ZIP 操作在 OSS 模式暂未实现')
}
async extractFileFromZipToTemp(_zipPath: string, _filePath: string): Promise<string> {
throw new Error('ZIP 操作在 OSS 模式暂未实现')
}
async getZipFileInfo(_zipPath: string, _filePath: string): Promise<FileItem> {
throw new Error('ZIP 操作在 OSS 模式暂未实现')
}
// ====== 系统操作 ======
async openPath(_path: string): Promise<void> {
throw new Error('OSS 模式不支持打开本地路径')
}
async getFileServerURL(): Promise<string> {
return ''
}
getPreviewToken(): string {
return ''
}
async resolveShortcut(_lnkPath: string): Promise<any> {
return null
}
async detectFileTypeByContent(_path: string): Promise<DetectTypeResult> {
return { extension: '', category: 'unknown', mime_type: '', confidence: 0 }
}
async getCommonPaths(): Promise<Record<string, string>> {
return OssGetCommonPaths(this.requireConn())
}
// ====== 回收站(无)======
async getRecycleBinEntries(): Promise<any[]> {
return []
}
async restoreFromRecycleBin(_path: string): Promise<void> {}
async deletePermanently(_path: string): Promise<void> {}
async emptyRecycleBin(): Promise<void> {}
// ====== 预览辅助 ======
async downloadForPreview(remotePath: string): Promise<string> {
if (this.previewCache.has(remotePath)) {
this.previewOrder = this.previewOrder.filter(p => p !== remotePath)
this.previewOrder.push(remotePath)
return this.previewCache.get(remotePath)!
}
const localPath = await OssDownloadToTemp(this.requireConn(), remotePath)
if (this.previewOrder.length >= PREVIEW_CACHE_MAX) {
const oldest = this.previewOrder.shift()!
this.previewCache.delete(oldest)
}
this.previewCache.set(remotePath, localPath)
this.previewOrder.push(remotePath)
return localPath
}
/** 获取预签名 URL(用于直接预览) */
async getSignedUrl(key: string): Promise<string> {
return OssGetSignedURL(this.requireConn(), key)
}
}