- Fixed a problem with synchronisation taking a long time to start in some cases.
- Now we can disable E2EE encryption.
Improved:
- `Setup Wizard` is now more clear.
- `Minimal Setup` is now more simple.
- Self-hosted LiveSync now be able to use even if there are vaults with the same name.
- Now Self-hosted LiveSync waits until set-up is complete.
- Show reload prompts when possibly recommended while settings.
New feature:
- A guidance dialogue prompting for settings will be shown after the installation.
Changed
- Some setting names has been changed
This commit is contained in:
vorotamoroz
2024-02-20 05:13:53 +00:00
parent 1552fa9d9e
commit 65619c2478
13 changed files with 291 additions and 198 deletions

View File

@@ -5,7 +5,7 @@ import { PouchDB } from "./lib/src/pouchdb-browser.js";
import { askSelectString, askYesNo, askString } from "./utils";
import { decrypt, encrypt } from "./lib/src/e2ee_v2";
import { LiveSyncCommands } from "./LiveSyncCommands";
import { delay } from "./lib/src/utils";
import { delay, fireAndForget } from "./lib/src/utils";
import { confirmWithMessage } from "./dialogs";
import { Platform } from "./deps";
import { fetchAllUsedChunks } from "./lib/src/utils_couchdb";
@@ -17,25 +17,25 @@ export class SetupLiveSync extends LiveSyncCommands {
this.plugin.addCommand({
id: "livesync-copysetupuri",
name: "Copy the setup URI",
callback: this.command_copySetupURI.bind(this),
name: "Copy settings as a new setup URI",
callback: () => fireAndForget(this.command_copySetupURI()),
});
this.plugin.addCommand({
id: "livesync-copysetupuri-short",
name: "Copy the setup URI (With customization sync)",
callback: this.command_copySetupURIWithSync.bind(this),
name: "Copy settings as a new setup URI (With customization sync)",
callback: () => fireAndForget(this.command_copySetupURIWithSync()),
});
this.plugin.addCommand({
id: "livesync-copysetupurifull",
name: "Copy the setup URI (Full)",
callback: this.command_copySetupURIFull.bind(this),
name: "Copy settings as a new setup URI (Full)",
callback: () => fireAndForget(this.command_copySetupURIFull()),
});
this.plugin.addCommand({
id: "livesync-opensetupuri",
name: "Open the setup URI",
callback: this.command_openSetupURI.bind(this),
name: "Use the copied setup URI (Formerly Open setup URI)",
callback: () => fireAndForget(this.command_openSetupURI()),
});
}
onInitializeDatabase(showNotice: boolean) { }
@@ -76,7 +76,7 @@ export class SetupLiveSync extends LiveSyncCommands {
Logger("Setup URI copied to clipboard", LOG_LEVEL_NOTICE);
}
async command_copySetupURIWithSync() {
this.command_copySetupURI(false);
await this.command_copySetupURI(false);
}
async command_openSetupURI() {
const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`);
@@ -108,6 +108,7 @@ export class SetupLiveSync extends LiveSyncCommands {
newSettingW.configPassphraseStore = "";
newSettingW.encryptedPassphrase = "";
newSettingW.encryptedCouchDBConnection = "";
newSettingW.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}`
const setupJustImport = "Just import setting";
const setupAsNew = "Set it up as secondary or subsequent device";
const setupAsMerge = "Secondary device but try keeping local changes";
@@ -115,6 +116,7 @@ export class SetupLiveSync extends LiveSyncCommands {
const setupManually = "Leave everything to me";
newSettingW.syncInternalFiles = false;
newSettingW.usePluginSync = false;
newSettingW.isConfigured = true;
// Migrate completely obsoleted configuration.
if (!newSettingW.useIndexedDBAdapter) {
newSettingW.useIndexedDBAdapter = true;
@@ -333,10 +335,18 @@ Of course, we are able to disable these features.`
const ret = await confirmWithMessage(this.plugin, "Database adapter", message, choices, CHOICE_YES, 10);
if (ret == CHOICE_YES) {
this.plugin.settings.useIndexedDBAdapter = false;
this.plugin.settings.useIndexedDBAdapter = true;
}
}
}
async resetLocalDatabase() {
if (this.plugin.settings.isConfigured && this.plugin.settings.additionalSuffixOfDatabaseName == "") {
// Discard the non-suffixed database
await this.plugin.resetLocalDatabase();
}
this.plugin.settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}`
await this.plugin.resetLocalDatabase();
}
async fetchRemoteChunks() {
if (!this.plugin.settings.doNotSuspendOnFetching && this.plugin.settings.readChunksOnline) {
Logger(`Fetching chunks`, LOG_LEVEL_NOTICE);
@@ -351,10 +361,11 @@ Of course, we are able to disable these features.`
}
async fetchLocal() {
this.suspendExtraSync();
this.askUseNewAdapter();
await this.askUseNewAdapter();
this.plugin.settings.isConfigured = true;
await this.suspendReflectingDatabase();
await this.plugin.realizeSettingSyncMode();
await this.plugin.resetLocalDatabase();
await this.resetLocalDatabase();
await delay(1000);
await this.plugin.markRemoteResolved();
await this.plugin.openDatabase();
@@ -369,10 +380,11 @@ Of course, we are able to disable these features.`
}
async fetchLocalWithKeepLocal() {
this.suspendExtraSync();
this.askUseNewAdapter();
await this.askUseNewAdapter();
this.plugin.settings.isConfigured = true;
await this.suspendReflectingDatabase();
await this.plugin.realizeSettingSyncMode();
await this.plugin.resetLocalDatabase();
await this.resetLocalDatabase();
await delay(1000);
await this.plugin.initializeDatabase(true);
await this.plugin.markRemoteResolved();
@@ -388,6 +400,7 @@ Of course, we are able to disable these features.`
}
async rebuildRemote() {
this.suspendExtraSync();
this.plugin.settings.isConfigured = true;
await this.plugin.realizeSettingSyncMode();
await this.plugin.markRemoteLocked();
await this.plugin.tryResetRemoteDatabase();
@@ -401,9 +414,10 @@ Of course, we are able to disable these features.`
}
async rebuildEverything() {
this.suspendExtraSync();
this.askUseNewAdapter();
await this.askUseNewAdapter();
this.plugin.settings.isConfigured = true;
await this.plugin.realizeSettingSyncMode();
await this.plugin.resetLocalDatabase();
await this.resetLocalDatabase();
await delay(1000);
await this.plugin.initializeDatabase(true);
await this.plugin.markRemoteLocked();

View File

@@ -26,6 +26,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}
this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL_NOTICE);
}
askReload() {
scheduleTask("configReload", 250, async () => {
if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") {
// @ts-ignore
this.app.commands.executeCommandById("app:reload")
}
})
}
closeSetting() {
// @ts-ignore
this.plugin.app.setting.close()
}
display(): void {
const { containerEl } = this;
let encrypt = this.plugin.settings.encrypt;
@@ -136,29 +148,27 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
const setupWizardEl = containerEl.createDiv();
setupWizardEl.createEl("h3", { text: "Setup wizard" });
new Setting(setupWizardEl)
.setName("Discard the existing configuration and set up")
.setName("Use the copied setup URI")
.setDesc("To setup Self-hosted LiveSync, this method is the most preferred one.")
.addButton((text) => {
// eslint-disable-next-line require-await
text.setButtonText("Next").onClick(async () => {
if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) {
this.plugin.replicator.closeReplication();
this.plugin.settings = { ...DEFAULT_SETTINGS };
this.plugin.saveSettings();
Logger("Configuration has been flushed, please open it again", LOG_LEVEL_NOTICE)
// @ts-ignore
this.plugin.app.setting.close()
} else {
containerEl.addClass("isWizard");
applyDisplayEnabled();
inWizard = true;
changeDisplay("0")
}
text.setButtonText("Use").onClick(async () => {
this.closeSetting();
await this.plugin.addOnSetup.command_openSetupURI();
})
})
if (this.plugin.settings.isConfigured) {
new Setting(setupWizardEl)
.setName("Copy current settings as a new setup URI")
.addButton((text) => {
text.setButtonText("Copy").onClick(async () => {
await this.plugin.addOnSetup.command_copySetupURI();
})
})
}
new Setting(setupWizardEl)
.setName("Do not discard the existing configuration and set up again")
.setName("Minimal setup")
.addButton((text) => {
text.setButtonText("Next").onClick(async () => {
text.setButtonText("Start").onClick(async () => {
this.plugin.settings.liveSync = false;
this.plugin.settings.periodicReplication = false;
this.plugin.settings.syncOnSave = false;
@@ -172,27 +182,34 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
applyDisplayEnabled();
inWizard = true;
changeDisplay("0")
})
})
const infoWarnForSubsequent = setupWizardEl.createEl("div", { text: `To set up second or subsequent device, please use 'Copy setup URI' and 'Open setup URI'` });
infoWarnForSubsequent.addClass("op-warn-info");
new Setting(setupWizardEl)
.setName("Copy setup URI")
.addButton((text) => {
text.setButtonText("Copy setup URI").onClick(() => {
// @ts-ignore
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri")
if (!this.plugin.settings.isConfigured) {
new Setting(setupWizardEl)
.setName("Enable LiveSync on this device as the set-up was completed manually")
.addButton((text) => {
text.setButtonText("Enable").onClick(async () => {
this.plugin.settings.isConfigured = true;
await this.plugin.saveSettings();
this.askReload();
})
})
})
.addButton((text) => {
text.setButtonText("Open setup URI").onClick(() => {
// @ts-ignore
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-opensetupuri")
}
if (this.plugin.settings.isConfigured) {
new Setting(setupWizardEl)
.setName("Discard exist settings and databases")
.addButton((text) => {
text.setButtonText("Discard").onClick(async () => {
if (await askYesNo(this.plugin.app, "Do you really want to discard exist settings and databases?") == "yes") {
this.plugin.settings = { ...DEFAULT_SETTINGS };
await this.plugin.saveSettingData();
await this.plugin.resetLocalDatabase();
// await this.plugin.initializeDatabase();
this.askReload();
}
}).setWarning()
})
})
}
setupWizardEl.createEl("h3", { text: "Online Tips" });
const repo = "vrtmrz/obsidian-livesync";
const topPath = "/docs/troubleshooting.md";
@@ -338,6 +355,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
new Setting(containerRemoteDatabaseEl)
.setName("Test Database Connection")
.setClass("wizardHidden")
.setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.")
.addButton((button) =>
button
@@ -349,8 +367,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
);
new Setting(containerRemoteDatabaseEl)
.setName("Check database configuration")
// .setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.")
.setName("Check and Fix database configuration")
.setDesc("Check the database configuration, and fix if there are any problems.")
.addButton((button) =>
button
.setButtonText("Check")
@@ -557,18 +575,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
passphraseSetting?.controlEl.toggleClass("sls-item-dirty", passphrase != this.plugin.settings.passphrase);
dynamicIteration?.controlEl.toggleClass("sls-item-dirty", useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount);
usePathObfuscationEl?.controlEl.toggleClass("sls-item-dirty", usePathObfuscation != this.plugin.settings.usePathObfuscation);
if (encrypt != this.plugin.settings.encrypt ||
passphrase != this.plugin.settings.passphrase ||
useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount ||
usePathObfuscation != this.plugin.settings.usePathObfuscation) {
applyE2EButtons.settingEl.removeClass("sls-setting-hidden");
} else {
applyE2EButtons.settingEl.addClass("sls-setting-hidden");
}
} else {
passphraseSetting.settingEl.addClass("sls-setting-hidden");
dynamicIteration.settingEl.addClass("sls-setting-hidden");
usePathObfuscationEl.settingEl.addClass("sls-setting-hidden");
}
if (encrypt != this.plugin.settings.encrypt ||
passphrase != this.plugin.settings.passphrase ||
useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount ||
usePathObfuscation != this.plugin.settings.usePathObfuscation) {
applyE2EButtons.settingEl.removeClass("sls-setting-hidden");
} else {
applyE2EButtons.settingEl.addClass("sls-setting-hidden");
}
}
@@ -703,6 +721,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
this.plugin.settings.passphrase = passphrase;
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
this.plugin.settings.usePathObfuscation = usePathObfuscation;
this.plugin.settings.isConfigured = true;
await this.plugin.saveSettings();
updateE2EControls();
if (sendToServer) {
@@ -731,26 +750,23 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
this.plugin.settings.passphrase = passphrase;
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
this.plugin.settings.usePathObfuscation = usePathObfuscation;
this.plugin.settings.isConfigured = true;
Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL_NOTICE)
await this.plugin.saveSettings();
updateE2EControls();
applyDisplayEnabled();
// @ts-ignore
this.plugin.app.setting.close();
this.closeSetting();
await delay(2000);
await performRebuildDB(this.plugin, method);
}
let rebuildRemote = false;
new Setting(containerRemoteDatabaseEl)
.setName("")
.setClass("wizardOnly")
.addButton((button) =>
button
.setButtonText("Next")
.setClass("mod-cta")
.setCta()
.setDisabled(false)
.onClick(() => {
if (!this.plugin.settings.encrypt) {
@@ -759,33 +775,13 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
this.plugin.settings.customChunkSize = 0;
} else {
this.plugin.settings.customChunkSize = 100;
this.plugin.settings.customChunkSize = 50;
}
rebuildRemote = false;
changeDisplay("30")
})
);
new Setting(containerRemoteDatabaseEl)
.setName("")
.setClass("wizardOnly")
.addButton((button) =>
button
.setButtonText("Discard existing database and proceed")
.setDisabled(false)
.setWarning()
.onClick(() => {
if (!this.plugin.settings.encrypt) {
this.plugin.settings.passphrase = "";
}
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
this.plugin.settings.customChunkSize = 0;
} else {
this.plugin.settings.customChunkSize = 100;
}
rebuildRemote = true;
changeDisplay("30")
})
);
)
;
addScreenElement("0", containerRemoteDatabaseEl);
const containerGeneralSettingsEl = containerEl.createDiv();
@@ -1049,25 +1045,20 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
...presetAllDisabled
}
}
this.plugin.saveSettings();
await this.plugin.saveSettings();
this.display();
await this.plugin.realizeSettingSyncMode();
if (inWizard) {
// @ts-ignore
this.plugin.app.setting.close()
await this.plugin.resetLocalDatabase();
await this.plugin.initializeDatabase(true);
if (rebuildRemote) {
await this.plugin.markRemoteLocked();
await this.plugin.tryResetRemoteDatabase();
await this.plugin.markRemoteLocked();
await this.plugin.markRemoteResolved();
this.closeSetting();
if (!this.plugin.settings.isConfigured) {
this.plugin.settings.isConfigured = true;
await this.plugin.saveSettings();
await rebuildDB("localOnly");
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();
} else {
this.askReload();
}
await this.plugin.replicate(true);
Logger("All done! Please set up subsequent devices with 'Copy setup URI' and 'Open setup URI'.", LOG_LEVEL_NOTICE);
// @ts-ignore
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri")
}
})
);
@@ -1286,24 +1277,21 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
.addButton((button) => {
button.setButtonText("Merge")
.onClick(async () => {
// @ts-ignore
this.plugin.app.setting.close()
this.closeSetting()
await this.plugin.addOnSetup.configureHiddenFileSync("MERGE");
})
})
.addButton((button) => {
button.setButtonText("Fetch")
.onClick(async () => {
// @ts-ignore
this.plugin.app.setting.close()
this.closeSetting()
await this.plugin.addOnSetup.configureHiddenFileSync("FETCH");
})
})
.addButton((button) => {
button.setButtonText("Overwrite")
.onClick(async () => {
// @ts-ignore
this.plugin.app.setting.close()
this.closeSetting()
await this.plugin.addOnSetup.configureHiddenFileSync("OVERWRITE");
})
});
@@ -1694,6 +1682,18 @@ ${stringifyYaml(pluginConfig)}`;
c.addClass("op-warn");
}
}
new Setting(containerHatchEl)
.setName("Back to non-configured")
.addButton((button) =>
button
.setButtonText("Back")
.setDisabled(false)
.onClick(async () => {
this.plugin.settings.isConfigured = false;
await this.plugin.saveSettings();
this.askReload();
}));
const hatchWarn = containerHatchEl.createEl("div", { text: `To stop the boot up sequence for fixing problems on databases, you can put redflag.md on top of your vault (Rebooting obsidian is required).` });
hatchWarn.addClass("op-warn-info");
@@ -1844,12 +1844,7 @@ ${stringifyYaml(pluginConfig)}`;
toggle.setValue(this.plugin.settings.suspendFileWatching).onChange(async (value) => {
this.plugin.settings.suspendFileWatching = value;
await this.plugin.saveSettings();
scheduleTask("configReload", 250, async () => {
if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") {
// @ts-ignore
this.app.commands.executeCommandById("app:reload")
}
})
this.askReload();
})
);
new Setting(containerHatchEl)
@@ -1859,12 +1854,7 @@ ${stringifyYaml(pluginConfig)}`;
toggle.setValue(this.plugin.settings.suspendParseReplicationResult).onChange(async (value) => {
this.plugin.settings.suspendParseReplicationResult = value;
await this.plugin.saveSettings();
scheduleTask("configReload", 250, async () => {
if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") {
// @ts-ignore
this.app.commands.executeCommandById("app:reload")
}
})
this.askReload();
})
);
new Setting(containerHatchEl)
@@ -1949,7 +1939,7 @@ ${stringifyYaml(pluginConfig)}`;
let newDatabaseName = this.plugin.settings.additionalSuffixOfDatabaseName + "";
new Setting(containerHatchEl)
.setName("Database suffix")
.setDesc("LiveSync could not treat multiple vaults which have same name, please add some suffix from here.")
.setDesc("LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.")
.addText((text) => {
text.setPlaceholder("")
.setValue(newDatabaseName)
@@ -2163,8 +2153,7 @@ ${stringifyYaml(pluginConfig)}`;
.setDisabled(false)
.setWarning()
.onClick(async () => {
// @ts-ignore
this.plugin.app.setting.close()
this.closeSetting()
await this.plugin.dbGC();
})
);
@@ -2186,7 +2175,7 @@ ${stringifyYaml(pluginConfig)}`;
applyDisplayEnabled();
if (this.selectedScreen == "") {
if (lastVersion != this.plugin.settings.lastReadUpdates) {
if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) {
if (this.plugin.settings.isConfigured) {
changeDisplay("100");
} else {
changeDisplay("110")

View File

@@ -91,6 +91,8 @@ export class StorageEventManagerObsidian extends StorageEventManager {
}
// Cache file and waiting to can be proceed.
async appendWatchEvent(params: { type: FileEventType, file: TAbstractFile | InternalFileInfo, oldPath?: string }[], ctx?: any) {
if (!this.plugin.settings.isConfigured) return;
if (this.plugin.settings.suspendFileWatching) return;
for (const param of params) {
if (shouldBeIgnored(param.file.path)) {
continue;
@@ -106,7 +108,6 @@ export class StorageEventManagerObsidian extends StorageEventManager {
}
if (file instanceof TFolder) continue;
if (!await this.plugin.isTargetFile(file.path)) continue;
if (this.plugin.settings.suspendFileWatching) continue;
let cache: null | string | ArrayBuffer;
// new file or something changed, cache the changes.

Submodule src/lib updated: 71d28f285d...46256dba3a

View File

@@ -76,7 +76,13 @@ export default class ObsidianLiveSyncPlugin extends Plugin
replicator!: LiveSyncDBReplicator;
statusBar?: HTMLElement;
suspended = false;
_suspended = false;
get suspended() {
return this._suspended || !this.settings?.isConfigured;
}
set suspended(value: boolean) {
this._suspended = value;
}
deviceAndVaultName = "";
isMobile = false;
isReady = false;
@@ -403,7 +409,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin
if (notes.length == 0) {
Logger("There are no old documents");
Logger(`Checking expired file history done`);
return;
}
for (const v of notes) {
@@ -420,6 +425,43 @@ export default class ObsidianLiveSyncPlugin extends Plugin
Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL_NOTICE);
return;
}
if (!this.settings.isConfigured) {
const message = `Hello and welcome to Self-hosted LiveSync.
Your device seems to **not be configured yet**. Please finish the setup and synchronise your vaults!
Click anywhere to stop counting down.
## At the first device
- With Setup URI -> Use \`Use the copied setup URI\`.
If you have configured it automatically, you should have one.
- Without Setup URI -> Use \`Setup wizard\` in setting dialogue. **\`Minimal setup\` is recommended**.
- What is the Setup URI? -> Do not worry! We have [some docs](https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use) now. Please refer to them once.
## At the subsequent device
- With Setup URI -> Use \`Use the copied setup URI\`.
If you do not have it yet, you can copy it on the first device.
- Without Setup URI -> Use \`Setup wizard\` in setting dialogue, but **strongly recommends using setup URI**.
`
const OPEN_SETUP = "Open setting dialog";
const USE_SETUP = "Use the copied setup URI";
const DISMISS = "Dismiss";
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");
} catch (ex) {
Logger("Something went wrong on opening setting dialog, please open it manually", LOG_LEVEL_NOTICE);
}
} else if (ret == USE_SETUP) {
fireAndForget(this.addOnSetup.command_openSetupURI());
}
return;
}
try {
if (this.isRedFlagRaised() || this.isRedFlag2Raised() || this.isRedFlag3Raised()) {
@@ -736,7 +778,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
this.statusBar = this.addStatusBarItem();
this.statusBar.addClass("syncstatusbar");
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
if (lastVersion > this.settings.lastReadUpdates) {
if (lastVersion > this.settings.lastReadUpdates && this.settings.isConfigured) {
Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL_NOTICE);
}
@@ -877,6 +919,16 @@ Note: We can always able to read V1 format. It will be progressively converted.
async loadSettings() {
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ObsidianLiveSyncSettings;
if (typeof settings.isConfigured == "undefined") {
// If migrated, mark true
if (JSON.stringify(settings) !== JSON.stringify(DEFAULT_SETTINGS)) {
settings.isConfigured = true;
} else {
settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}`
settings.isConfigured = false;
}
}
const passphrase = await this.getPassphrase(settings);
if (passphrase === false) {
Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT);
@@ -1193,8 +1245,8 @@ We can perform a command in this file.
async watchWindowVisibilityAsync() {
if (this.settings.suspendFileWatching) return;
if (!this.settings.isConfigured) return;
if (!this.isReady) return;
// if (this.suspended) return;
const isHidden = document.hidden;
await this.applyBatchChange();
if (isHidden) {
@@ -1307,6 +1359,7 @@ We can perform a command in this file.
watchWorkspaceOpen(file: TFile | null) {
if (this.settings.suspendFileWatching) return;
if (!this.settings.isConfigured) return;
if (!this.isReady) return;
if (!file) return;
scheduleTask("watch-workspace-open", 500, () => fireAndForget(() => this.watchWorkspaceOpenAsync(file)));
@@ -1314,6 +1367,7 @@ We can perform a command in this file.
async watchWorkspaceOpenAsync(file: TFile) {
if (this.settings.suspendFileWatching) return;
if (!this.settings.isConfigured) return;
if (!this.isReady) return;
await this.applyBatchChange();
if (file == null) {
@@ -1579,17 +1633,18 @@ We can perform a command in this file.
localStorage.setItem(lsKey, saveData);
}
async loadQueuedFiles() {
if (!this.settings.suspendParseReplicationResult) {
const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName();
const ids = [...new Set(JSON.parse(localStorage.getItem(lsKey) || "[]"))] as string[];
const batchSize = 100;
const chunkedIds = arrayToChunkedArray(ids, batchSize);
for await (const idsBatch of chunkedIds) {
const ret = await this.localDatabase.allDocsRaw<EntryDoc>({ keys: idsBatch, include_docs: true, limit: 100 });
this.replicationResultProcessor.enqueueAll(ret.rows.map(doc => doc.doc));
await this.replicationResultProcessor.waitForPipeline();
}
if (this.settings.suspendParseReplicationResult) return;
if (!this.settings.isConfigured) return;
const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName();
const ids = [...new Set(JSON.parse(localStorage.getItem(lsKey) || "[]"))] as string[];
const batchSize = 100;
const chunkedIds = arrayToChunkedArray(ids, batchSize);
for await (const idsBatch of chunkedIds) {
const ret = await this.localDatabase.allDocsRaw<EntryDoc>({ keys: idsBatch, include_docs: true, limit: 100 });
this.replicationResultProcessor.enqueueAll(ret.rows.map(doc => doc.doc));
await this.replicationResultProcessor.waitForPipeline();
}
}
databaseQueueCount = reactiveSource(0);
@@ -1953,6 +2008,12 @@ Or if you are sure know what had been happened, we can unlock the database from
async syncAllFiles(showingNotice?: boolean) {
// synchronize all files between database and storage.
if (!this.settings.isConfigured) {
if (showingNotice) {
Logger("LiveSync is not configured yet. Synchronising between the storage and the local database is now prevented.", LOG_LEVEL_NOTICE, "syncAll");
}
return;
}
let initialScan = false;
if (showingNotice) {
Logger("Initializing", LOG_LEVEL_NOTICE, "syncAll");