3f5901766d
* chore: import opendal * feat: 添加S3备份支持及相关设置界面 - 在IpcChannel中新增S3备份相关IPC事件,支持备份、恢复、 列表、删除文件及连接检测 - 在ipc主进程注册对应的S3备份处理函数,集成backupManager - 新增S3设置页面,支持配置Endpoint、Region、Bucket、AccessKey等 参数,并提供同步和备份策略的UI控制 - 删除未使用的RemoteStorage.ts,简化代码库 提升备份功能的灵活性,支持S3作为远程存储目标 * feat(S3 Backup): 完善S3备份功能 - 支持自动备份 - 优化设置前端 - 优化备份恢复代码 * feat(i18n): add S3 storage translations * feat(settings): 优化数据设置页面和S3设置页面UI * feat(settings): optimize S3 settings state structure and update usage * refactor: simplify S3 backup and restore modal logic * feat(s3 backup): improve S3 settings defaults and modal props * fix(i18n): optimize S3 access key translations * feat(backup): optimize logging and progress reporting * fix(settings): set S3 maxBackups as unlimited by default * chore(package): restore opendal dependency in package.json --------- Co-authored-by: suyao <sy20010504@gmail.com>
84 lines
2.7 KiB
TypeScript
84 lines
2.7 KiB
TypeScript
import Logger from 'electron-log'
|
|
import type { Operator as OperatorType } from 'opendal'
|
|
const { Operator } = require('opendal')
|
|
|
|
export default class S3Storage {
|
|
public instance: OperatorType | undefined
|
|
|
|
/**
|
|
*
|
|
* @param scheme is the scheme for opendal services. Available value includes "azblob", "azdls", "cos", "gcs", "obs", "oss", "s3", "webdav", "webhdfs", "aliyun-drive", "alluxio", "azfile", "dropbox", "gdrive", "onedrive", "postgresql", "mysql", "redis", "swift", "mongodb", "alluxio", "b2", "seafile", "upyun", "koofr", "yandex-disk"
|
|
* @param options is the options for given opendal services. Valid options depend on the scheme. Checkout https://docs.rs/opendal/latest/opendal/services/index.html for all valid options.
|
|
*
|
|
* For example, use minio as remote storage:
|
|
*
|
|
* ```typescript
|
|
* const storage = new S3Storage('s3', {
|
|
* endpoint: 'http://localhost:9000',
|
|
* region: 'us-east-1',
|
|
* bucket: 'testbucket',
|
|
* access_key_id: 'user',
|
|
* secret_access_key: 'password',
|
|
* root: '/path/to/basepath',
|
|
* })
|
|
* ```
|
|
*/
|
|
constructor(scheme: string, options?: Record<string, string> | undefined | null) {
|
|
this.instance = new Operator(scheme, options)
|
|
|
|
this.putFileContents = this.putFileContents.bind(this)
|
|
this.getFileContents = this.getFileContents.bind(this)
|
|
}
|
|
|
|
public putFileContents = async (filename: string, data: string | Buffer) => {
|
|
if (!this.instance) {
|
|
return new Error('RemoteStorage client not initialized')
|
|
}
|
|
|
|
try {
|
|
return await this.instance.write(filename, data)
|
|
} catch (error) {
|
|
Logger.error('[RemoteStorage] Error putting file contents:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
public getFileContents = async (filename: string) => {
|
|
if (!this.instance) {
|
|
throw new Error('RemoteStorage client not initialized')
|
|
}
|
|
|
|
try {
|
|
return await this.instance.read(filename)
|
|
} catch (error) {
|
|
Logger.error('[RemoteStorage] Error getting file contents:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
public deleteFile = async (filename: string) => {
|
|
if (!this.instance) {
|
|
throw new Error('RemoteStorage client not initialized')
|
|
}
|
|
try {
|
|
return await this.instance.delete(filename)
|
|
} catch (error) {
|
|
Logger.error('[RemoteStorage] Error deleting file:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
public checkConnection = async () => {
|
|
if (!this.instance) {
|
|
throw new Error('RemoteStorage client not initialized')
|
|
}
|
|
try {
|
|
// 检查根目录是否可访问
|
|
return await this.instance.stat('/')
|
|
} catch (error) {
|
|
Logger.error('[RemoteStorage] Error checking connection:', error)
|
|
throw error
|
|
}
|
|
}
|
|
}
|