diff --git a/README.md b/README.md index e3fb240..0d4c87c 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ If you have deleted or renamed files, please wait until ⏳ icon disappeared. - Rarely, a file in the database could be corrupted. The plugin will not write to local storage when a file looks corrupted. If a local version of the file is on your device, the corruption could be fixed by editing the local file and synchronizing it. But if the file does not exist on any of your devices, then it can not be rescued. In this case, you can delete these items from the settings dialog. - To stop the boot-up sequence (eg. for fixing problems on databases), you can put a `redflag.md` file (or directory) at the root of your vault. Tip for iOS: a redflag directory can be created at the root of the vault using the File application. +- Also, with `redflag2.md` placed, we can automatically rebuild both the local and the remote databases during the boot-up sequence. With `redflag3.md`, we can discard only the local database and fetch from the remote again. - Q: The database is growing, how can I shrink it down? A: each of the docs is saved with their past 100 revisions for detecting and resolving conflicts. Picturing that one device has been offline for a while, and comes online again. The device has to compare its notes with the remotely saved ones. If there exists a historic revision in which the note used to be identical, it could be updated safely (like git fast-forward). Even if that is not in revision histories, we only have to check the differences after the revision that both devices commonly have. This is like git's conflict-resolving method. So, We have to make the database again like an enlarged git repo if you want to solve the root of the problem. - And more technical Information is in the [Technical Information](docs/tech_info.md) diff --git a/src/lib b/src/lib index a765f8e..85061f0 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit a765f8eac5e4a46d4a93b6e48038a7e4f3b7a88e +Subproject commit 85061f036829514e6749158a83a495e5c7b7fc50 diff --git a/src/main.ts b/src/main.ts index 5552421..05588c7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import { debounce, Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, PluginManifest, App } from "obsidian"; import { Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch"; -import { EntryDoc, LoadedEntry, ObsidianLiveSyncSettings, diff_check_result, diff_result_leaf, EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, InternalFileEntry, SALT_OF_PASSPHRASE, ConfigPassphraseStore, CouchDBConnection, FLAGMD_REDFLAG2 } from "./lib/src/types"; +import { EntryDoc, LoadedEntry, ObsidianLiveSyncSettings, diff_check_result, diff_result_leaf, EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, InternalFileEntry, SALT_OF_PASSPHRASE, ConfigPassphraseStore, CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3 } from "./lib/src/types"; import { PluginDataEntry, PERIODIC_PLUGIN_SWEEP, PluginList, DevicePluginList, InternalFileInfo, queueItem, FileInfo } from "./types"; import { delay, getDocData, isDocContentSame } from "./lib/src/utils"; import { Logger } from "./lib/src/logger"; @@ -169,6 +169,19 @@ export default class ObsidianLiveSyncPlugin extends Plugin { await app.vault.delete(redflag, true); } } + isRedFlag3Raised(): boolean { + const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG3)); + if (redflag != null) { + return true; + } + return false; + } + async deleteRedFlag3() { + const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG3)); + if (redflag != null) { + await app.vault.delete(redflag, true); + } + } showHistory(file: TFile | string) { if (!this.settings.useHistory) { @@ -376,7 +389,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin { this.registerFileWatchEvents(); if (this.localDatabase.isReady) try { - if (this.isRedFlagRaised() || this.isRedFlag2Raised()) { + if (this.isRedFlagRaised() || this.isRedFlag2Raised() || this.isRedFlag3Raised()) { this.settings.batchSave = false; this.settings.liveSync = false; this.settings.periodicReplication = false; @@ -398,6 +411,26 @@ export default class ObsidianLiveSyncPlugin extends Plugin { await this.markRemoteLocked(); await this.replicateAllToServer(true); await this.deleteRedFlag2(); + if (await askYesNo(this.app, "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"); + } + } else if (this.isRedFlag3Raised()) { + Logger(`${FLAGMD_REDFLAG3} has been detected! Self-hosted LiveSync will discard the local database and fetch everything from the remote once again.`, LOG_LEVEL.NOTICE); + await this.resetLocalDatabase(); + await this.markRemoteResolved(); + await this.openDatabase(); + this.isReady = true; + await this.replicate(true); + await this.deleteRedFlag3(); + if (await askYesNo(this.app, "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"); + } } else { await this.openDatabase(); const warningMessage = "The red flag is raised! The whole initialize steps are skipped, and any file changes are not captured."; @@ -1632,6 +1665,19 @@ export default class ObsidianLiveSyncPlugin extends Plugin { async parseIncomingDoc(doc: PouchDB.Core.ExistingDocument) { if (!this.isTargetFile(id2path(doc._id))) return; const skipOldFile = this.settings.skipOlderFilesOnSync && false; //patched temporary. + // Do not handle internal files if the feature has not been enabled. + if (isInternalMetadata(doc._id) && !this.settings.syncInternalFiles) return; + // It is better for your own safety, not to handle the following files + const ignoreFiles = [ + "_design/replicate", + FLAGMD_REDFLAG, + FLAGMD_REDFLAG2, + FLAGMD_REDFLAG3 + ]; + if (!isInternalMetadata(doc._id) && ignoreFiles.contains(id2path(doc._id))) { + return; + + } if ((!isInternalMetadata(doc._id)) && skipOldFile) { const info = getAbstractFileByPath(id2path(doc._id)); @@ -1911,7 +1957,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin { if (this.settings.syncInternalFiles && this.settings.syncInternalFilesBeforeReplication && !this.settings.watchInternalFileChanges) { await this.syncInternalFilesAndDatabase("push", showMessage); } - this.localDatabase.openReplication(this.settings, false, showMessage, this.parseReplicationResult); + await this.localDatabase.openReplication(this.settings, false, showMessage, this.parseReplicationResult); } async initializeDatabase(showingNotice?: boolean) {