mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2025-12-23 22:51:30 +00:00
New feature:
- Now we can check configuration mismatching between clients before synchronisation. - Now we can perform remote database compaction from the `Maintenance` pane. Fixed: - We can detect the bucket could not be reachable.
This commit is contained in:
2
src/lib
2
src/lib
Submodule src/lib updated: 1417452fec...3c0ff967e9
60
src/main.ts
60
src/main.ts
@@ -2,9 +2,9 @@ const isDebug = false;
|
|||||||
|
|
||||||
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch, stringifyYaml, parseYaml } from "./deps";
|
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch, stringifyYaml, parseYaml } from "./deps";
|
||||||
import { Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, type RequestUrlParam, type RequestUrlResponse, requestUrl, type MarkdownFileInfo } from "./deps";
|
import { Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, type RequestUrlParam, type RequestUrlResponse, requestUrl, type MarkdownFileInfo } from "./deps";
|
||||||
import { type EntryDoc, type LoadedEntry, type ObsidianLiveSyncSettings, type diff_check_result, type diff_result_leaf, type EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, type diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, type ConfigPassphraseStore, type CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, type DatabaseConnectingStatus, type EntryHasPath, type DocumentID, type FilePathWithPrefix, type FilePath, type AnyEntry, LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_URGENT, LOG_LEVEL_VERBOSE, type SavingEntry, MISSING_OR_ERROR, NOT_CONFLICTED, AUTO_MERGED, CANCELLED, LEAVE_TO_SUBSEQUENT, FLAGMD_REDFLAG2_HR, FLAGMD_REDFLAG3_HR, REMOTE_MINIO, REMOTE_COUCHDB, type BucketSyncSetting, } from "./lib/src/common/types.ts";
|
import { type EntryDoc, type LoadedEntry, type ObsidianLiveSyncSettings, type diff_check_result, type diff_result_leaf, type EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, type diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, type ConfigPassphraseStore, type CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, type DatabaseConnectingStatus, type EntryHasPath, type DocumentID, type FilePathWithPrefix, type FilePath, type AnyEntry, LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_URGENT, LOG_LEVEL_VERBOSE, type SavingEntry, MISSING_OR_ERROR, NOT_CONFLICTED, AUTO_MERGED, CANCELLED, LEAVE_TO_SUBSEQUENT, FLAGMD_REDFLAG2_HR, FLAGMD_REDFLAG3_HR, REMOTE_MINIO, REMOTE_COUCHDB, type BucketSyncSetting, TweakValuesShouldMatchedTemplate, confName, type TweakValues, } from "./lib/src/common/types.ts";
|
||||||
import { type InternalFileInfo, type CacheData, type FileEventItem, FileWatchEventQueueMax } from "./common/types.ts";
|
import { type InternalFileInfo, type CacheData, type FileEventItem, FileWatchEventQueueMax } from "./common/types.ts";
|
||||||
import { arrayToChunkedArray, createBlob, delay, determineTypeFromBlob, fireAndForget, getDocData, isAnyNote, isDocContentSame, isObjectDifferent, readContent, sendValue, throttle, type SimpleStore } from "./lib/src/common/utils.ts";
|
import { arrayToChunkedArray, createBlob, delay, determineTypeFromBlob, escapeMarkdownValue, extractObject, fireAndForget, getDocData, isAnyNote, isDocContentSame, isObjectDifferent, readContent, sendValue, throttle, type SimpleStore } from "./lib/src/common/utils.ts";
|
||||||
import { Logger, setGlobalLogFunction } from "./lib/src/common/logger.ts";
|
import { Logger, setGlobalLogFunction } from "./lib/src/common/logger.ts";
|
||||||
import { PouchDB } from "./lib/src/pouchdb/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb/pouchdb-browser.js";
|
||||||
import { ConflictResolveModal } from "./ui/ConflictResolveModal.ts";
|
import { ConflictResolveModal } from "./ui/ConflictResolveModal.ts";
|
||||||
@@ -2052,6 +2052,61 @@ We can perform a command in this file.
|
|||||||
await this.loadQueuedFiles();
|
await this.loadQueuedFiles();
|
||||||
const ret = await this.replicator.openReplication(this.settings, false, showMessage, false);
|
const ret = await this.replicator.openReplication(this.settings, false, showMessage, false);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
if (this.replicator.tweakSettingsMismatched) {
|
||||||
|
const remoteSettings = this.replicator.mismatchedTweakValues;
|
||||||
|
const mustSettings = remoteSettings.map(e => extractObject(TweakValuesShouldMatchedTemplate, e));
|
||||||
|
const items = Object.entries(TweakValuesShouldMatchedTemplate);
|
||||||
|
// Making tables:
|
||||||
|
let table = `| Value name | Ours | ${mustSettings.map((_, i) => `Remote ${i + 1} |`).join("")}\n` +
|
||||||
|
`|: --- |: --- :${`|: --- :`.repeat(mustSettings.length)}|\n`
|
||||||
|
for (const v of items) {
|
||||||
|
const key = v[0] as keyof typeof TweakValuesShouldMatchedTemplate;
|
||||||
|
const value = mustSettings.map(e => e[key]);
|
||||||
|
table += `| ${confName(key)} | ${escapeMarkdownValue(this.settings[key])} | ${value.map((v) => `${escapeMarkdownValue(v)} |`).join("")}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = `
|
||||||
|
Configuration mismatching between the clients has been detected.
|
||||||
|
This can be harmful or extra capacity consumption. We have to make these value unified.
|
||||||
|
|
||||||
|
Configured values:
|
||||||
|
|
||||||
|
${table}
|
||||||
|
|
||||||
|
Please select a unification method.
|
||||||
|
|
||||||
|
However, even if we answer that you will \`Use mine\`, we will be prompted to accept it again on the other device and have to decide accept or not.`;
|
||||||
|
|
||||||
|
//TODO: apply this settings.
|
||||||
|
const CHOICE_USE_REMOTE = "Use Remote ";
|
||||||
|
const CHOICE_USR_MINE = "Use ours";
|
||||||
|
const CHOICE_DISMISS = "Dismiss";
|
||||||
|
// const ourConfig = extractObject(TweakValuesShouldMatchedTemplate, this.settings);
|
||||||
|
const CHOICE_AND_VALUES = [
|
||||||
|
...mustSettings.map((e, i) => [`${CHOICE_USE_REMOTE} ${i + 1}`, e]),
|
||||||
|
[CHOICE_USR_MINE, true],
|
||||||
|
[CHOICE_DISMISS, false]
|
||||||
|
]
|
||||||
|
const CHOICES = Object.fromEntries(CHOICE_AND_VALUES) as Record<string, TweakValues | boolean>;
|
||||||
|
const retKey = await confirmWithMessage(this, "Locked", message, Object.keys(CHOICES), CHOICE_DISMISS, 60);
|
||||||
|
if (!retKey) return;
|
||||||
|
const conf = CHOICES[retKey];
|
||||||
|
if (!conf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (conf === true) {
|
||||||
|
await this.replicator.resetRemoteTweakSettings(this.settings);
|
||||||
|
Logger(`Tweak values on the remote server have been cleared, and will be overwritten in next synchronisation.`, LOG_LEVEL_NOTICE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (conf) {
|
||||||
|
this.settings = { ...this.settings, ...conf };
|
||||||
|
await this.saveSettingData();
|
||||||
|
Logger(`Tweak Values have been overwritten by the chosen one.`, LOG_LEVEL_NOTICE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
if (this.replicator.remoteLockedAndDeviceNotAccepted) {
|
if (this.replicator.remoteLockedAndDeviceNotAccepted) {
|
||||||
if (this.replicator.remoteCleaned && this.settings.useIndexedDBAdapter) {
|
if (this.replicator.remoteCleaned && this.settings.useIndexedDBAdapter) {
|
||||||
Logger(`The remote database has been cleaned.`, showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
Logger(`The remote database has been cleaned.`, showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
||||||
@@ -2108,6 +2163,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ import {
|
|||||||
REMOTE_MINIO,
|
REMOTE_MINIO,
|
||||||
type BucketSyncSetting,
|
type BucketSyncSetting,
|
||||||
type RemoteType,
|
type RemoteType,
|
||||||
PREFERRED_JOURNAL_SYNC
|
PREFERRED_JOURNAL_SYNC,
|
||||||
|
confName
|
||||||
} from "../lib/src/common/types.ts";
|
} from "../lib/src/common/types.ts";
|
||||||
import { createBlob, delay, extractObject, isDocContentSame, readAsBlob } from "../lib/src/common/utils.ts";
|
import { createBlob, delay, extractObject, isDocContentSame, readAsBlob } from "../lib/src/common/utils.ts";
|
||||||
import { versionNumberString2Number } from "../lib/src/string_and_binary/strbin.ts";
|
import { versionNumberString2Number } from "../lib/src/string_and_binary/strbin.ts";
|
||||||
@@ -698,7 +699,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
|
|||||||
|
|
||||||
containerRemoteDatabaseEl.createEl("h4", { text: "Effective Storage Using" }).addClass("wizardHidden")
|
containerRemoteDatabaseEl.createEl("h4", { text: "Effective Storage Using" }).addClass("wizardHidden")
|
||||||
new Setting(containerRemoteDatabaseEl)
|
new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("Incubate Chunks in Document")
|
.setName(confName("useEden"))
|
||||||
.setDesc("If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.")
|
.setDesc("If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.")
|
||||||
.addToggle((toggle) =>
|
.addToggle((toggle) =>
|
||||||
toggle.setValue(this.plugin.settings.useEden).onChange(async (value) => {
|
toggle.setValue(this.plugin.settings.useEden).onChange(async (value) => {
|
||||||
@@ -762,7 +763,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
|
|||||||
.setClass("wizardHidden");
|
.setClass("wizardHidden");
|
||||||
}
|
}
|
||||||
new Setting(containerRemoteDatabaseEl)
|
new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("Data Compression (Experimental)")
|
.setName(confName("enableCompression"))
|
||||||
.setDesc("Compresses data during transfer, saving space in the remote database. Note: Please ensure that all devices have v0.22.18 and connected tools are also supported compression.")
|
.setDesc("Compresses data during transfer, saving space in the remote database. Note: Please ensure that all devices have v0.22.18 and connected tools are also supported compression.")
|
||||||
.addToggle((toggle) =>
|
.addToggle((toggle) =>
|
||||||
toggle.setValue(this.plugin.settings.enableCompression).onChange(async (value) => {
|
toggle.setValue(this.plugin.settings.enableCompression).onChange(async (value) => {
|
||||||
@@ -778,7 +779,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
|
|||||||
containerRemoteDatabaseEl.createEl("h4", { text: "Confidentiality" });
|
containerRemoteDatabaseEl.createEl("h4", { text: "Confidentiality" });
|
||||||
|
|
||||||
const e2e = new Setting(containerRemoteDatabaseEl)
|
const e2e = new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("End-to-End Encryption")
|
.setName(confName("encrypt"))
|
||||||
.setDesc("Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommend.")
|
.setDesc("Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommend.")
|
||||||
.addToggle((toggle) =>
|
.addToggle((toggle) =>
|
||||||
toggle.setValue(encrypt).onChange(async (value) => {
|
toggle.setValue(encrypt).onChange(async (value) => {
|
||||||
@@ -846,7 +847,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
|
|||||||
});
|
});
|
||||||
|
|
||||||
const usePathObfuscationEl = new Setting(containerRemoteDatabaseEl)
|
const usePathObfuscationEl = new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("Path Obfuscation")
|
.setName(confName("usePathObfuscation"))
|
||||||
.setDesc("Obfuscate paths of files. If we configured, we should rebuild the database.")
|
.setDesc("Obfuscate paths of files. If we configured, we should rebuild the database.")
|
||||||
.addToggle((toggle) =>
|
.addToggle((toggle) =>
|
||||||
toggle.setValue(usePathObfuscation).onChange(async (value) => {
|
toggle.setValue(usePathObfuscation).onChange(async (value) => {
|
||||||
@@ -863,7 +864,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
|
|||||||
);
|
);
|
||||||
|
|
||||||
const dynamicIteration = new Setting(containerRemoteDatabaseEl)
|
const dynamicIteration = new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("Use dynamic iteration count (experimental)")
|
.setName(confName("useDynamicIterationCount"))
|
||||||
.setDesc("Balancing the encryption/decryption load against the length of the passphrase if toggled.")
|
.setDesc("Balancing the encryption/decryption load against the length of the passphrase if toggled.")
|
||||||
.addToggle((toggle) => {
|
.addToggle((toggle) => {
|
||||||
toggle.setValue(useDynamicIterationCount)
|
toggle.setValue(useDynamicIterationCount)
|
||||||
@@ -1650,7 +1651,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
|
|||||||
);
|
);
|
||||||
|
|
||||||
new Setting(containerSyncSettingEl)
|
new Setting(containerSyncSettingEl)
|
||||||
.setName("Enhance chunk size")
|
.setName(confName("customChunkSize"))
|
||||||
.setDesc("Enhance chunk size for binary files (Ratio). This cannot be increased when using IBM Cloudant.")
|
.setDesc("Enhance chunk size for binary files (Ratio). This cannot be increased when using IBM Cloudant.")
|
||||||
.setClass("wizardHidden")
|
.setClass("wizardHidden")
|
||||||
.addText((text) => {
|
.addText((text) => {
|
||||||
@@ -2284,7 +2285,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
})
|
})
|
||||||
|
|
||||||
new Setting(containerHatchEl)
|
new Setting(containerHatchEl)
|
||||||
.setName("The Hash algorithm for chunk IDs")
|
.setName(confName("hashAlg"))
|
||||||
.setDesc("xxhash64 is the current default.")
|
.setDesc("xxhash64 is the current default.")
|
||||||
.setClass("wizardHidden")
|
.setClass("wizardHidden")
|
||||||
.addDropdown((dropdown) =>
|
.addDropdown((dropdown) =>
|
||||||
@@ -2313,6 +2314,15 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
new Setting(containerHatchEl)
|
||||||
|
.setName("Do not check configuration mismatch before replication")
|
||||||
|
.setDesc("")
|
||||||
|
.addToggle((toggle) =>
|
||||||
|
toggle.setValue(this.plugin.settings.disableCheckingConfigMismatch).onChange(async (value) => {
|
||||||
|
this.plugin.settings.disableCheckingConfigMismatch = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
})
|
||||||
|
);
|
||||||
addScreenElement("50", containerHatchEl);
|
addScreenElement("50", containerHatchEl);
|
||||||
|
|
||||||
|
|
||||||
@@ -2409,6 +2419,26 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
|
|
||||||
containerMaintenanceEl.createEl("h4", { text: "Remote" });
|
containerMaintenanceEl.createEl("h4", { text: "Remote" });
|
||||||
|
|
||||||
|
if (this.plugin.settings.remoteType == REMOTE_COUCHDB) {
|
||||||
|
new Setting(containerMaintenanceEl)
|
||||||
|
.setName("Perform compaction")
|
||||||
|
.setDesc("Compaction discards all of Eden in the non-latest revisions, reducing the storage usage. However, this operation requires the same free space on the remote as the current database.")
|
||||||
|
.addButton((button) =>
|
||||||
|
button
|
||||||
|
.setButtonText("Perform")
|
||||||
|
.setDisabled(false)
|
||||||
|
.onClick(async () => {
|
||||||
|
const replicator = this.plugin.replicator as LiveSyncCouchDBReplicator;
|
||||||
|
Logger(`Compaction has been began`, LOG_LEVEL_NOTICE, "compaction")
|
||||||
|
if (await replicator.compactRemote(this.plugin.settings)) {
|
||||||
|
Logger(`Compaction has been completed!`, LOG_LEVEL_NOTICE, "compaction");
|
||||||
|
} else {
|
||||||
|
Logger(`Compaction has been failed!`, LOG_LEVEL_NOTICE, "compaction");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
new Setting(containerMaintenanceEl)
|
new Setting(containerMaintenanceEl)
|
||||||
.setName("Lock remote")
|
.setName("Lock remote")
|
||||||
.setDesc("Lock remote to prevent synchronization with other devices.")
|
.setDesc("Lock remote to prevent synchronization with other devices.")
|
||||||
@@ -2435,6 +2465,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if (this.plugin.settings.remoteType != REMOTE_COUCHDB) {
|
if (this.plugin.settings.remoteType != REMOTE_COUCHDB) {
|
||||||
new Setting(containerMaintenanceEl)
|
new Setting(containerMaintenanceEl)
|
||||||
.setName("Reset journal received history")
|
.setName("Reset journal received history")
|
||||||
|
|||||||
Reference in New Issue
Block a user