mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2025-12-16 03:05:57 +00:00
Fixed status message and lag on boot time scan.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-livesync",
|
"id": "obsidian-livesync",
|
||||||
"name": "Self-hosted LiveSync",
|
"name": "Self-hosted LiveSync",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"minAppVersion": "0.9.12",
|
"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.",
|
"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",
|
"author": "vorotamoroz",
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"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.",
|
"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",
|
"main": "main.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
50
src/KeyValueDB.ts
Normal file
50
src/KeyValueDB.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { deleteDB, IDBPDatabase, openDB } from "idb";
|
||||||
|
export interface KeyValueDatabase {
|
||||||
|
get<T>(key: string): Promise<T>;
|
||||||
|
set<T>(key: string, value: T): Promise<IDBValidKey>;
|
||||||
|
del(key: string): Promise<void>;
|
||||||
|
clear(): Promise<void>;
|
||||||
|
keys(query?: IDBValidKey | IDBKeyRange, count?: number): Promise<IDBValidKey[]>;
|
||||||
|
close(): void;
|
||||||
|
destroy(): void;
|
||||||
|
}
|
||||||
|
const databaseCache: { [key: string]: IDBPDatabase<any> } = {};
|
||||||
|
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<T>(key: string): Promise<T> {
|
||||||
|
return (await dbPromise).get(storeKey, key);
|
||||||
|
},
|
||||||
|
async set<T>(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);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -26,6 +26,7 @@ import { path2id } from "./utils";
|
|||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { checkRemoteVersion, connectRemoteCouchDBWithSetting, getLastPostFailedBySize } from "./utils_couchdb";
|
import { checkRemoteVersion, connectRemoteCouchDBWithSetting, getLastPostFailedBySize } from "./utils_couchdb";
|
||||||
import { openDB, deleteDB, IDBPDatabase } from "idb";
|
import { openDB, deleteDB, IDBPDatabase } from "idb";
|
||||||
|
import { KeyValueDatabase, OpenKeyValueDatabase } from "./KeyValueDB";
|
||||||
|
|
||||||
type ReplicationCallback = (e: PouchDB.Core.ExistingDocument<EntryDoc>[]) => Promise<void>;
|
type ReplicationCallback = (e: PouchDB.Core.ExistingDocument<EntryDoc>[]) => Promise<void>;
|
||||||
class LRUCache {
|
class LRUCache {
|
||||||
@@ -75,6 +76,7 @@ export class LocalPouchDB {
|
|||||||
dbname: string;
|
dbname: string;
|
||||||
settings: RemoteDBSettings;
|
settings: RemoteDBSettings;
|
||||||
localDatabase: PouchDB.Database<EntryDoc>;
|
localDatabase: PouchDB.Database<EntryDoc>;
|
||||||
|
kvDB: KeyValueDatabase;
|
||||||
nodeid = "";
|
nodeid = "";
|
||||||
isReady = false;
|
isReady = false;
|
||||||
|
|
||||||
@@ -115,6 +117,7 @@ export class LocalPouchDB {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
onunload() {
|
onunload() {
|
||||||
|
this.kvDB.close();
|
||||||
this.recentModifiedDocs = [];
|
this.recentModifiedDocs = [];
|
||||||
this.leafArrivedCallbacks;
|
this.leafArrivedCallbacks;
|
||||||
this.changeHandler = this.cancelHandler(this.changeHandler);
|
this.changeHandler = this.cancelHandler(this.changeHandler);
|
||||||
@@ -139,6 +142,7 @@ export class LocalPouchDB {
|
|||||||
if (this.localDatabase != null) {
|
if (this.localDatabase != null) {
|
||||||
this.localDatabase.close();
|
this.localDatabase.close();
|
||||||
}
|
}
|
||||||
|
this.kvDB.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
async isOldDatabaseExists() {
|
async isOldDatabaseExists() {
|
||||||
@@ -167,6 +171,7 @@ export class LocalPouchDB {
|
|||||||
revs_limit: 100,
|
revs_limit: 100,
|
||||||
deterministic_revs: true,
|
deterministic_revs: true,
|
||||||
});
|
});
|
||||||
|
this.kvDB = OpenKeyValueDatabase(this.dbname + "-livesync-kv");
|
||||||
Logger("Database info", LOG_LEVEL.VERBOSE);
|
Logger("Database info", LOG_LEVEL.VERBOSE);
|
||||||
Logger(await this.localDatabase.info(), LOG_LEVEL.VERBOSE);
|
Logger(await this.localDatabase.info(), LOG_LEVEL.VERBOSE);
|
||||||
Logger("Open Database...");
|
Logger("Open Database...");
|
||||||
@@ -1108,6 +1113,7 @@ export class LocalPouchDB {
|
|||||||
Logger("Database closed for reset Database.");
|
Logger("Database closed for reset Database.");
|
||||||
this.isReady = false;
|
this.isReady = false;
|
||||||
await this.localDatabase.destroy();
|
await this.localDatabase.destroy();
|
||||||
|
await this.kvDB.destroy();
|
||||||
this.localDatabase = null;
|
this.localDatabase = null;
|
||||||
await this.initializeDatabase();
|
await this.initializeDatabase();
|
||||||
Logger("Local Database Reset", LOG_LEVEL.NOTICE);
|
Logger("Local Database Reset", LOG_LEVEL.NOTICE);
|
||||||
|
|||||||
55
src/main.ts
55
src/main.ts
@@ -26,6 +26,7 @@ import { ConflictResolveModal } from "./ConflictResolveModal";
|
|||||||
import { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab";
|
import { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab";
|
||||||
import { DocumentHistoryModal } from "./DocumentHistoryModal";
|
import { DocumentHistoryModal } from "./DocumentHistoryModal";
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
import PluginPane from "./PluginPane.svelte";
|
import PluginPane from "./PluginPane.svelte";
|
||||||
import { id2path, path2id } from "./utils";
|
import { id2path, path2id } from "./utils";
|
||||||
import { decrypt, encrypt } from "./lib/src/e2ee";
|
import { decrypt, encrypt } from "./lib/src/e2ee";
|
||||||
@@ -1206,8 +1207,19 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
const procsDisp = procs == 0 ? "" : ` ⏳${procs}`;
|
const procsDisp = procs == 0 ? "" : ` ⏳${procs}`;
|
||||||
const message = `Sync:${w} ↑${sent} ↓${arrived}${waiting}${procsDisp}${queued}`;
|
const message = `Sync:${w} ↑${sent} ↓${arrived}${waiting}${procsDisp}${queued}`;
|
||||||
const locks = getLocks();
|
const locks = getLocks();
|
||||||
const pendingTask = locks.pending.length ? `\nPending:${locks.pending.join(", ")}` : "";
|
const pendingTask = locks.pending.length
|
||||||
const runningTask = locks.running.length ? `\nRunning:${locks.running.join(", ")}` : "";
|
? "\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);
|
this.setStatusBarText(message + pendingTask + runningTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1613,23 +1625,30 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
|
|
||||||
const storageMtime = ~~(file.stat.mtime / 1000);
|
const storageMtime = ~~(file.stat.mtime / 1000);
|
||||||
const docMtime = ~~(doc.mtime / 1000);
|
const docMtime = ~~(doc.mtime / 1000);
|
||||||
if (storageMtime > docMtime) {
|
const dK = `${file.path}-diff`;
|
||||||
//newer local file.
|
const isLastDiff = (await this.localDatabase.kvDB.get<{ storageMtime: number; docMtime: number }>(dK)) || { storageMtime: 0, docMtime: 0 };
|
||||||
Logger("STORAGE -> DB :" + file.path);
|
if (isLastDiff.docMtime == docMtime && isLastDiff.storageMtime == storageMtime) {
|
||||||
Logger(`${storageMtime} > ${docMtime}`);
|
// Logger("CHECKED :" + file.path, LOG_LEVEL.VERBOSE);
|
||||||
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 {
|
} else {
|
||||||
// Logger("EVEN :" + file.path, LOG_LEVEL.VERBOSE);
|
if (storageMtime > docMtime) {
|
||||||
// Logger(`${storageMtime} = ${docMtime}`, LOG_LEVEL.VERBOSE);
|
//newer local file.
|
||||||
//eq.case
|
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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user