strict anywhere
This commit is contained in:
parent
480cf224c6
commit
8dde6c59d2
@ -48,6 +48,7 @@ export interface DropboxConfig {
|
|||||||
|
|
||||||
export type WebdavAuthType = "digest" | "basic";
|
export type WebdavAuthType = "digest" | "basic";
|
||||||
export type WebdavDepthType =
|
export type WebdavDepthType =
|
||||||
|
| "auto"
|
||||||
| "auto_unknown"
|
| "auto_unknown"
|
||||||
| "auto_1"
|
| "auto_1"
|
||||||
| "auto_infinity"
|
| "auto_infinity"
|
||||||
@ -112,7 +113,7 @@ export interface RemotelySavePluginSettings {
|
|||||||
|
|
||||||
export interface RemoteItem {
|
export interface RemoteItem {
|
||||||
key: string;
|
key: string;
|
||||||
lastModified: number;
|
lastModified?: number;
|
||||||
size: number;
|
size: number;
|
||||||
remoteType: SUPPORTED_SERVICES_TYPE;
|
remoteType: SUPPORTED_SERVICES_TYPE;
|
||||||
etag?: string;
|
etag?: string;
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export const exportQrCodeUri = async (
|
|||||||
currentVaultName: string,
|
currentVaultName: string,
|
||||||
pluginVersion: string
|
pluginVersion: string
|
||||||
) => {
|
) => {
|
||||||
const settings2 = cloneDeep(settings);
|
const settings2: Partial<RemotelySavePluginSettings> = cloneDeep(settings);
|
||||||
delete settings2.dropbox;
|
delete settings2.dropbox;
|
||||||
delete settings2.onedrive;
|
delete settings2.onedrive;
|
||||||
delete settings2.vaultRandomID;
|
delete settings2.vaultRandomID;
|
||||||
|
|||||||
@ -436,8 +436,8 @@ export const insertRenameRecordByVault = async (
|
|||||||
vaultRandomID: string
|
vaultRandomID: string
|
||||||
) => {
|
) => {
|
||||||
// log.info(fileOrFolder);
|
// log.info(fileOrFolder);
|
||||||
let k1: FileFolderHistoryRecord;
|
let k1: FileFolderHistoryRecord | undefined;
|
||||||
let k2: FileFolderHistoryRecord;
|
let k2: FileFolderHistoryRecord | undefined;
|
||||||
const actionWhen = Date.now();
|
const actionWhen = Date.now();
|
||||||
if (fileOrFolder instanceof TFile) {
|
if (fileOrFolder instanceof TFile) {
|
||||||
k1 = {
|
k1 = {
|
||||||
@ -473,8 +473,10 @@ export const insertRenameRecordByVault = async (
|
|||||||
// TAbstractFile does not contain these info
|
// TAbstractFile does not contain these info
|
||||||
// but from API_VER_STAT_FOLDER we can manually stat them by path.
|
// but from API_VER_STAT_FOLDER we can manually stat them by path.
|
||||||
const s = await statFix(fileOrFolder.vault, fileOrFolder.path);
|
const s = await statFix(fileOrFolder.vault, fileOrFolder.path);
|
||||||
ctime = s.ctime;
|
if (s !== undefined && s !== null) {
|
||||||
mtime = s.mtime;
|
ctime = s.ctime;
|
||||||
|
mtime = s.mtime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
k1 = {
|
k1 = {
|
||||||
key: key,
|
key: key,
|
||||||
@ -500,8 +502,8 @@ export const insertRenameRecordByVault = async (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.fileHistoryTbl.setItem(`${vaultRandomID}\t${k1.key}`, k1),
|
db.fileHistoryTbl.setItem(`${vaultRandomID}\t${k1!.key}`, k1),
|
||||||
db.fileHistoryTbl.setItem(`${vaultRandomID}\t${k2.key}`, k2),
|
db.fileHistoryTbl.setItem(`${vaultRandomID}\t${k2!.key}`, k2),
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
82
src/main.ts
82
src/main.ts
@ -133,18 +133,18 @@ const getIconSvg = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default class RemotelySavePlugin extends Plugin {
|
export default class RemotelySavePlugin extends Plugin {
|
||||||
settings: RemotelySavePluginSettings;
|
settings!: RemotelySavePluginSettings;
|
||||||
db: InternalDBs;
|
db!: InternalDBs;
|
||||||
syncStatus: SyncStatusType;
|
syncStatus!: SyncStatusType;
|
||||||
statusBarElement: HTMLSpanElement;
|
statusBarElement!: HTMLSpanElement;
|
||||||
oauth2Info: OAuth2Info;
|
oauth2Info!: OAuth2Info;
|
||||||
currLogLevel: string;
|
currLogLevel!: string;
|
||||||
currSyncMsg?: string;
|
currSyncMsg?: string;
|
||||||
syncRibbon?: HTMLElement;
|
syncRibbon?: HTMLElement;
|
||||||
autoRunIntervalID?: number;
|
autoRunIntervalID?: number;
|
||||||
syncOnSaveIntervalID?: number;
|
syncOnSaveIntervalID?: number;
|
||||||
i18n: I18n;
|
i18n!: I18n;
|
||||||
vaultRandomID: string;
|
vaultRandomID!: string;
|
||||||
debugServerTemp?: string;
|
debugServerTemp?: string;
|
||||||
|
|
||||||
async syncRun(triggerSource: SyncTriggerSourceType = "manual") {
|
async syncRun(triggerSource: SyncTriggerSourceType = "manual") {
|
||||||
@ -175,7 +175,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
|
|
||||||
let originLabel = `${this.manifest.name}`;
|
let originLabel = `${this.manifest.name}`;
|
||||||
if (this.syncRibbon !== undefined) {
|
if (this.syncRibbon !== undefined) {
|
||||||
originLabel = this.syncRibbon.getAttribute("aria-label");
|
originLabel = this.syncRibbon.getAttribute("aria-label") as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -286,7 +286,8 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.db,
|
this.db,
|
||||||
this.vaultRandomID
|
this.vaultRandomID
|
||||||
);
|
);
|
||||||
let localConfigDirContents: ObsConfigDirFileType[] = undefined;
|
let localConfigDirContents: ObsConfigDirFileType[] | undefined =
|
||||||
|
undefined;
|
||||||
if (this.settings.syncConfigDir) {
|
if (this.settings.syncConfigDir) {
|
||||||
localConfigDirContents = await listFilesInObsFolder(
|
localConfigDirContents = await listFilesInObsFolder(
|
||||||
this.app.vault.configDir,
|
this.app.vault.configDir,
|
||||||
@ -312,11 +313,11 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
client.serviceType,
|
client.serviceType,
|
||||||
triggerSource,
|
triggerSource,
|
||||||
this.app.vault,
|
this.app.vault,
|
||||||
this.settings.syncConfigDir,
|
this.settings.syncConfigDir ?? false,
|
||||||
this.app.vault.configDir,
|
this.app.vault.configDir,
|
||||||
this.settings.syncUnderscoreItems,
|
this.settings.syncUnderscoreItems ?? false,
|
||||||
this.settings.skipSizeLargerThan,
|
this.settings.skipSizeLargerThan ?? -1,
|
||||||
this.settings.ignorePaths,
|
this.settings.ignorePaths ?? [],
|
||||||
this.settings.password
|
this.settings.password
|
||||||
);
|
);
|
||||||
log.info(plan.mixedStates); // for debugging
|
log.info(plan.mixedStates); // for debugging
|
||||||
@ -350,7 +351,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
new SizesConflictModal(
|
new SizesConflictModal(
|
||||||
self.app,
|
self.app,
|
||||||
self,
|
self,
|
||||||
this.settings.skipSizeLargerThan,
|
this.settings.skipSizeLargerThan ?? -1,
|
||||||
ss,
|
ss,
|
||||||
this.settings.password !== ""
|
this.settings.password !== ""
|
||||||
).open();
|
).open();
|
||||||
@ -397,7 +398,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.manifest.id
|
this.manifest.id
|
||||||
}-${Date.now()}: finish sync, triggerSource=${triggerSource}`
|
}-${Date.now()}: finish sync, triggerSource=${triggerSource}`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
const msg = t("syncrun_abort", {
|
const msg = t("syncrun_abort", {
|
||||||
manifestID: this.manifest.id,
|
manifestID: this.manifest.id,
|
||||||
theDate: `${Date.now()}`,
|
theDate: `${Date.now()}`,
|
||||||
@ -412,7 +413,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
getNotice(e.message, 10 * 1000);
|
getNotice(e.message, 10 * 1000);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getNotice(error.message, 10 * 1000);
|
getNotice(error?.message ?? "error while sync", 10 * 1000);
|
||||||
}
|
}
|
||||||
this.syncStatus = "idle";
|
this.syncStatus = "idle";
|
||||||
if (this.syncRibbon !== undefined) {
|
if (this.syncRibbon !== undefined) {
|
||||||
@ -445,7 +446,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
await this.checkIfPresetRulesFollowed();
|
await this.checkIfPresetRulesFollowed();
|
||||||
|
|
||||||
// lang should be load early, but after settings
|
// lang should be load early, but after settings
|
||||||
this.i18n = new I18n(this.settings.lang, async (lang: LangTypeAndAuto) => {
|
this.i18n = new I18n(this.settings.lang!, async (lang: LangTypeAndAuto) => {
|
||||||
this.settings.lang = lang;
|
this.settings.lang = lang;
|
||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
});
|
});
|
||||||
@ -475,8 +476,11 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
vaultBasePath,
|
vaultBasePath,
|
||||||
vaultRandomIDFromOldConfigFile
|
vaultRandomIDFromOldConfigFile
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
new Notice(err.message, 10 * 1000);
|
new Notice(
|
||||||
|
err?.message ?? "error of prepareDBAndVaultRandomID",
|
||||||
|
10 * 1000
|
||||||
|
);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,14 +570,18 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.registerObsidianProtocolHandler(
|
this.registerObsidianProtocolHandler(
|
||||||
COMMAND_CALLBACK_DROPBOX,
|
COMMAND_CALLBACK_DROPBOX,
|
||||||
async (inputParams) => {
|
async (inputParams) => {
|
||||||
if (inputParams.code !== undefined) {
|
if (
|
||||||
|
inputParams.code !== undefined &&
|
||||||
|
this.oauth2Info?.verifier !== undefined
|
||||||
|
) {
|
||||||
if (this.oauth2Info.helperModal !== undefined) {
|
if (this.oauth2Info.helperModal !== undefined) {
|
||||||
this.oauth2Info.helperModal.contentEl.empty();
|
const k = this.oauth2Info.helperModal.contentEl;
|
||||||
|
k.empty();
|
||||||
|
|
||||||
t("protocol_dropbox_connecting")
|
t("protocol_dropbox_connecting")
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.forEach((val) => {
|
.forEach((val) => {
|
||||||
this.oauth2Info.helperModal.contentEl.createEl("p", {
|
k.createEl("p", {
|
||||||
text: val,
|
text: val,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -596,7 +604,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
const self = this;
|
const self = this;
|
||||||
setConfigBySuccessfullAuthInplaceDropbox(
|
setConfigBySuccessfullAuthInplaceDropbox(
|
||||||
this.settings.dropbox,
|
this.settings.dropbox,
|
||||||
authRes,
|
authRes!,
|
||||||
() => self.saveSettings()
|
() => self.saveSettings()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -655,14 +663,18 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.registerObsidianProtocolHandler(
|
this.registerObsidianProtocolHandler(
|
||||||
COMMAND_CALLBACK_ONEDRIVE,
|
COMMAND_CALLBACK_ONEDRIVE,
|
||||||
async (inputParams) => {
|
async (inputParams) => {
|
||||||
if (inputParams.code !== undefined) {
|
if (
|
||||||
|
inputParams.code !== undefined &&
|
||||||
|
this.oauth2Info?.verifier !== undefined
|
||||||
|
) {
|
||||||
if (this.oauth2Info.helperModal !== undefined) {
|
if (this.oauth2Info.helperModal !== undefined) {
|
||||||
this.oauth2Info.helperModal.contentEl.empty();
|
const k = this.oauth2Info.helperModal.contentEl;
|
||||||
|
k.empty();
|
||||||
|
|
||||||
t("protocol_onedrive_connecting")
|
t("protocol_onedrive_connecting")
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.forEach((val) => {
|
.forEach((val) => {
|
||||||
this.oauth2Info.helperModal.contentEl.createEl("p", {
|
k.createEl("p", {
|
||||||
text: val,
|
text: val,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -824,7 +836,13 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.syncRibbon = undefined;
|
this.syncRibbon = undefined;
|
||||||
if (this.oauth2Info !== undefined) {
|
if (this.oauth2Info !== undefined) {
|
||||||
this.oauth2Info.helperModal = undefined;
|
this.oauth2Info.helperModal = undefined;
|
||||||
this.oauth2Info = undefined;
|
this.oauth2Info = {
|
||||||
|
verifier: "",
|
||||||
|
helperModal: undefined,
|
||||||
|
authDiv: undefined,
|
||||||
|
revokeDiv: undefined,
|
||||||
|
revokeAuthSetting: undefined,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,7 +950,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
let dropboxExpired = false;
|
let dropboxExpired = false;
|
||||||
if (
|
if (
|
||||||
this.settings.dropbox.refreshToken !== "" &&
|
this.settings.dropbox.refreshToken !== "" &&
|
||||||
current >= this.settings.dropbox.credentialsShouldBeDeletedAtTime
|
current >= this.settings!.dropbox!.credentialsShouldBeDeletedAtTime!
|
||||||
) {
|
) {
|
||||||
dropboxExpired = true;
|
dropboxExpired = true;
|
||||||
this.settings.dropbox = cloneDeep(DEFAULT_DROPBOX_CONFIG);
|
this.settings.dropbox = cloneDeep(DEFAULT_DROPBOX_CONFIG);
|
||||||
@ -942,7 +960,7 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
let onedriveExpired = false;
|
let onedriveExpired = false;
|
||||||
if (
|
if (
|
||||||
this.settings.onedrive.refreshToken !== "" &&
|
this.settings.onedrive.refreshToken !== "" &&
|
||||||
current >= this.settings.onedrive.credentialsShouldBeDeletedAtTime
|
current >= this.settings!.onedrive!.credentialsShouldBeDeletedAtTime!
|
||||||
) {
|
) {
|
||||||
onedriveExpired = true;
|
onedriveExpired = true;
|
||||||
this.settings.onedrive = cloneDeep(DEFAULT_ONEDRIVE_CONFIG);
|
this.settings.onedrive = cloneDeep(DEFAULT_ONEDRIVE_CONFIG);
|
||||||
@ -1078,11 +1096,11 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
// );
|
// );
|
||||||
if (
|
if (
|
||||||
currentTime - lastModified <
|
currentTime - lastModified <
|
||||||
this.settings.syncOnSaveAfterMilliseconds
|
this.settings!.syncOnSaveAfterMilliseconds!
|
||||||
) {
|
) {
|
||||||
if (!runScheduled) {
|
if (!runScheduled) {
|
||||||
const scheduleTimeFromNow =
|
const scheduleTimeFromNow =
|
||||||
this.settings.syncOnSaveAfterMilliseconds -
|
this.settings!.syncOnSaveAfterMilliseconds! -
|
||||||
(currentTime - lastModified);
|
(currentTime - lastModified);
|
||||||
log.info(
|
log.info(
|
||||||
`schedule a run for ${scheduleTimeFromNow} milliseconds later`
|
`schedule a run for ${scheduleTimeFromNow} milliseconds later`
|
||||||
|
|||||||
@ -26,8 +26,8 @@ export interface MetadataOnRemote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const isEqualMetadataOnRemote = (
|
export const isEqualMetadataOnRemote = (
|
||||||
a: MetadataOnRemote,
|
a: MetadataOnRemote | undefined,
|
||||||
b: MetadataOnRemote
|
b: MetadataOnRemote | undefined
|
||||||
) => {
|
) => {
|
||||||
const m1 = a === undefined ? { deletions: [] } : a;
|
const m1 = a === undefined ? { deletions: [] } : a;
|
||||||
const m2 = b === undefined ? { deletions: [] } : b;
|
const m2 = b === undefined ? { deletions: [] } : b;
|
||||||
|
|||||||
17
src/misc.ts
17
src/misc.ts
@ -126,8 +126,12 @@ export const base64ToArrayBuffer = (b64text: string) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const hexStringToTypedArray = (hex: string) => {
|
export const hexStringToTypedArray = (hex: string) => {
|
||||||
|
const f = hex.match(/[\da-f]{2}/gi);
|
||||||
|
if (f === null) {
|
||||||
|
throw Error(`input ${hex} is not hex, no way to transform`);
|
||||||
|
}
|
||||||
return new Uint8Array(
|
return new Uint8Array(
|
||||||
hex.match(/[\da-f]{2}/gi).map(function (h) {
|
f.map(function (h) {
|
||||||
return parseInt(h, 16);
|
return parseInt(h, 16);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -236,7 +240,7 @@ export const setToString = (a: Set<string>, delimiter: string = ",") => {
|
|||||||
export const extractSvgSub = (x: string, subEl: string = "rect") => {
|
export const extractSvgSub = (x: string, subEl: string = "rect") => {
|
||||||
const parser = new window.DOMParser();
|
const parser = new window.DOMParser();
|
||||||
const dom = parser.parseFromString(x, "image/svg+xml");
|
const dom = parser.parseFromString(x, "image/svg+xml");
|
||||||
const svg = dom.querySelector("svg");
|
const svg = dom.querySelector("svg")!;
|
||||||
svg.setAttribute("viewbox", "0 0 10 10");
|
svg.setAttribute("viewbox", "0 0 10 10");
|
||||||
return svg.innerHTML;
|
return svg.innerHTML;
|
||||||
};
|
};
|
||||||
@ -317,7 +321,7 @@ export const getTypeName = (obj: any) => {
|
|||||||
* @param x
|
* @param x
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const atWhichLevel = (x: string) => {
|
export const atWhichLevel = (x: string | undefined) => {
|
||||||
if (
|
if (
|
||||||
x === undefined ||
|
x === undefined ||
|
||||||
x === "" ||
|
x === "" ||
|
||||||
@ -413,11 +417,14 @@ export const toText = (x: any) => {
|
|||||||
*/
|
*/
|
||||||
export const statFix = async (vault: Vault, path: string) => {
|
export const statFix = async (vault: Vault, path: string) => {
|
||||||
const s = await vault.adapter.stat(path);
|
const s = await vault.adapter.stat(path);
|
||||||
|
if (s === undefined || s === null) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
if (s.ctime === undefined || s.ctime === null || Number.isNaN(s.ctime)) {
|
if (s.ctime === undefined || s.ctime === null || Number.isNaN(s.ctime)) {
|
||||||
s.ctime = undefined;
|
s.ctime = undefined as any; // force assignment
|
||||||
}
|
}
|
||||||
if (s.mtime === undefined || s.mtime === null || Number.isNaN(s.mtime)) {
|
if (s.mtime === undefined || s.mtime === null || Number.isNaN(s.mtime)) {
|
||||||
s.mtime = undefined;
|
s.mtime = undefined as any; // force assignment
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(s.size === undefined || s.size === null || Number.isNaN(s.size)) &&
|
(s.size === undefined || s.size === null || Number.isNaN(s.size)) &&
|
||||||
|
|||||||
@ -53,9 +53,9 @@ export const listFilesInObsFolder = async (
|
|||||||
const CHUNK_SIZE = 10;
|
const CHUNK_SIZE = 10;
|
||||||
const contents: ObsConfigDirFileType[] = [];
|
const contents: ObsConfigDirFileType[] = [];
|
||||||
while (q.length > 0) {
|
while (q.length > 0) {
|
||||||
const itemsToFetch = [];
|
const itemsToFetch: string[] = [];
|
||||||
while (q.length > 0) {
|
while (q.length > 0) {
|
||||||
itemsToFetch.push(q.pop());
|
itemsToFetch.push(q.pop()!);
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemsToFetchChunks = chunk(itemsToFetch, CHUNK_SIZE);
|
const itemsToFetchChunks = chunk(itemsToFetch, CHUNK_SIZE);
|
||||||
@ -63,8 +63,11 @@ export const listFilesInObsFolder = async (
|
|||||||
const r = singleChunk.map(async (x) => {
|
const r = singleChunk.map(async (x) => {
|
||||||
const statRes = await statFix(vault, x);
|
const statRes = await statFix(vault, x);
|
||||||
|
|
||||||
|
if (statRes === undefined || statRes === null) {
|
||||||
|
throw Error("something goes wrong while listing hidden folder");
|
||||||
|
}
|
||||||
const isFolder = statRes.type === "folder";
|
const isFolder = statRes.type === "folder";
|
||||||
let children: ListedFiles = undefined;
|
let children: ListedFiles | undefined = undefined;
|
||||||
if (isFolder) {
|
if (isFolder) {
|
||||||
children = await vault.adapter.list(x);
|
children = await vault.adapter.list(x);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,10 +43,10 @@ export class RemoteClient {
|
|||||||
"remember to provide vault name and callback while init webdav client"
|
"remember to provide vault name and callback while init webdav client"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const remoteBaseDir = webdavConfig.remoteBaseDir || vaultName;
|
const remoteBaseDir = webdavConfig!.remoteBaseDir || vaultName;
|
||||||
this.webdavConfig = webdavConfig;
|
this.webdavConfig = webdavConfig;
|
||||||
this.webdavClient = webdav.getWebdavClient(
|
this.webdavClient = webdav.getWebdavClient(
|
||||||
this.webdavConfig,
|
this.webdavConfig!,
|
||||||
remoteBaseDir,
|
remoteBaseDir,
|
||||||
saveUpdatedConfigFunc
|
saveUpdatedConfigFunc
|
||||||
);
|
);
|
||||||
@ -56,10 +56,10 @@ export class RemoteClient {
|
|||||||
"remember to provide vault name and callback while init dropbox client"
|
"remember to provide vault name and callback while init dropbox client"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const remoteBaseDir = dropboxConfig.remoteBaseDir || vaultName;
|
const remoteBaseDir = dropboxConfig!.remoteBaseDir || vaultName;
|
||||||
this.dropboxConfig = dropboxConfig;
|
this.dropboxConfig = dropboxConfig;
|
||||||
this.dropboxClient = dropbox.getDropboxClient(
|
this.dropboxClient = dropbox.getDropboxClient(
|
||||||
this.dropboxConfig,
|
this.dropboxConfig!,
|
||||||
remoteBaseDir,
|
remoteBaseDir,
|
||||||
saveUpdatedConfigFunc
|
saveUpdatedConfigFunc
|
||||||
);
|
);
|
||||||
@ -69,10 +69,10 @@ export class RemoteClient {
|
|||||||
"remember to provide vault name and callback while init onedrive client"
|
"remember to provide vault name and callback while init onedrive client"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const remoteBaseDir = onedriveConfig.remoteBaseDir || vaultName;
|
const remoteBaseDir = onedriveConfig!.remoteBaseDir || vaultName;
|
||||||
this.onedriveConfig = onedriveConfig;
|
this.onedriveConfig = onedriveConfig;
|
||||||
this.onedriveClient = onedrive.getOnedriveClient(
|
this.onedriveClient = onedrive.getOnedriveClient(
|
||||||
this.onedriveConfig,
|
this.onedriveConfig!,
|
||||||
remoteBaseDir,
|
remoteBaseDir,
|
||||||
saveUpdatedConfigFunc
|
saveUpdatedConfigFunc
|
||||||
);
|
);
|
||||||
@ -84,17 +84,17 @@ export class RemoteClient {
|
|||||||
getRemoteMeta = async (fileOrFolderPath: string) => {
|
getRemoteMeta = async (fileOrFolderPath: string) => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.getRemoteMeta(
|
return await s3.getRemoteMeta(
|
||||||
s3.getS3Client(this.s3Config),
|
s3.getS3Client(this.s3Config!),
|
||||||
this.s3Config,
|
this.s3Config!,
|
||||||
fileOrFolderPath
|
fileOrFolderPath
|
||||||
);
|
);
|
||||||
} else if (this.serviceType === "webdav") {
|
} else if (this.serviceType === "webdav") {
|
||||||
return await webdav.getRemoteMeta(this.webdavClient, fileOrFolderPath);
|
return await webdav.getRemoteMeta(this.webdavClient!, fileOrFolderPath);
|
||||||
} else if (this.serviceType === "dropbox") {
|
} else if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.getRemoteMeta(this.dropboxClient, fileOrFolderPath);
|
return await dropbox.getRemoteMeta(this.dropboxClient!, fileOrFolderPath);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.getRemoteMeta(
|
return await onedrive.getRemoteMeta(
|
||||||
this.onedriveClient,
|
this.onedriveClient!,
|
||||||
fileOrFolderPath
|
fileOrFolderPath
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -104,7 +104,7 @@ export class RemoteClient {
|
|||||||
|
|
||||||
uploadToRemote = async (
|
uploadToRemote = async (
|
||||||
fileOrFolderPath: string,
|
fileOrFolderPath: string,
|
||||||
vault: Vault,
|
vault: Vault | undefined,
|
||||||
isRecursively: boolean = false,
|
isRecursively: boolean = false,
|
||||||
password: string = "",
|
password: string = "",
|
||||||
remoteEncryptedKey: string = "",
|
remoteEncryptedKey: string = "",
|
||||||
@ -114,8 +114,8 @@ export class RemoteClient {
|
|||||||
) => {
|
) => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.uploadToRemote(
|
return await s3.uploadToRemote(
|
||||||
s3.getS3Client(this.s3Config),
|
s3.getS3Client(this.s3Config!),
|
||||||
this.s3Config,
|
this.s3Config!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
isRecursively,
|
isRecursively,
|
||||||
@ -126,7 +126,7 @@ export class RemoteClient {
|
|||||||
);
|
);
|
||||||
} else if (this.serviceType === "webdav") {
|
} else if (this.serviceType === "webdav") {
|
||||||
return await webdav.uploadToRemote(
|
return await webdav.uploadToRemote(
|
||||||
this.webdavClient,
|
this.webdavClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
isRecursively,
|
isRecursively,
|
||||||
@ -137,7 +137,7 @@ export class RemoteClient {
|
|||||||
);
|
);
|
||||||
} else if (this.serviceType === "dropbox") {
|
} else if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.uploadToRemote(
|
return await dropbox.uploadToRemote(
|
||||||
this.dropboxClient,
|
this.dropboxClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
isRecursively,
|
isRecursively,
|
||||||
@ -149,7 +149,7 @@ export class RemoteClient {
|
|||||||
);
|
);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.uploadToRemote(
|
return await onedrive.uploadToRemote(
|
||||||
this.onedriveClient,
|
this.onedriveClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
isRecursively,
|
isRecursively,
|
||||||
@ -167,15 +167,15 @@ export class RemoteClient {
|
|||||||
listAllFromRemote = async () => {
|
listAllFromRemote = async () => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.listAllFromRemote(
|
return await s3.listAllFromRemote(
|
||||||
s3.getS3Client(this.s3Config),
|
s3.getS3Client(this.s3Config!),
|
||||||
this.s3Config
|
this.s3Config!
|
||||||
);
|
);
|
||||||
} else if (this.serviceType === "webdav") {
|
} else if (this.serviceType === "webdav") {
|
||||||
return await webdav.listAllFromRemote(this.webdavClient);
|
return await webdav.listAllFromRemote(this.webdavClient!);
|
||||||
} else if (this.serviceType === "dropbox") {
|
} else if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.listAllFromRemote(this.dropboxClient);
|
return await dropbox.listAllFromRemote(this.dropboxClient!);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.listAllFromRemote(this.onedriveClient);
|
return await onedrive.listAllFromRemote(this.onedriveClient!);
|
||||||
} else {
|
} else {
|
||||||
throw Error(`not supported service type ${this.serviceType}`);
|
throw Error(`not supported service type ${this.serviceType}`);
|
||||||
}
|
}
|
||||||
@ -191,8 +191,8 @@ export class RemoteClient {
|
|||||||
) => {
|
) => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.downloadFromRemote(
|
return await s3.downloadFromRemote(
|
||||||
s3.getS3Client(this.s3Config),
|
s3.getS3Client(this.s3Config!),
|
||||||
this.s3Config,
|
this.s3Config!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
mtime,
|
mtime,
|
||||||
@ -202,7 +202,7 @@ export class RemoteClient {
|
|||||||
);
|
);
|
||||||
} else if (this.serviceType === "webdav") {
|
} else if (this.serviceType === "webdav") {
|
||||||
return await webdav.downloadFromRemote(
|
return await webdav.downloadFromRemote(
|
||||||
this.webdavClient,
|
this.webdavClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
mtime,
|
mtime,
|
||||||
@ -212,7 +212,7 @@ export class RemoteClient {
|
|||||||
);
|
);
|
||||||
} else if (this.serviceType === "dropbox") {
|
} else if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.downloadFromRemote(
|
return await dropbox.downloadFromRemote(
|
||||||
this.dropboxClient,
|
this.dropboxClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
mtime,
|
mtime,
|
||||||
@ -222,7 +222,7 @@ export class RemoteClient {
|
|||||||
);
|
);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.downloadFromRemote(
|
return await onedrive.downloadFromRemote(
|
||||||
this.onedriveClient,
|
this.onedriveClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
vault,
|
vault,
|
||||||
mtime,
|
mtime,
|
||||||
@ -242,29 +242,29 @@ export class RemoteClient {
|
|||||||
) => {
|
) => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.deleteFromRemote(
|
return await s3.deleteFromRemote(
|
||||||
s3.getS3Client(this.s3Config),
|
s3.getS3Client(this.s3Config!),
|
||||||
this.s3Config,
|
this.s3Config!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
password,
|
password,
|
||||||
remoteEncryptedKey
|
remoteEncryptedKey
|
||||||
);
|
);
|
||||||
} else if (this.serviceType === "webdav") {
|
} else if (this.serviceType === "webdav") {
|
||||||
return await webdav.deleteFromRemote(
|
return await webdav.deleteFromRemote(
|
||||||
this.webdavClient,
|
this.webdavClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
password,
|
password,
|
||||||
remoteEncryptedKey
|
remoteEncryptedKey
|
||||||
);
|
);
|
||||||
} else if (this.serviceType === "dropbox") {
|
} else if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.deleteFromRemote(
|
return await dropbox.deleteFromRemote(
|
||||||
this.dropboxClient,
|
this.dropboxClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
password,
|
password,
|
||||||
remoteEncryptedKey
|
remoteEncryptedKey
|
||||||
);
|
);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.deleteFromRemote(
|
return await onedrive.deleteFromRemote(
|
||||||
this.onedriveClient,
|
this.onedriveClient!,
|
||||||
fileOrFolderPath,
|
fileOrFolderPath,
|
||||||
password,
|
password,
|
||||||
remoteEncryptedKey
|
remoteEncryptedKey
|
||||||
@ -277,17 +277,17 @@ export class RemoteClient {
|
|||||||
checkConnectivity = async (callbackFunc?: any) => {
|
checkConnectivity = async (callbackFunc?: any) => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.checkConnectivity(
|
return await s3.checkConnectivity(
|
||||||
s3.getS3Client(this.s3Config),
|
s3.getS3Client(this.s3Config!),
|
||||||
this.s3Config,
|
this.s3Config!,
|
||||||
callbackFunc
|
callbackFunc
|
||||||
);
|
);
|
||||||
} else if (this.serviceType === "webdav") {
|
} else if (this.serviceType === "webdav") {
|
||||||
return await webdav.checkConnectivity(this.webdavClient, callbackFunc);
|
return await webdav.checkConnectivity(this.webdavClient!, callbackFunc);
|
||||||
} else if (this.serviceType === "dropbox") {
|
} else if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.checkConnectivity(this.dropboxClient, callbackFunc);
|
return await dropbox.checkConnectivity(this.dropboxClient!, callbackFunc);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.checkConnectivity(
|
return await onedrive.checkConnectivity(
|
||||||
this.onedriveClient,
|
this.onedriveClient!,
|
||||||
callbackFunc
|
callbackFunc
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -297,9 +297,9 @@ export class RemoteClient {
|
|||||||
|
|
||||||
getUser = async () => {
|
getUser = async () => {
|
||||||
if (this.serviceType === "dropbox") {
|
if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.getUserDisplayName(this.dropboxClient);
|
return await dropbox.getUserDisplayName(this.dropboxClient!);
|
||||||
} else if (this.serviceType === "onedrive") {
|
} else if (this.serviceType === "onedrive") {
|
||||||
return await onedrive.getUserDisplayName(this.onedriveClient);
|
return await onedrive.getUserDisplayName(this.onedriveClient!);
|
||||||
} else {
|
} else {
|
||||||
throw Error(`not supported service type ${this.serviceType}`);
|
throw Error(`not supported service type ${this.serviceType}`);
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ export class RemoteClient {
|
|||||||
|
|
||||||
revokeAuth = async () => {
|
revokeAuth = async () => {
|
||||||
if (this.serviceType === "dropbox") {
|
if (this.serviceType === "dropbox") {
|
||||||
return await dropbox.revokeAuth(this.dropboxClient);
|
return await dropbox.revokeAuth(this.dropboxClient!);
|
||||||
} else {
|
} else {
|
||||||
throw Error(`not supported service type ${this.serviceType}`);
|
throw Error(`not supported service type ${this.serviceType}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import { log } from "./moreOnLog";
|
|||||||
|
|
||||||
export const DEFAULT_DROPBOX_CONFIG: DropboxConfig = {
|
export const DEFAULT_DROPBOX_CONFIG: DropboxConfig = {
|
||||||
accessToken: "",
|
accessToken: "",
|
||||||
clientID: process.env.DEFAULT_DROPBOX_APP_KEY,
|
clientID: process.env.DEFAULT_DROPBOX_APP_KEY ?? "",
|
||||||
refreshToken: "",
|
refreshToken: "",
|
||||||
accessTokenExpiresInSeconds: 0,
|
accessTokenExpiresInSeconds: 0,
|
||||||
accessTokenExpiresAtTime: 0,
|
accessTokenExpiresAtTime: 0,
|
||||||
@ -76,7 +76,7 @@ const fromDropboxItemToRemoteItem = (
|
|||||||
| files.DeletedMetadataReference,
|
| files.DeletedMetadataReference,
|
||||||
remoteBaseDir: string
|
remoteBaseDir: string
|
||||||
): RemoteItem => {
|
): RemoteItem => {
|
||||||
let key = getNormPath(x.path_display, remoteBaseDir);
|
let key = getNormPath(x.path_display!, remoteBaseDir);
|
||||||
if (x[".tag"] === "folder" && !key.endsWith("/")) {
|
if (x[".tag"] === "folder" && !key.endsWith("/")) {
|
||||||
key = `${key}/`;
|
key = `${key}/`;
|
||||||
}
|
}
|
||||||
@ -101,7 +101,8 @@ const fromDropboxItemToRemoteItem = (
|
|||||||
remoteType: "dropbox",
|
remoteType: "dropbox",
|
||||||
etag: `${x.id}\t${x.content_hash}`,
|
etag: `${x.id}\t${x.content_hash}`,
|
||||||
} as RemoteItem;
|
} as RemoteItem;
|
||||||
} else if (x[".tag"] === "deleted") {
|
} else {
|
||||||
|
// x[".tag"] === "deleted"
|
||||||
throw Error("do not support deleted tag");
|
throw Error("do not support deleted tag");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -188,7 +189,7 @@ export const getAuthUrlAndVerifier = async (
|
|||||||
: `obsidian://${COMMAND_CALLBACK_DROPBOX}`;
|
: `obsidian://${COMMAND_CALLBACK_DROPBOX}`;
|
||||||
const authUrl = (
|
const authUrl = (
|
||||||
await auth.getAuthenticationUrl(
|
await auth.getAuthenticationUrl(
|
||||||
callback,
|
callback as any,
|
||||||
undefined,
|
undefined,
|
||||||
"code",
|
"code",
|
||||||
"offline",
|
"offline",
|
||||||
@ -282,9 +283,7 @@ export const setConfigBySuccessfullAuthInplace = async (
|
|||||||
|
|
||||||
if (authRes.refresh_token !== undefined) {
|
if (authRes.refresh_token !== undefined) {
|
||||||
config.refreshToken = authRes.refresh_token;
|
config.refreshToken = authRes.refresh_token;
|
||||||
}
|
config.accountID = authRes.account_id!;
|
||||||
if (authRes.refresh_token !== undefined) {
|
|
||||||
config.accountID = authRes.account_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saveUpdatedConfigFunc !== undefined) {
|
if (saveUpdatedConfigFunc !== undefined) {
|
||||||
@ -307,7 +306,7 @@ interface ErrSubType {
|
|||||||
async function retryReq<T>(
|
async function retryReq<T>(
|
||||||
reqFunc: () => Promise<DropboxResponse<T>>,
|
reqFunc: () => Promise<DropboxResponse<T>>,
|
||||||
extraHint: string = ""
|
extraHint: string = ""
|
||||||
): Promise<DropboxResponse<T>> {
|
): Promise<DropboxResponse<T> | undefined> {
|
||||||
const waitSeconds = [1, 2, 4, 8]; // hard code exponential backoff
|
const waitSeconds = [1, 2, 4, 8]; // hard code exponential backoff
|
||||||
for (let idx = 0; idx < waitSeconds.length; ++idx) {
|
for (let idx = 0; idx < waitSeconds.length; ++idx) {
|
||||||
try {
|
try {
|
||||||
@ -369,7 +368,7 @@ export class WrappedDropboxClient {
|
|||||||
dropboxConfig: DropboxConfig;
|
dropboxConfig: DropboxConfig;
|
||||||
remoteBaseDir: string;
|
remoteBaseDir: string;
|
||||||
saveUpdatedConfigFunc: () => Promise<any>;
|
saveUpdatedConfigFunc: () => Promise<any>;
|
||||||
dropbox: Dropbox;
|
dropbox!: Dropbox;
|
||||||
vaultFolderExists: boolean;
|
vaultFolderExists: boolean;
|
||||||
constructor(
|
constructor(
|
||||||
dropboxConfig: DropboxConfig,
|
dropboxConfig: DropboxConfig,
|
||||||
@ -507,6 +506,9 @@ export const getRemoteMeta = async (
|
|||||||
path: remotePath,
|
path: remotePath,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
if (rsp === undefined) {
|
||||||
|
throw Error("dropbox.filesGetMetadata undefinded");
|
||||||
|
}
|
||||||
if (rsp.status !== 200) {
|
if (rsp.status !== 200) {
|
||||||
throw Error(JSON.stringify(rsp));
|
throw Error(JSON.stringify(rsp));
|
||||||
}
|
}
|
||||||
@ -516,7 +518,7 @@ export const getRemoteMeta = async (
|
|||||||
export const uploadToRemote = async (
|
export const uploadToRemote = async (
|
||||||
client: WrappedDropboxClient,
|
client: WrappedDropboxClient,
|
||||||
fileOrFolderPath: string,
|
fileOrFolderPath: string,
|
||||||
vault: Vault,
|
vault: Vault | undefined,
|
||||||
isRecursively: boolean = false,
|
isRecursively: boolean = false,
|
||||||
password: string = "",
|
password: string = "",
|
||||||
remoteEncryptedKey: string = "",
|
remoteEncryptedKey: string = "",
|
||||||
@ -611,6 +613,11 @@ export const uploadToRemote = async (
|
|||||||
localContent = rawContent;
|
localContent = rawContent;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (vault === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`the vault variable is not passed but we want to read ${fileOrFolderPath} for Dropbox`
|
||||||
|
);
|
||||||
|
}
|
||||||
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
||||||
}
|
}
|
||||||
let remoteContent = localContent;
|
let remoteContent = localContent;
|
||||||
@ -700,6 +707,9 @@ const downloadFromRemoteRaw = async (
|
|||||||
}),
|
}),
|
||||||
`downloadFromRemoteRaw=${remotePath}`
|
`downloadFromRemoteRaw=${remotePath}`
|
||||||
);
|
);
|
||||||
|
if (rsp === undefined) {
|
||||||
|
throw Error(`unknown rsp from dropbox download: ${rsp}`);
|
||||||
|
}
|
||||||
if ((rsp.result as any).fileBlob !== undefined) {
|
if ((rsp.result as any).fileBlob !== undefined) {
|
||||||
// we get a Blob
|
// we get a Blob
|
||||||
const content = (rsp.result as any).fileBlob as Blob;
|
const content = (rsp.result as any).fileBlob as Blob;
|
||||||
|
|||||||
@ -31,8 +31,8 @@ const REDIRECT_URI = `obsidian://${COMMAND_CALLBACK_ONEDRIVE}`;
|
|||||||
|
|
||||||
export const DEFAULT_ONEDRIVE_CONFIG: OnedriveConfig = {
|
export const DEFAULT_ONEDRIVE_CONFIG: OnedriveConfig = {
|
||||||
accessToken: "",
|
accessToken: "",
|
||||||
clientID: process.env.DEFAULT_ONEDRIVE_CLIENT_ID,
|
clientID: process.env.DEFAULT_ONEDRIVE_CLIENT_ID ?? "",
|
||||||
authority: process.env.DEFAULT_ONEDRIVE_AUTHORITY,
|
authority: process.env.DEFAULT_ONEDRIVE_AUTHORITY ?? "",
|
||||||
refreshToken: "",
|
refreshToken: "",
|
||||||
accessTokenExpiresInSeconds: 0,
|
accessTokenExpiresInSeconds: 0,
|
||||||
accessTokenExpiresAtTime: 0,
|
accessTokenExpiresAtTime: 0,
|
||||||
@ -199,7 +199,7 @@ export const setConfigBySuccessfullAuthInplace = async (
|
|||||||
config.accessTokenExpiresAtTime =
|
config.accessTokenExpiresAtTime =
|
||||||
Date.now() + authRes.expires_in - 5 * 60 * 1000;
|
Date.now() + authRes.expires_in - 5 * 60 * 1000;
|
||||||
config.accessTokenExpiresInSeconds = authRes.expires_in;
|
config.accessTokenExpiresInSeconds = authRes.expires_in;
|
||||||
config.refreshToken = authRes.refresh_token;
|
config.refreshToken = authRes.refresh_token!;
|
||||||
|
|
||||||
// manually set it expired after 80 days;
|
// manually set it expired after 80 days;
|
||||||
config.credentialsShouldBeDeletedAtTime =
|
config.credentialsShouldBeDeletedAtTime =
|
||||||
@ -256,7 +256,9 @@ const getNormPath = (fileOrFolderPath: string, remoteBaseDir: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const constructFromDriveItemToRemoteItemError = (x: DriveItem) => {
|
const constructFromDriveItemToRemoteItemError = (x: DriveItem) => {
|
||||||
return `parentPath="${x.parentReference.path}", selfName="${x.name}"`;
|
return `parentPath="${
|
||||||
|
x.parentReference?.path ?? "(no parentReference or path)"
|
||||||
|
}", selfName="${x.name}"`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fromDriveItemToRemoteItem = (
|
const fromDriveItemToRemoteItem = (
|
||||||
@ -281,6 +283,14 @@ const fromDriveItemToRemoteItem = (
|
|||||||
// another possibile prefix
|
// another possibile prefix
|
||||||
const FOURTH_COMMON_PREFIX_RAW = `/drive/items/`;
|
const FOURTH_COMMON_PREFIX_RAW = `/drive/items/`;
|
||||||
|
|
||||||
|
if (
|
||||||
|
x.parentReference === undefined ||
|
||||||
|
x.parentReference === null ||
|
||||||
|
x.parentReference.path === undefined ||
|
||||||
|
x.parentReference.path === null
|
||||||
|
) {
|
||||||
|
throw Error("x.parentReference.path is undefinded or null");
|
||||||
|
}
|
||||||
const fullPathOriginal = `${x.parentReference.path}/${x.name}`;
|
const fullPathOriginal = `${x.parentReference.path}/${x.name}`;
|
||||||
const matchFirstPrefixRes = fullPathOriginal.match(FIRST_COMMON_PREFIX_REGEX);
|
const matchFirstPrefixRes = fullPathOriginal.match(FIRST_COMMON_PREFIX_REGEX);
|
||||||
const matchSecondPrefixRes = fullPathOriginal.match(
|
const matchSecondPrefixRes = fullPathOriginal.match(
|
||||||
@ -309,6 +319,11 @@ const fromDriveItemToRemoteItem = (
|
|||||||
// it's something like
|
// it's something like
|
||||||
// /drive/items/<some_id>!<another_id>:/${remoteBaseDir}/<subfolder>
|
// /drive/items/<some_id>!<another_id>:/${remoteBaseDir}/<subfolder>
|
||||||
// with uri encoded!
|
// with uri encoded!
|
||||||
|
if (x.name === undefined || x.name === null) {
|
||||||
|
throw Error(
|
||||||
|
`OneDrive item no name variable while matching ${FOURTH_COMMON_PREFIX_RAW}`
|
||||||
|
);
|
||||||
|
}
|
||||||
const parPath = decodeURIComponent(x.parentReference.path);
|
const parPath = decodeURIComponent(x.parentReference.path);
|
||||||
key = parPath.substring(parPath.indexOf(":") + 1);
|
key = parPath.substring(parPath.indexOf(":") + 1);
|
||||||
if (key.startsWith(`/${remoteBaseDir}/`)) {
|
if (key.startsWith(`/${remoteBaseDir}/`)) {
|
||||||
@ -337,8 +352,8 @@ const fromDriveItemToRemoteItem = (
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
key: key,
|
key: key,
|
||||||
lastModified: Date.parse(x.fileSystemInfo.lastModifiedDateTime),
|
lastModified: Date.parse(x!.fileSystemInfo!.lastModifiedDateTime!),
|
||||||
size: isFolder ? 0 : x.size,
|
size: isFolder ? 0 : x.size!,
|
||||||
remoteType: "onedrive",
|
remoteType: "onedrive",
|
||||||
etag: x.cTag || "", // do NOT use x.eTag because it changes if meta changes
|
etag: x.cTag || "", // do NOT use x.eTag because it changes if meta changes
|
||||||
};
|
};
|
||||||
@ -381,7 +396,7 @@ class MyAuthProvider implements AuthenticationProvider {
|
|||||||
}
|
}
|
||||||
const r2 = r as AccessCodeResponseSuccessfulType;
|
const r2 = r as AccessCodeResponseSuccessfulType;
|
||||||
this.onedriveConfig.accessToken = r2.access_token;
|
this.onedriveConfig.accessToken = r2.access_token;
|
||||||
this.onedriveConfig.refreshToken = r2.refresh_token;
|
this.onedriveConfig.refreshToken = r2.refresh_token!;
|
||||||
this.onedriveConfig.accessTokenExpiresInSeconds = r2.expires_in;
|
this.onedriveConfig.accessTokenExpiresInSeconds = r2.expires_in;
|
||||||
this.onedriveConfig.accessTokenExpiresAtTime =
|
this.onedriveConfig.accessTokenExpiresAtTime =
|
||||||
currentTs + r2.expires_in * 1000 - 60 * 2 * 1000;
|
currentTs + r2.expires_in * 1000 - 60 * 2 * 1000;
|
||||||
@ -680,7 +695,7 @@ export const getRemoteMeta = async (
|
|||||||
export const uploadToRemote = async (
|
export const uploadToRemote = async (
|
||||||
client: WrappedOnedriveClient,
|
client: WrappedOnedriveClient,
|
||||||
fileOrFolderPath: string,
|
fileOrFolderPath: string,
|
||||||
vault: Vault,
|
vault: Vault | undefined,
|
||||||
isRecursively: boolean = false,
|
isRecursively: boolean = false,
|
||||||
password: string = "",
|
password: string = "",
|
||||||
remoteEncryptedKey: string = "",
|
remoteEncryptedKey: string = "",
|
||||||
@ -784,6 +799,11 @@ export const uploadToRemote = async (
|
|||||||
localContent = rawContent;
|
localContent = rawContent;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (vault === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`the vault variable is not passed but we want to read ${fileOrFolderPath} for OneDrive`
|
||||||
|
);
|
||||||
|
}
|
||||||
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
||||||
}
|
}
|
||||||
let remoteContent = localContent;
|
let remoteContent = localContent;
|
||||||
@ -842,7 +862,7 @@ export const uploadToRemote = async (
|
|||||||
`${uploadFile}:/createUploadSession`,
|
`${uploadFile}:/createUploadSession`,
|
||||||
k
|
k
|
||||||
);
|
);
|
||||||
const uploadUrl = s.uploadUrl;
|
const uploadUrl = s.uploadUrl!;
|
||||||
log.debug("uploadSession = ");
|
log.debug("uploadSession = ");
|
||||||
log.debug(s);
|
log.debug(s);
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ import PQueue from "p-queue";
|
|||||||
* But this uses Obsidian requestUrl instead.
|
* But this uses Obsidian requestUrl instead.
|
||||||
*/
|
*/
|
||||||
class ObsHttpHandler extends FetchHttpHandler {
|
class ObsHttpHandler extends FetchHttpHandler {
|
||||||
requestTimeoutInMs: number;
|
requestTimeoutInMs: number | undefined;
|
||||||
constructor(options?: FetchHttpHandlerOptions) {
|
constructor(options?: FetchHttpHandlerOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
this.requestTimeoutInMs =
|
this.requestTimeoutInMs =
|
||||||
@ -95,7 +95,7 @@ class ObsHttpHandler extends FetchHttpHandler {
|
|||||||
transformedHeaders[keyLower] = request.headers[key];
|
transformedHeaders[keyLower] = request.headers[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
let contentType: string = undefined;
|
let contentType: string | undefined = undefined;
|
||||||
if (transformedHeaders["content-type"] !== undefined) {
|
if (transformedHeaders["content-type"] !== undefined) {
|
||||||
contentType = transformedHeaders["content-type"];
|
contentType = transformedHeaders["content-type"];
|
||||||
}
|
}
|
||||||
@ -226,17 +226,17 @@ const fromS3ObjectToRemoteItem = (
|
|||||||
mtimeRecords: Record<string, number>,
|
mtimeRecords: Record<string, number>,
|
||||||
ctimeRecords: Record<string, number>
|
ctimeRecords: Record<string, number>
|
||||||
) => {
|
) => {
|
||||||
let mtime = x.LastModified.valueOf();
|
let mtime = x.LastModified!.valueOf();
|
||||||
if (x.Key in mtimeRecords) {
|
if (x.Key! in mtimeRecords) {
|
||||||
const m2 = mtimeRecords[x.Key];
|
const m2 = mtimeRecords[x.Key!];
|
||||||
if (m2 !== 0) {
|
if (m2 !== 0) {
|
||||||
mtime = m2;
|
mtime = m2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const r: RemoteItem = {
|
const r: RemoteItem = {
|
||||||
key: getLocalNoPrefixPath(x.Key, remotePrefix),
|
key: getLocalNoPrefixPath(x.Key!, remotePrefix),
|
||||||
lastModified: mtime,
|
lastModified: mtime,
|
||||||
size: x.Size,
|
size: x.Size!,
|
||||||
remoteType: "s3",
|
remoteType: "s3",
|
||||||
etag: x.ETag,
|
etag: x.ETag,
|
||||||
};
|
};
|
||||||
@ -249,7 +249,7 @@ const fromS3HeadObjectToRemoteItem = (
|
|||||||
remotePrefix: string,
|
remotePrefix: string,
|
||||||
useAccurateMTime: boolean
|
useAccurateMTime: boolean
|
||||||
) => {
|
) => {
|
||||||
let mtime = x.LastModified.valueOf();
|
let mtime = x.LastModified!.valueOf();
|
||||||
if (useAccurateMTime && x.Metadata !== undefined) {
|
if (useAccurateMTime && x.Metadata !== undefined) {
|
||||||
const m2 = Math.round(
|
const m2 = Math.round(
|
||||||
parseFloat(x.Metadata.mtime || x.Metadata.MTime || "0")
|
parseFloat(x.Metadata.mtime || x.Metadata.MTime || "0")
|
||||||
@ -317,6 +317,7 @@ export const getRemoteMeta = async (
|
|||||||
fileOrFolderPathWithRemotePrefix: string
|
fileOrFolderPathWithRemotePrefix: string
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
|
s3Config.remotePrefix !== undefined &&
|
||||||
s3Config.remotePrefix !== "" &&
|
s3Config.remotePrefix !== "" &&
|
||||||
!fileOrFolderPathWithRemotePrefix.startsWith(s3Config.remotePrefix)
|
!fileOrFolderPathWithRemotePrefix.startsWith(s3Config.remotePrefix)
|
||||||
) {
|
) {
|
||||||
@ -332,8 +333,8 @@ export const getRemoteMeta = async (
|
|||||||
return fromS3HeadObjectToRemoteItem(
|
return fromS3HeadObjectToRemoteItem(
|
||||||
fileOrFolderPathWithRemotePrefix,
|
fileOrFolderPathWithRemotePrefix,
|
||||||
res,
|
res,
|
||||||
s3Config.remotePrefix,
|
s3Config.remotePrefix ?? "",
|
||||||
s3Config.useAccurateMTime
|
s3Config.useAccurateMTime ?? false
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -341,7 +342,7 @@ export const uploadToRemote = async (
|
|||||||
s3Client: S3Client,
|
s3Client: S3Client,
|
||||||
s3Config: S3Config,
|
s3Config: S3Config,
|
||||||
fileOrFolderPath: string,
|
fileOrFolderPath: string,
|
||||||
vault: Vault,
|
vault: Vault | undefined,
|
||||||
isRecursively: boolean = false,
|
isRecursively: boolean = false,
|
||||||
password: string = "",
|
password: string = "",
|
||||||
remoteEncryptedKey: string = "",
|
remoteEncryptedKey: string = "",
|
||||||
@ -354,7 +355,7 @@ export const uploadToRemote = async (
|
|||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
uploadFile = remoteEncryptedKey;
|
uploadFile = remoteEncryptedKey;
|
||||||
}
|
}
|
||||||
uploadFile = getRemoteWithPrefixPath(uploadFile, s3Config.remotePrefix);
|
uploadFile = getRemoteWithPrefixPath(uploadFile, s3Config.remotePrefix ?? "");
|
||||||
const isFolder = fileOrFolderPath.endsWith("/");
|
const isFolder = fileOrFolderPath.endsWith("/");
|
||||||
|
|
||||||
if (isFolder && isRecursively) {
|
if (isFolder && isRecursively) {
|
||||||
@ -407,8 +408,13 @@ export const uploadToRemote = async (
|
|||||||
mtime = rawContentMTime;
|
mtime = rawContentMTime;
|
||||||
ctime = rawContentCTime;
|
ctime = rawContentCTime;
|
||||||
} else {
|
} else {
|
||||||
|
if (vault === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`the vault variable is not passed but we want to read ${fileOrFolderPath} for S3`
|
||||||
|
);
|
||||||
|
}
|
||||||
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
||||||
const s = await vault?.adapter?.stat(fileOrFolderPath);
|
const s = await vault.adapter.stat(fileOrFolderPath);
|
||||||
if (s !== undefined && s !== null) {
|
if (s !== undefined && s !== null) {
|
||||||
mtime = s.mtime;
|
mtime = s.mtime;
|
||||||
ctime = s.ctime;
|
ctime = s.ctime;
|
||||||
@ -500,12 +506,12 @@ const listFromRemoteRaw = async (
|
|||||||
if (rspHead.Metadata === undefined) {
|
if (rspHead.Metadata === undefined) {
|
||||||
// pass
|
// pass
|
||||||
} else {
|
} else {
|
||||||
mtimeRecords[content.Key] = Math.round(
|
mtimeRecords[content.Key!] = Math.round(
|
||||||
parseFloat(
|
parseFloat(
|
||||||
rspHead.Metadata.mtime || rspHead.Metadata.MTime || "0"
|
rspHead.Metadata.mtime || rspHead.Metadata.MTime || "0"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
ctimeRecords[content.Key] = Math.round(
|
ctimeRecords[content.Key!] = Math.round(
|
||||||
parseFloat(
|
parseFloat(
|
||||||
rspHead.Metadata.ctime || rspHead.Metadata.CTime || "0"
|
rspHead.Metadata.ctime || rspHead.Metadata.CTime || "0"
|
||||||
)
|
)
|
||||||
@ -515,7 +521,7 @@ const listFromRemoteRaw = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isTruncated = rsp.IsTruncated;
|
isTruncated = rsp.IsTruncated ?? false;
|
||||||
confCmd.ContinuationToken = rsp.NextContinuationToken;
|
confCmd.ContinuationToken = rsp.NextContinuationToken;
|
||||||
if (
|
if (
|
||||||
isTruncated &&
|
isTruncated &&
|
||||||
@ -536,7 +542,7 @@ const listFromRemoteRaw = async (
|
|||||||
Contents: contents.map((x) =>
|
Contents: contents.map((x) =>
|
||||||
fromS3ObjectToRemoteItem(
|
fromS3ObjectToRemoteItem(
|
||||||
x,
|
x,
|
||||||
s3Config.remotePrefix,
|
s3Config.remotePrefix ?? "",
|
||||||
mtimeRecords,
|
mtimeRecords,
|
||||||
ctimeRecords
|
ctimeRecords
|
||||||
)
|
)
|
||||||
@ -559,8 +565,11 @@ export const listAllFromRemote = async (
|
|||||||
* @returns Promise<ArrayBuffer>
|
* @returns Promise<ArrayBuffer>
|
||||||
*/
|
*/
|
||||||
const getObjectBodyToArrayBuffer = async (
|
const getObjectBodyToArrayBuffer = async (
|
||||||
b: Readable | ReadableStream | Blob
|
b: Readable | ReadableStream | Blob | undefined
|
||||||
) => {
|
) => {
|
||||||
|
if (b === undefined) {
|
||||||
|
throw Error(`ObjectBody is undefined and don't know how to deal with it`);
|
||||||
|
}
|
||||||
if (b instanceof Readable) {
|
if (b instanceof Readable) {
|
||||||
return (await new Promise((resolve, reject) => {
|
return (await new Promise((resolve, reject) => {
|
||||||
const chunks: Uint8Array[] = [];
|
const chunks: Uint8Array[] = [];
|
||||||
@ -583,6 +592,7 @@ const downloadFromRemoteRaw = async (
|
|||||||
fileOrFolderPathWithRemotePrefix: string
|
fileOrFolderPathWithRemotePrefix: string
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
|
s3Config.remotePrefix !== undefined &&
|
||||||
s3Config.remotePrefix !== "" &&
|
s3Config.remotePrefix !== "" &&
|
||||||
!fileOrFolderPathWithRemotePrefix.startsWith(s3Config.remotePrefix)
|
!fileOrFolderPathWithRemotePrefix.startsWith(s3Config.remotePrefix)
|
||||||
) {
|
) {
|
||||||
@ -626,7 +636,10 @@ export const downloadFromRemote = async (
|
|||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
downloadFile = remoteEncryptedKey;
|
downloadFile = remoteEncryptedKey;
|
||||||
}
|
}
|
||||||
downloadFile = getRemoteWithPrefixPath(downloadFile, s3Config.remotePrefix);
|
downloadFile = getRemoteWithPrefixPath(
|
||||||
|
downloadFile,
|
||||||
|
s3Config.remotePrefix ?? ""
|
||||||
|
);
|
||||||
const remoteContent = await downloadFromRemoteRaw(
|
const remoteContent = await downloadFromRemoteRaw(
|
||||||
s3Client,
|
s3Client,
|
||||||
s3Config,
|
s3Config,
|
||||||
@ -668,7 +681,7 @@ export const deleteFromRemote = async (
|
|||||||
}
|
}
|
||||||
remoteFileName = getRemoteWithPrefixPath(
|
remoteFileName = getRemoteWithPrefixPath(
|
||||||
remoteFileName,
|
remoteFileName,
|
||||||
s3Config.remotePrefix
|
s3Config.remotePrefix ?? ""
|
||||||
);
|
);
|
||||||
await s3Client.send(
|
await s3Client.send(
|
||||||
new DeleteObjectCommand({
|
new DeleteObjectCommand({
|
||||||
@ -734,7 +747,7 @@ export const checkConnectivity = async (
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return results.$metadata.httpStatusCode === 200;
|
return results.$metadata.httpStatusCode === 200;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
log.debug(err);
|
log.debug(err);
|
||||||
if (callbackFunc !== undefined) {
|
if (callbackFunc !== undefined) {
|
||||||
if (s3Config.s3Endpoint.contains(s3Config.s3BucketName)) {
|
if (s3Config.s3Endpoint.contains(s3Config.s3BucketName)) {
|
||||||
|
|||||||
@ -39,12 +39,16 @@ if (VALID_REQURL) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let contentType: string | undefined =
|
let contentType: string | undefined =
|
||||||
r.headers["Content-Type"] ||
|
r.headers["Content-Type"] || r.headers["content-type"];
|
||||||
r.headers["content-type"] ||
|
if (options.headers !== undefined) {
|
||||||
options.headers["Content-Type"] ||
|
contentType =
|
||||||
options.headers["content-type"] ||
|
contentType ||
|
||||||
options.headers["Accept"] ||
|
options.headers["Content-Type"] ||
|
||||||
options.headers["accept"];
|
options.headers["content-type"] ||
|
||||||
|
options.headers["Accept"] ||
|
||||||
|
options.headers["accept"];
|
||||||
|
}
|
||||||
|
|
||||||
if (contentType !== undefined) {
|
if (contentType !== undefined) {
|
||||||
contentType = contentType.toLowerCase();
|
contentType = contentType.toLowerCase();
|
||||||
}
|
}
|
||||||
@ -106,7 +110,7 @@ if (VALID_REQURL) {
|
|||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let r2: Response = undefined;
|
let r2: Response | undefined = undefined;
|
||||||
if ([101, 103, 204, 205, 304].includes(r.status)) {
|
if ([101, 103, 204, 205, 304].includes(r.status)) {
|
||||||
// A null body status is a status that is 101, 103, 204, 205, or 304.
|
// A null body status is a status that is 101, 103, 204, 205, or 304.
|
||||||
// https://fetch.spec.whatwg.org/#statuses
|
// https://fetch.spec.whatwg.org/#statuses
|
||||||
@ -193,7 +197,7 @@ const fromWebdavItemToRemoteItem = (x: FileStat, remoteBaseDir: string) => {
|
|||||||
export class WrappedWebdavClient {
|
export class WrappedWebdavClient {
|
||||||
webdavConfig: WebdavConfig;
|
webdavConfig: WebdavConfig;
|
||||||
remoteBaseDir: string;
|
remoteBaseDir: string;
|
||||||
client: WebDAVClient;
|
client!: WebDAVClient;
|
||||||
vaultFolderExists: boolean;
|
vaultFolderExists: boolean;
|
||||||
saveUpdatedConfigFunc: () => Promise<any>;
|
saveUpdatedConfigFunc: () => Promise<any>;
|
||||||
constructor(
|
constructor(
|
||||||
@ -340,7 +344,7 @@ export const getRemoteMeta = async (
|
|||||||
export const uploadToRemote = async (
|
export const uploadToRemote = async (
|
||||||
client: WrappedWebdavClient,
|
client: WrappedWebdavClient,
|
||||||
fileOrFolderPath: string,
|
fileOrFolderPath: string,
|
||||||
vault: Vault,
|
vault: Vault | undefined,
|
||||||
isRecursively: boolean = false,
|
isRecursively: boolean = false,
|
||||||
password: string = "",
|
password: string = "",
|
||||||
remoteEncryptedKey: string = "",
|
remoteEncryptedKey: string = "",
|
||||||
@ -392,6 +396,11 @@ export const uploadToRemote = async (
|
|||||||
localContent = rawContent;
|
localContent = rawContent;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (vault == undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`the vault variable is not passed but we want to read ${fileOrFolderPath} for webdav`
|
||||||
|
);
|
||||||
|
}
|
||||||
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
||||||
}
|
}
|
||||||
let remoteContent = localContent;
|
let remoteContent = localContent;
|
||||||
@ -428,9 +437,9 @@ export const listAllFromRemote = async (client: WrappedWebdavClient) => {
|
|||||||
const q = new Queue([`/${client.remoteBaseDir}`]);
|
const q = new Queue([`/${client.remoteBaseDir}`]);
|
||||||
const CHUNK_SIZE = 10;
|
const CHUNK_SIZE = 10;
|
||||||
while (q.length > 0) {
|
while (q.length > 0) {
|
||||||
const itemsToFetch = [];
|
const itemsToFetch: string[] = [];
|
||||||
while (q.length > 0) {
|
while (q.length > 0) {
|
||||||
itemsToFetch.push(q.pop());
|
itemsToFetch.push(q.pop()!);
|
||||||
}
|
}
|
||||||
const itemsToFetchChunks = chunk(itemsToFetch, CHUNK_SIZE);
|
const itemsToFetchChunks = chunk(itemsToFetch, CHUNK_SIZE);
|
||||||
// log.debug(itemsToFetchChunks);
|
// log.debug(itemsToFetchChunks);
|
||||||
|
|||||||
@ -416,7 +416,7 @@ class DropboxAuthModal extends Modal {
|
|||||||
const self = this;
|
const self = this;
|
||||||
setConfigBySuccessfullAuthInplace(
|
setConfigBySuccessfullAuthInplace(
|
||||||
this.plugin.settings.dropbox,
|
this.plugin.settings.dropbox,
|
||||||
authRes,
|
authRes!,
|
||||||
() => self.plugin.saveSettings()
|
() => self.plugin.saveSettings()
|
||||||
);
|
);
|
||||||
const client = new RemoteClient(
|
const client = new RemoteClient(
|
||||||
@ -784,7 +784,7 @@ const getEyesElements = () => {
|
|||||||
|
|
||||||
const wrapTextWithPasswordHide = (text: TextComponent) => {
|
const wrapTextWithPasswordHide = (text: TextComponent) => {
|
||||||
const { eye, eyeOff } = getEyesElements();
|
const { eye, eyeOff } = getEyesElements();
|
||||||
const hider = text.inputEl.insertAdjacentElement("afterend", createSpan());
|
const hider = text.inputEl.insertAdjacentElement("afterend", createSpan())!;
|
||||||
// the init type of hider is "hidden" === eyeOff === password
|
// the init type of hider is "hidden" === eyeOff === password
|
||||||
hider.innerHTML = eyeOff;
|
hider.innerHTML = eyeOff;
|
||||||
hider.addEventListener("click", (e) => {
|
hider.addEventListener("click", (e) => {
|
||||||
@ -1534,8 +1534,8 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
dropdown
|
dropdown
|
||||||
.setValue(this.plugin.settings.webdav.authType)
|
.setValue(this.plugin.settings.webdav.authType)
|
||||||
.onChange(async (val: WebdavAuthType) => {
|
.onChange(async (val) => {
|
||||||
this.plugin.settings.webdav.authType = val;
|
this.plugin.settings.webdav.authType = val as WebdavAuthType;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1548,20 +1548,20 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
dropdown.addOption("manual_1", t("settings_webdav_depth_1"));
|
dropdown.addOption("manual_1", t("settings_webdav_depth_1"));
|
||||||
dropdown.addOption("manual_infinity", t("settings_webdav_depth_inf"));
|
dropdown.addOption("manual_infinity", t("settings_webdav_depth_inf"));
|
||||||
|
|
||||||
let initVal = "auto";
|
let initVal: WebdavDepthType = "auto";
|
||||||
const autoOptions: Set<WebdavDepthType> = new Set([
|
const autoOptions: Set<WebdavDepthType> = new Set([
|
||||||
"auto_unknown",
|
"auto_unknown",
|
||||||
"auto_1",
|
"auto_1",
|
||||||
"auto_infinity",
|
"auto_infinity",
|
||||||
]);
|
]);
|
||||||
if (autoOptions.has(this.plugin.settings.webdav.depth)) {
|
if (autoOptions.has(this.plugin.settings.webdav.depth as any)) {
|
||||||
initVal = "auto";
|
initVal = "auto";
|
||||||
} else {
|
} else {
|
||||||
initVal = this.plugin.settings.webdav.depth || "auto";
|
initVal = this.plugin.settings.webdav.depth || "auto";
|
||||||
}
|
}
|
||||||
|
|
||||||
type DepthOption = "auto" | "manual_1" | "manual_infinity";
|
type DepthOption = "auto" | "manual_1" | "manual_infinity";
|
||||||
dropdown.setValue(initVal).onChange(async (val: DepthOption) => {
|
dropdown.setValue(initVal).onChange(async (val) => {
|
||||||
if (val === "auto") {
|
if (val === "auto") {
|
||||||
this.plugin.settings.webdav.depth = "auto_unknown";
|
this.plugin.settings.webdav.depth = "auto_unknown";
|
||||||
this.plugin.settings.webdav.manualRecursive = false;
|
this.plugin.settings.webdav.manualRecursive = false;
|
||||||
@ -1656,8 +1656,8 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
dropdown.addOption("onedrive", t("settings_chooseservice_onedrive"));
|
dropdown.addOption("onedrive", t("settings_chooseservice_onedrive"));
|
||||||
dropdown
|
dropdown
|
||||||
.setValue(this.plugin.settings.serviceType)
|
.setValue(this.plugin.settings.serviceType)
|
||||||
.onChange(async (val: SUPPORTED_SERVICES_TYPE) => {
|
.onChange(async (val) => {
|
||||||
this.plugin.settings.serviceType = val;
|
this.plugin.settings.serviceType = val as SUPPORTED_SERVICES_TYPE;
|
||||||
s3Div.toggleClass(
|
s3Div.toggleClass(
|
||||||
"s3-hide",
|
"s3-hide",
|
||||||
this.plugin.settings.serviceType !== "s3"
|
this.plugin.settings.serviceType !== "s3"
|
||||||
@ -1815,11 +1815,11 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
// );
|
// );
|
||||||
if (
|
if (
|
||||||
currentTime - lastModified <
|
currentTime - lastModified <
|
||||||
this.plugin.settings.syncOnSaveAfterMilliseconds
|
this.plugin.settings.syncOnSaveAfterMilliseconds!
|
||||||
) {
|
) {
|
||||||
if (!runScheduled) {
|
if (!runScheduled) {
|
||||||
const scheduleTimeFromNow =
|
const scheduleTimeFromNow =
|
||||||
this.plugin.settings.syncOnSaveAfterMilliseconds -
|
this.plugin.settings.syncOnSaveAfterMilliseconds! -
|
||||||
(currentTime - lastModified);
|
(currentTime - lastModified);
|
||||||
log.info(
|
log.info(
|
||||||
`schedule a run for ${scheduleTimeFromNow} milliseconds later`
|
`schedule a run for ${scheduleTimeFromNow} milliseconds later`
|
||||||
@ -1864,7 +1864,7 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
.setDesc(t("settings_enablestatusbar_info_desc"))
|
.setDesc(t("settings_enablestatusbar_info_desc"))
|
||||||
.addToggle((toggle) => {
|
.addToggle((toggle) => {
|
||||||
toggle
|
toggle
|
||||||
.setValue(this.plugin.settings.enableStatusBarInfo)
|
.setValue(this.plugin.settings.enableStatusBarInfo ?? false)
|
||||||
.onChange(async (val) => {
|
.onChange(async (val) => {
|
||||||
this.plugin.settings.enableStatusBarInfo = val;
|
this.plugin.settings.enableStatusBarInfo = val;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
@ -1897,7 +1897,7 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
.addTextArea((textArea) => {
|
.addTextArea((textArea) => {
|
||||||
textArea
|
textArea
|
||||||
.setValue(`${this.plugin.settings.ignorePaths.join("\n")}`)
|
.setValue(`${(this.plugin.settings.ignorePaths ?? []).join("\n")}`)
|
||||||
.onChange(async (value) => {
|
.onChange(async (value) => {
|
||||||
this.plugin.settings.ignorePaths = value
|
this.plugin.settings.ignorePaths = value
|
||||||
.trim()
|
.trim()
|
||||||
@ -1999,9 +1999,9 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
t("settings_deletetowhere_obsidian_trash")
|
t("settings_deletetowhere_obsidian_trash")
|
||||||
);
|
);
|
||||||
dropdown
|
dropdown
|
||||||
.setValue(this.plugin.settings.deleteToWhere)
|
.setValue(this.plugin.settings.deleteToWhere ?? "system")
|
||||||
.onChange(async (val: "system" | "obsidian") => {
|
.onChange(async (val) => {
|
||||||
this.plugin.settings.deleteToWhere = val;
|
this.plugin.settings.deleteToWhere = val as "system" | "obsidian";
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -2044,7 +2044,7 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
dropdown.addOption("info", "info");
|
dropdown.addOption("info", "info");
|
||||||
dropdown.addOption("debug", "debug");
|
dropdown.addOption("debug", "debug");
|
||||||
dropdown
|
dropdown
|
||||||
.setValue(this.plugin.settings.currLogLevel)
|
.setValue(this.plugin.settings.currLogLevel ?? "info")
|
||||||
.onChange(async (val: string) => {
|
.onChange(async (val: string) => {
|
||||||
this.plugin.settings.currLogLevel = val;
|
this.plugin.settings.currLogLevel = val;
|
||||||
log.setLevel(val as any);
|
log.setLevel(val as any);
|
||||||
|
|||||||
115
src/sync.ts
115
src/sync.ts
@ -186,7 +186,7 @@ export const parseRemoteItems = async (
|
|||||||
password: string = ""
|
password: string = ""
|
||||||
) => {
|
) => {
|
||||||
const remoteStates = [] as FileOrFolderMixedState[];
|
const remoteStates = [] as FileOrFolderMixedState[];
|
||||||
let metadataFile: FileOrFolderMixedState = undefined;
|
let metadataFile: FileOrFolderMixedState | undefined = undefined;
|
||||||
if (remote === undefined) {
|
if (remote === undefined) {
|
||||||
return {
|
return {
|
||||||
remoteStates: remoteStates,
|
remoteStates: remoteStates,
|
||||||
@ -212,8 +212,8 @@ export const parseRemoteItems = async (
|
|||||||
remoteType,
|
remoteType,
|
||||||
db,
|
db,
|
||||||
key,
|
key,
|
||||||
entry.lastModified,
|
entry.lastModified ?? Date.now(),
|
||||||
entry.etag,
|
entry.etag ?? "",
|
||||||
vaultRandomID
|
vaultRandomID
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ export const parseRemoteItems = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const fetchMetadataFile = async (
|
export const fetchMetadataFile = async (
|
||||||
metadataFile: FileOrFolderMixedState,
|
metadataFile: FileOrFolderMixedState | undefined,
|
||||||
client: RemoteClient,
|
client: RemoteClient,
|
||||||
vault: Vault,
|
vault: Vault,
|
||||||
password: string = ""
|
password: string = ""
|
||||||
@ -283,7 +283,7 @@ export const fetchMetadataFile = async (
|
|||||||
const buf = await client.downloadFromRemote(
|
const buf = await client.downloadFromRemote(
|
||||||
metadataFile.key,
|
metadataFile.key,
|
||||||
vault,
|
vault,
|
||||||
metadataFile.mtimeRemote,
|
metadataFile.mtimeRemote ?? Date.now(),
|
||||||
password,
|
password,
|
||||||
metadataFile.remoteEncryptedKey,
|
metadataFile.remoteEncryptedKey,
|
||||||
true
|
true
|
||||||
@ -325,8 +325,8 @@ const ensembleMixedStates = async (
|
|||||||
remoteStates: FileOrFolderMixedState[],
|
remoteStates: FileOrFolderMixedState[],
|
||||||
local: TAbstractFile[],
|
local: TAbstractFile[],
|
||||||
localConfigDirContents: ObsConfigDirFileType[] | undefined,
|
localConfigDirContents: ObsConfigDirFileType[] | undefined,
|
||||||
remoteDeleteHistory: DeletionOnRemote[],
|
remoteDeleteHistory: DeletionOnRemote[] | undefined,
|
||||||
localFileHistory: FileFolderHistoryRecord[],
|
localFileHistory: FileFolderHistoryRecord[] | undefined,
|
||||||
syncConfigDir: boolean,
|
syncConfigDir: boolean,
|
||||||
configDir: string,
|
configDir: string,
|
||||||
syncUnderscoreItems: boolean,
|
syncUnderscoreItems: boolean,
|
||||||
@ -413,7 +413,10 @@ const ensembleMixedStates = async (
|
|||||||
if (syncConfigDir && localConfigDirContents !== undefined) {
|
if (syncConfigDir && localConfigDirContents !== undefined) {
|
||||||
for (const entry of localConfigDirContents) {
|
for (const entry of localConfigDirContents) {
|
||||||
const key = entry.key;
|
const key = entry.key;
|
||||||
let mtimeLocal = Math.max(entry.mtime ?? 0, entry.ctime ?? 0);
|
let mtimeLocal: number | undefined = Math.max(
|
||||||
|
entry.mtime ?? 0,
|
||||||
|
entry.ctime ?? 0
|
||||||
|
);
|
||||||
if (Number.isNaN(mtimeLocal) || mtimeLocal === 0) {
|
if (Number.isNaN(mtimeLocal) || mtimeLocal === 0) {
|
||||||
mtimeLocal = undefined;
|
mtimeLocal = undefined;
|
||||||
}
|
}
|
||||||
@ -453,7 +456,7 @@ const ensembleMixedStates = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entry of remoteDeleteHistory) {
|
for (const entry of remoteDeleteHistory ?? []) {
|
||||||
const key = entry.key;
|
const key = entry.key;
|
||||||
const r = {
|
const r = {
|
||||||
key: key,
|
key: key,
|
||||||
@ -485,7 +488,7 @@ const ensembleMixedStates = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entry of localFileHistory) {
|
for (const entry of localFileHistory ?? []) {
|
||||||
let key = entry.key;
|
let key = entry.key;
|
||||||
if (entry.keyType === "folder") {
|
if (entry.keyType === "folder") {
|
||||||
if (!entry.key.endsWith("/")) {
|
if (!entry.key.endsWith("/")) {
|
||||||
@ -532,7 +535,7 @@ const ensembleMixedStates = async (
|
|||||||
changeLocalMtimeUsingMapping: true,
|
changeLocalMtimeUsingMapping: true,
|
||||||
};
|
};
|
||||||
if (results.hasOwnProperty(key)) {
|
if (results.hasOwnProperty(key)) {
|
||||||
let mtimeLocal = Math.max(
|
let mtimeLocal: number | undefined = Math.max(
|
||||||
r.mtimeLocal ?? 0,
|
r.mtimeLocal ?? 0,
|
||||||
results[key].mtimeLocal ?? 0
|
results[key].mtimeLocal ?? 0
|
||||||
);
|
);
|
||||||
@ -624,13 +627,13 @@ const assignOperationToFileInplace = (
|
|||||||
|
|
||||||
// 1. mtimeLocal
|
// 1. mtimeLocal
|
||||||
if (r.existLocal) {
|
if (r.existLocal) {
|
||||||
const mtimeRemote = r.existRemote ? r.mtimeRemote : -1;
|
const mtimeRemote = r.existRemote ? r.mtimeRemote! : -1;
|
||||||
const deltimeRemote = r.deltimeRemote !== undefined ? r.deltimeRemote : -1;
|
const deltimeRemote = r.deltimeRemote !== undefined ? r.deltimeRemote : -1;
|
||||||
const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1;
|
const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1;
|
||||||
if (
|
if (
|
||||||
r.mtimeLocal >= mtimeRemote &&
|
r.mtimeLocal! >= mtimeRemote &&
|
||||||
r.mtimeLocal >= deltimeLocal &&
|
r.mtimeLocal! >= deltimeLocal &&
|
||||||
r.mtimeLocal >= deltimeRemote
|
r.mtimeLocal! >= deltimeRemote
|
||||||
) {
|
) {
|
||||||
if (sizeLocalComp === undefined) {
|
if (sizeLocalComp === undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -654,7 +657,7 @@ const assignOperationToFileInplace = (
|
|||||||
} else {
|
} else {
|
||||||
// limit the sizes
|
// limit the sizes
|
||||||
if (sizeLocalComp <= skipSizeLargerThan) {
|
if (sizeLocalComp <= skipSizeLargerThan) {
|
||||||
if (sizeRemoteComp <= skipSizeLargerThan) {
|
if (sizeRemoteComp! <= skipSizeLargerThan) {
|
||||||
r.decision = "uploadLocalToRemote";
|
r.decision = "uploadLocalToRemote";
|
||||||
r.decisionBranch = 18;
|
r.decisionBranch = 18;
|
||||||
} else {
|
} else {
|
||||||
@ -662,7 +665,7 @@ const assignOperationToFileInplace = (
|
|||||||
r.decisionBranch = 19;
|
r.decisionBranch = 19;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sizeRemoteComp <= skipSizeLargerThan) {
|
if (sizeRemoteComp! <= skipSizeLargerThan) {
|
||||||
r.decision = "errorLocalTooLargeConflictRemote";
|
r.decision = "errorLocalTooLargeConflictRemote";
|
||||||
r.decisionBranch = 20;
|
r.decisionBranch = 20;
|
||||||
} else {
|
} else {
|
||||||
@ -713,13 +716,13 @@ const assignOperationToFileInplace = (
|
|||||||
|
|
||||||
// 2. mtimeRemote
|
// 2. mtimeRemote
|
||||||
if (r.existRemote) {
|
if (r.existRemote) {
|
||||||
const mtimeLocal = r.existLocal ? r.mtimeLocal : -1;
|
const mtimeLocal = r.existLocal ? r.mtimeLocal! : -1;
|
||||||
const deltimeRemote = r.deltimeRemote !== undefined ? r.deltimeRemote : -1;
|
const deltimeRemote = r.deltimeRemote !== undefined ? r.deltimeRemote : -1;
|
||||||
const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1;
|
const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1;
|
||||||
if (
|
if (
|
||||||
r.mtimeRemote > mtimeLocal &&
|
r.mtimeRemote! > mtimeLocal &&
|
||||||
r.mtimeRemote >= deltimeLocal &&
|
r.mtimeRemote! >= deltimeLocal &&
|
||||||
r.mtimeRemote >= deltimeRemote
|
r.mtimeRemote! >= deltimeRemote
|
||||||
) {
|
) {
|
||||||
// we have remote laregest mtime,
|
// we have remote laregest mtime,
|
||||||
// and the local not existing or smaller mtime
|
// and the local not existing or smaller mtime
|
||||||
@ -771,8 +774,8 @@ const assignOperationToFileInplace = (
|
|||||||
|
|
||||||
// 3. deltimeLocal
|
// 3. deltimeLocal
|
||||||
if (r.deltimeLocal !== undefined && r.deltimeLocal !== 0) {
|
if (r.deltimeLocal !== undefined && r.deltimeLocal !== 0) {
|
||||||
const mtimeLocal = r.existLocal ? r.mtimeLocal : -1;
|
const mtimeLocal = r.existLocal ? r.mtimeLocal! : -1;
|
||||||
const mtimeRemote = r.existRemote ? r.mtimeRemote : -1;
|
const mtimeRemote = r.existRemote ? r.mtimeRemote! : -1;
|
||||||
const deltimeRemote = r.deltimeRemote !== undefined ? r.deltimeRemote : -1;
|
const deltimeRemote = r.deltimeRemote !== undefined ? r.deltimeRemote : -1;
|
||||||
if (
|
if (
|
||||||
r.deltimeLocal >= mtimeLocal &&
|
r.deltimeLocal >= mtimeLocal &&
|
||||||
@ -787,9 +790,9 @@ const assignOperationToFileInplace = (
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const localTooLargeToDelete =
|
const localTooLargeToDelete =
|
||||||
r.existLocal && sizeLocalComp > skipSizeLargerThan;
|
r.existLocal && sizeLocalComp! > skipSizeLargerThan;
|
||||||
const remoteTooLargeToDelete =
|
const remoteTooLargeToDelete =
|
||||||
r.existRemote && sizeRemoteComp > skipSizeLargerThan;
|
r.existRemote && sizeRemoteComp! > skipSizeLargerThan;
|
||||||
if (localTooLargeToDelete) {
|
if (localTooLargeToDelete) {
|
||||||
if (remoteTooLargeToDelete) {
|
if (remoteTooLargeToDelete) {
|
||||||
r.decision = "skipUsingLocalDelTooLarge";
|
r.decision = "skipUsingLocalDelTooLarge";
|
||||||
@ -824,8 +827,8 @@ const assignOperationToFileInplace = (
|
|||||||
|
|
||||||
// 4. deltimeRemote
|
// 4. deltimeRemote
|
||||||
if (r.deltimeRemote !== undefined && r.deltimeRemote !== 0) {
|
if (r.deltimeRemote !== undefined && r.deltimeRemote !== 0) {
|
||||||
const mtimeLocal = r.existLocal ? r.mtimeLocal : -1;
|
const mtimeLocal = r.existLocal ? r.mtimeLocal! : -1;
|
||||||
const mtimeRemote = r.existRemote ? r.mtimeRemote : -1;
|
const mtimeRemote = r.existRemote ? r.mtimeRemote! : -1;
|
||||||
const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1;
|
const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1;
|
||||||
if (
|
if (
|
||||||
r.deltimeRemote >= mtimeLocal &&
|
r.deltimeRemote >= mtimeLocal &&
|
||||||
@ -840,9 +843,9 @@ const assignOperationToFileInplace = (
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const localTooLargeToDelete =
|
const localTooLargeToDelete =
|
||||||
r.existLocal && sizeLocalComp > skipSizeLargerThan;
|
r.existLocal && sizeLocalComp! > skipSizeLargerThan;
|
||||||
const remoteTooLargeToDelete =
|
const remoteTooLargeToDelete =
|
||||||
r.existRemote && sizeRemoteComp > skipSizeLargerThan;
|
r.existRemote && sizeRemoteComp! > skipSizeLargerThan;
|
||||||
if (localTooLargeToDelete) {
|
if (localTooLargeToDelete) {
|
||||||
if (remoteTooLargeToDelete) {
|
if (remoteTooLargeToDelete) {
|
||||||
r.decision = "skipUsingRemoteDelTooLarge";
|
r.decision = "skipUsingRemoteDelTooLarge";
|
||||||
@ -905,7 +908,13 @@ const assignOperationToFolderInplace = async (
|
|||||||
// if it was created after deletion, we should keep it as is
|
// if it was created after deletion, we should keep it as is
|
||||||
if (requireApiVersion(API_VER_STAT_FOLDER)) {
|
if (requireApiVersion(API_VER_STAT_FOLDER)) {
|
||||||
if (r.existLocal) {
|
if (r.existLocal) {
|
||||||
const { ctime, mtime } = await statFix(vault, r.key);
|
let ctime = 0;
|
||||||
|
let mtime = 0;
|
||||||
|
const s = await statFix(vault, r.key);
|
||||||
|
if (s !== undefined && s !== null) {
|
||||||
|
ctime = s.ctime;
|
||||||
|
mtime = s.mtime;
|
||||||
|
}
|
||||||
const cmtime = Math.max(ctime ?? 0, mtime ?? 0);
|
const cmtime = Math.max(ctime ?? 0, mtime ?? 0);
|
||||||
if (
|
if (
|
||||||
!Number.isNaN(cmtime) &&
|
!Number.isNaN(cmtime) &&
|
||||||
@ -936,9 +945,9 @@ const assignOperationToFolderInplace = async (
|
|||||||
if (
|
if (
|
||||||
r.existLocal &&
|
r.existLocal &&
|
||||||
r.changeLocalMtimeUsingMapping &&
|
r.changeLocalMtimeUsingMapping &&
|
||||||
r.mtimeLocal > 0 &&
|
r.mtimeLocal! > 0 &&
|
||||||
r.mtimeLocal > deltimeLocal &&
|
r.mtimeLocal! > deltimeLocal &&
|
||||||
r.mtimeLocal > deltimeRemote
|
r.mtimeLocal! > deltimeRemote
|
||||||
) {
|
) {
|
||||||
keptFolder.add(getParentFolder(r.key));
|
keptFolder.add(getParentFolder(r.key));
|
||||||
if (r.existLocal && r.existRemote) {
|
if (r.existLocal && r.existRemote) {
|
||||||
@ -1018,8 +1027,8 @@ export const getSyncPlan = async (
|
|||||||
remoteStates: FileOrFolderMixedState[],
|
remoteStates: FileOrFolderMixedState[],
|
||||||
local: TAbstractFile[],
|
local: TAbstractFile[],
|
||||||
localConfigDirContents: ObsConfigDirFileType[] | undefined,
|
localConfigDirContents: ObsConfigDirFileType[] | undefined,
|
||||||
remoteDeleteHistory: DeletionOnRemote[],
|
remoteDeleteHistory: DeletionOnRemote[] | undefined,
|
||||||
localFileHistory: FileFolderHistoryRecord[],
|
localFileHistory: FileFolderHistoryRecord[] | undefined,
|
||||||
remoteType: SUPPORTED_SERVICES_TYPE,
|
remoteType: SUPPORTED_SERVICES_TYPE,
|
||||||
triggerSource: SyncTriggerSourceType,
|
triggerSource: SyncTriggerSourceType,
|
||||||
vault: Vault,
|
vault: Vault,
|
||||||
@ -1071,30 +1080,30 @@ export const getSyncPlan = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SIZES_GO_WRONG_DECISIONS.has(val.decision)) {
|
if (SIZES_GO_WRONG_DECISIONS.has(val.decision!)) {
|
||||||
sizesGoWrong.push(val);
|
sizesGoWrong.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DELETION_DECISIONS.has(val.decision)) {
|
if (DELETION_DECISIONS.has(val.decision!)) {
|
||||||
if (val.decision === "uploadLocalDelHistToRemote") {
|
if (val.decision === "uploadLocalDelHistToRemote") {
|
||||||
deletions.push({
|
deletions.push({
|
||||||
key: key,
|
key: key,
|
||||||
actionWhen: val.deltimeLocal,
|
actionWhen: val.deltimeLocal!,
|
||||||
});
|
});
|
||||||
} else if (val.decision === "keepRemoteDelHist") {
|
} else if (val.decision === "keepRemoteDelHist") {
|
||||||
deletions.push({
|
deletions.push({
|
||||||
key: key,
|
key: key,
|
||||||
actionWhen: val.deltimeRemote,
|
actionWhen: val.deltimeRemote!,
|
||||||
});
|
});
|
||||||
} else if (val.decision === "uploadLocalDelHistToRemoteFolder") {
|
} else if (val.decision === "uploadLocalDelHistToRemoteFolder") {
|
||||||
deletions.push({
|
deletions.push({
|
||||||
key: key,
|
key: key,
|
||||||
actionWhen: val.deltimeLocal,
|
actionWhen: val.deltimeLocal!,
|
||||||
});
|
});
|
||||||
} else if (val.decision === "keepRemoteDelHistFolder") {
|
} else if (val.decision === "keepRemoteDelHistFolder") {
|
||||||
deletions.push({
|
deletions.push({
|
||||||
key: key,
|
key: key,
|
||||||
actionWhen: val.deltimeRemote,
|
actionWhen: val.deltimeRemote!,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw Error(`do not know how to delete for decision ${val.decision}`);
|
throw Error(`do not know how to delete for decision ${val.decision}`);
|
||||||
@ -1131,7 +1140,7 @@ const uploadExtraMeta = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const key = DEFAULT_FILE_NAME_FOR_METADATAONREMOTE;
|
const key = DEFAULT_FILE_NAME_FOR_METADATAONREMOTE;
|
||||||
let remoteEncryptedKey = key;
|
let remoteEncryptedKey: string | undefined = key;
|
||||||
|
|
||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
if (metadataFile === undefined) {
|
if (metadataFile === undefined) {
|
||||||
@ -1180,7 +1189,7 @@ const dispatchOperationToActual = async (
|
|||||||
localDeleteFunc: any,
|
localDeleteFunc: any,
|
||||||
password: string = ""
|
password: string = ""
|
||||||
) => {
|
) => {
|
||||||
let remoteEncryptedKey = key;
|
let remoteEncryptedKey: string | undefined = key;
|
||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
remoteEncryptedKey = r.remoteEncryptedKey;
|
remoteEncryptedKey = r.remoteEncryptedKey;
|
||||||
if (remoteEncryptedKey === undefined || remoteEncryptedKey === "") {
|
if (remoteEncryptedKey === undefined || remoteEncryptedKey === "") {
|
||||||
@ -1233,12 +1242,12 @@ const dispatchOperationToActual = async (
|
|||||||
client.serviceType,
|
client.serviceType,
|
||||||
db,
|
db,
|
||||||
r.key,
|
r.key,
|
||||||
r.mtimeLocal,
|
r.mtimeLocal!,
|
||||||
r.sizeLocal,
|
r.sizeLocal!,
|
||||||
r.key,
|
r.key,
|
||||||
remoteObjMeta.lastModified,
|
remoteObjMeta.lastModified ?? Date.now(),
|
||||||
remoteObjMeta.size,
|
remoteObjMeta.size,
|
||||||
remoteObjMeta.etag,
|
remoteObjMeta.etag ?? "",
|
||||||
vaultRandomID
|
vaultRandomID
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1248,7 +1257,7 @@ const dispatchOperationToActual = async (
|
|||||||
await client.downloadFromRemote(
|
await client.downloadFromRemote(
|
||||||
r.key,
|
r.key,
|
||||||
vault,
|
vault,
|
||||||
r.mtimeRemote,
|
r.mtimeRemote!,
|
||||||
password,
|
password,
|
||||||
remoteEncryptedKey
|
remoteEncryptedKey
|
||||||
);
|
);
|
||||||
@ -1269,12 +1278,12 @@ const dispatchOperationToActual = async (
|
|||||||
client.serviceType,
|
client.serviceType,
|
||||||
db,
|
db,
|
||||||
r.key,
|
r.key,
|
||||||
r.mtimeLocal,
|
r.mtimeLocal!,
|
||||||
r.sizeLocal,
|
r.sizeLocal!,
|
||||||
r.key,
|
r.key,
|
||||||
remoteObjMeta.lastModified,
|
remoteObjMeta.lastModified ?? Date.now(),
|
||||||
remoteObjMeta.size,
|
remoteObjMeta.size,
|
||||||
remoteObjMeta.etag,
|
remoteObjMeta.etag ?? "",
|
||||||
vaultRandomID
|
vaultRandomID
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1388,7 +1397,7 @@ export const doActualSync = async (
|
|||||||
vault: Vault,
|
vault: Vault,
|
||||||
syncPlan: SyncPlanType,
|
syncPlan: SyncPlanType,
|
||||||
sortedKeys: string[],
|
sortedKeys: string[],
|
||||||
metadataFile: FileOrFolderMixedState,
|
metadataFile: FileOrFolderMixedState | undefined,
|
||||||
origMetadata: MetadataOnRemote,
|
origMetadata: MetadataOnRemote,
|
||||||
sizesGoWrong: FileOrFolderMixedState[],
|
sizesGoWrong: FileOrFolderMixedState[],
|
||||||
deletions: DeletionOnRemote[],
|
deletions: DeletionOnRemote[],
|
||||||
|
|||||||
@ -45,8 +45,8 @@ describe("Metadata operations tests", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should treat undefined correctly", async () => {
|
it("should treat undefined correctly", async () => {
|
||||||
const a: MetadataOnRemote = undefined;
|
const a: MetadataOnRemote | undefined = undefined;
|
||||||
let b: MetadataOnRemote = {
|
let b: MetadataOnRemote | undefined = {
|
||||||
deletions: [
|
deletions: [
|
||||||
{ key: "xxx", actionWhen: 1 },
|
{ key: "xxx", actionWhen: 1 },
|
||||||
{ key: "yyy", actionWhen: 2 },
|
{ key: "yyy", actionWhen: 2 },
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
"inlineSources": true,
|
"inlineSources": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
|
"strict": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user