diff --git a/src/CmdConfigSync.ts b/src/CmdConfigSync.ts index 451dd97..2250465 100644 --- a/src/CmdConfigSync.ts +++ b/src/CmdConfigSync.ts @@ -178,9 +178,7 @@ export class ConfigSync extends LiveSyncCommands { get kvDB() { return this.plugin.kvDB; } - ensureDirectoryEx(fullPath: string) { - return this.plugin.ensureDirectoryEx(fullPath); - } + pluginDialog: PluginDialogModal = null; periodicPluginSweepProcessor = new PeriodicProcessor(this.plugin, async () => await this.scanAllConfigFiles(false)); @@ -433,7 +431,7 @@ export class ConfigSync extends LiveSyncCommands { try { // console.dir(f); const path = `${baseDir}/${f.filename}`; - await this.ensureDirectoryEx(path); + await this.vaultAccess.ensureDirectory(path); if (!content) { const dt = decodeBinary(f.data); await this.vaultAccess.adapterWrite(path, dt); diff --git a/src/CmdHiddenFileSync.ts b/src/CmdHiddenFileSync.ts index 2da9f36..8521a71 100644 --- a/src/CmdHiddenFileSync.ts +++ b/src/CmdHiddenFileSync.ts @@ -20,9 +20,6 @@ export class HiddenFileSync extends LiveSyncCommands { get kvDB() { return this.plugin.kvDB; } - ensureDirectoryEx(fullPath: string) { - return this.plugin.ensureDirectoryEx(fullPath); - } getConflictedDoc(path: FilePathWithPrefix, rev: string) { return this.plugin.getConflictedDoc(path, rev); } @@ -202,7 +199,7 @@ export class HiddenFileSync extends LiveSyncCommands { const filename = stripAllPrefixes(path); const isExists = await this.plugin.vaultAccess.adapterExists(filename); if (!isExists) { - await this.ensureDirectoryEx(filename); + await this.vaultAccess.ensureDirectory(filename); } await this.plugin.vaultAccess.adapterWrite(filename, result); const stat = await this.vaultAccess.adapterStat(filename); @@ -498,7 +495,7 @@ export class HiddenFileSync extends LiveSyncCommands { type: "newnote", }; } - const ret = await this.localDatabase.putDBEntry(saveData, true); + const ret = await this.localDatabase.putDBEntry(saveData); Logger(`STORAGE --> DB:${file.path}: (hidden) Done`); return ret; } catch (ex) { @@ -599,7 +596,7 @@ export class HiddenFileSync extends LiveSyncCommands { return true; } if (!isExists) { - await this.ensureDirectoryEx(filename); + await this.vaultAccess.ensureDirectory(filename); await this.plugin.vaultAccess.adapterWrite(filename, decodeBinary(fileOnDB.data), { mtime: fileOnDB.mtime, ctime: fileOnDB.ctime }); try { //@ts-ignore internalAPI @@ -668,7 +665,7 @@ export class HiddenFileSync extends LiveSyncCommands { if (!keep && result) { const isExists = await this.plugin.vaultAccess.adapterExists(filename); if (!isExists) { - await this.ensureDirectoryEx(filename); + await this.vaultAccess.ensureDirectory(filename); } await this.plugin.vaultAccess.adapterWrite(filename, result); const stat = await this.plugin.vaultAccess.adapterStat(filename); diff --git a/src/CmdSetupLiveSync.ts b/src/CmdSetupLiveSync.ts index 513e90a..d6bc7e5 100644 --- a/src/CmdSetupLiveSync.ts +++ b/src/CmdSetupLiveSync.ts @@ -359,7 +359,7 @@ Of course, we are able to disable these features.` Logger(`Fetching chunks done`, LOG_LEVEL_NOTICE); } } - async fetchLocal() { + async fetchLocal(makeLocalChunkBeforeSync?: boolean) { this.suspendExtraSync(); await this.askUseNewAdapter(); this.plugin.settings.isConfigured = true; @@ -368,8 +368,11 @@ Of course, we are able to disable these features.` await this.resetLocalDatabase(); await delay(1000); await this.plugin.openDatabase(); - await this.plugin.markRemoteResolved(); this.plugin.isReady = true; + if (makeLocalChunkBeforeSync) { + await this.plugin.initializeDatabase(true); + } + await this.plugin.markRemoteResolved(); await delay(500); await this.plugin.replicateAllFromServer(true); await delay(1000); @@ -379,24 +382,7 @@ Of course, we are able to disable these features.` await this.askHiddenFileConfiguration({ enableFetch: true }); } async fetchLocalWithKeepLocal() { - this.suspendExtraSync(); - await this.askUseNewAdapter(); - this.plugin.settings.isConfigured = true; - await this.suspendReflectingDatabase(); - await this.plugin.realizeSettingSyncMode(); - await this.resetLocalDatabase(); - await delay(1000); - await this.plugin.initializeDatabase(true); - await this.plugin.openDatabase(); - await this.plugin.markRemoteResolved(); - this.plugin.isReady = true; - await delay(500); - await this.plugin.replicateAllFromServer(true); - await delay(1000); - await this.plugin.replicateAllFromServer(true); - await this.fetchRemoteChunks(); - await this.resumeReflectingDatabase(); - await this.askHiddenFileConfiguration({ enableFetch: true }); + return await this.fetchLocal(true); } async rebuildRemote() { this.suspendExtraSync(); diff --git a/src/ObsidianLiveSyncSettingTab.ts b/src/ObsidianLiveSyncSettingTab.ts index c4b90b0..d84707c 100644 --- a/src/ObsidianLiveSyncSettingTab.ts +++ b/src/ObsidianLiveSyncSettingTab.ts @@ -663,7 +663,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { .setWarning() .setDisabled(false) .onClick(async () => { - await rebuildDB("localOnly"); + await rebuildDB("localOnlyWithChunks"); }) ) .addButton((button) => @@ -732,7 +732,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { } }; - const rebuildDB = async (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice") => { + const rebuildDB = async (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks") => { if (encrypt && passphrase == "") { Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL_NOTICE); return; @@ -1053,9 +1053,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { if (!this.plugin.settings.isConfigured) { this.plugin.settings.isConfigured = true; await this.plugin.saveSettings(); - await rebuildDB("localOnly"); + await rebuildDB("localOnlyWithChunks"); Logger("All done! Please set up subsequent devices with 'Copy current settings as a new setup URI' and 'Use the copied setup URI'.", LOG_LEVEL_NOTICE); - await this.plugin.addOnSetup.command_openSetupURI(); + await this.plugin.addOnSetup.command_copySetupURI(); } else { this.askReload(); } @@ -1922,7 +1922,7 @@ ${stringifyYaml(pluginConfig)}`; toggle.setValue(!this.plugin.settings.useIndexedDBAdapter).onChange(async (value) => { this.plugin.settings.useIndexedDBAdapter = !value; await this.plugin.saveSettings(); - await rebuildDB("localOnly"); + await rebuildDB("localOnlyWithChunks"); }) ); @@ -2119,6 +2119,19 @@ ${stringifyYaml(pluginConfig)}`; .setButtonText("Fetch") .setWarning() .setDisabled(false) + .onClick(async () => { + await rebuildDB("localOnlyWithChunks"); + }) + ) + + new Setting(containerMaintenanceEl) + .setName("Fetch rebuilt DB with all remote chunks") + .setDesc("Restore or reconstruct local database from remote database but use remote chunk .") + .addButton((button) => + button + .setButtonText("Fetch all") + .setWarning() + .setDisabled(false) .onClick(async () => { await rebuildDB("localOnly"); }) diff --git a/src/SerializedFileAccess.ts b/src/SerializedFileAccess.ts index ea1f549..a2baebc 100644 --- a/src/SerializedFileAccess.ts +++ b/src/SerializedFileAccess.ts @@ -1,5 +1,6 @@ import { type App, TFile, type DataWriteOptions, TFolder, TAbstractFile } from "./deps"; import { serialized } from "./lib/src/lock"; +import { Logger } from "./lib/src/logger"; import type { FilePath } from "./lib/src/types"; import { createBinaryBlob, isDocContentSame } from "./lib/src/utils"; import type { InternalFileInfo } from "./types"; @@ -107,6 +108,15 @@ export class SerializedFileAccess { return await processWriteFile(path, () => this.app.vault.createBinary(path, toArrayBuffer(data), options)); } } + + trigger(name: string, ...data: any[]) { + return this.app.vault.trigger(name, ...data); + } + + async adapterAppend(normalizedPath: string, data: string, options?: DataWriteOptions) { + return await this.app.vault.adapter.append(normalizedPath, data, options) + } + async delete(file: TFile | TFolder, force = false) { return await processWriteFile(file, () => this.app.vault.delete(file, force)); } @@ -127,6 +137,31 @@ export class SerializedFileAccess { // } } + getFiles() { + return this.app.vault.getFiles(); + } + + async ensureDirectory(fullPath: string) { + const pathElements = fullPath.split("/"); + pathElements.pop(); + let c = ""; + for (const v of pathElements) { + c += v; + try { + await this.app.vault.adapter.mkdir(c); + } catch (ex) { + // basically skip exceptions. + if (ex.message && ex.message == "Folder already exists.") { + // especially this message is. + } else { + Logger("Folder Create Error"); + Logger(ex); + } + } + c += "/"; + } + } + touchedFiles: string[] = []; diff --git a/src/lib b/src/lib index 1a34883..8a8177c 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 1a3488339e22532b421920fe834436a49fcd0819 +Subproject commit 8a8177c1f068a4fe2f2951a1b388261e7ee51fad diff --git a/src/main.ts b/src/main.ts index f3cb325..4636949 100644 --- a/src/main.ts +++ b/src/main.ts @@ -84,7 +84,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin this._suspended = value; } deviceAndVaultName = ""; - isMobile = false; isReady = false; packageVersion = ""; manifestVersion = ""; @@ -248,6 +247,22 @@ export default class ObsidianLiveSyncPlugin extends Plugin } } + get isMobile() { + // @ts-ignore: internal API + return this.app.isMobile + } + + get vaultName() { + return this.app.vault.getName() + } + getActiveFile() { + return this.app.workspace.getActiveFile(); + } + + get appId() { + return `${("appId" in this.app ? this.app.appId : "")}`; + } + id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix { const tempId = id2path(id, entry); if (stripPrefix && isInternalMetadata(tempId)) { @@ -309,13 +324,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin // end interfaces getVaultName(): string { - return this.app.vault.getName() + (this.settings?.additionalSuffixOfDatabaseName ? ("-" + this.settings.additionalSuffixOfDatabaseName) : ""); - } - - setInterval(handler: () => any, timeout?: number): number { - const timer = window.setInterval(handler, timeout); - this.registerInterval(timer); - return timer; + return this.vaultName + (this.settings?.additionalSuffixOfDatabaseName ? ("-" + this.settings.additionalSuffixOfDatabaseName) : ""); } isFlagFileExist(path: string) { @@ -361,7 +370,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin } notes.sort((a, b) => b.mtime - a.mtime); const notesList = notes.map(e => e.dispPath); - const target = await askSelectString(this.app, "File to view History", notesList); + const target = await this.askSelectString("File to view History", notesList); if (target) { const targetId = notes.find(e => e.dispPath == target); this.showHistory(targetId.path, targetId.id); @@ -379,7 +388,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin Logger("There are no conflicted documents", LOG_LEVEL_NOTICE); return false; } - const target = await askSelectString(this.app, "File to resolve conflict", notesList); + const target = await this.askSelectString("File to resolve conflict", notesList); if (target) { const targetItem = notes.find(e => e.dispPath == target); this.resolveConflicted(targetItem.path); @@ -458,10 +467,7 @@ Click anywhere to stop counting down. const ret = await confirmWithMessage(this, "Welcome to Self-hosted LiveSync", message, [USE_SETUP, OPEN_SETUP, DISMISS], DISMISS, 40); if (ret === OPEN_SETUP) { try { - //@ts-ignore: undocumented api - this.app.setting.open(); - //@ts-ignore: undocumented api - this.app.setting.openTabById("obsidian-livesync"); + this.openSetting(); } catch (ex) { Logger("Something went wrong on opening setting dialog, please open it manually", LOG_LEVEL_NOTICE); } @@ -482,22 +488,20 @@ Click anywhere to stop counting down. Logger(`${FLAGMD_REDFLAG2} or ${FLAGMD_REDFLAG2_HR} has been detected! Self-hosted LiveSync suspends all sync and rebuild everything.`, LOG_LEVEL_NOTICE); await this.addOnSetup.rebuildEverything(); await this.deleteRedFlag2(); - if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { + if (await this.askYesNo("Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { this.settings.suspendFileWatching = false; await this.saveSettings(); - // @ts-ignore - this.app.commands.executeCommandById("app:reload") + this.performAppReload(); } } else if (this.isRedFlag3Raised()) { Logger(`${FLAGMD_REDFLAG3} or ${FLAGMD_REDFLAG3_HR} has been detected! Self-hosted LiveSync will discard the local database and fetch everything from the remote once again.`, LOG_LEVEL_NOTICE); await this.addOnSetup.fetchLocal(); await this.deleteRedFlag3(); if (this.settings.suspendFileWatching) { - if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { + if (await this.askYesNo("Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { this.settings.suspendFileWatching = false; await this.saveSettings(); - // @ts-ignore - this.app.commands.executeCommandById("app:reload") + this.performAppReload(); } } } else { @@ -546,8 +550,7 @@ Click anywhere to stop counting down. this.askInPopup(`conflicting-detected-on-safety`, `Some files have been left conflicted! Press {HERE} to resolve them, or you can do it later by "Pick a file to resolve conflict`, (anchor) => { anchor.text = "HERE"; anchor.addEventListener("click", () => { - // @ts-ignore - this.app.commands.executeCommandById("obsidian-livesync:livesync-all-conflictcheck"); + this.performCommand("obsidian-livesync:livesync-all-conflictcheck"); }); } ); @@ -629,7 +632,7 @@ Note: We can always able to read V1 format. It will be progressively converted. // this.localDatabase.getDBEntry(getPathFromTFile(file), {}, true, false); // }, callback: () => { - const file = this.app.workspace.getActiveFile(); + const file = this.getActiveFile(); if (!file) return; this.localDatabase.getDBEntry(getPathFromTFile(file), {}, true, false); }, @@ -678,7 +681,7 @@ Note: We can always able to read V1 format. It will be progressively converted. id: "livesync-history", name: "Show history", callback: () => { - const file = this.app.workspace.getActiveFile(); + const file = this.getActiveFile(); if (file) this.showHistory(file, null); } }); @@ -791,8 +794,7 @@ Note: We can always able to read V1 format. It will be progressively converted. } //@ts-ignore - if (this.app.isMobile) { - this.isMobile = true; + if (this.isMobile) { this.settings.disableRequestURI = true; } if (last_version && Number(last_version) < VER) { @@ -869,8 +871,6 @@ Note: We can always able to read V1 format. It will be progressively converted. } const vaultName = this.getVaultName(); Logger("Waiting for ready..."); - //@ts-ignore - this.isMobile = this.app.isMobile; this.localDatabase = new LiveSyncLocalDB(vaultName, this); initializeStores(vaultName); return await this.localDatabase.initializeDatabase(); @@ -933,7 +933,7 @@ Note: We can always able to read V1 format. It will be progressively converted. if (JSON.stringify(settings) !== JSON.stringify(DEFAULT_SETTINGS)) { settings.isConfigured = true; } else { - settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}` + settings.additionalSuffixOfDatabaseName = this.appId; settings.isConfigured = false; } } @@ -1057,7 +1057,7 @@ Note: We can always able to read V1 format. It will be progressively converted. } async parseSettingFromMarkdown(filename: string, data?: string) { - const file = this.app.vault.getAbstractFileByPath(filename); + const file = this.vaultAccess.getAbstractFileByPath(filename); if (!(file instanceof TFile)) return { preamble: "", body: "", @@ -1066,7 +1066,7 @@ Note: We can always able to read V1 format. It will be progressively converted. if (data) { return this.extractSettingFromWholeText(data); } - const parseData = data ?? await this.app.vault.read(file); + const parseData = data ?? await this.vaultAccess.vaultRead(file); return this.extractSettingFromWholeText(parseData); } @@ -1115,7 +1115,7 @@ Note: We can always able to read V1 format. It will be progressively converted. const APPLY_AND_REBUILD = "Apply settings and restart obsidian with red_flag_rebuild.md"; const APPLY_AND_FETCH = "Apply settings and restart obsidian with red_flag_fetch.md"; const CANCEL = "Cancel"; - const result = await askSelectString(this.app, "Ready for apply the setting.", [APPLY_AND_RESTART, APPLY_ONLY, APPLY_AND_FETCH, APPLY_AND_REBUILD, CANCEL]); + const result = await this.askSelectString("Ready for apply the setting.", [APPLY_AND_RESTART, APPLY_ONLY, APPLY_AND_FETCH, APPLY_AND_REBUILD, CANCEL]); if (result == APPLY_ONLY || result == APPLY_AND_RESTART || result == APPLY_AND_REBUILD || result == APPLY_AND_FETCH) { this.settings = settingToApply; await this.saveSettingData(); @@ -1124,13 +1124,12 @@ Note: We can always able to read V1 format. It will be progressively converted. return; } if (result == APPLY_AND_REBUILD) { - await this.app.vault.create(FLAGMD_REDFLAG2_HR, ""); + await this.vaultAccess.vaultCreate(FLAGMD_REDFLAG2_HR, ""); } if (result == APPLY_AND_FETCH) { - await this.app.vault.create(FLAGMD_REDFLAG3_HR, ""); + await this.vaultAccess.vaultCreate(FLAGMD_REDFLAG3_HR, ""); } - // @ts-ignore - this.app.commands.executeCommandById("app:reload"); + this.performAppReload(); } } ) @@ -1150,11 +1149,11 @@ Note: We can always able to read V1 format. It will be progressively converted. async saveSettingToMarkdown(filename: string) { const saveData = this.generateSettingForMarkdown(); - let file = this.app.vault.getAbstractFileByPath(filename); + let file = this.vaultAccess.getAbstractFileByPath(filename); if (!file) { - await this.ensureDirectoryEx(filename); + await this.vaultAccess.ensureDirectory(filename); const initialContent = `This file contains Self-hosted LiveSync settings as YAML. Except for the \`livesync-setting\` code block, we can add a note for free. @@ -1167,21 +1166,21 @@ We can perform a command in this file. ` - file = await this.app.vault.create(filename, initialContent + SETTING_HEADER + "\n" + SETTING_FOOTER); + file = await this.vaultAccess.vaultCreate(filename, initialContent + SETTING_HEADER + "\n" + SETTING_FOOTER); } if (!(file instanceof TFile)) { Logger(`Markdown Setting: ${filename} already exists as a folder`, LOG_LEVEL_NOTICE); return; } - const data = await this.app.vault.read(file); + const data = await this.vaultAccess.vaultRead(file); const { preamble, body, postscript } = this.extractSettingFromWholeText(data); const newBody = stringifyYaml(saveData); if (newBody == body) { Logger("Markdown setting: Nothing had been changed", LOG_LEVEL_VERBOSE); } else { - await this.app.vault.modify(file, preamble + SETTING_HEADER + newBody + SETTING_FOOTER + postscript); + await this.vaultAccess.vaultModify(file, preamble + SETTING_HEADER + newBody + SETTING_FOOTER + postscript); Logger(`Markdown setting: ${filename} has been updated!`, LOG_LEVEL_VERBOSE); } } @@ -1224,8 +1223,7 @@ We can perform a command in this file. const _this = this; //@ts-ignore window.CodeMirrorAdapter.commands.save = () => { - //@ts-ignore - _this.app.commands.executeCommandById('editor:save-file'); + _this.performCommand('editor:save-file'); }; } registerWatchEvents() { @@ -1235,7 +1233,6 @@ We can perform a command in this file. this.registerDomEvent(window, "offline", this.watchOnline); } - watchOnline() { scheduleTask("watch-online", 500, () => fireAndForget(() => this.watchOnlineAsync())); } @@ -1456,9 +1453,9 @@ We can perform a command in this file. const logDate = `${PREFIXMD_LOGFILE}${time}.md`; const file = this.vaultAccess.getAbstractFileByPath(normalizePath(logDate)); if (!file) { - this.app.vault.adapter.append(normalizePath(logDate), "```\n"); + this.vaultAccess.adapterAppend(normalizePath(logDate), "```\n"); } - this.app.vault.adapter.append(normalizePath(logDate), vaultName + ":" + newMessage + "\n"); + this.vaultAccess.adapterAppend(normalizePath(logDate), vaultName + ":" + newMessage + "\n"); } recentLogProcessor.enqueue(newMessage); @@ -1496,28 +1493,6 @@ We can perform a command in this file. }) } } - - async ensureDirectory(fullPath: string) { - const pathElements = fullPath.split("/"); - pathElements.pop(); - let c = ""; - for (const v of pathElements) { - c += v; - try { - await this.app.vault.createFolder(c); - } catch (ex) { - // basically skip exceptions. - if (ex.message && ex.message == "Folder already exists.") { - // especially this message is. - } else { - Logger("Folder Create Error"); - Logger(ex); - } - } - c += "/"; - } - } - async processEntryDoc(docEntry: EntryBody, file: TFile | undefined, force?: boolean) { const mode = file == undefined ? "create" : "modify"; @@ -1577,7 +1552,7 @@ We can perform a command in this file. return; } const writeData = doc.datatype == "newnote" ? decodeBinary(doc.data) : getDocData(doc.data); - await this.ensureDirectoryEx(path); + await this.vaultAccess.ensureDirectory(path); try { let outFile; let isChanged = true; @@ -1592,7 +1567,7 @@ We can perform a command in this file. if (isChanged) { Logger(msg + path); this.vaultAccess.touch(outFile); - this.app.vault.trigger(mode, outFile); + this.vaultAccess.trigger(mode, outFile); } else { Logger(msg + "Skipped, the file is the same: " + path, LOG_LEVEL_VERBOSE); } @@ -1626,7 +1601,7 @@ We can perform a command in this file. queueConflictCheck(file: FilePathWithPrefix | TFile) { const path = file instanceof TFile ? getPathFromTFile(file) : file; if (this.settings.checkConflictOnlyOnOpen) { - const af = this.app.workspace.getActiveFile(); + const af = this.getActiveFile(); if (af && af.path != path) { Logger(`${file} is conflicted, merging process has been postponed.`, LOG_LEVEL_NOTICE); return; @@ -1927,7 +1902,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid const CHOICE_DISMISS = "Dismiss"; const ret = await confirmWithMessage(this, "Cleaned", message, [CHOICE_FETCH, CHOICE_CLEAN, CHOICE_DISMISS], CHOICE_DISMISS, 30); if (ret == CHOICE_FETCH) { - await performRebuildDB(this, "localOnly"); + await performRebuildDB(this, "localOnlyWithChunks"); } if (ret == CHOICE_CLEAN) { const remoteDB = await this.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.getIsMobile(), true); @@ -1961,7 +1936,7 @@ Or if you are sure know what had been happened, we can unlock the database from const CHOICE_DISMISS = "Dismiss"; const ret = await confirmWithMessage(this, "Locked", message, [CHOICE_FETCH, CHOICE_DISMISS], CHOICE_DISMISS, 10); if (ret == CHOICE_FETCH) { - await performRebuildDB(this, "localOnly"); + await performRebuildDB(this, "localOnlyWithChunks"); } } } @@ -2036,7 +2011,7 @@ Or if you are sure know what had been happened, we can unlock the database from await this.collectDeletedFiles(); Logger("Collecting local files on the storage", LOG_LEVEL_VERBOSE); - const filesStorageSrc = this.app.vault.getFiles(); + const filesStorageSrc = this.vaultAccess.getFiles(); const filesStorage = [] as typeof filesStorageSrc; for (const f of filesStorageSrc) { @@ -2534,7 +2509,7 @@ Or if you are sure know what had been happened, we can unlock the database from return; } if (this.settings.showMergeDialogOnlyOnActive) { - const af = this.app.workspace.getActiveFile(); + const af = this.getActiveFile(); if (af && af.path != filename) { Logger(`${filename} is conflicted. Merging process has been postponed to the file have got opened.`, LOG_LEVEL_NOTICE); return; @@ -2820,27 +2795,6 @@ Or if you are sure know what had been happened, we can unlock the database from await this.replicator.tryCreateRemoteDatabase(this.settings); } - async ensureDirectoryEx(fullPath: string) { - const pathElements = fullPath.split("/"); - pathElements.pop(); - let c = ""; - for (const v of pathElements) { - c += v; - try { - await this.app.vault.adapter.mkdir(c); - } catch (ex) { - // basically skip exceptions. - if (ex.message && ex.message == "Folder already exists.") { - // especially this message is. - } else { - Logger("Folder Create Error"); - Logger(ex); - } - } - c += "/"; - } - } - filterTargetFiles(files: InternalFileInfo[], targetFiles: string[] | false = false) { const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns .replace(/\n| /g, "") @@ -2949,6 +2903,12 @@ Or if you are sure know what had been happened, we can unlock the database from }); } + askYesNo(message: string): Promise<"yes" | "no"> { + return askYesNo(this.app, message); + } + askSelectString(message: string, items: string[]): Promise { + return askSelectString(this.app, message, items); + } askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void) { @@ -2967,7 +2927,6 @@ Or if you are sure know what had been happened, we can unlock the database from const popupKey = "popup-" + key; scheduleTask(popupKey, 1000, async () => { const popup = await memoIfNotExist(popupKey, () => new Notice(fragment, 0)); - //@ts-ignore const isShown = popup?.noticeEl?.isShown(); if (!isShown) { memoObject(popupKey, new Notice(fragment, 0)); @@ -2976,7 +2935,6 @@ Or if you are sure know what had been happened, we can unlock the database from const popup = retrieveMemoObject(popupKey); if (!popup) return; - //@ts-ignore if (popup?.noticeEl?.isShown()) { popup.hide(); } @@ -2984,5 +2942,19 @@ Or if you are sure know what had been happened, we can unlock the database from }); }); } + openSetting() { + //@ts-ignore: undocumented api + this.app.setting.open(); + //@ts-ignore: undocumented api + this.app.setting.openTabById("obsidian-livesync"); + } + + performAppReload() { + this.performCommand("app:reload"); + } + performCommand(id: string) { + // @ts-ignore + this.app.commands.executeCommandById(id) + } } diff --git a/src/utils.ts b/src/utils.ts index 0da42b1..cae34fd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -405,10 +405,13 @@ export const requestToCouchDB = async (baseUri: string, username: string, passwo return await _requestToCouchDB(baseUri, username, password, origin, uri, body, method); }; -export async function performRebuildDB(plugin: ObsidianLiveSyncPlugin, method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice") { +export async function performRebuildDB(plugin: ObsidianLiveSyncPlugin, method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks") { if (method == "localOnly") { await plugin.addOnSetup.fetchLocal(); } + if (method == "localOnlyWithChunks") { + await plugin.addOnSetup.fetchLocal(true); + } if (method == "remoteOnly") { await plugin.addOnSetup.rebuildRemote(); }