Compare commits

...

4 Commits

Author SHA1 Message Date
vorotamoroz
7046928068 bump 2023-03-01 12:59:48 +09:00
vorotamoroz
333fcbaaeb - Fixed:
- Requests of reading chunks online are now split into a reasonable(and configurable) size.
    - No longer error message will be shown on Linux devices with hidden file synchronisation.
  - Improved:
    - The interval of reading chunks online is now configurable.
    - Boot sequence has been speeded up, more.
  - Misc:
    - Messages on the boot sequence will now be more detailed. If you want to see them, please enable the verbose log.
    - Logs became be kept for 1000 lines while the verbose log is enabled.
2023-03-01 12:58:29 +09:00
vorotamoroz
009f92c307 bump 2023-02-28 17:25:46 +09:00
vorotamoroz
3e541bd061 Fixed:
- Some messages have been refined.
- Boot sequence has been speeded up.
- Opening the local database multiple times in a short duration has been suppressed.
2023-02-28 17:15:43 +09:00
7 changed files with 86 additions and 68 deletions

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-livesync",
"name": "Self-hosted LiveSync",
"version": "0.17.27",
"version": "0.17.29",
"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",

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "obsidian-livesync",
"version": "0.17.27",
"version": "0.17.29",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "obsidian-livesync",
"version": "0.17.27",
"version": "0.17.29",
"license": "MIT",
"dependencies": {
"diff-match-patch": "^1.0.5",

View File

@@ -1,6 +1,6 @@
{
"name": "obsidian-livesync",
"version": "0.17.27",
"version": "0.17.29",
"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",

View File

@@ -453,6 +453,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
this.plugin.settings.syncOnStart = false;
this.plugin.settings.syncOnFileOpen = false;
this.plugin.settings.syncAfterMerge = false;
this.plugin.settings.syncInternalFiles = false;
this.plugin.settings.usePluginSync = false;
Logger("Hidden files and plugin synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL.NOTICE)
await this.plugin.saveSettings();
applyDisplayEnabled();
@@ -1324,7 +1327,38 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
});
text.inputEl.setAttribute("type", "number");
});
new Setting(containerSyncSettingEl)
.setName("The maximum number of reading chunks online concurrently")
.setDesc("")
.addText((text) => {
text.setPlaceholder("")
.setValue(this.plugin.settings.concurrencyOfReadChunksOnline + "")
.onChange(async (value) => {
let v = Number(value);
if (isNaN(v) || v < 10) {
v = 10;
}
this.plugin.settings.concurrencyOfReadChunksOnline = v;
await this.plugin.saveSettings();
});
text.inputEl.setAttribute("type", "number");
});
new Setting(containerSyncSettingEl)
.setName("The minimum interval for reading chunks online")
.setDesc("")
.addText((text) => {
text.setPlaceholder("")
.setValue(this.plugin.settings.minimumIntervalOfReadChunksOnline + "")
.onChange(async (value) => {
let v = Number(value);
if (isNaN(v) || v < 10) {
v = 10;
}
this.plugin.settings.minimumIntervalOfReadChunksOnline = v;
await this.plugin.saveSettings();
});
text.inputEl.setAttribute("type", "number");
});
addScreenElement("30", containerSyncSettingEl);
const containerMiscellaneousEl = containerEl.createDiv();
containerMiscellaneousEl.createEl("h3", { text: "Miscellaneous" });

Submodule src/lib updated: fbb3fcd8b4...f5ca1c09d9

View File

@@ -64,7 +64,6 @@ function filename2idInternalMetadata(str: string): string {
}
const CHeader = "h:";
const CHeaderEnd = "h;";
// const CHeaderLength = CHeader.length;
function isChunk(str: string): boolean {
return str.startsWith(CHeader);
@@ -235,30 +234,18 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
}
async collectDeletedFiles() {
const pageLimit = 1000;
let nextKey = "";
const limitDays = this.settings.automaticallyDeleteMetadataOfDeletedFiles;
if (limitDays <= 0) return;
Logger(`Checking expired file history`);
const limit = Date.now() - (86400 * 1000 * limitDays);
const notes: { path: string, mtime: number, ttl: number, doc: PouchDB.Core.ExistingDocument<EntryDoc & PouchDB.Core.AllDocsMeta> }[] = [];
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 (doc.type == "newnote" || doc.type == "plain") {
if (doc.deleted && (doc.mtime - limit) < 0) {
notes.push({ path: id2path(doc._id), mtime: doc.mtime, ttl: (doc.mtime - limit) / 1000 / 86400, doc: doc });
}
}
if (isChunk(nextKey)) {
// skip the chunk zone.
nextKey = CHeaderEnd;
for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) {
if (doc.type == "newnote" || doc.type == "plain") {
if (doc.deleted && (doc.mtime - limit) < 0) {
notes.push({ path: id2path(doc._id), mtime: doc.mtime, ttl: (doc.mtime - limit) / 1000 / 86400, doc: doc });
}
}
} while (nextKey != "");
}
if (notes.length == 0) {
Logger("There are no old documents");
Logger(`Checking expired file history done`);
@@ -331,7 +318,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
if (this.settings.suspendFileWatching) {
Logger("'Suspend file watching' turned on. Are you sure this is what you intended? Every modification on the vault will be ignored.", LOG_LEVEL.NOTICE);
}
const isInitialized = await this.initializeDatabase();
const isInitialized = await this.initializeDatabase(false, false);
if (!isInitialized) {
//TODO:stop all sync.
return false;
@@ -435,7 +422,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
this.settings = newSettingW;
this.usedPassphrase = "";
await this.saveSettings();
await this.resetLocalOldDatabase();
await this.resetLocalDatabase();
await this.localDatabase.initializeDatabase();
await this.markRemoteResolved();
@@ -448,7 +434,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
this.settings = newSettingW;
this.usedPassphrase = "";
await this.saveSettings();
await this.resetLocalOldDatabase();
await this.resetLocalDatabase();
await this.localDatabase.initializeDatabase();
await this.initializeDatabase(true);
@@ -486,7 +471,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
this.usedPassphrase = "";
await this.saveSettings();
if (keepLocalDB == "no") {
this.resetLocalOldDatabase();
this.resetLocalDatabase();
this.localDatabase.initializeDatabase();
const rebuild = await askYesNo(this.app, "Rebuild the database?");
@@ -535,6 +519,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
const lsKey = "obsidian-live-sync-ver" + this.getVaultName();
const last_version = localStorage.getItem(lsKey);
await this.loadSettings();
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
if (lastVersion > this.settings.lastReadUpdates) {
Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL.NOTICE);
@@ -785,7 +770,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
await this.localDatabase.close();
}
const vaultName = this.getVaultName();
Logger("Open Database...");
Logger("Waiting for ready...");
//@ts-ignore
const isMobile = this.app.isMobile;
this.localDatabase = new LocalPouchDB(this.settings, vaultName, isMobile);
@@ -1317,7 +1302,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
}
this.app.vault.adapter.append(normalizePath(logDate), vaultName + ":" + newMessage + "\n");
}
logMessageStore.apply(e => [...e, newMessage].slice(-100));
logMessageStore.apply(e => [...e, newMessage].slice(this.settings.showVerboseLog ? -1000 : -100));
this.setStatusBarText(null, messageContent);
if (level >= LOG_LEVEL.NOTICE) {
@@ -1586,9 +1571,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
const filename = id2path(id2filenameInternalMetadata(queue.entry._id));
// await this.syncInternalFilesAndDatabase("pull", false, false, [filename])
this.procInternalFile(filename);
}
if (isValidPath(id2path(queue.entry._id))) {
} else if (isValidPath(id2path(queue.entry._id))) {
this.handleDBChanged(queue.entry);
} else {
Logger(`Skipped: ${queue.entry._id}`, LOG_LEVEL.VERBOSE);
}
} else if (now > queue.timeout) {
if (!queue.warned) Logger(`Timed out: ${queue.entry._id} could not collect ${queue.missingChildren.length} chunks. plugin keeps watching, but you have to check the file after the replication.`, LOG_LEVEL.NOTICE);
@@ -1925,9 +1911,9 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
await this.localDatabase.openReplication(this.settings, false, showMessage, this.parseReplicationResult);
}
async initializeDatabase(showingNotice?: boolean) {
async initializeDatabase(showingNotice?: boolean, reopenDatabase = true) {
this.isReady = false;
if (await this.openDatabase()) {
if ((!reopenDatabase) || await this.openDatabase()) {
if (this.localDatabase.isReady) {
await this.syncAllFiles(showingNotice);
}
@@ -1989,18 +1975,23 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
Logger("Initializing", LOG_LEVEL.NOTICE, "syncAll");
}
Logger("Initialize and checking database files");
Logger("Checking deleted files");
await this.collectDeletedFiles();
Logger("Collecting local files on the storage", LOG_LEVEL.VERBOSE);
const filesStorage = this.app.vault.getFiles().filter(e => this.isTargetFile(e));
const filesStorageName = filesStorage.map((e) => e.path);
const wf = await this.localDatabase.localDatabase.allDocs();
const filesDatabase = wf.rows.filter((e) =>
!isChunk(e.id) &&
!isPluginMetadata(e.id) &&
e.id != "obsydian_livesync_version" &&
e.id != "_design/replicate"
)
.filter(e => isValidPath(e.id)).map((e) => id2path(e.id)).filter(e => this.isTargetFile(e));
Logger("Collecting local files on the DB", LOG_LEVEL.VERBOSE);
const filesDatabase = [] as string[]
for await (const docId of this.localDatabase.findAllDocNames()) {
const path = id2path(docId);
if (isValidPath(docId) && this.isTargetFile(path)) {
filesDatabase.push(path);
}
}
Logger("Opening the key-value database", LOG_LEVEL.VERBOSE);
const isInitialized = await (this.localDatabase.kvDB.get<boolean>("initialized")) || false;
// Make chunk bigger if it is the initial scan. There must be non-active docs.
if (filesDatabase.length == 0 && !isInitialized) {
@@ -2013,33 +2004,18 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
const onlyInStorageNames = onlyInStorage.map((e) => e.path);
const syncFiles = filesStorage.filter((e) => onlyInStorageNames.indexOf(e.path) == -1);
Logger("Initialize and checking database files");
Logger("Updating database by new files");
this.setStatusBarText(`UPDATE DATABASE`);
const runAll = async<T>(procedureName: string, objects: T[], callback: (arg: T) => Promise<void>) => {
// const count = objects.length;
Logger(procedureName);
// let i = 0;
const semaphore = Semaphore(25);
// Logger(`${procedureName} exec.`);
if (!this.localDatabase.isReady) throw Error("Database is not ready!");
const processes = objects.map(e => (async (v) => {
const releaser = await semaphore.acquire(1, procedureName);
try {
await callback(v);
// i++;
// if (i % 50 == 0) {
// const notify = `${procedureName} : ${i}/${count}`;
// if (showingNotice) {
// Logger(notify, LOG_LEVEL.NOTICE, "syncAll");
// } else {
// Logger(notify);
// }
// this.setStatusBarText(notify);
// }
} catch (ex) {
Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE);
Logger(ex);
@@ -2079,7 +2055,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
const syncFilesX = syncFiles.splice(0, 100);
const docs = await this.localDatabase.localDatabase.allDocs({ keys: syncFilesX.map(e => path2id(e.path)), include_docs: true })
const syncFilesToSync = syncFilesX.map((e) => ({ file: e, doc: docs.rows.find(ee => ee.id == path2id(e.path)).doc as LoadedEntry }));
await runAll(`CHECK FILE STATUS:${syncFiles.length}/${docsCount}`, syncFilesToSync, async (e) => {
caches = await this.syncFileBetweenDBandStorage(e.file, e.doc, initialScan, caches);
});
@@ -2686,6 +2661,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
const dK = `${file.path}-diff`;
const isLastDiff = dK in caches ? caches[dK] : { storageMtime: 0, docMtime: 0 };
if (isLastDiff.docMtime == docMtime && isLastDiff.storageMtime == storageMtime) {
Logger("STORAGE .. DB :" + file.path, LOG_LEVEL.VERBOSE);
caches[dK] = { storageMtime, docMtime };
return caches;
}
@@ -2708,11 +2684,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
}
caches[dK] = { storageMtime, docMtime };
return caches;
} else {
// Logger("EVEN :" + file.path, LOG_LEVEL.VERBOSE);
// Logger(`${storageMtime} = ${docMtime}`, LOG_LEVEL.VERBOSE);
//eq.case
}
Logger("STORAGE == DB :" + file.path + "", LOG_LEVEL.VERBOSE);
caches[dK] = { storageMtime, docMtime };
return caches;
@@ -2827,11 +2800,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
async resetLocalDatabase() {
clearTouched();
await this.localDatabase.resetDatabase();
await this.localDatabase.resetLocalOldDatabase();
}
async resetLocalOldDatabase() {
clearTouched();
await this.localDatabase.resetLocalOldDatabase();
}
async tryResetRemoteDatabase() {

View File

@@ -75,5 +75,21 @@
- The plugin data can be resolved when conflicted.
- The semaphore status display has been changed to count only.
- Applying to the storage will be concurrent with a few files.
- 0.17.28
-Fixed:
- Some messages have been refined.
- Boot sequence has been speeded up.
- Opening the local database multiple times in a short duration has been suppressed.
- Older migration logic.
- Note: If you have used 0.10.0 or lower and have not upgraded, you will need to run 0.17.27 or earlier once or reinstall Obsidian.
- 0.17.29
- Fixed:
- Requests of reading chunks online are now split into a reasonable(and configurable) size.
- No longer error message will be shown on Linux devices with hidden file synchronisation.
- Improved:
- The interval of reading chunks online is now configurable.
- Boot sequence has been speeded up, more.
- Misc:
- Messages on the boot sequence will now be more detailed. If you want to see them, please enable the verbose log.
- Logs became be kept for 1000 lines while the verbose log is enabled.
... To continue on to `updates_old.md`.