mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-10 09:41:55 +00:00
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:
467
src/main.ts
467
src/main.ts
@@ -1,396 +1,110 @@
|
||||
import { Notice, Plugin, type App, type PluginManifest } from "./deps";
|
||||
import {
|
||||
type EntryDoc,
|
||||
type ObsidianLiveSyncSettings,
|
||||
type HasSettings,
|
||||
LOG_LEVEL_INFO,
|
||||
} from "./lib/src/common/types.ts";
|
||||
import { type SimpleStore } from "./lib/src/common/utils.ts";
|
||||
import { type LiveSyncLocalDBEnv } from "./lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||
import { type LiveSyncReplicatorEnv } from "./lib/src/replication/LiveSyncAbstractReplicator.js";
|
||||
|
||||
import { LiveSyncCommands } from "./features/LiveSyncCommands.ts";
|
||||
import { HiddenFileSync } from "./features/HiddenFileSync/CmdHiddenFileSync.ts";
|
||||
import { ConfigSync } from "./features/ConfigSync/CmdConfigSync.ts";
|
||||
import { type LiveSyncJournalReplicatorEnv } from "./lib/src/replication/journal/LiveSyncJournalReplicator.js";
|
||||
import { type LiveSyncCouchDBReplicatorEnv } from "./lib/src/replication/couchdb/LiveSyncReplicator.js";
|
||||
import type { CheckPointInfo } from "./lib/src/replication/journal/JournalSyncTypes.js";
|
||||
import type { IObsidianModule } from "./modules/AbstractObsidianModule.ts";
|
||||
import { ModuleDev } from "./modules/extras/ModuleDev.ts";
|
||||
import { ModuleMigration } from "./modules/essential/ModuleMigration.ts";
|
||||
|
||||
// import { ModuleCheckRemoteSize } from "./modules/essentialObsidian/ModuleCheckRemoteSize.ts";
|
||||
import { ModuleConflictResolver } from "./modules/coreFeatures/ModuleConflictResolver.ts";
|
||||
import { ModuleInteractiveConflictResolver } from "./modules/features/ModuleInteractiveConflictResolver.ts";
|
||||
import { ModuleLog } from "./modules/features/ModuleLog.ts";
|
||||
// import { ModuleRedFlag } from "./modules/coreFeatures/ModuleRedFlag.ts";
|
||||
import { ModuleObsidianMenu } from "./modules/essentialObsidian/ModuleObsidianMenu.ts";
|
||||
import { ModuleSetupObsidian } from "./modules/features/ModuleSetupObsidian.ts";
|
||||
import { SetupManager } from "./modules/features/SetupManager.ts";
|
||||
import type { StorageAccess } from "@lib/interfaces/StorageAccess.ts";
|
||||
import type { Confirm } from "./lib/src/interfaces/Confirm.ts";
|
||||
import type { Rebuilder } from "@lib/interfaces/DatabaseRebuilder.ts";
|
||||
import type { DatabaseFileAccess } from "@lib/interfaces/DatabaseFileAccess.ts";
|
||||
import { ModuleObsidianEvents } from "./modules/essentialObsidian/ModuleObsidianEvents.ts";
|
||||
import { AbstractModule } from "./modules/AbstractModule.ts";
|
||||
import { ModuleObsidianSettingDialogue } from "./modules/features/ModuleObsidianSettingTab.ts";
|
||||
import { ModuleObsidianDocumentHistory } from "./modules/features/ModuleObsidianDocumentHistory.ts";
|
||||
import { ModuleObsidianGlobalHistory } from "./modules/features/ModuleGlobalHistory.ts";
|
||||
import { ModuleObsidianSettingsAsMarkdown } from "./modules/features/ModuleObsidianSettingAsMarkdown.ts";
|
||||
// import { ModuleInitializerFile } from "./modules/essential/ModuleInitializerFile.ts";
|
||||
import { ModuleReplicator } from "./modules/core/ModuleReplicator.ts";
|
||||
import { ModuleReplicatorCouchDB } from "./modules/core/ModuleReplicatorCouchDB.ts";
|
||||
import { ModuleReplicatorMinIO } from "./modules/core/ModuleReplicatorMinIO.ts";
|
||||
import { ModulePeriodicProcess } from "./modules/core/ModulePeriodicProcess.ts";
|
||||
import { ModuleConflictChecker } from "./modules/coreFeatures/ModuleConflictChecker.ts";
|
||||
import { ModuleResolvingMismatchedTweaks } from "./modules/coreFeatures/ModuleResolveMismatchedTweaks.ts";
|
||||
import { ModuleIntegratedTest } from "./modules/extras/ModuleIntegratedTest.ts";
|
||||
import { ModuleReplicateTest } from "./modules/extras/ModuleReplicateTest.ts";
|
||||
import { ModuleLiveSyncMain } from "./modules/main/ModuleLiveSyncMain.ts";
|
||||
import { LocalDatabaseMaintenance } from "./features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts";
|
||||
import { P2PReplicator } from "./features/P2PSync/CmdP2PReplicator.ts";
|
||||
import type { InjectableServiceHub } from "./lib/src/services/implements/injectable/InjectableServiceHub.ts";
|
||||
import { ObsidianServiceHub } from "./modules/services/ObsidianServiceHub.ts";
|
||||
import type { ServiceContext } from "./lib/src/services/base/ServiceBase.ts";
|
||||
import { ServiceRebuilder } from "@lib/serviceModules/Rebuilder.ts";
|
||||
import type { IFileHandler } from "@lib/interfaces/FileHandler.ts";
|
||||
import { ServiceDatabaseFileAccess } from "@/serviceModules/DatabaseFileAccess.ts";
|
||||
import { ServiceFileAccessObsidian } from "@/serviceModules/ServiceFileAccessImpl.ts";
|
||||
import { StorageAccessManager } from "@lib/managers/StorageProcessingManager.ts";
|
||||
import { __$checkInstanceBinding } from "./lib/src/dev/checks.ts";
|
||||
import { ServiceFileHandler } from "./serviceModules/FileHandler.ts";
|
||||
import { FileAccessObsidian } from "./serviceModules/FileAccessObsidian.ts";
|
||||
import { StorageEventManagerObsidian } from "./managers/StorageEventManagerObsidian.ts";
|
||||
import { onLayoutReadyFeatures } from "./serviceFeatures/onLayoutReady.ts";
|
||||
import type { ServiceModules } from "./types.ts";
|
||||
import { useTargetFilters } from "@lib/serviceFeatures/targetFilter.ts";
|
||||
import { setNoticeClass } from "@lib/mock_and_interop/wrapper.ts";
|
||||
import { useCheckRemoteSize } from "./lib/src/serviceFeatures/checkRemoteSize.ts";
|
||||
import { useRedFlagFeatures } from "./serviceFeatures/redFlag.ts";
|
||||
import { useOfflineScanner } from "./lib/src/serviceFeatures/offlineScanner.ts";
|
||||
import type { ObsidianServiceContext } from "./lib/src/services/implements/obsidian/ObsidianServiceContext.ts";
|
||||
import { LiveSyncBaseCore } from "./LiveSyncBaseCore.ts";
|
||||
import { ModuleSetupObsidian } from "./modules/features/ModuleSetupObsidian.ts";
|
||||
import { ModuleObsidianMenu } from "./modules/essentialObsidian/ModuleObsidianMenu.ts";
|
||||
import { ModuleObsidianSettingsAsMarkdown } from "./modules/features/ModuleObsidianSettingAsMarkdown.ts";
|
||||
import { SetupManager } from "./modules/features/SetupManager.ts";
|
||||
import { ModuleMigration } from "./modules/essential/ModuleMigration.ts";
|
||||
import { enableI18nFeature } from "./serviceFeatures/onLayoutReady/enablei18n.ts";
|
||||
export type LiveSyncCore = LiveSyncBaseCore<ObsidianServiceContext, LiveSyncCommands>;
|
||||
export default class ObsidianLiveSyncPlugin extends Plugin {
|
||||
core: LiveSyncCore;
|
||||
|
||||
export default class ObsidianLiveSyncPlugin
|
||||
extends Plugin
|
||||
implements
|
||||
LiveSyncLocalDBEnv,
|
||||
LiveSyncReplicatorEnv,
|
||||
LiveSyncJournalReplicatorEnv,
|
||||
LiveSyncCouchDBReplicatorEnv,
|
||||
HasSettings<ObsidianLiveSyncSettings>
|
||||
{
|
||||
/**
|
||||
* The service hub for managing all services.
|
||||
*/
|
||||
_services: InjectableServiceHub<ServiceContext> | undefined = undefined;
|
||||
|
||||
get services() {
|
||||
if (!this._services) {
|
||||
throw new Error("Services not initialised yet");
|
||||
}
|
||||
return this._services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service Modules
|
||||
*/
|
||||
protected _serviceModules: ServiceModules;
|
||||
|
||||
get serviceModules() {
|
||||
return this._serviceModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* addOns: Non-essential and graphically features
|
||||
*/
|
||||
addOns = [] as LiveSyncCommands[];
|
||||
|
||||
/**
|
||||
* The modules of the plug-in. Modules are responsible for specific features or functionalities of the plug-in, such as file handling, conflict resolution, replication, etc.
|
||||
*/
|
||||
private modules = [
|
||||
// Move to registerModules
|
||||
] as (IObsidianModule | AbstractModule)[];
|
||||
|
||||
/**
|
||||
* register an add-onn to the plug-in.
|
||||
* Add-ons are features that are not essential to the core functionality of the plugin,
|
||||
* @param addOn
|
||||
*/
|
||||
private _registerAddOn(addOn: LiveSyncCommands) {
|
||||
this.addOns.push(addOn);
|
||||
this.services.appLifecycle.onUnload.addHandler(() => Promise.resolve(addOn.onunload()).then(() => true));
|
||||
}
|
||||
|
||||
private registerAddOns() {
|
||||
this._registerAddOn(new ConfigSync(this));
|
||||
this._registerAddOn(new HiddenFileSync(this));
|
||||
this._registerAddOn(new LocalDatabaseMaintenance(this));
|
||||
this._registerAddOn(new P2PReplicator(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an add-on by its class name. Returns undefined if not found.
|
||||
* @param cls
|
||||
* @returns
|
||||
*/
|
||||
getAddOn<T extends LiveSyncCommands>(cls: string) {
|
||||
for (const addon of this.addOns) {
|
||||
if (addon.constructor.name == cls) return addon as T;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a module by its class. Throws an error if not found.
|
||||
* Mostly used for getting SetupManager.
|
||||
* @param constructor
|
||||
* @returns
|
||||
*/
|
||||
getModule<T extends IObsidianModule>(constructor: new (...args: any[]) => T): T {
|
||||
for (const module of this.modules) {
|
||||
if (module.constructor === constructor) return module as T;
|
||||
}
|
||||
throw new Error(`Module ${constructor} not found or not loaded.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a module to the plug-in.
|
||||
* @param module The module to register.
|
||||
*/
|
||||
private _registerModule(module: IObsidianModule) {
|
||||
this.modules.push(module);
|
||||
}
|
||||
private registerModules() {
|
||||
this._registerModule(new ModuleLiveSyncMain(this));
|
||||
this._registerModule(new ModuleConflictChecker(this));
|
||||
this._registerModule(new ModuleReplicatorMinIO(this));
|
||||
this._registerModule(new ModuleReplicatorCouchDB(this));
|
||||
this._registerModule(new ModuleReplicator(this));
|
||||
this._registerModule(new ModuleConflictResolver(this));
|
||||
this._registerModule(new ModulePeriodicProcess(this));
|
||||
// this._registerModule(new ModuleInitializerFile(this));
|
||||
this._registerModule(new ModuleObsidianEvents(this, this));
|
||||
this._registerModule(new ModuleResolvingMismatchedTweaks(this));
|
||||
this._registerModule(new ModuleObsidianSettingsAsMarkdown(this));
|
||||
this._registerModule(new ModuleObsidianSettingDialogue(this, this));
|
||||
this._registerModule(new ModuleLog(this, this));
|
||||
this._registerModule(new ModuleObsidianMenu(this));
|
||||
this._registerModule(new ModuleSetupObsidian(this));
|
||||
this._registerModule(new ModuleObsidianDocumentHistory(this, this));
|
||||
this._registerModule(new ModuleMigration(this));
|
||||
// this._registerModule(new ModuleRedFlag(this));
|
||||
this._registerModule(new ModuleInteractiveConflictResolver(this, this));
|
||||
this._registerModule(new ModuleObsidianGlobalHistory(this, this));
|
||||
// this._registerModule(new ModuleCheckRemoteSize(this));
|
||||
// Test and Dev Modules
|
||||
this._registerModule(new ModuleDev(this, this));
|
||||
this._registerModule(new ModuleReplicateTest(this, this));
|
||||
this._registerModule(new ModuleIntegratedTest(this, this));
|
||||
this._registerModule(new SetupManager(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind module functions to services.
|
||||
*/
|
||||
private bindModuleFunctions() {
|
||||
for (const module of this.modules) {
|
||||
if (module instanceof AbstractModule) {
|
||||
module.onBindFunction(this, this.services);
|
||||
__$checkInstanceBinding(module); // Check if all functions are properly bound, and log warnings if not.
|
||||
} else {
|
||||
this.services.API.addLog(
|
||||
`Module ${module.constructor.name} does not have onBindFunction, skipping binding.`,
|
||||
LOG_LEVEL_INFO
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.UI.confirm instead. The confirm function to show a confirmation dialog to the user.
|
||||
*/
|
||||
get confirm(): Confirm {
|
||||
return this.services.UI.confirm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.setting.currentSettings instead. The current settings of the plug-in.
|
||||
*/
|
||||
get settings() {
|
||||
return this.services.setting.settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.setting.settings instead. Set the settings of the plug-in.
|
||||
*/
|
||||
set settings(value: ObsidianLiveSyncSettings) {
|
||||
this.services.setting.settings = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.setting.currentSettings instead. Get the settings of the plug-in.
|
||||
* @returns The current settings of the plug-in.
|
||||
*/
|
||||
getSettings(): ObsidianLiveSyncSettings {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.database.localDatabase instead. The local database instance.
|
||||
*/
|
||||
get localDatabase() {
|
||||
return this.services.database.localDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.database.localDatabase instead. Get the PouchDB database instance. Note that this is not the same as the local database instance, which is a wrapper around the PouchDB database.
|
||||
* @returns The PouchDB database instance.
|
||||
*/
|
||||
getDatabase(): PouchDB.Database<EntryDoc> {
|
||||
return this.localDatabase.localDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.keyValueDB.simpleStore instead. A simple key-value store for storing non-file data, such as checkpoints, sync status, etc.
|
||||
*/
|
||||
get simpleStore() {
|
||||
return this.services.keyValueDB.simpleStore as SimpleStore<CheckPointInfo>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.replication.getActiveReplicator instead. Get the active replicator instance. Note that there can be multiple replicators, but only one can be active at a time.
|
||||
*/
|
||||
get replicator() {
|
||||
return this.services.replicator.getActiveReplicator()!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete Use services.keyValueDB.kvDB instead. Get the key-value database instance. This is used for storing large data that cannot be stored in the simple store, such as file metadata, etc.
|
||||
*/
|
||||
get kvDB() {
|
||||
return this.services.keyValueDB.kvDB;
|
||||
}
|
||||
|
||||
/// Modules which were relied on services
|
||||
/**
|
||||
* Storage Accessor for handling file operations.
|
||||
* @obsolete Use serviceModules.storageAccess instead.
|
||||
*/
|
||||
get storageAccess(): StorageAccess {
|
||||
return this.serviceModules.storageAccess;
|
||||
}
|
||||
/**
|
||||
* Database File Accessor for handling file operations related to the database, such as exporting the database, importing from a file, etc.
|
||||
* @obsolete Use serviceModules.databaseFileAccess instead.
|
||||
*/
|
||||
get databaseFileAccess(): DatabaseFileAccess {
|
||||
return this.serviceModules.databaseFileAccess;
|
||||
}
|
||||
/**
|
||||
* File Handler for handling file operations related to replication, such as resolving conflicts, applying changes from replication, etc.
|
||||
* @obsolete Use serviceModules.fileHandler instead.
|
||||
*/
|
||||
get fileHandler(): IFileHandler {
|
||||
return this.serviceModules.fileHandler;
|
||||
}
|
||||
/**
|
||||
* Rebuilder for handling database rebuilding operations.
|
||||
* @obsolete Use serviceModules.rebuilder instead.
|
||||
*/
|
||||
get rebuilder(): Rebuilder {
|
||||
return this.serviceModules.rebuilder;
|
||||
}
|
||||
|
||||
// requestCount = reactiveSource(0);
|
||||
// responseCount = reactiveSource(0);
|
||||
// totalQueued = reactiveSource(0);
|
||||
// batched = reactiveSource(0);
|
||||
// processing = reactiveSource(0);
|
||||
// databaseQueueCount = reactiveSource(0);
|
||||
// storageApplyingCount = reactiveSource(0);
|
||||
// replicationResultCount = reactiveSource(0);
|
||||
|
||||
// pendingFileEventCount = reactiveSource(0);
|
||||
// processingFileEventCount = reactiveSource(0);
|
||||
|
||||
// _totalProcessingCount?: ReactiveValue<number>;
|
||||
|
||||
// replicationStat = reactiveSource({
|
||||
// sent: 0,
|
||||
// arrived: 0,
|
||||
// maxPullSeq: 0,
|
||||
// maxPushSeq: 0,
|
||||
// lastSyncPullSeq: 0,
|
||||
// lastSyncPushSeq: 0,
|
||||
// syncStatus: "CLOSED" as DatabaseConnectingStatus,
|
||||
// });
|
||||
|
||||
private initialiseServices() {
|
||||
this._services = new ObsidianServiceHub(this);
|
||||
}
|
||||
/**
|
||||
* Initialise service modules.
|
||||
*/
|
||||
private initialiseServiceModules() {
|
||||
private initialiseServiceModules(
|
||||
core: LiveSyncBaseCore<ObsidianServiceContext, LiveSyncCommands>,
|
||||
services: InjectableServiceHub<ObsidianServiceContext>
|
||||
): ServiceModules {
|
||||
const storageAccessManager = new StorageAccessManager();
|
||||
// If we want to implement to the other platform, implement ObsidianXXXXXService.
|
||||
const vaultAccess = new FileAccessObsidian(this.app, {
|
||||
storageAccessManager: storageAccessManager,
|
||||
vaultService: this.services.vault,
|
||||
settingService: this.services.setting,
|
||||
APIService: this.services.API,
|
||||
pathService: this.services.path,
|
||||
vaultService: services.vault,
|
||||
settingService: services.setting,
|
||||
APIService: services.API,
|
||||
pathService: services.path,
|
||||
});
|
||||
const storageEventManager = new StorageEventManagerObsidian(this, this, {
|
||||
fileProcessing: this.services.fileProcessing,
|
||||
setting: this.services.setting,
|
||||
vaultService: this.services.vault,
|
||||
const storageEventManager = new StorageEventManagerObsidian(this, core, {
|
||||
fileProcessing: services.fileProcessing,
|
||||
setting: services.setting,
|
||||
vaultService: services.vault,
|
||||
storageAccessManager: storageAccessManager,
|
||||
APIService: this.services.API,
|
||||
APIService: services.API,
|
||||
});
|
||||
const storageAccess = new ServiceFileAccessObsidian({
|
||||
API: this.services.API,
|
||||
setting: this.services.setting,
|
||||
fileProcessing: this.services.fileProcessing,
|
||||
vault: this.services.vault,
|
||||
appLifecycle: this.services.appLifecycle,
|
||||
API: services.API,
|
||||
setting: services.setting,
|
||||
fileProcessing: services.fileProcessing,
|
||||
vault: services.vault,
|
||||
appLifecycle: services.appLifecycle,
|
||||
storageEventManager: storageEventManager,
|
||||
storageAccessManager: storageAccessManager,
|
||||
vaultAccess: vaultAccess,
|
||||
});
|
||||
|
||||
const databaseFileAccess = new ServiceDatabaseFileAccess({
|
||||
API: this.services.API,
|
||||
database: this.services.database,
|
||||
path: this.services.path,
|
||||
API: services.API,
|
||||
database: services.database,
|
||||
path: services.path,
|
||||
storageAccess: storageAccess,
|
||||
vault: this.services.vault,
|
||||
vault: services.vault,
|
||||
});
|
||||
|
||||
const fileHandler = new ServiceFileHandler({
|
||||
API: this.services.API,
|
||||
API: services.API,
|
||||
databaseFileAccess: databaseFileAccess,
|
||||
conflict: this.services.conflict,
|
||||
setting: this.services.setting,
|
||||
fileProcessing: this.services.fileProcessing,
|
||||
vault: this.services.vault,
|
||||
path: this.services.path,
|
||||
replication: this.services.replication,
|
||||
conflict: services.conflict,
|
||||
setting: services.setting,
|
||||
fileProcessing: services.fileProcessing,
|
||||
vault: services.vault,
|
||||
path: services.path,
|
||||
replication: services.replication,
|
||||
storageAccess: storageAccess,
|
||||
});
|
||||
const rebuilder = new ServiceRebuilder({
|
||||
API: this.services.API,
|
||||
database: this.services.database,
|
||||
appLifecycle: this.services.appLifecycle,
|
||||
setting: this.services.setting,
|
||||
remote: this.services.remote,
|
||||
databaseEvents: this.services.databaseEvents,
|
||||
replication: this.services.replication,
|
||||
replicator: this.services.replicator,
|
||||
UI: this.services.UI,
|
||||
vault: this.services.vault,
|
||||
API: services.API,
|
||||
database: services.database,
|
||||
appLifecycle: services.appLifecycle,
|
||||
setting: services.setting,
|
||||
remote: services.remote,
|
||||
databaseEvents: services.databaseEvents,
|
||||
replication: services.replication,
|
||||
replicator: services.replicator,
|
||||
UI: services.UI,
|
||||
vault: services.vault,
|
||||
fileHandler: fileHandler,
|
||||
storageAccess: storageAccess,
|
||||
control: this.services.control,
|
||||
control: services.control,
|
||||
});
|
||||
return {
|
||||
rebuilder,
|
||||
@@ -404,24 +118,7 @@ export default class ObsidianLiveSyncPlugin
|
||||
* @obsolete Use services.setting.saveSettingData instead. Save the settings to the disk. This is usually called after changing the settings in the code, to persist the changes.
|
||||
*/
|
||||
async saveSettings() {
|
||||
await this.services.setting.saveSettingData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise ServiceFeatures.
|
||||
* (Please refer `serviceFeatures` for more details)
|
||||
*/
|
||||
initialiseServiceFeatures() {
|
||||
for (const feature of onLayoutReadyFeatures) {
|
||||
const curriedFeature = () => feature(this);
|
||||
this.services.appLifecycle.onLayoutReady.addHandler(curriedFeature);
|
||||
}
|
||||
useRedFlagFeatures(this);
|
||||
useOfflineScanner(this);
|
||||
|
||||
// enable target filter feature.
|
||||
useTargetFilters(this);
|
||||
useCheckRemoteSize(this);
|
||||
await this.core.services.setting.saveSettingData();
|
||||
}
|
||||
|
||||
constructor(app: App, manifest: PluginManifest) {
|
||||
@@ -429,26 +126,60 @@ export default class ObsidianLiveSyncPlugin
|
||||
// Maybe no more need to setNoticeClass, but for safety, set it in the constructor of the main plugin class.
|
||||
// TODO: remove this.
|
||||
setNoticeClass(Notice);
|
||||
this.initialiseServices();
|
||||
this.registerModules();
|
||||
this.registerAddOns();
|
||||
this._serviceModules = this.initialiseServiceModules();
|
||||
this.initialiseServiceFeatures();
|
||||
this.bindModuleFunctions();
|
||||
|
||||
const serviceHub = new ObsidianServiceHub(this);
|
||||
|
||||
this.core = new LiveSyncBaseCore(
|
||||
serviceHub,
|
||||
(core, serviceHub) => {
|
||||
return this.initialiseServiceModules(core, serviceHub);
|
||||
},
|
||||
(core) => {
|
||||
const extraModules = [
|
||||
new ModuleObsidianEvents(this, core),
|
||||
new ModuleObsidianSettingDialogue(this, core),
|
||||
new ModuleObsidianMenu(core),
|
||||
new ModuleSetupObsidian(core),
|
||||
new ModuleObsidianSettingsAsMarkdown(core),
|
||||
new ModuleLog(this, core),
|
||||
new ModuleObsidianDocumentHistory(this, core),
|
||||
new ModuleInteractiveConflictResolver(this, core),
|
||||
new ModuleObsidianGlobalHistory(this, core),
|
||||
new ModuleDev(this, core),
|
||||
new ModuleReplicateTest(this, core),
|
||||
new ModuleIntegratedTest(this, core),
|
||||
new SetupManager(core), // this should be moved to core?
|
||||
new ModuleMigration(core),
|
||||
];
|
||||
return extraModules;
|
||||
},
|
||||
(core) => {
|
||||
const addOns = [
|
||||
new ConfigSync(this, core),
|
||||
new HiddenFileSync(this, core),
|
||||
new LocalDatabaseMaintenance(this, core),
|
||||
new P2PReplicator(this, core),
|
||||
];
|
||||
return addOns;
|
||||
},
|
||||
(core) => {
|
||||
//TODO Fix: useXXXX
|
||||
const featuresInitialiser = enableI18nFeature;
|
||||
const curriedFeature = () => featuresInitialiser(core);
|
||||
core.services.appLifecycle.onLayoutReady.addHandler(curriedFeature);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async _startUp() {
|
||||
if (!(await this.services.control.onLoad())) return;
|
||||
const onReady = this.services.control.onReady.bind(this.services.control);
|
||||
if (!(await this.core.services.control.onLoad())) return;
|
||||
const onReady = this.core.services.control.onReady.bind(this.core.services.control);
|
||||
this.app.workspace.onLayoutReady(onReady);
|
||||
}
|
||||
override onload() {
|
||||
void this._startUp();
|
||||
}
|
||||
override onunload() {
|
||||
return void this.services.control.onUnload();
|
||||
return void this.core.services.control.onUnload();
|
||||
}
|
||||
}
|
||||
|
||||
// For now,
|
||||
export type LiveSyncCore = ObsidianLiveSyncPlugin;
|
||||
|
||||
Reference in New Issue
Block a user