webdav also sync in vault folder

This commit is contained in:
fyears 2021-12-11 23:55:12 +08:00
parent 437e041e71
commit 44480be707
3 changed files with 128 additions and 50 deletions

View File

@ -834,7 +834,9 @@ class RemotelySaveSettingTab extends PluginSettingTab {
const client = new RemoteClient( const client = new RemoteClient(
"webdav", "webdav",
undefined, undefined,
this.plugin.settings.webdav this.plugin.settings.webdav,
undefined,
this.app.vault.getName()
); );
const res = await client.checkConnectivity(); const res = await client.checkConnectivity();
if (res) { if (res) {

View File

@ -14,7 +14,7 @@ export class RemoteClient {
readonly serviceType: SUPPORTED_SERVICES_TYPE; readonly serviceType: SUPPORTED_SERVICES_TYPE;
readonly s3Client?: s3.S3Client; readonly s3Client?: s3.S3Client;
readonly s3Config?: S3Config; readonly s3Config?: S3Config;
readonly webdavClient?: webdav.WebDAVClient; readonly webdavClient?: webdav.WrappedWebdavClient;
readonly webdavConfig?: WebdavConfig; readonly webdavConfig?: WebdavConfig;
readonly dropboxClient?: dropbox.WrappedDropboxClient; readonly dropboxClient?: dropbox.WrappedDropboxClient;
readonly dropboxConfig?: DropboxConfig; readonly dropboxConfig?: DropboxConfig;
@ -34,8 +34,11 @@ export class RemoteClient {
this.s3Config = s3Config; this.s3Config = s3Config;
this.s3Client = s3.getS3Client(this.s3Config); this.s3Client = s3.getS3Client(this.s3Config);
} else if (serviceType === "webdav") { } else if (serviceType === "webdav") {
if (vaultName === undefined) {
throw Error("remember to provide vault name while init webdav client");
}
this.webdavConfig = webdavConfig; this.webdavConfig = webdavConfig;
this.webdavClient = webdav.getWebdavClient(this.webdavConfig); this.webdavClient = webdav.getWebdavClient(this.webdavConfig, vaultName);
} else if (serviceType === "dropbox") { } else if (serviceType === "dropbox") {
if (vaultName === undefined || saveUpdatedConfigFunc === undefined) { if (vaultName === undefined || saveUpdatedConfigFunc === undefined) {
throw Error( throw Error(

View File

@ -21,22 +21,35 @@ export const DEFAULT_WEBDAV_CONFIG = {
authType: "basic", authType: "basic",
} as WebdavConfig; } as WebdavConfig;
const getWebdavPath = (fileOrFolderPath: string) => { const getWebdavPath = (fileOrFolderPath: string, vaultName: string) => {
let key = fileOrFolderPath;
if (fileOrFolderPath === "/" || fileOrFolderPath === "") {
// special
key = `/${vaultName}/`;
}
if (!fileOrFolderPath.startsWith("/")) { if (!fileOrFolderPath.startsWith("/")) {
return `/${fileOrFolderPath}`; key = `/${vaultName}/${fileOrFolderPath}`;
} }
return fileOrFolderPath; return key;
}; };
const getNormPath = (fileOrFolderPath: string) => { const getNormPath = (fileOrFolderPath: string, vaultName: string) => {
if (fileOrFolderPath.startsWith("/")) { if (
return fileOrFolderPath.slice(1); !(
fileOrFolderPath === `/${vaultName}` ||
fileOrFolderPath.startsWith(`/${vaultName}/`)
)
) {
throw Error(`"${fileOrFolderPath}" doesn't starts with "/${vaultName}/"`);
} }
return fileOrFolderPath; // if (fileOrFolderPath.startsWith("/")) {
// return fileOrFolderPath.slice(1);
// }
return fileOrFolderPath.slice(`/${vaultName}/`.length);
}; };
const fromWebdavItemToRemoteItem = (x: FileStat) => { const fromWebdavItemToRemoteItem = (x: FileStat, vaultName: string) => {
let key = getNormPath(x.filename); let key = getNormPath(x.filename, vaultName);
if (x.type === "directory" && !key.endsWith("/")) { if (x.type === "directory" && !key.endsWith("/")) {
key = `${key}/`; key = `${key}/`;
} }
@ -49,45 +62,90 @@ const fromWebdavItemToRemoteItem = (x: FileStat) => {
} as RemoteItem; } as RemoteItem;
}; };
export const getWebdavClient = (webdavConfig: WebdavConfig) => { export class WrappedWebdavClient {
if (webdavConfig.username !== "" && webdavConfig.password !== "") { webdavConfig: WebdavConfig;
return createClient(webdavConfig.address, { vaultName: string;
username: webdavConfig.username, client: WebDAVClient;
password: webdavConfig.password, vaultFolderExists: boolean;
authType: constructor(webdavConfig: WebdavConfig, vaultName: string) {
webdavConfig.authType === "digest" this.webdavConfig = webdavConfig;
? AuthType.Digest this.vaultName = vaultName;
: AuthType.Password, this.vaultFolderExists = false;
});
} else {
console.log("no password");
return createClient(webdavConfig.address);
} }
init = async () => {
// init client if not inited
if (this.client === undefined) {
if (
this.webdavConfig.username !== "" &&
this.webdavConfig.password !== ""
) {
this.client = createClient(this.webdavConfig.address, {
username: this.webdavConfig.username,
password: this.webdavConfig.password,
authType:
this.webdavConfig.authType === "digest"
? AuthType.Digest
: AuthType.Password,
});
} else {
console.log("no password");
this.client = createClient(this.webdavConfig.address);
}
}
// check vault folder
if (this.vaultFolderExists) {
// pass
} else {
const res = await this.client.exists(`/${this.vaultName}`);
if (res) {
console.log("exits!");
this.vaultFolderExists = true;
} else {
console.log("not exists, creating");
await this.client.createDirectory(`/${this.vaultName}`);
console.log("created!");
this.vaultFolderExists = true;
}
}
};
}
export const getWebdavClient = (
webdavConfig: WebdavConfig,
vaultName: string
) => {
return new WrappedWebdavClient(webdavConfig, vaultName);
}; };
export const getRemoteMeta = async ( export const getRemoteMeta = async (
client: WebDAVClient, client: WrappedWebdavClient,
fileOrFolderPath: string fileOrFolderPath: string
) => { ) => {
const res = (await client.stat(getWebdavPath(fileOrFolderPath), { await client.init();
const remotePath = getWebdavPath(fileOrFolderPath, client.vaultName);
console.log(`remotePath = ${remotePath}`);
const res = (await client.client.stat(remotePath, {
details: false, details: false,
})) as FileStat; })) as FileStat;
return fromWebdavItemToRemoteItem(res); return fromWebdavItemToRemoteItem(res, client.vaultName);
}; };
export const uploadToRemote = async ( export const uploadToRemote = async (
client: WebDAVClient, client: WrappedWebdavClient,
fileOrFolderPath: string, fileOrFolderPath: string,
vault: Vault, vault: Vault,
isRecursively: boolean = false, isRecursively: boolean = false,
password: string = "", password: string = "",
remoteEncryptedKey: string = "" remoteEncryptedKey: string = ""
) => { ) => {
await client.init();
let uploadFile = fileOrFolderPath; let uploadFile = fileOrFolderPath;
if (password !== "") { if (password !== "") {
uploadFile = remoteEncryptedKey; uploadFile = remoteEncryptedKey;
} }
uploadFile = getWebdavPath(uploadFile); uploadFile = getWebdavPath(uploadFile, client.vaultName);
const isFolder = fileOrFolderPath.endsWith("/"); const isFolder = fileOrFolderPath.endsWith("/");
@ -97,14 +155,14 @@ export const uploadToRemote = async (
// folder // folder
if (password === "") { if (password === "") {
// if not encrypted, mkdir a remote folder // if not encrypted, mkdir a remote folder
await client.createDirectory(uploadFile, { await client.client.createDirectory(uploadFile, {
recursive: true, recursive: true,
}); });
const res = await getRemoteMeta(client, uploadFile); const res = await getRemoteMeta(client, uploadFile);
return res; return res;
} else { } else {
// if encrypted, upload a fake file with the encrypted file name // if encrypted, upload a fake file with the encrypted file name
await client.putFileContents(uploadFile, "", { await client.client.putFileContents(uploadFile, "", {
overwrite: true, overwrite: true,
onUploadProgress: (progress) => { onUploadProgress: (progress) => {
console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`); console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`);
@ -124,9 +182,9 @@ export const uploadToRemote = async (
// we need to create folders before uploading // we need to create folders before uploading
const dir = getPathFolder(uploadFile); const dir = getPathFolder(uploadFile);
if (dir !== "/" && dir !== "") { if (dir !== "/" && dir !== "") {
await client.createDirectory(dir, { recursive: true }); await client.client.createDirectory(dir, { recursive: true });
} }
await client.putFileContents(uploadFile, remoteContent, { await client.client.putFileContents(uploadFile, remoteContent, {
overwrite: true, overwrite: true,
onUploadProgress: (progress) => { onUploadProgress: (progress) => {
console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`); console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`);
@ -137,26 +195,36 @@ export const uploadToRemote = async (
} }
}; };
export const listFromRemote = async (client: WebDAVClient, prefix?: string) => { export const listFromRemote = async (
client: WrappedWebdavClient,
prefix?: string
) => {
if (prefix !== undefined) { if (prefix !== undefined) {
throw Error("prefix not supported"); throw Error("prefix not supported");
} }
const contents = (await client.getDirectoryContents("/", { await client.init();
deep: true, const contents = (await client.client.getDirectoryContents(
details: false /* no need for verbose details here */, `/${client.vaultName}`,
glob: "/**" /* avoid dot files by using glob */, {
})) as FileStat[]; deep: true,
details: false /* no need for verbose details here */,
glob: "/**" /* avoid dot files by using glob */,
}
)) as FileStat[];
return { return {
Contents: contents.map((x) => fromWebdavItemToRemoteItem(x)), Contents: contents.map((x) =>
fromWebdavItemToRemoteItem(x, client.vaultName)
),
}; };
}; };
const downloadFromRemoteRaw = async ( const downloadFromRemoteRaw = async (
client: WebDAVClient, client: WrappedWebdavClient,
fileOrFolderPath: string fileOrFolderPath: string
) => { ) => {
const buff = (await client.getFileContents( await client.init();
getWebdavPath(fileOrFolderPath) const buff = (await client.client.getFileContents(
getWebdavPath(fileOrFolderPath, client.vaultName)
)) as BufferLike; )) as BufferLike;
if (buff instanceof ArrayBuffer) { if (buff instanceof ArrayBuffer) {
return buff; return buff;
@ -167,13 +235,15 @@ const downloadFromRemoteRaw = async (
}; };
export const downloadFromRemote = async ( export const downloadFromRemote = async (
client: WebDAVClient, client: WrappedWebdavClient,
fileOrFolderPath: string, fileOrFolderPath: string,
vault: Vault, vault: Vault,
mtime: number, mtime: number,
password: string = "", password: string = "",
remoteEncryptedKey: string = "" remoteEncryptedKey: string = ""
) => { ) => {
await client.init();
const isFolder = fileOrFolderPath.endsWith("/"); const isFolder = fileOrFolderPath.endsWith("/");
await mkdirpInVault(fileOrFolderPath, vault); await mkdirpInVault(fileOrFolderPath, vault);
@ -189,7 +259,7 @@ export const downloadFromRemote = async (
if (password !== "") { if (password !== "") {
downloadFile = remoteEncryptedKey; downloadFile = remoteEncryptedKey;
} }
downloadFile = getWebdavPath(downloadFile); downloadFile = getWebdavPath(downloadFile, client.vaultName);
const remoteContent = await downloadFromRemoteRaw(client, downloadFile); const remoteContent = await downloadFromRemoteRaw(client, downloadFile);
let localContent = remoteContent; let localContent = remoteContent;
if (password !== "") { if (password !== "") {
@ -202,7 +272,7 @@ export const downloadFromRemote = async (
}; };
export const deleteFromRemote = async ( export const deleteFromRemote = async (
client: WebDAVClient, client: WrappedWebdavClient,
fileOrFolderPath: string, fileOrFolderPath: string,
password: string = "", password: string = "",
remoteEncryptedKey: string = "" remoteEncryptedKey: string = ""
@ -214,9 +284,11 @@ export const deleteFromRemote = async (
if (password !== "") { if (password !== "") {
remoteFileName = remoteEncryptedKey; remoteFileName = remoteEncryptedKey;
} }
remoteFileName = getWebdavPath(remoteFileName); remoteFileName = getWebdavPath(remoteFileName, client.vaultName);
await client.init();
try { try {
await client.deleteFile(remoteFileName); await client.client.deleteFile(remoteFileName);
// console.log(`delete ${remoteFileName} succeeded`); // console.log(`delete ${remoteFileName} succeeded`);
} catch (err) { } catch (err) {
console.error("some error while deleting"); console.error("some error while deleting");
@ -224,7 +296,8 @@ export const deleteFromRemote = async (
} }
}; };
export const checkConnectivity = async (client: WebDAVClient) => { export const checkConnectivity = async (client: WrappedWebdavClient) => {
await client.init();
try { try {
const results = await getRemoteMeta(client, "/"); const results = await getRemoteMeta(client, "/");
if (results === undefined) { if (results === undefined) {