From d4b53280e30e81ceebd16209a57a2820a014e282 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Wed, 15 Jun 2022 17:45:37 +0900 Subject: [PATCH] Fixed status message and lag on boot time scan. --- manifest.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/KeyValueDB.ts | 50 +++++++++++++++++++++++++++++++++++++++++ src/LocalPouchDB.ts | 6 +++++ src/main.ts | 55 ++++++++++++++++++++++++++++++--------------- 6 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 src/KeyValueDB.ts diff --git a/manifest.json b/manifest.json index 5c0b1a5..d3ddd50 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-livesync", "name": "Self-hosted LiveSync", - "version": "0.11.3", + "version": "0.11.4", "minAppVersion": "0.9.12", "description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", "author": "vorotamoroz", diff --git a/package-lock.json b/package-lock.json index b6d575a..bbcd7d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-livesync", - "version": "0.11.3", + "version": "0.11.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-livesync", - "version": "0.11.3", + "version": "0.11.4", "license": "MIT", "dependencies": { "diff-match-patch": "^1.0.5", diff --git a/package.json b/package.json index 49806a1..6af8d08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-livesync", - "version": "0.11.3", + "version": "0.11.4", "description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", "main": "main.js", "type": "module", diff --git a/src/KeyValueDB.ts b/src/KeyValueDB.ts new file mode 100644 index 0000000..ffd7067 --- /dev/null +++ b/src/KeyValueDB.ts @@ -0,0 +1,50 @@ +import { deleteDB, IDBPDatabase, openDB } from "idb"; +export interface KeyValueDatabase { + get(key: string): Promise; + set(key: string, value: T): Promise; + del(key: string): Promise; + clear(): Promise; + keys(query?: IDBValidKey | IDBKeyRange, count?: number): Promise; + close(): void; + destroy(): void; +} +const databaseCache: { [key: string]: IDBPDatabase } = {}; +export const OpenKeyValueDatabase = (dbKey: string): KeyValueDatabase => { + if (dbKey in databaseCache) { + databaseCache[dbKey].close(); + delete databaseCache[dbKey]; + } + const storeKey = dbKey; + const dbPromise = openDB(dbKey, 1, { + upgrade(db) { + db.createObjectStore(storeKey); + }, + }); + ~(async () => (databaseCache[dbKey] = await dbPromise))(); + return { + async get(key: string): Promise { + return (await dbPromise).get(storeKey, key); + }, + async set(key: string, value: T) { + return (await dbPromise).put(storeKey, value, key); + }, + async del(key: string) { + return (await dbPromise).delete(storeKey, key); + }, + async clear() { + return (await dbPromise).clear(storeKey); + }, + async keys(query?: IDBValidKey | IDBKeyRange, count?: number) { + return (await dbPromise).getAllKeys(storeKey, query, count); + }, + async close() { + delete databaseCache[dbKey]; + return (await dbPromise).close(); + }, + async destroy() { + delete databaseCache[dbKey]; + (await dbPromise).close(); + await deleteDB(dbKey); + }, + }; +}; diff --git a/src/LocalPouchDB.ts b/src/LocalPouchDB.ts index 0473fb5..2f5db25 100644 --- a/src/LocalPouchDB.ts +++ b/src/LocalPouchDB.ts @@ -26,6 +26,7 @@ import { path2id } from "./utils"; import { Logger } from "./lib/src/logger"; import { checkRemoteVersion, connectRemoteCouchDBWithSetting, getLastPostFailedBySize } from "./utils_couchdb"; import { openDB, deleteDB, IDBPDatabase } from "idb"; +import { KeyValueDatabase, OpenKeyValueDatabase } from "./KeyValueDB"; type ReplicationCallback = (e: PouchDB.Core.ExistingDocument[]) => Promise; class LRUCache { @@ -75,6 +76,7 @@ export class LocalPouchDB { dbname: string; settings: RemoteDBSettings; localDatabase: PouchDB.Database; + kvDB: KeyValueDatabase; nodeid = ""; isReady = false; @@ -115,6 +117,7 @@ export class LocalPouchDB { return null; } onunload() { + this.kvDB.close(); this.recentModifiedDocs = []; this.leafArrivedCallbacks; this.changeHandler = this.cancelHandler(this.changeHandler); @@ -139,6 +142,7 @@ export class LocalPouchDB { if (this.localDatabase != null) { this.localDatabase.close(); } + this.kvDB.close(); } async isOldDatabaseExists() { @@ -167,6 +171,7 @@ export class LocalPouchDB { revs_limit: 100, deterministic_revs: true, }); + this.kvDB = OpenKeyValueDatabase(this.dbname + "-livesync-kv"); Logger("Database info", LOG_LEVEL.VERBOSE); Logger(await this.localDatabase.info(), LOG_LEVEL.VERBOSE); Logger("Open Database..."); @@ -1108,6 +1113,7 @@ export class LocalPouchDB { Logger("Database closed for reset Database."); this.isReady = false; await this.localDatabase.destroy(); + await this.kvDB.destroy(); this.localDatabase = null; await this.initializeDatabase(); Logger("Local Database Reset", LOG_LEVEL.NOTICE); diff --git a/src/main.ts b/src/main.ts index 97c92b2..688cc41 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,6 +26,7 @@ import { ConflictResolveModal } from "./ConflictResolveModal"; import { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab"; import { DocumentHistoryModal } from "./DocumentHistoryModal"; +//@ts-ignore import PluginPane from "./PluginPane.svelte"; import { id2path, path2id } from "./utils"; import { decrypt, encrypt } from "./lib/src/e2ee"; @@ -1206,8 +1207,19 @@ export default class ObsidianLiveSyncPlugin extends Plugin { const procsDisp = procs == 0 ? "" : ` ⏳${procs}`; const message = `Sync:${w} ↑${sent} ↓${arrived}${waiting}${procsDisp}${queued}`; const locks = getLocks(); - const pendingTask = locks.pending.length ? `\nPending:${locks.pending.join(", ")}` : ""; - const runningTask = locks.running.length ? `\nRunning:${locks.running.join(", ")}` : ""; + const pendingTask = locks.pending.length + ? "\nPending: " + + Object.entries([...new Set([...locks.pending])].reduce((p, c) => ({ ...p, [c]: p[c] ?? 0 + 1 }), {} as { [key: string]: number })) + .map((e) => `${e[0]}${e[1] == 1 ? "" : `(${e[1]})`}`) + .join(", ") + : ""; + + const runningTask = locks.running.length + ? "\nRunning: " + + Object.entries([...new Set([...locks.running])].reduce((p, c) => ({ ...p, [c]: p[c] ?? 0 + 1 }), {} as { [key: string]: number })) + .map((e) => `${e[0]}${e[1] == 1 ? "" : `(${e[1]})`}`) + .join(", ") + : ""; this.setStatusBarText(message + pendingTask + runningTask); } @@ -1613,23 +1625,30 @@ export default class ObsidianLiveSyncPlugin extends Plugin { const storageMtime = ~~(file.stat.mtime / 1000); const docMtime = ~~(doc.mtime / 1000); - if (storageMtime > docMtime) { - //newer local file. - Logger("STORAGE -> DB :" + file.path); - Logger(`${storageMtime} > ${docMtime}`); - await this.updateIntoDB(file); - } else if (storageMtime < docMtime) { - //newer database file. - Logger("STORAGE <- DB :" + file.path); - Logger(`${storageMtime} < ${docMtime}`); - const docx = await this.localDatabase.getDBEntry(file.path, null, false, false); - if (docx != false) { - await this.doc2storage_modify(docx, file); - } + const dK = `${file.path}-diff`; + const isLastDiff = (await this.localDatabase.kvDB.get<{ storageMtime: number; docMtime: number }>(dK)) || { storageMtime: 0, docMtime: 0 }; + if (isLastDiff.docMtime == docMtime && isLastDiff.storageMtime == storageMtime) { + // Logger("CHECKED :" + file.path, LOG_LEVEL.VERBOSE); } else { - // Logger("EVEN :" + file.path, LOG_LEVEL.VERBOSE); - // Logger(`${storageMtime} = ${docMtime}`, LOG_LEVEL.VERBOSE); - //eq.case + if (storageMtime > docMtime) { + //newer local file. + Logger("STORAGE -> DB :" + file.path); + Logger(`${storageMtime} > ${docMtime}`); + await this.updateIntoDB(file); + } else if (storageMtime < docMtime) { + //newer database file. + Logger("STORAGE <- DB :" + file.path); + Logger(`${storageMtime} < ${docMtime}`); + const docx = await this.localDatabase.getDBEntry(file.path, null, false, false); + if (docx != false) { + await this.doc2storage_modify(docx, file); + } + } else { + // Logger("EVEN :" + file.path, LOG_LEVEL.VERBOSE); + // Logger(`${storageMtime} = ${docMtime}`, LOG_LEVEL.VERBOSE); + //eq.case + } + await this.localDatabase.kvDB.set(dK, { storageMtime, docMtime }); } }