From be3d61c1c74a30408eaa93d333bfae66361a1911 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Fri, 17 Feb 2023 17:35:06 +0900 Subject: [PATCH] - New feature: - If any conflicted files have been left, they will be reported. - Fixed: - Now the name of the conflicting file is shown on the conflict-resolving dialogue. - Hidden files are now able to be merged again. - No longer error caused at plug-in being loaded. - Improved: - Caching chunks are now limited in total size of cached chunks. --- src/ConflictResolveModal.ts | 2 +- src/ObsidianLiveSyncSettingTab.ts | 32 +++++++++++++ src/lib | 2 +- src/main.ts | 78 ++++++++++++++----------------- 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/src/ConflictResolveModal.ts b/src/ConflictResolveModal.ts index f999ef4..4742808 100644 --- a/src/ConflictResolveModal.ts +++ b/src/ConflictResolveModal.ts @@ -22,7 +22,7 @@ export class ConflictResolveModal extends Modal { contentEl.empty(); contentEl.createEl("h2", { text: "This document has conflicted changes." }); - contentEl.createEl("span", this.filename); + contentEl.createEl("span", { text: this.filename }); const div = contentEl.createDiv(""); div.addClass("op-scrollable"); let diff = ""; diff --git a/src/ObsidianLiveSyncSettingTab.ts b/src/ObsidianLiveSyncSettingTab.ts index 6d46c50..20d1794 100644 --- a/src/ObsidianLiveSyncSettingTab.ts +++ b/src/ObsidianLiveSyncSettingTab.ts @@ -1292,6 +1292,38 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { return toggle; } ); + new Setting(containerSyncSettingEl) + .setName("A number of hashes to be cached") + .setDesc("") + .addText((text) => { + text.setPlaceholder("") + .setValue(this.plugin.settings.hashCacheMaxCount + "") + .onChange(async (value) => { + let v = Number(value); + if (isNaN(v) || v < 10) { + v = 10; + } + this.plugin.settings.hashCacheMaxCount = v; + await this.plugin.saveSettings(); + }); + text.inputEl.setAttribute("type", "number"); + }); + new Setting(containerSyncSettingEl) + .setName("The total length of hashes to be cached") + .setDesc("(Mega chars)") + .addText((text) => { + text.setPlaceholder("") + .setValue(this.plugin.settings.hashCacheMaxAmount + "") + .onChange(async (value) => { + let v = Number(value); + if (isNaN(v) || v < 1) { + v = 1; + } + this.plugin.settings.hashCacheMaxAmount = v; + await this.plugin.saveSettings(); + }); + text.inputEl.setAttribute("type", "number"); + }); addScreenElement("30", containerSyncSettingEl); const containerMiscellaneousEl = containerEl.createDiv(); diff --git a/src/lib b/src/lib index 6c8d0b0..e4d825a 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 6c8d0b0c321d3945f57a3f70d9b6f39a8e2fbb3e +Subproject commit e4d825ae13e4a591be0598cf9661ee0651f0a58c diff --git a/src/main.ts b/src/main.ts index 4441613..4f9e796 100644 --- a/src/main.ts +++ b/src/main.ts @@ -138,6 +138,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin { deviceAndVaultName: string; isMobile = false; isReady = false; + packageVersion = ""; + manifestVersion = ""; watchedFileEventQueue = [] as FileEventItem[]; @@ -194,26 +196,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin { } async fileHistory() { - const pageLimit = 1000; - let nextKey = ""; const notes: { path: string, mtime: number }[] = []; - do { - const docs = await this.localDatabase.localDatabase.allDocs({ limit: pageLimit, startkey: nextKey, include_docs: true }); - nextKey = ""; - for (const row of docs.rows) { - const doc = row.doc; - nextKey = `${row.id}\u{10ffff}`; - if (!("type" in doc)) continue; - if (doc.type == "newnote" || doc.type == "plain") { - notes.push({ path: id2path(doc._id), mtime: doc.mtime }); - } - if (isChunk(nextKey)) { - // skip the chunk zone. - nextKey = CHeaderEnd; - } - } - } while (nextKey != ""); - + for await (const doc of this.localDatabase.findAllDocs()) { + notes.push({ path: id2path(doc._id), mtime: doc.mtime }); + } notes.sort((a, b) => b.mtime - a.mtime); const notesList = notes.map(e => e.path); const target = await askSelectString(this.app, "File to view History", notesList); @@ -222,31 +208,11 @@ export default class ObsidianLiveSyncPlugin extends Plugin { } } async pickFileForResolve() { - const pageLimit = 1000; - let nextKey = ""; const notes: { path: string, mtime: number }[] = []; - do { - const docs = await this.localDatabase.localDatabase.allDocs({ limit: pageLimit, startkey: nextKey, conflicts: true, include_docs: true }); - nextKey = ""; - for (const row of docs.rows) { - const doc = row.doc; - nextKey = `${row.id}\u{10ffff}`; - if (isChunk(nextKey)) { - // skip the chunk zone. - nextKey = CHeaderEnd; - } - if (!("_conflicts" in doc)) continue; - if (isInternalMetadata(row.id)) continue; - // We have to check also deleted files. - // if (doc._deleted) continue; - // if ("deleted" in doc && doc.deleted) continue; - if (doc.type == "newnote" || doc.type == "plain") { - // const docId = doc._id.startsWith("i:") ? doc._id.substring("i:".length) : doc._id; - notes.push({ path: id2path(doc._id), mtime: doc.mtime }); - } - - } - } while (nextKey != ""); + for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { + if (!("_conflicts" in doc)) continue; + notes.push({ path: id2path(doc._id), mtime: doc.mtime }); + } notes.sort((a, b) => b.mtime - a.mtime); const notesList = notes.map(e => e.path); if (notesList.length == 0) { @@ -257,6 +223,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin { if (target) { if (isInternalMetadata(target)) { //NOP + await this.resolveConflictOnInternalFile(target); } else { await this.showIfConflicted(target); } @@ -371,12 +338,33 @@ export default class ObsidianLiveSyncPlugin extends Plugin { if (this.settings.syncOnStart) { this.localDatabase.openReplication(this.settings, false, false, this.parseReplicationResult); } + this.scanStat(); } catch (ex) { Logger("Error while loading Self-hosted LiveSync", LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.VERBOSE); } } + /** + * Scan status + */ + async scanStat() { + const notes: { path: string, mtime: number }[] = []; + Logger(`Additional safety scan..`, LOG_LEVEL.VERBOSE); + for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { + if (!("_conflicts" in doc)) continue; + notes.push({ path: id2path(doc._id), mtime: doc.mtime }); + } + if (notes.length > 0) { + Logger(`Some files have been left conflicted! Please resolve them by "Pick a file to resolve conflict". The list is written in the log.`, LOG_LEVEL.NOTICE); + for (const note of notes) { + Logger(`Conflicted: ${note.path}`); + } + } else { + Logger(`There are no conflicted files`, LOG_LEVEL.VERBOSE); + } + Logger(`Additional safety scan done`, LOG_LEVEL.VERBOSE); + } async command_copySetupURI() { const encryptingPassphrase = await askString(this.app, "Encrypt your settings", "The passphrase to encrypt the setup URI", ""); if (encryptingPassphrase === false) return; @@ -536,6 +524,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin { //@ts-ignore const packageVersion: string = PACKAGE_VERSION || "0.0.0"; + this.manifestVersion = manifestVersion; + this.packageVersion = packageVersion; Logger(`Self-hosted LiveSync v${manifestVersion} ${packageVersion} `); const lsKey = "obsidian-live-sync-ver" + this.getVaultName(); @@ -1315,7 +1305,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin { const newMessage = timestamp + "->" + messageContent; console.log(vaultName + ":" + newMessage); - if (this.settings.writeLogToTheFile) { + if (this.settings?.writeLogToTheFile) { const time = now.toISOString().split("T")[0]; const logDate = `${PREFIXMD_LOGFILE}${time}.md`; const file = this.app.vault.getAbstractFileByPath(normalizePath(logDate));