diff --git a/src/baseTypes.ts b/src/baseTypes.ts index dae6467..287037c 100644 --- a/src/baseTypes.ts +++ b/src/baseTypes.ts @@ -26,7 +26,12 @@ export interface DropboxConfig { } export type WebdavAuthType = "digest" | "basic"; -export type WebdavDepthType = "auto_unknown" | "auto_1" | "auto_infinity" | "manual_1" | "manual_infinity"; +export type WebdavDepthType = + | "auto_unknown" + | "auto_1" + | "auto_infinity" + | "manual_1" + | "manual_infinity"; export interface WebdavConfig { address: string; diff --git a/src/remote.ts b/src/remote.ts index 008944b..678af64 100644 --- a/src/remote.ts +++ b/src/remote.ts @@ -41,11 +41,17 @@ export class RemoteClient { this.s3Config = s3Config; this.s3Client = s3.getS3Client(this.s3Config); } else if (serviceType === "webdav") { - if (vaultName === undefined) { - throw Error("remember to provide vault name while init webdav client"); + if (vaultName === undefined || saveUpdatedConfigFunc === undefined) { + throw Error( + "remember to provide vault name and callback while init webdav client" + ); } this.webdavConfig = webdavConfig; - this.webdavClient = webdav.getWebdavClient(this.webdavConfig, vaultName); + this.webdavClient = webdav.getWebdavClient( + this.webdavConfig, + vaultName, + saveUpdatedConfigFunc + ); } else if (serviceType === "dropbox") { if (vaultName === undefined || saveUpdatedConfigFunc === undefined) { throw Error( diff --git a/src/remoteForWebdav.ts b/src/remoteForWebdav.ts index dbd6e95..9a36fa9 100644 --- a/src/remoteForWebdav.ts +++ b/src/remoteForWebdav.ts @@ -118,6 +118,7 @@ export const DEFAULT_WEBDAV_CONFIG = { password: "", authType: "basic", manualRecursive: false, + depth: "auto_unknown", } as WebdavConfig; const getWebdavPath = (fileOrFolderPath: string, vaultName: string) => { @@ -166,10 +167,16 @@ export class WrappedWebdavClient { vaultName: string; client: WebDAVClient; vaultFolderExists: boolean; - constructor(webdavConfig: WebdavConfig, vaultName: string) { + saveUpdatedConfigFunc: () => Promise; + constructor( + webdavConfig: WebdavConfig, + vaultName: string, + saveUpdatedConfigFunc: () => Promise + ) { this.webdavConfig = webdavConfig; this.vaultName = vaultName; this.vaultFolderExists = false; + this.saveUpdatedConfigFunc = saveUpdatedConfigFunc; } init = async () => { @@ -208,14 +215,68 @@ export class WrappedWebdavClient { this.vaultFolderExists = true; } } + + // adjust depth parameter + if (this.webdavConfig.depth === "auto_unknown") { + let testPassed = false; + try { + const res = await this.client.customRequest(`/${this.vaultName}`, { + method: "PROPFIND", + headers: { + Depth: "Infinity", + }, + responseType: "text", + }); + if (res.status === 403) { + throw Error("not support Infinity, get 403"); + } else { + testPassed = true; + this.webdavConfig.depth = "auto_infinity"; + this.webdavConfig.manualRecursive = false; + } + } catch (error) { + testPassed = false; + } + if (!testPassed) { + try { + const res = await this.client.customRequest(`/${this.vaultName}`, { + method: "PROPFIND", + headers: { + Depth: "1", + }, + responseType: "text", + }); + testPassed = true; + this.webdavConfig.depth = "auto_1"; + this.webdavConfig.manualRecursive = true; + } catch (error) { + testPassed = false; + } + } + if (testPassed) { + // the depth option has been changed + // save the setting + if (this.saveUpdatedConfigFunc !== undefined) { + await this.saveUpdatedConfigFunc(); + log.info( + `webdav depth="auto_unknown" is changed to ${this.webdavConfig.depth}` + ); + } + } + } }; } export const getWebdavClient = ( webdavConfig: WebdavConfig, - vaultName: string + vaultName: string, + saveUpdatedConfigFunc: () => Promise ) => { - return new WrappedWebdavClient(webdavConfig, vaultName); + return new WrappedWebdavClient( + webdavConfig, + vaultName, + saveUpdatedConfigFunc + ); }; export const getRemoteMeta = async ( @@ -318,7 +379,10 @@ export const listFromRemote = async ( await client.init(); let contents = [] as FileStat[]; - if (client.webdavConfig.manualRecursive) { + if ( + client.webdavConfig.depth === "auto_1" || + client.webdavConfig.depth === "manual_1" + ) { // the remote doesn't support infinity propfind, // we need to do a bfs here const q = new Queue([`/${client.vaultName}`]); diff --git a/src/settings.ts b/src/settings.ts index c58245b..ac2e64a 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1076,7 +1076,7 @@ export class RemotelySaveSettingTab extends PluginSettingTab { new Setting(webdavDiv) .setName("depth header sent to servers") .setDesc( - "Webdav servers should be configured to allow requests with header Depth being '1' or 'infinity'. The plugin needs to know this info. If you are not sure what's this, choose \"auto\"." + "Webdav servers should be configured to allow requests with header Depth being '1' or 'Infinity'. The plugin needs to know this info. If you are not sure what's this, choose \"auto\"." ) .addDropdown((dropdown) => { dropdown.addOption("auto", "auto detect"); @@ -1084,29 +1084,31 @@ export class RemotelySaveSettingTab extends PluginSettingTab { dropdown.addOption("manual_infinity", "only supports depth='infinity'"); let initVal = "auto"; - const autoOptions: Set = new Set(["auto_unknown", "auto_1", "auto_infinity"]); + const autoOptions: Set = new Set([ + "auto_unknown", + "auto_1", + "auto_infinity", + ]); if (autoOptions.has(this.plugin.settings.webdav.depth)) { initVal = "auto"; } else { initVal = this.plugin.settings.webdav.depth || "auto"; } - type DepthOption = "auto" | "manual_1" | "manual_infinity" - dropdown - .setValue( initVal) - .onChange(async (val: DepthOption) => { - if (val === "auto") { - this.plugin.settings.webdav.depth = "auto_unknown"; - this.plugin.settings.webdav.manualRecursive = false; - } else if (val === "manual_1") { - this.plugin.settings.webdav.depth = "manual_1"; - this.plugin.settings.webdav.manualRecursive = true; - } else if (val === "manual_infinity") { - this.plugin.settings.webdav.depth = "manual_infinity"; - this.plugin.settings.webdav.manualRecursive = false; - } - await this.plugin.saveSettings(); - }); + type DepthOption = "auto" | "manual_1" | "manual_infinity"; + dropdown.setValue(initVal).onChange(async (val: DepthOption) => { + if (val === "auto") { + this.plugin.settings.webdav.depth = "auto_unknown"; + this.plugin.settings.webdav.manualRecursive = false; + } else if (val === "manual_1") { + this.plugin.settings.webdav.depth = "manual_1"; + this.plugin.settings.webdav.manualRecursive = true; + } else if (val === "manual_infinity") { + this.plugin.settings.webdav.depth = "manual_infinity"; + this.plugin.settings.webdav.manualRecursive = false; + } + await this.plugin.saveSettings(); + }); }); new Setting(webdavDiv) @@ -1116,13 +1118,15 @@ export class RemotelySaveSettingTab extends PluginSettingTab { button.setButtonText("Check"); button.onClick(async () => { new Notice("Checking..."); + const self = this; const client = new RemoteClient( "webdav", undefined, this.plugin.settings.webdav, undefined, undefined, - this.app.vault.getName() + this.app.vault.getName(), + () => self.plugin.saveSettings() ); const res = await client.checkConnectivity(); if (res) {