| 24 | }; |
| 25 | |
| 26 | export default class WebDAVFileSystem implements FileSystem { |
| 27 | client: WebDAVClient; |
| 28 | |
| 29 | url: string; |
| 30 | |
| 31 | basePath: string = "/"; |
| 32 | |
| 33 | static fromCredentials(url: string, options: WebDAVClientOptions) { |
| 34 | initWebDAVPatch(); |
| 35 | options = { |
| 36 | ...options, |
| 37 | headers: { |
| 38 | "X-Requested-With": "XMLHttpRequest", // Nextcloud 等需要 |
| 39 | // "requesttoken": csrfToken, // 按账号各自传入 |
| 40 | }, |
| 41 | }; |
| 42 | return new WebDAVFileSystem(createClient(url, options), url, "/"); |
| 43 | } |
| 44 | |
| 45 | static fromSameClient(fs: WebDAVFileSystem, basePath: string) { |
| 46 | return new WebDAVFileSystem(fs.client, fs.url, basePath); |
| 47 | } |
| 48 | |
| 49 | private constructor(client: WebDAVClient, url: string, basePath: string) { |
| 50 | this.client = client; |
| 51 | this.url = url; |
| 52 | this.basePath = basePath; |
| 53 | } |
| 54 | |
| 55 | async verify(): Promise<void> { |
| 56 | // 只做只读校验:凭据 + URL 可达性。 |
| 57 | // 写权限不在此处探测——不同 basePath 写策略不同(坚果云等根目录不可写的服务会被误杀,见 #1444), |
| 58 | // 真正的写操作会在 backupToCloud / buildFileSystem 中由 createDir 立即触发并报错。 |
| 59 | try { |
| 60 | await this.client.getQuota(); |
| 61 | await this.client.getDirectoryContents(this.basePath); |
| 62 | } catch (e: any) { |
| 63 | if (e.response?.status === 401) { |
| 64 | throw new WarpTokenError(e); |
| 65 | } |
| 66 | throw new Error(`WebDAV verify failed: ${e.message}`); // 保留原始信息 |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | async open(file: FileInfo): Promise<FileReader> { |
| 71 | return new WebDAVFileReader(this.client, joinPath(file.path, file.name)); |
| 72 | } |
| 73 | |
| 74 | async openDir(path: string): Promise<FileSystem> { |
| 75 | return WebDAVFileSystem.fromSameClient(this, joinPath(this.basePath, path)); |
| 76 | } |
| 77 | |
| 78 | async create(path: string, _opts?: FileCreateOptions): Promise<FileWriter> { |
| 79 | return new WebDAVFileWriter(this.client, joinPath(this.basePath, path)); |
| 80 | } |
| 81 | |
| 82 | async createDir(path: string, _opts?: FileCreateOptions): Promise<void> { |
| 83 | try { |
nothing calls this directly
no outgoing calls
no test coverage detected