11th March, 2026

Now, Self-hosted LiveSync has finally begun to be split into the Self-hosted LiveSync plugin for Obsidian, and a properly abstracted version of it.
This may not offer much benefit to Obsidian plugin users, or might even cause a slight inconvenience, but I believe it will certainly help improve testability and make the ecosystem better.
However, I do not see the point in putting something with little benefit into beta, so I am handling this on the alpha branch. I would actually preferred to create an R&D branch, but I was not keen on the ampersand, and I feel it will eventually become a proper beta anyway.

### Refactored

- Separated `ObsidianLiveSyncPlugin` into `ObsidianLiveSyncPlugin` and `LiveSyncBaseCore`.
- Now `LiveSyncCore` indicates the type specified version of `LiveSyncBaseCore`.
- Referencing `plugin.xxx` has been rewritten to referencing the corresponding service or `core.xxx`.

### Internal API changes

- Storage Access APIs are now yielding Promises. This is to allow more limited storage platforms to be supported.

### R&D

- Browser-version of Self-hosted LiveSync is now in development. This is not intended for public use now, but I will eventually make it available for testing.
- We can see the code in `src/apps/webapp` for the browser version.
This commit is contained in:
vorotamoroz
2026-03-11 05:47:00 +01:00
parent 9cf630320c
commit 0dfd42259d
77 changed files with 2849 additions and 909 deletions

View File

@@ -1,10 +1,16 @@
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
import type { AnyEntry, FilePathWithPrefix } from "@lib/common/types";
import type { LiveSyncCore } from "@/main";
import type { IMinimumLiveSyncCommands, LiveSyncBaseCore } from "@/LiveSyncBaseCore";
import { stripAllPrefixes } from "@lib/string_and_binary/path";
import { createInstanceLogFunction } from "@lib/services/lib/logUtils";
import type { ServiceContext } from "@/lib/src/services/base/ServiceBase";
export abstract class AbstractModule {
export abstract class AbstractModule<
T extends LiveSyncBaseCore<ServiceContext, IMinimumLiveSyncCommands> = LiveSyncBaseCore<
ServiceContext,
IMinimumLiveSyncCommands
>,
> {
_log = createInstanceLogFunction(this.constructor.name, this.services.API);
get services() {
if (!this.core._services) {
@@ -36,13 +42,13 @@ export abstract class AbstractModule {
return stripAllPrefixes(this.services.path.getPath(entry));
}
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
onBindFunction(core: T, services: typeof core.services) {
// Override if needed.
}
constructor(public core: LiveSyncCore) {
constructor(public core: T) {
Logger(`[${this.constructor.name}] Loaded`, LOG_LEVEL_VERBOSE);
}
saveSettings = this.core.saveSettings.bind(this.core);
saveSettings = this.core.services.setting.saveSettingData.bind(this.core.services.setting);
addTestResult(key: string, value: boolean, summary?: string, message?: string) {
this.services.test.addTestResult(`${this.constructor.name}`, key, value, summary, message);

View File

@@ -1,4 +1,4 @@
import { PeriodicProcessor } from "../../common/utils";
import { PeriodicProcessor } from "@/common/PeriodicProcessor";
import type { LiveSyncCore } from "../../main";
import { AbstractModule } from "../AbstractModule";

View File

@@ -6,7 +6,8 @@ import { balanceChunkPurgedDBs } from "@lib/pouchdb/chunks";
import { purgeUnreferencedChunks } from "@lib/pouchdb/chunks";
import { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator";
import { type EntryDoc, type RemoteType } from "../../lib/src/common/types";
import { scheduleTask } from "../../common/utils";
import { scheduleTask } from "octagonal-wheels/concurrency/task";
import { EVENT_FILE_SAVED, EVENT_SETTING_SAVED, eventHub } from "../../common/events";
import { $msg } from "../../lib/src/common/i18n";

View File

@@ -8,8 +8,7 @@ import {
type MetaEntry,
} from "@lib/common/types";
import type { ModuleReplicator } from "./ModuleReplicator";
import { isChunk, isValidPath } from "@/common/utils";
import type { LiveSyncCore } from "@/main";
import { isChunk } from "@/lib/src/common/typeUtils";
import {
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
@@ -22,6 +21,7 @@ import { fireAndForget, isAnyNote, throttle } from "@lib/common/utils";
import { Semaphore } from "octagonal-wheels/concurrency/semaphore_v2";
import { serialized } from "octagonal-wheels/concurrency/lock";
import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore";
const KV_KEY_REPLICATION_RESULT_PROCESSOR_SNAPSHOT = "replicationResultProcessorSnapshot";
type ReplicateResultProcessorState = {
@@ -54,7 +54,7 @@ export class ReplicateResultProcessor {
get services() {
return this.replicator.core.services;
}
get core(): LiveSyncCore {
get core(): LiveSyncBaseCore {
return this.replicator.core;
}
@@ -414,7 +414,7 @@ export class ReplicateResultProcessor {
if (await this.services.replication.processOptionalSynchroniseResult(dbDoc)) {
// Already processed
this.log(`Processed by other processor: ${docNote}`, LOG_LEVEL_DEBUG);
} else if (isValidPath(this.getPath(doc))) {
} else if (this.services.vault.isValidPath(this.getPath(doc))) {
// Apply to storage if the path is valid
await this.applyToStorage(doc as MetaEntry);
this.log(`Processed: ${docNote}`, LOG_LEVEL_DEBUG);

View File

@@ -11,13 +11,9 @@ import {
type diff_check_result,
type FilePathWithPrefix,
} from "../../lib/src/common/types";
import {
compareMTime,
displayRev,
isCustomisationSyncMetadata,
isPluginMetadata,
TARGET_IS_NEW,
} from "../../common/utils";
import { isCustomisationSyncMetadata, isPluginMetadata } from "@lib/common/typeUtils.ts";
import { TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols.ts";
import { compareMTime, displayRev } from "@lib/common/utils.ts";
import diff_match_patch from "diff-match-patch";
import { stripAllPrefixes, isPlainText } from "../../lib/src/string_and_binary/path";
import { eventHub } from "../../common/events.ts";
@@ -214,7 +210,7 @@ export class ModuleConflictResolver extends AbstractModule {
private async _resolveAllConflictedFilesByNewerOnes() {
this._log(`Resolving conflicts by newer ones`, LOG_LEVEL_NOTICE);
const files = this.core.storageAccess.getFileNames();
const files = await this.core.storageAccess.getFileNames();
let i = 0;
for (const file of files) {

View File

@@ -0,0 +1,86 @@
import type { LiveSyncCore } from "@/main";
import { LOG_LEVEL_NOTICE } from "octagonal-wheels/common/logger";
import { fireAndForget } from "octagonal-wheels/promises";
import { AbstractModule } from "../AbstractModule";
// Separated Module for basic menu commands, which are not related to obsidian specific features. It is expected to be used in other platforms with minimal changes.
// However, it is odd that it has here at all; it really ought to be in each respective feature. It will likely be moved eventually. Until now, addCommand pointed to Obsidian's version.
export class ModuleBasicMenu extends AbstractModule {
_everyOnloadStart(): Promise<boolean> {
this.addCommand({
id: "livesync-replicate",
name: "Replicate now",
callback: async () => {
await this.services.replication.replicate();
},
});
this.addCommand({
id: "livesync-dump",
name: "Dump information of this doc ",
callback: () => {
const file = this.services.vault.getActiveFilePath();
if (!file) return;
fireAndForget(() => this.localDatabase.getDBEntry(file, {}, true, false));
},
});
this.addCommand({
id: "livesync-toggle",
name: "Toggle LiveSync",
callback: async () => {
if (this.settings.liveSync) {
this.settings.liveSync = false;
this._log("LiveSync Disabled.", LOG_LEVEL_NOTICE);
} else {
this.settings.liveSync = true;
this._log("LiveSync Enabled.", LOG_LEVEL_NOTICE);
}
await this.services.control.applySettings();
await this.services.setting.saveSettingData();
},
});
this.addCommand({
id: "livesync-suspendall",
name: "Toggle All Sync.",
callback: async () => {
if (this.services.appLifecycle.isSuspended()) {
this.services.appLifecycle.setSuspended(false);
this._log("Self-hosted LiveSync resumed", LOG_LEVEL_NOTICE);
} else {
this.services.appLifecycle.setSuspended(true);
this._log("Self-hosted LiveSync suspended", LOG_LEVEL_NOTICE);
}
await this.services.control.applySettings();
await this.services.setting.saveSettingData();
},
});
this.addCommand({
id: "livesync-scan-files",
name: "Scan storage and database again",
callback: async () => {
await this.services.vault.scanVault(true);
},
});
this.addCommand({
id: "livesync-runbatch",
name: "Run pended batch processes",
callback: async () => {
await this.services.fileProcessing.commitPendingFileEvents();
},
});
// TODO, Replicator is possibly one of features. It should be moved to features.
this.addCommand({
id: "livesync-abortsync",
name: "Abort synchronization immediately",
callback: () => {
this.core.replicator.terminateSync();
},
});
return Promise.resolve(true);
}
override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
}
}

View File

@@ -73,7 +73,7 @@ export class ModuleInitializerFile extends AbstractModule {
await this.collectDeletedFiles();
this._log("Collecting local files on the storage", LOG_LEVEL_VERBOSE);
const filesStorageSrc = this.core.storageAccess.getFiles();
const filesStorageSrc = await this.core.storageAccess.getFiles();
const _filesStorage = [] as typeof filesStorageSrc;
@@ -300,7 +300,7 @@ export class ModuleInitializerFile extends AbstractModule {
throw new Error(`Missing doc:${(file as any).path}`);
}
if ("path" in file) {
const w = this.core.storageAccess.getFileStub((file as any).path);
const w = await this.core.storageAccess.getFileStub((file as any).path);
if (w) {
file = w;
} else {

View File

@@ -8,7 +8,7 @@ import {
eventHub,
} from "../../common/events.ts";
import { AbstractModule } from "../AbstractModule.ts";
import { $msg } from "src/lib/src/common/i18n.ts";
import { $msg } from "@lib/common/i18n.ts";
import { performDoctorConsultation, RebuildOptions } from "../../lib/src/common/configForDoc.ts";
import { isValidPath } from "../../common/utils.ts";
import { isMetaEntry } from "../../lib/src/common/types.ts";
@@ -40,7 +40,7 @@ export class ModuleMigration extends AbstractModule {
);
if (isModified) {
this.settings = settings;
await this.core.saveSettings();
await this.saveSettings();
}
if (!skipRebuild) {
if (shouldRebuild) {
@@ -231,7 +231,7 @@ export class ModuleMigration extends AbstractModule {
if (ret == FIX) {
for (const file of recoverable) {
// Overwrite the database with the files on the storage
const stubFile = this.core.storageAccess.getFileStub(file.path);
const stubFile = await this.core.storageAccess.getFileStub(file.path);
if (stubFile == null) {
Logger(`Could not find stub file for ${file.path}`, LOG_LEVEL_NOTICE);
continue;

View File

@@ -35,13 +35,13 @@ export class ModuleCheckRemoteSize extends AbstractModule {
);
if (ret == ANSWER_0) {
this.settings.notifyThresholdOfRemoteStorageSize = 0;
await this.core.saveSettings();
await this.saveSettings();
} else if (ret == ANSWER_800) {
this.settings.notifyThresholdOfRemoteStorageSize = 800;
await this.core.saveSettings();
await this.saveSettings();
} else if (ret == ANSWER_2000) {
this.settings.notifyThresholdOfRemoteStorageSize = 2000;
await this.core.saveSettings();
await this.saveSettings();
}
}
if (this.settings.notifyThresholdOfRemoteStorageSize > 0) {
@@ -88,7 +88,8 @@ export class ModuleCheckRemoteSize extends AbstractModule {
}),
LOG_LEVEL_NOTICE
);
await this.core.saveSettings();
// await this.core.saveSettings();
await this.core.services.setting.saveSettingData();
} else {
// Dismiss or Close the dialog
}

View File

@@ -1,10 +1,10 @@
import { fireAndForget } from "octagonal-wheels/promises";
import { addIcon, type Editor, type MarkdownFileInfo, type MarkdownView } from "../../deps.ts";
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types.ts";
import { $msg } from "src/lib/src/common/i18n.ts";
import type { LiveSyncCore } from "../../main.ts";
import { type Editor, type MarkdownFileInfo, type MarkdownView } from "@/deps.ts";
import { addIcon } from "@/deps.ts";
import { type FilePathWithPrefix } from "@lib/common/types.ts";
import { $msg } from "@lib/common/i18n.ts";
import type { LiveSyncCore } from "@/main.ts";
import { AbstractModule } from "../AbstractModule.ts";
// Obsidian specific menu commands.
export class ModuleObsidianMenu extends AbstractModule {
_everyOnloadStart(): Promise<boolean> {
// UI
@@ -22,22 +22,6 @@ export class ModuleObsidianMenu extends AbstractModule {
await this.services.replication.replicate(true);
}).addClass("livesync-ribbon-replicate");
this.addCommand({
id: "livesync-replicate",
name: "Replicate now",
callback: async () => {
await this.services.replication.replicate();
},
});
this.addCommand({
id: "livesync-dump",
name: "Dump information of this doc ",
callback: () => {
const file = this.services.vault.getActiveFilePath();
if (!file) return;
fireAndForget(() => this.localDatabase.getDBEntry(file, {}, true, false));
},
});
this.addCommand({
id: "livesync-checkdoc-conflicted",
name: "Resolve if conflicted.",
@@ -48,61 +32,6 @@ export class ModuleObsidianMenu extends AbstractModule {
},
});
this.addCommand({
id: "livesync-toggle",
name: "Toggle LiveSync",
callback: async () => {
if (this.settings.liveSync) {
this.settings.liveSync = false;
this._log("LiveSync Disabled.", LOG_LEVEL_NOTICE);
} else {
this.settings.liveSync = true;
this._log("LiveSync Enabled.", LOG_LEVEL_NOTICE);
}
await this.services.control.applySettings();
await this.services.setting.saveSettingData();
},
});
this.addCommand({
id: "livesync-suspendall",
name: "Toggle All Sync.",
callback: async () => {
if (this.services.appLifecycle.isSuspended()) {
this.services.appLifecycle.setSuspended(false);
this._log("Self-hosted LiveSync resumed", LOG_LEVEL_NOTICE);
} else {
this.services.appLifecycle.setSuspended(true);
this._log("Self-hosted LiveSync suspended", LOG_LEVEL_NOTICE);
}
await this.services.control.applySettings();
await this.services.setting.saveSettingData();
},
});
this.addCommand({
id: "livesync-scan-files",
name: "Scan storage and database again",
callback: async () => {
await this.services.vault.scanVault(true);
},
});
this.addCommand({
id: "livesync-runbatch",
name: "Run pended batch processes",
callback: async () => {
await this.services.fileProcessing.commitPendingFileEvents();
},
});
// TODO, Replicator is possibly one of features. It should be moved to features.
this.addCommand({
id: "livesync-abortsync",
name: "Abort synchronization immediately",
callback: () => {
this.core.replicator.terminateSync();
},
});
return Promise.resolve(true);
}

View File

@@ -1,3 +1,4 @@
// I intend to discontinue maintenance of this class. It seems preferable to test it externally.
import { delay } from "octagonal-wheels/promises";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
@@ -169,7 +170,7 @@ export class ModuleReplicateTest extends AbstractObsidianModule {
this._log("No storage access", LOG_LEVEL_INFO);
return;
}
const files = this.core.storageAccess.getFiles();
const files = await this.core.storageAccess.getFiles();
const out = [] as any[];
const webcrypto = await getWebCrypto();
for (const file of files) {
@@ -205,8 +206,8 @@ export class ModuleReplicateTest extends AbstractObsidianModule {
}
async __dumpFileListIncludeHidden(outFile?: string) {
const ignorePatterns = getFileRegExp(this.plugin.settings, "syncInternalFilesIgnorePatterns");
const targetPatterns = getFileRegExp(this.plugin.settings, "syncInternalFilesTargetPatterns");
const ignorePatterns = getFileRegExp(this.core.settings, "syncInternalFilesIgnorePatterns");
const targetPatterns = getFileRegExp(this.core.settings, "syncInternalFilesTargetPatterns");
const out = [] as any[];
const files = await this.core.storageAccess.getFilesIncludeHidden("", targetPatterns, ignorePatterns);
// console.dir(files);

View File

@@ -9,6 +9,7 @@
import { writable } from "svelte/store";
export let plugin: ObsidianLiveSyncPlugin;
export let moduleDev: ModuleDev;
$: core = plugin.core;
let performanceTestResult = "";
let functionCheckResult = "";
let testRunning = false;
@@ -42,7 +43,7 @@
// performTest();
eventHub.onceEvent(EVENT_LAYOUT_READY, async () => {
if (await plugin.storageAccess.isExistsIncludeHidden("_AUTO_TEST.md")) {
if (await core.storageAccess.isExistsIncludeHidden("_AUTO_TEST.md")) {
new Notice("Auto test file found, running tests...");
fireAndForget(async () => {
await allTest();
@@ -57,14 +58,14 @@
function moduleMultiDeviceTest() {
if (moduleTesting) return;
moduleTesting = true;
plugin.services.test.testMultiDevice().finally(() => {
core.services.test.testMultiDevice().finally(() => {
moduleTesting = false;
});
}
function moduleSingleDeviceTest() {
if (moduleTesting) return;
moduleTesting = true;
plugin.services.test.test().finally(() => {
core.services.test.test().finally(() => {
moduleTesting = false;
});
}
@@ -72,8 +73,8 @@
if (moduleTesting) return;
moduleTesting = true;
try {
await plugin.services.test.test();
await plugin.services.test.testMultiDevice();
await core.services.test.test();
await core.services.test.testMultiDevice();
} finally {
moduleTesting = false;
}

View File

@@ -38,8 +38,8 @@ export function addDebugFileLog(message: any, stackLog = false) {
// const out = "--" + timestamp + "--\n" + messageContent + " " + (stack || "");
// const out
try {
await plugin.storageAccess.appendHiddenFile(
plugin.app.vault.configDir + "/ls-debug/" + outFile,
await plugin.core.storageAccess.appendHiddenFile(
plugin.core.services.API.getSystemConfigDir() + "/ls-debug/" + outFile,
JSON.stringify(out) + "\n"
);
} catch {

View File

@@ -48,7 +48,7 @@ async function formatPerfResults(items: NamedMeasureResult[]) {
}
export async function perf_trench(plugin: ObsidianLiveSyncPlugin) {
clearResult("trench");
const trench = new Trench(plugin.simpleStore);
const trench = new Trench(plugin.core.simpleStore);
const result = [] as NamedMeasureResult[];
result.push(
await measure("trench-short-string", async () => {
@@ -57,7 +57,7 @@ export async function perf_trench(plugin: ObsidianLiveSyncPlugin) {
})
);
{
const testBinary = await plugin.storageAccess.readHiddenFileBinary("testdata/10kb.png");
const testBinary = await plugin.core.storageAccess.readHiddenFileBinary("testdata/10kb.png");
const uint8Array = new Uint8Array(testBinary);
result.push(
await measure("trench-binary-10kb", async () => {
@@ -67,7 +67,7 @@ export async function perf_trench(plugin: ObsidianLiveSyncPlugin) {
);
}
{
const testBinary = await plugin.storageAccess.readHiddenFileBinary("testdata/100kb.jpeg");
const testBinary = await plugin.core.storageAccess.readHiddenFileBinary("testdata/100kb.jpeg");
const uint8Array = new Uint8Array(testBinary);
result.push(
await measure("trench-binary-100kb", async () => {
@@ -77,7 +77,7 @@ export async function perf_trench(plugin: ObsidianLiveSyncPlugin) {
);
}
{
const testBinary = await plugin.storageAccess.readHiddenFileBinary("testdata/1mb.png");
const testBinary = await plugin.core.storageAccess.readHiddenFileBinary("testdata/1mb.png");
const uint8Array = new Uint8Array(testBinary);
result.push(
await measure("trench-binary-1mb", async () => {

View File

@@ -15,6 +15,7 @@ import { isErrorOfMissingDoc } from "../../../lib/src/pouchdb/utils_couchdb.ts";
import { fireAndForget, getDocData, readContent } from "../../../lib/src/common/utils.ts";
import { isPlainText, stripPrefix } from "../../../lib/src/string_and_binary/path.ts";
import { scheduleOnceIfDuplicated } from "octagonal-wheels/concurrency/lock";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
function isImage(path: string) {
const ext = path.split(".").splice(-1)[0].toLowerCase();
@@ -46,8 +47,9 @@ function readDocument(w: LoadedEntry) {
}
export class DocumentHistoryModal extends Modal {
plugin: ObsidianLiveSyncPlugin;
core: LiveSyncBaseCore;
get services() {
return this.plugin.services;
return this.core.services;
}
range!: HTMLInputElement;
contentView!: HTMLDivElement;
@@ -66,6 +68,7 @@ export class DocumentHistoryModal extends Modal {
constructor(
app: App,
core: LiveSyncBaseCore,
plugin: ObsidianLiveSyncPlugin,
file: TFile | FilePathWithPrefix,
id?: DocumentID,
@@ -73,6 +76,7 @@ export class DocumentHistoryModal extends Modal {
) {
super(app);
this.plugin = plugin;
this.core = core;
this.file = file instanceof TFile ? getPathFromTFile(file) : file;
this.id = id;
this.initialRev = revision;
@@ -88,7 +92,7 @@ export class DocumentHistoryModal extends Modal {
if (!this.id) {
this.id = await this.services.path.path2id(this.file);
}
const db = this.plugin.localDatabase;
const db = this.core.localDatabase;
try {
const w = await db.getRaw(this.id, { revs_info: true });
this.revs_info = w._revs_info?.filter((e) => e?.status == "available") ?? [];
@@ -137,7 +141,7 @@ export class DocumentHistoryModal extends Modal {
}
async showExactRev(rev: string) {
const db = this.plugin.localDatabase;
const db = this.core.localDatabase;
const w = await db.getDBEntry(this.file, { rev: rev }, false, false, true);
this.currentText = "";
this.currentDeleted = false;
@@ -292,7 +296,7 @@ export class DocumentHistoryModal extends Modal {
return;
}
const d = readContent(this.currentDoc);
await this.plugin.storageAccess.writeHiddenFileAuto(pathToWrite, d);
await this.core.storageAccess.writeHiddenFileAuto(pathToWrite, d);
await focusFile(pathToWrite);
this.close();
});

View File

@@ -6,7 +6,9 @@
import { diff_match_patch } from "../../../deps.ts";
import { DocumentHistoryModal } from "../DocumentHistory/DocumentHistoryModal.ts";
import { isPlainText, stripAllPrefixes } from "../../../lib/src/string_and_binary/path.ts";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
export let plugin: ObsidianLiveSyncPlugin;
export let core: LiveSyncBaseCore;
let showDiffInfo = false;
let showChunkCorrected = false;
@@ -44,12 +46,12 @@
let history = [] as HistoryData[];
let loading = false;
function getPath(entry: AnyEntry): FilePathWithPrefix {
return plugin.services.path.getPath(entry);
return core.services.path.getPath(entry);
}
async function fetchChanges(): Promise<HistoryData[]> {
try {
const db = plugin.localDatabase;
const db = core.localDatabase;
let result = [] as typeof history;
for await (const docA of db.findAllNormalDocs()) {
if (docA.mtime < range_from_epoch) {
@@ -112,11 +114,11 @@
}
if (rev == docA._rev) {
if (checkStorageDiff) {
const isExist = await plugin.storageAccess.isExistsIncludeHidden(
const isExist = await core.storageAccess.isExistsIncludeHidden(
stripAllPrefixes(getPath(docA))
);
if (isExist) {
const data = await plugin.storageAccess.readHiddenFileBinary(
const data = await core.storageAccess.readHiddenFileBinary(
stripAllPrefixes(getPath(docA))
);
const d = readAsBlob(doc);
@@ -189,7 +191,7 @@
onDestroy(() => {});
function showHistory(file: string, rev: string) {
new DocumentHistoryModal(plugin.app, plugin, file as unknown as FilePathWithPrefix, undefined, rev).open();
new DocumentHistoryModal(plugin.app, plugin.core, plugin, file as unknown as FilePathWithPrefix, undefined, rev).open();
}
function openFile(file: string) {
plugin.app.workspace.openLinkText(file, file);

View File

@@ -11,6 +11,7 @@ export class GlobalHistoryView extends SvelteItemView {
target: target,
props: {
plugin: this.plugin,
core: this.plugin.core,
},
});
}

View File

@@ -254,8 +254,7 @@ export class ModuleLog extends AbstractObsidianModule {
}
// Case Sensitivity
if (this.services.vault.shouldCheckCaseInsensitively()) {
const f = this.core.storageAccess
.getFiles()
const f = (await this.core.storageAccess.getFiles())
.map((e) => e.path)
.filter((e) => e.toLowerCase() == thisFile.path.toLowerCase());
if (f.length > 1) {
@@ -405,8 +404,8 @@ export class ModuleLog extends AbstractObsidianModule {
this.logHistory = this.statusDiv.createDiv({ cls: "livesync-status-loghistory" });
eventHub.onEvent(EVENT_LAYOUT_READY, () => this.adjustStatusDivPosition());
if (this.settings?.showStatusOnStatusbar) {
this.statusBar = this.core.addStatusBarItem();
this.statusBar.addClass("syncstatusbar");
this.statusBar = this.services.API.addStatusBarItem();
this.statusBar?.addClass("syncstatusbar");
}
this.adjustStatusDivPosition();
return Promise.resolve(true);

View File

@@ -34,7 +34,7 @@ export class ModuleObsidianDocumentHistory extends AbstractObsidianModule {
}
showHistory(file: TFile | FilePathWithPrefix, id?: DocumentID) {
new DocumentHistoryModal(this.app, this.plugin, file, id).open();
new DocumentHistoryModal(this.app, this.core, this.plugin, file, id).open();
}
async fileHistory() {

View File

@@ -2,6 +2,7 @@ import { ObsidianLiveSyncSettingTab } from "./SettingDialogue/ObsidianLiveSyncSe
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
import { EVENT_REQUEST_OPEN_SETTING_WIZARD, EVENT_REQUEST_OPEN_SETTINGS, eventHub } from "../../common/events.ts";
import type { LiveSyncCore } from "@/main.ts";
export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
settingTab!: ObsidianLiveSyncSettingTab;
@@ -29,7 +30,7 @@ export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
get appId() {
return `${"appId" in this.app ? this.app.appId : ""}`;
}
override onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
}
}

View File

@@ -86,8 +86,11 @@ export function createStub(name: string, key: string, value: string, panel: stri
export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
plugin: ObsidianLiveSyncPlugin;
get core() {
return this.plugin.core;
}
get services() {
return this.plugin.services;
return this.core.services;
}
selectedScreen = "";
@@ -122,9 +125,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
continue;
}
//@ts-ignore
this.plugin.settings[k] = this.editingSettings[k];
this.core.settings[k] = this.editingSettings[k];
//@ts-ignore
this.initialSettings[k] = this.plugin.settings[k];
this.initialSettings[k] = this.core.settings[k];
}
keys.forEach((e) => this.refreshSetting(e));
}
@@ -164,14 +167,14 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
continue;
}
//@ts-ignore
this.plugin.settings[k] = this.editingSettings[k];
this.core.settings[k] = this.editingSettings[k];
//@ts-ignore
this.initialSettings[k] = this.plugin.settings[k];
this.initialSettings[k] = this.core.settings[k];
hasChanged = true;
}
if (hasChanged) {
await this.plugin.saveSettings();
await this.services.setting.saveSettingData();
}
// if (runOnSaved) {
@@ -231,7 +234,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
*/
reloadAllSettings(skipUpdate: boolean = false) {
const localSetting = this.reloadAllLocalSettings();
this._editingSettings = { ...this.plugin.settings, ...localSetting };
this._editingSettings = { ...this.core.settings, ...localSetting };
this._editingSettings = { ...this.editingSettings, ...this.computeAllLocalSettings() };
this.initialSettings = { ...this.editingSettings };
if (!skipUpdate) this.requestUpdate();
@@ -242,7 +245,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
*/
refreshSetting(key: AllSettingItemKey) {
const localSetting = this.reloadAllLocalSettings();
if (key in this.plugin.settings) {
if (key in this.core.settings) {
if (key in localSetting) {
//@ts-ignore
this.initialSettings[key] = localSetting[key];
@@ -250,7 +253,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
this.editingSettings[key] = localSetting[key];
} else {
//@ts-ignore
this.initialSettings[key] = this.plugin.settings[key];
this.initialSettings[key] = this.core.settings[key];
//@ts-ignore
this.editingSettings[key] = this.initialSettings[key];
}
@@ -319,7 +322,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
closeSetting() {
// @ts-ignore
this.plugin.app.setting.close();
this.core.app.setting.close();
}
handleElement(element: HTMLElement, func: OnUpdateFunc) {
@@ -381,7 +384,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
requestReload() {
if (this.isShown) {
const newConf = this.plugin.settings;
const newConf = this.core.settings;
const keys = Object.keys(newConf) as (keyof ObsidianLiveSyncSettings)[];
let hasLoaded = false;
for (const k of keys) {
@@ -389,7 +392,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
// Something has changed
if (this.isDirty(k as AllSettingItemKey)) {
// And modified.
this.plugin.confirm.askInPopup(
this.core.confirm.askInPopup(
`config-reloaded-${k}`,
$msg("obsidianLiveSyncSettingTab.msgSettingModified", {
setting: getConfName(k as AllSettingItemKey),
@@ -457,7 +460,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
this.editingSettings.syncOnStart = false;
this.editingSettings.syncOnFileOpen = false;
this.editingSettings.syncAfterMerge = false;
this.plugin.replicator.closeReplication();
this.core.replicator.closeReplication();
await this.saveAllDirtySettings();
this.containerEl.addClass("isWizard");
this.inWizard = true;
@@ -514,8 +517,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
if (this.isConfiguredAs("syncOnStart", true)) return true;
if (this.isConfiguredAs("syncAfterMerge", true)) return true;
if (this.isConfiguredAs("syncOnFileOpen", true)) return true;
if (this.plugin?.replicator?.syncStatus == "CONNECTED") return true;
if (this.plugin?.replicator?.syncStatus == "PAUSED") return true;
if (this.core?.replicator?.syncStatus == "CONNECTED") return true;
if (this.core?.replicator?.syncStatus == "PAUSED") return true;
return false;
}
@@ -605,7 +608,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
await this.saveAllDirtySettings();
this.closeSetting();
await delay(2000);
await this.plugin.rebuilder.$performRebuildDB(method);
await this.core.rebuilder.$performRebuildDB(method);
};
async confirmRebuild() {
if (!(await this.isPassphraseValid())) {
@@ -633,7 +636,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
if (result == OPTION_FETCH) {
if (!(await this.checkWorkingPassphrase())) {
if (
(await this.plugin.confirm.askYesNoDialog($msg("obsidianLiveSyncSettingTab.msgAreYouSureProceed"), {
(await this.core.confirm.askYesNoDialog($msg("obsidianLiveSyncSettingTab.msgAreYouSureProceed"), {
defaultOption: "No",
})) != "yes"
)
@@ -646,16 +649,16 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
await this.saveAllDirtySettings();
await this.applyAllSettings();
if (result == OPTION_FETCH) {
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
await this.core.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
this.services.appLifecycle.scheduleRestart();
this.closeSetting();
// await rebuildDB("localOnly");
} else if (result == OPTION_REBUILD_BOTH) {
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
await this.core.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
this.services.appLifecycle.scheduleRestart();
this.closeSetting();
} else if (result == OPTION_ONLY_SETTING) {
await this.plugin.saveSettings();
await this.services.setting.saveSettingData();
}
}
@@ -868,7 +871,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}
getMinioJournalSyncClient() {
return new JournalSyncMinio(this.plugin.settings, this.plugin.simpleStore, this.plugin);
return new JournalSyncMinio(this.core.settings, this.core.simpleStore, this.core);
}
async resetRemoteBucket() {
const minioJournal = this.getMinioJournalSyncClient();

View File

@@ -165,7 +165,7 @@ export function paneHatch(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement,
}
const obsidianInfo = {
navigator: navigator.userAgent,
fileSystem: this.plugin.services.vault.isStorageInsensitive() ? "insensitive" : "sensitive",
fileSystem: this.core.services.vault.isStorageInsensitive() ? "insensitive" : "sensitive",
};
const msgConfig = `# ---- Obsidian info ----
${stringifyYaml(obsidianInfo)}
@@ -221,7 +221,7 @@ ${stringifyYaml({
void addPanel(paneEl, "Recovery and Repair").then((paneEl) => {
const addResult = async (path: string, file: FilePathWithPrefix | false, fileOnDB: LoadedEntry | false) => {
const storageFileStat = file ? await this.plugin.storageAccess.statHidden(file) : null;
const storageFileStat = file ? await this.core.storageAccess.statHidden(file) : null;
resultArea.appendChild(
this.createEl(resultArea, "div", {}, (el) => {
el.appendChild(this.createEl(el, "h6", { text: path }));
@@ -256,7 +256,7 @@ ${stringifyYaml({
this.createEl(el, "button", { text: "Storage -> Database" }, (buttonEl) => {
buttonEl.onClickEvent(async () => {
if (file.startsWith(".")) {
const addOn = this.plugin.getAddOn<HiddenFileSync>(HiddenFileSync.name);
const addOn = this.core.getAddOn<HiddenFileSync>(HiddenFileSync.name);
if (addOn) {
const file = (await addOn.scanInternalFiles()).find((e) => e.path == path);
if (!file) {
@@ -275,7 +275,7 @@ ${stringifyYaml({
}
}
} else {
if (!(await this.plugin.fileHandler.storeFileToDB(file as FilePath, true))) {
if (!(await this.core.fileHandler.storeFileToDB(file as FilePath, true))) {
Logger(
`Failed to store the file to the database: ${file}`,
LOG_LEVEL_NOTICE
@@ -293,7 +293,7 @@ ${stringifyYaml({
this.createEl(el, "button", { text: "Database -> Storage" }, (buttonEl) => {
buttonEl.onClickEvent(async () => {
if (fileOnDB.path.startsWith(ICHeader)) {
const addOn = this.plugin.getAddOn<HiddenFileSync>(HiddenFileSync.name);
const addOn = this.core.getAddOn<HiddenFileSync>(HiddenFileSync.name);
if (addOn) {
if (
!(await addOn.extractInternalFileFromDatabase(path as FilePath, true))
@@ -307,7 +307,7 @@ ${stringifyYaml({
}
} else {
if (
!(await this.plugin.fileHandler.dbToStorage(
!(await this.core.fileHandler.dbToStorage(
fileOnDB as MetaEntry,
null,
true
@@ -332,7 +332,7 @@ ${stringifyYaml({
const checkBetweenStorageAndDatabase = async (file: FilePathWithPrefix, fileOnDB: LoadedEntry) => {
const dataContent = readAsBlob(fileOnDB);
const content = createBlob(await this.plugin.storageAccess.readHiddenFileBinary(file));
const content = createBlob(await this.core.storageAccess.readHiddenFileBinary(file));
if (await isDocContentSame(content, dataContent)) {
Logger(`Compare: SAME: ${file}`);
} else {
@@ -348,7 +348,7 @@ ${stringifyYaml({
.setButtonText("Recreate all")
.setCta()
.onClick(async () => {
await this.plugin.fileHandler.createAllChunks(true);
await this.core.fileHandler.createAllChunks(true);
})
);
new Setting(paneEl)
@@ -377,21 +377,21 @@ ${stringifyYaml({
.setCta()
.onClick(async () => {
Logger("Start verifying all files", LOG_LEVEL_NOTICE, "verify");
const ignorePatterns = getFileRegExp(this.plugin.settings, "syncInternalFilesIgnorePatterns");
const targetPatterns = getFileRegExp(this.plugin.settings, "syncInternalFilesTargetPatterns");
this.plugin.localDatabase.clearCaches();
const ignorePatterns = getFileRegExp(this.core.settings, "syncInternalFilesIgnorePatterns");
const targetPatterns = getFileRegExp(this.core.settings, "syncInternalFilesTargetPatterns");
this.core.localDatabase.clearCaches();
Logger("Start verifying all files", LOG_LEVEL_NOTICE, "verify");
const files = this.plugin.settings.syncInternalFiles
? await this.plugin.storageAccess.getFilesIncludeHidden("/", targetPatterns, ignorePatterns)
: await this.plugin.storageAccess.getFileNames();
const files = this.core.settings.syncInternalFiles
? await this.core.storageAccess.getFilesIncludeHidden("/", targetPatterns, ignorePatterns)
: await this.core.storageAccess.getFileNames();
const documents = [] as FilePath[];
const adn = this.plugin.localDatabase.findAllDocs();
const adn = this.core.localDatabase.findAllDocs();
for await (const i of adn) {
const path = this.services.path.getPath(i);
if (path.startsWith(ICXHeader)) continue;
if (path.startsWith(PSCHeader)) continue;
if (!this.plugin.settings.syncInternalFiles && path.startsWith(ICHeader)) continue;
if (!this.core.settings.syncInternalFiles && path.startsWith(ICHeader)) continue;
documents.push(stripAllPrefixes(path));
}
const allPaths = [...new Set([...documents, ...files])];
@@ -411,8 +411,8 @@ ${stringifyYaml({
if (shouldBeIgnored(path)) {
return incProc();
}
const stat = (await this.plugin.storageAccess.isExistsIncludeHidden(path))
? await this.plugin.storageAccess.statHidden(path)
const stat = (await this.core.storageAccess.isExistsIncludeHidden(path))
? await this.core.storageAccess.statHidden(path)
: false;
const fileOnStorage = stat != null ? stat : false;
if (!(await this.services.vault.isTargetFile(path))) return incProc();
@@ -422,7 +422,7 @@ ${stringifyYaml({
try {
const isHiddenFile = path.startsWith(".");
const dbPath = isHiddenFile ? addPrefix(path, ICHeader) : path;
const fileOnDB = await this.plugin.localDatabase.getDBEntry(dbPath);
const fileOnDB = await this.core.localDatabase.getDBEntry(dbPath);
if (fileOnDB && this.services.vault.isFileSizeTooLarge(fileOnDB.size))
return incProc();
@@ -466,10 +466,10 @@ ${stringifyYaml({
.setDisabled(false)
.setWarning()
.onClick(async () => {
for await (const docName of this.plugin.localDatabase.findAllDocNames()) {
for await (const docName of this.core.localDatabase.findAllDocNames()) {
if (!docName.startsWith("f:")) {
const idEncoded = await this.services.path.path2id(docName as FilePathWithPrefix);
const doc = await this.plugin.localDatabase.getRaw(docName as DocumentID);
const doc = await this.core.localDatabase.getRaw(docName as DocumentID);
if (!doc) continue;
if (doc.type != "newnote" && doc.type != "plain") {
continue;
@@ -482,7 +482,7 @@ ${stringifyYaml({
// @ts-ignore
delete newDoc._rev;
try {
const obfuscatedDoc = await this.plugin.localDatabase.getRaw(idEncoded, {
const obfuscatedDoc = await this.core.localDatabase.getRaw(idEncoded, {
revs_info: true,
});
// Unfortunately we have to delete one of them.
@@ -499,14 +499,14 @@ ${stringifyYaml({
-32
);
}
const ret = await this.plugin.localDatabase.putRaw(newDoc, { force: true });
const ret = await this.core.localDatabase.putRaw(newDoc, { force: true });
if (ret.ok) {
Logger(
`${docName} has been converted as conflicted document`,
LOG_LEVEL_NOTICE
);
doc._deleted = true;
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
if ((await this.core.localDatabase.putRaw(doc)).ok) {
Logger(`Old ${docName} has been deleted`, LOG_LEVEL_NOTICE);
}
await this.services.conflict.queueCheckForIfOpen(docName as FilePathWithPrefix);
@@ -517,10 +517,10 @@ ${stringifyYaml({
} catch (ex: any) {
if (ex?.status == 404) {
// We can perform this safely
if ((await this.plugin.localDatabase.putRaw(newDoc)).ok) {
if ((await this.core.localDatabase.putRaw(newDoc)).ok) {
Logger(`${docName} has been converted`, LOG_LEVEL_NOTICE);
doc._deleted = true;
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
if ((await this.core.localDatabase.putRaw(doc)).ok) {
Logger(`Old ${docName} has been deleted`, LOG_LEVEL_NOTICE);
}
}
@@ -555,7 +555,7 @@ ${stringifyYaml({
.setWarning()
.onClick(async () => {
Logger(`Deleting customization sync data`, LOG_LEVEL_NOTICE);
const entriesToDelete = await this.plugin.localDatabase.allDocsRaw({
const entriesToDelete = await this.core.localDatabase.allDocsRaw({
startkey: "ix:",
endkey: "ix:\u{10ffff}",
include_docs: true,
@@ -564,7 +564,7 @@ ${stringifyYaml({
...e.doc,
_deleted: true,
}));
const r = await this.plugin.localDatabase.bulkDocsRaw(newData as any[]);
const r = await this.core.localDatabase.bulkDocsRaw(newData as any[]);
// Do not care about the result.
Logger(
`${r.length} items have been removed, to confirm how many items are left, please perform it again.`,

View File

@@ -11,8 +11,8 @@ export function paneMaintenance(
paneEl: HTMLElement,
{ addPanel }: PageFunctions
): void {
const isRemoteLockedAndDeviceNotAccepted = () => this.plugin?.replicator?.remoteLockedAndDeviceNotAccepted;
const isRemoteLocked = () => this.plugin?.replicator?.remoteLocked;
const isRemoteLockedAndDeviceNotAccepted = () => this.core?.replicator?.remoteLockedAndDeviceNotAccepted;
const isRemoteLocked = () => this.core?.replicator?.remoteLocked;
// if (this.plugin?.replicator?.remoteLockedAndDeviceNotAccepted) {
this.createEl(
paneEl,
@@ -92,7 +92,7 @@ export function paneMaintenance(
.setDisabled(false)
.setWarning()
.onClick(async () => {
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG, "");
await this.core.storageAccess.writeFileAuto(FLAGMD_REDFLAG, "");
this.services.appLifecycle.performRestart();
})
);
@@ -108,7 +108,7 @@ export function paneMaintenance(
.setCta()
.setDisabled(false)
.onClick(async () => {
await this.plugin.storageAccess.writeFileAuto(FlagFilesHumanReadable.FETCH_ALL, "");
await this.core.storageAccess.writeFileAuto(FlagFilesHumanReadable.FETCH_ALL, "");
this.services.appLifecycle.performRestart();
})
);
@@ -121,7 +121,7 @@ export function paneMaintenance(
.setCta()
.setDisabled(false)
.onClick(async () => {
await this.plugin.storageAccess.writeFileAuto(FlagFilesHumanReadable.REBUILD_ALL, "");
await this.core.storageAccess.writeFileAuto(FlagFilesHumanReadable.REBUILD_ALL, "");
this.services.appLifecycle.performRestart();
})
);
@@ -137,8 +137,8 @@ export function paneMaintenance(
.setWarning()
.setDisabled(false)
.onClick(async () => {
if (this.plugin.replicator instanceof LiveSyncCouchDBReplicator) {
await this.plugin.replicator.sendChunks(this.plugin.settings, undefined, true, 0);
if (this.core.replicator instanceof LiveSyncCouchDBReplicator) {
await this.core.replicator.sendChunks(this.core.settings, undefined, true, 0);
}
})
)
@@ -299,7 +299,7 @@ export function paneMaintenance(
.setButtonText("Perform")
.setDisabled(false)
.onClick(async () => {
const replicator = this.plugin.replicator as LiveSyncCouchDBReplicator;
const replicator = this.core.replicator as LiveSyncCouchDBReplicator;
Logger(`Cleanup has been began`, LOG_LEVEL_NOTICE, "compaction");
if (await replicator.compactRemote(this.editingSettings)) {
Logger(`Cleanup has been completed!`, LOG_LEVEL_NOTICE, "compaction");

View File

@@ -31,7 +31,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
void addPanel(paneEl, "Compatibility (Database structure)").then((paneEl) => {
const migrateAllToIndexedDB = async () => {
const dbToName = this.plugin.localDatabase.dbname + SuffixDatabaseName + ExtraSuffixIndexedDB;
const dbToName = this.core.localDatabase.dbname + SuffixDatabaseName + ExtraSuffixIndexedDB;
const options = {
adapter: "indexeddb",
//@ts-ignore :missing def
@@ -42,18 +42,19 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
const openTo = () => {
return new PouchDB(dbToName, options);
};
if (await migrateDatabases("to IndexedDB", this.plugin.localDatabase.localDatabase, openTo)) {
if (await migrateDatabases("to IndexedDB", this.core.localDatabase.localDatabase, openTo)) {
Logger(
"Migration to IndexedDB completed. Obsidian will be restarted with new configuration immediately.",
LOG_LEVEL_NOTICE
);
this.plugin.settings.useIndexedDBAdapter = true;
await this.services.setting.saveSettingData();
// this.plugin.settings.useIndexedDBAdapter = true;
// await this.services.setting.saveSettingData();
await this.core.services.setting.applyPartial({ useIndexedDBAdapter: true }, true);
this.services.appLifecycle.performRestart();
}
};
const migrateAllToIDB = async () => {
const dbToName = this.plugin.localDatabase.dbname + SuffixDatabaseName;
const dbToName = this.core.localDatabase.dbname + SuffixDatabaseName;
const options = {
adapter: "idb",
auto_compaction: false,
@@ -62,13 +63,14 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
const openTo = () => {
return new PouchDB(dbToName, options);
};
if (await migrateDatabases("to IDB", this.plugin.localDatabase.localDatabase, openTo)) {
if (await migrateDatabases("to IDB", this.core.localDatabase.localDatabase, openTo)) {
Logger(
"Migration to IDB completed. Obsidian will be restarted with new configuration immediately.",
LOG_LEVEL_NOTICE
);
this.plugin.settings.useIndexedDBAdapter = false;
await this.services.setting.saveSettingData();
await this.core.services.setting.applyPartial({ useIndexedDBAdapter: false }, true);
// this.core.settings.useIndexedDBAdapter = false;
// await this.services.setting.saveSettingData();
this.services.appLifecycle.performRestart();
}
};
@@ -151,7 +153,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
} as Record<HashAlgorithm, string>,
});
this.addOnSaved("hashAlg", async () => {
await this.plugin.localDatabase._prepareHashFunctions();
await this.core.localDatabase._prepareHashFunctions();
});
});
void addPanel(paneEl, "Edge case addressing (Behaviour)").then((paneEl) => {
@@ -215,7 +217,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
this.addOnSaved("maxMTimeForReflectEvents", async (key) => {
const buttons = ["Restart Now", "Later"] as const;
const reboot = await this.plugin.confirm.askSelectStringDialogue(
const reboot = await this.core.confirm.askSelectStringDialogue(
"Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?",
buttons,
{

View File

@@ -68,7 +68,7 @@ export function paneRemoteConfig(
.addButton((button) =>
button
.onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
await setupManager.onlyE2EEConfiguration(UserMode.Update, originalSettings);
updateE2EESummary();
@@ -79,7 +79,7 @@ export function paneRemoteConfig(
.addButton((button) =>
button
.onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
await setupManager.onConfigureManually(originalSettings, UserMode.Update);
updateE2EESummary();
@@ -101,7 +101,7 @@ export function paneRemoteConfig(
.setButtonText("Change Remote and Setup")
.setCta()
.onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
await setupManager.onSelectServer(originalSettings, UserMode.Update);
})
@@ -127,7 +127,7 @@ export function paneRemoteConfig(
.setButtonText("Configure")
.setCta()
.onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
await setupManager.onCouchDBManualSetup(
UserMode.Update,
@@ -162,7 +162,7 @@ export function paneRemoteConfig(
.setButtonText("Configure")
.setCta()
.onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
await setupManager.onBucketManualSetup(
UserMode.Update,
@@ -202,7 +202,7 @@ export function paneRemoteConfig(
.setButtonText("Configure")
.setCta()
.onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
await setupManager.onP2PManualSetup(
UserMode.Update,

View File

@@ -35,7 +35,7 @@ export function paneSetup(
.setDesc($msg("Rerun the onboarding wizard to set up Self-hosted LiveSync again."))
.addButton((text) => {
text.setButtonText($msg("Rerun Wizard")).onClick(async () => {
const setupManager = this.plugin.getModule(SetupManager);
const setupManager = this.core.getModule(SetupManager);
await setupManager.onOnboard(UserMode.ExistingUser);
// await this.plugin.moduleSetupObsidian.onBoardingWizard(true);
});
@@ -86,14 +86,14 @@ export function paneSetup(
text.setButtonText($msg("obsidianLiveSyncSettingTab.btnDiscard"))
.onClick(async () => {
if (
(await this.plugin.confirm.askYesNoDialog(
(await this.core.confirm.askYesNoDialog(
$msg("obsidianLiveSyncSettingTab.msgDiscardConfirmation"),
{ defaultOption: "No" }
)) == "yes"
) {
this.editingSettings = { ...this.editingSettings, ...DEFAULT_SETTINGS };
await this.saveAllDirtySettings();
this.plugin.settings = { ...DEFAULT_SETTINGS };
this.core.settings = { ...DEFAULT_SETTINGS };
await this.services.setting.saveSettingData();
await this.services.database.resetDatabase();
// await this.plugin.initializeDatabase();

View File

@@ -109,7 +109,7 @@ export function paneSyncSettings(
await this.rebuildDB("localOnly");
// this.resetEditingSettings();
if (
(await this.plugin.confirm.askYesNoDialog(
(await this.core.confirm.askYesNoDialog(
$msg("obsidianLiveSyncSettingTab.msgGenerateSetupURI"),
{
defaultOption: "Yes",

View File

@@ -80,7 +80,7 @@ export class ModuleLiveSyncMain extends AbstractModule {
initialiseWorkerModule();
await this.services.appLifecycle.onWireUpEvents();
// debugger;
eventHub.emitEvent(EVENT_PLUGIN_LOADED, this.core);
eventHub.emitEvent(EVENT_PLUGIN_LOADED);
this._log($msg("moduleLiveSyncMain.logLoadingPlugin"));
if (!(await this.services.appLifecycle.onInitialise())) {
this._log($msg("moduleLiveSyncMain.logPluginInitCancelled"), LOG_LEVEL_NOTICE);

View File

@@ -171,4 +171,18 @@ export class ObsidianAPIService extends InjectableAPIService<ObsidianServiceCont
statusText: `${r.status}`,
});
}
override addStatusBarItem(): HTMLElement | undefined {
return this.context.plugin.addStatusBarItem();
}
override setInterval(handler: () => void, timeout: number): number {
const timerId = globalThis.setInterval(handler, timeout) as unknown as number;
this.context.plugin.registerInterval(timerId);
return timerId;
}
override getSystemConfigDir() {
return this.app.vault.configDir;
}
}