mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-02-18 18:18:48 +00:00
### Refactor
- Module dependency refined. (For details, please refer to updates.md)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
|
||||
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||
import {
|
||||
LOG_LEVEL_INFO,
|
||||
LOG_LEVEL_NOTICE,
|
||||
@@ -12,6 +12,7 @@ import type ObsidianLiveSyncPlugin from "../main.ts";
|
||||
import { MARK_DONE } from "../modules/features/ModuleLog.ts";
|
||||
import type { LiveSyncCore } from "../main.ts";
|
||||
import { __$checkInstanceBinding } from "../lib/src/dev/checks.ts";
|
||||
import { createInstanceLogFunction } from "@/lib/src/services/lib/logUtils.ts";
|
||||
|
||||
let noticeIndex = 0;
|
||||
export abstract class LiveSyncCommands {
|
||||
@@ -43,6 +44,7 @@ export abstract class LiveSyncCommands {
|
||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||
this.plugin = plugin;
|
||||
this.onBindFunction(plugin, plugin.services);
|
||||
this._log = createInstanceLogFunction(this.constructor.name, this.services.API);
|
||||
__$checkInstanceBinding(this);
|
||||
}
|
||||
abstract onunload(): void;
|
||||
@@ -58,13 +60,7 @@ export abstract class LiveSyncCommands {
|
||||
return this.services.database.isDatabaseReady();
|
||||
}
|
||||
|
||||
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
||||
if (typeof msg === "string" && level !== LOG_LEVEL_NOTICE) {
|
||||
msg = `[${this.constructor.name}]\u{200A} ${msg}`;
|
||||
}
|
||||
// console.log(msg);
|
||||
Logger(msg, level, key);
|
||||
};
|
||||
_log: ReturnType<typeof createInstanceLogFunction>;
|
||||
|
||||
_verbose = (msg: any, key?: string) => {
|
||||
this._log(msg, LOG_LEVEL_VERBOSE, key);
|
||||
|
||||
@@ -107,7 +107,7 @@ export class P2PReplicator extends LiveSyncCommands implements P2PReplicatorBase
|
||||
}
|
||||
|
||||
init() {
|
||||
this._simpleStore = this.services.database.openSimpleStore("p2p-sync");
|
||||
this._simpleStore = this.services.keyValueDB.openSimpleStore("p2p-sync");
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
|
||||
2
src/lib
2
src/lib
Submodule src/lib updated: 69e7a510f1...3ae1cbabda
189
src/main.ts
189
src/main.ts
@@ -1,4 +1,4 @@
|
||||
import { Plugin } from "./deps";
|
||||
import { Plugin, type App, type PluginManifest } from "./deps";
|
||||
import {
|
||||
type EntryDoc,
|
||||
type ObsidianLiveSyncSettings,
|
||||
@@ -6,12 +6,11 @@ import {
|
||||
type HasSettings,
|
||||
} from "./lib/src/common/types.ts";
|
||||
import { type SimpleStore } from "./lib/src/common/utils.ts";
|
||||
import { LiveSyncLocalDB, type LiveSyncLocalDBEnv } from "./lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||
import { type LiveSyncLocalDBEnv } from "./lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||
import {
|
||||
LiveSyncAbstractReplicator,
|
||||
type LiveSyncReplicatorEnv,
|
||||
} from "./lib/src/replication/LiveSyncAbstractReplicator.js";
|
||||
import { type KeyValueDatabase } from "./lib/src/interfaces/KeyValueDatabase.ts";
|
||||
import { LiveSyncCommands } from "./features/LiveSyncCommands.ts";
|
||||
import { HiddenFileSync } from "./features/HiddenFileSync/CmdHiddenFileSync.ts";
|
||||
import { ConfigSync } from "./features/ConfigSync/CmdConfigSync.ts";
|
||||
@@ -48,29 +47,23 @@ import { ModuleObsidianDocumentHistory } from "./modules/features/ModuleObsidian
|
||||
import { ModuleObsidianGlobalHistory } from "./modules/features/ModuleGlobalHistory.ts";
|
||||
import { ModuleObsidianSettingsAsMarkdown } from "./modules/features/ModuleObsidianSettingAsMarkdown.ts";
|
||||
import { ModuleInitializerFile } from "./modules/essential/ModuleInitializerFile.ts";
|
||||
import { ModuleKeyValueDB } from "./modules/essential/ModuleKeyValueDB.ts";
|
||||
import { ModulePouchDB } from "./modules/core/ModulePouchDB.ts";
|
||||
import { ModuleReplicator } from "./modules/core/ModuleReplicator.ts";
|
||||
import { ModuleReplicatorCouchDB } from "./modules/core/ModuleReplicatorCouchDB.ts";
|
||||
import { ModuleReplicatorMinIO } from "./modules/core/ModuleReplicatorMinIO.ts";
|
||||
import { ModuleTargetFilter } from "./modules/core/ModuleTargetFilter.ts";
|
||||
import { ModulePeriodicProcess } from "./modules/core/ModulePeriodicProcess.ts";
|
||||
import { ModuleRemoteGovernor } from "./modules/coreFeatures/ModuleRemoteGovernor.ts";
|
||||
import { ModuleLocalDatabaseObsidian } from "./modules/core/ModuleLocalDatabaseObsidian.ts";
|
||||
import { ModuleConflictChecker } from "./modules/coreFeatures/ModuleConflictChecker.ts";
|
||||
import { ModuleResolvingMismatchedTweaks } from "./modules/coreFeatures/ModuleResolveMismatchedTweaks.ts";
|
||||
import { ModuleIntegratedTest } from "./modules/extras/ModuleIntegratedTest.ts";
|
||||
import { ModuleRebuilder } from "./modules/core/ModuleRebuilder.ts";
|
||||
import { ModuleReplicateTest } from "./modules/extras/ModuleReplicateTest.ts";
|
||||
import { ModuleLiveSyncMain } from "./modules/main/ModuleLiveSyncMain.ts";
|
||||
import { ModuleExtraSyncObsidian } from "./modules/extraFeaturesObsidian/ModuleExtraSyncObsidian.ts";
|
||||
import { LocalDatabaseMaintenance } from "./features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts";
|
||||
import { P2PReplicator } from "./features/P2PSync/CmdP2PReplicator.ts";
|
||||
import type { LiveSyncManagers } from "./lib/src/managers/LiveSyncManagers.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 type { InjectableServiceHub } from "./lib/src/services/InjectableServices.ts";
|
||||
|
||||
export default class ObsidianLiveSyncPlugin
|
||||
extends Plugin
|
||||
@@ -84,16 +77,36 @@ export default class ObsidianLiveSyncPlugin
|
||||
/**
|
||||
* The service hub for managing all services.
|
||||
*/
|
||||
_services: InjectableServiceHub<ServiceContext> = new ObsidianServiceHub(this);
|
||||
_services: InjectableServiceHub<ServiceContext> | undefined = undefined;
|
||||
|
||||
get services() {
|
||||
if (!this._services) {
|
||||
throw new Error("Services not initialised yet");
|
||||
}
|
||||
return this._services;
|
||||
}
|
||||
|
||||
private initialiseServices() {
|
||||
this._services = new ObsidianServiceHub(this);
|
||||
}
|
||||
|
||||
// Keep order to display the dialogue in order.
|
||||
addOns = [] as LiveSyncCommands[];
|
||||
/**
|
||||
* Bind functions to the service hub (for migration purpose).
|
||||
*/
|
||||
// bindFunctions = (this.serviceHub as ObsidianServiceHub).bindFunctions.bind(this.serviceHub);
|
||||
|
||||
// --> Module System
|
||||
private _registerAddOn(addOn: LiveSyncCommands) {
|
||||
this.addOns.push(addOn);
|
||||
}
|
||||
private registerAddOns() {
|
||||
this._registerAddOn(new ConfigSync(this));
|
||||
this._registerAddOn(new HiddenFileSync(this));
|
||||
this._registerAddOn(new LocalDatabaseMaintenance(this));
|
||||
this._registerAddOn(new P2PReplicator(this));
|
||||
}
|
||||
|
||||
getAddOn<T extends LiveSyncCommands>(cls: string) {
|
||||
for (const addon of this.addOns) {
|
||||
if (addon.constructor.name == cls) return addon as T;
|
||||
@@ -101,56 +114,8 @@ export default class ObsidianLiveSyncPlugin
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Keep order to display the dialogue in order.
|
||||
addOns = [
|
||||
new ConfigSync(this),
|
||||
new HiddenFileSync(this),
|
||||
new LocalDatabaseMaintenance(this),
|
||||
new P2PReplicator(this),
|
||||
] as LiveSyncCommands[];
|
||||
|
||||
modules = [
|
||||
new ModuleLiveSyncMain(this),
|
||||
new ModuleExtraSyncObsidian(this, this),
|
||||
// Only on Obsidian
|
||||
new ModuleDatabaseFileAccess(this),
|
||||
// Common
|
||||
new ModulePouchDB(this),
|
||||
new ModuleConflictChecker(this),
|
||||
new ModuleLocalDatabaseObsidian(this),
|
||||
new ModuleReplicatorMinIO(this),
|
||||
new ModuleReplicatorCouchDB(this),
|
||||
new ModuleReplicator(this),
|
||||
new ModuleFileHandler(this),
|
||||
new ModuleConflictResolver(this),
|
||||
new ModuleRemoteGovernor(this),
|
||||
new ModuleTargetFilter(this),
|
||||
new ModulePeriodicProcess(this),
|
||||
// Essential Modules
|
||||
new ModuleKeyValueDB(this),
|
||||
new ModuleInitializerFile(this),
|
||||
new ModuleObsidianAPI(this, this),
|
||||
new ModuleObsidianEvents(this, this),
|
||||
new ModuleFileAccessObsidian(this, this),
|
||||
new ModuleObsidianSettings(this),
|
||||
new ModuleResolvingMismatchedTweaks(this),
|
||||
new ModuleObsidianSettingsAsMarkdown(this),
|
||||
new ModuleObsidianSettingDialogue(this, this),
|
||||
new ModuleLog(this, this),
|
||||
new ModuleObsidianMenu(this),
|
||||
new ModuleRebuilder(this),
|
||||
new ModuleSetupObsidian(this),
|
||||
new ModuleObsidianDocumentHistory(this, this),
|
||||
new ModuleMigration(this),
|
||||
new ModuleRedFlag(this),
|
||||
new ModuleInteractiveConflictResolver(this, this),
|
||||
new ModuleObsidianGlobalHistory(this, this),
|
||||
new ModuleCheckRemoteSize(this),
|
||||
// Test and Dev Modules
|
||||
new ModuleDev(this, this),
|
||||
new ModuleReplicateTest(this, this),
|
||||
new ModuleIntegratedTest(this, this),
|
||||
new SetupManager(this),
|
||||
private modules = [
|
||||
// Move to registerModules
|
||||
] as (IObsidianModule | AbstractModule)[];
|
||||
|
||||
getModule<T extends IObsidianModule>(constructor: new (...args: any[]) => T): T {
|
||||
@@ -159,26 +124,97 @@ export default class ObsidianLiveSyncPlugin
|
||||
}
|
||||
throw new Error(`Module ${constructor} not found or not loaded.`);
|
||||
}
|
||||
getModulesByType<T extends IObsidianModule>(constructor: new (...args: any[]) => T): T[] {
|
||||
const matchedModules: T[] = [];
|
||||
for (const module of this.modules) {
|
||||
if (module instanceof constructor) matchedModules.push(module);
|
||||
}
|
||||
return matchedModules;
|
||||
}
|
||||
|
||||
private _registerModule(module: IObsidianModule) {
|
||||
this.modules.push(module);
|
||||
}
|
||||
private registerModules() {
|
||||
this._registerModule(new ModuleLiveSyncMain(this));
|
||||
// Only on Obsidian
|
||||
this._registerModule(new ModuleDatabaseFileAccess(this));
|
||||
// Common
|
||||
this._registerModule(new ModuleConflictChecker(this));
|
||||
this._registerModule(new ModuleReplicatorMinIO(this));
|
||||
this._registerModule(new ModuleReplicatorCouchDB(this));
|
||||
this._registerModule(new ModuleReplicator(this));
|
||||
this._registerModule(new ModuleFileHandler(this));
|
||||
this._registerModule(new ModuleConflictResolver(this));
|
||||
this._registerModule(new ModuleRemoteGovernor(this));
|
||||
this._registerModule(new ModuleTargetFilter(this));
|
||||
this._registerModule(new ModulePeriodicProcess(this));
|
||||
// Essential Modules
|
||||
this._registerModule(new ModuleInitializerFile(this));
|
||||
this._registerModule(new ModuleObsidianAPI(this, this));
|
||||
this._registerModule(new ModuleObsidianEvents(this, this));
|
||||
this._registerModule(new ModuleFileAccessObsidian(this, this));
|
||||
this._registerModule(new ModuleObsidianSettings(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 ModuleRebuilder(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));
|
||||
}
|
||||
|
||||
settings!: ObsidianLiveSyncSettings;
|
||||
localDatabase!: LiveSyncLocalDB;
|
||||
managers!: LiveSyncManagers;
|
||||
simpleStore!: SimpleStore<CheckPointInfo>;
|
||||
replicator!: LiveSyncAbstractReplicator;
|
||||
get confirm(): Confirm {
|
||||
return this.services.UI.confirm;
|
||||
}
|
||||
storageAccess!: StorageAccess;
|
||||
databaseFileAccess!: DatabaseFileAccess;
|
||||
fileHandler!: ModuleFileHandler;
|
||||
rebuilder!: Rebuilder;
|
||||
|
||||
kvDB!: KeyValueDatabase;
|
||||
// This property will be changed from outside often, so will be set later.
|
||||
settings!: ObsidianLiveSyncSettings;
|
||||
|
||||
getSettings(): ObsidianLiveSyncSettings {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
get localDatabase() {
|
||||
return this.services.database.localDatabase;
|
||||
}
|
||||
|
||||
get managers() {
|
||||
return this.services.database.managers;
|
||||
}
|
||||
|
||||
getDatabase(): PouchDB.Database<EntryDoc> {
|
||||
return this.localDatabase.localDatabase;
|
||||
}
|
||||
getSettings(): ObsidianLiveSyncSettings {
|
||||
return this.settings;
|
||||
|
||||
get simpleStore() {
|
||||
return this.services.keyValueDB.simpleStore as SimpleStore<CheckPointInfo>;
|
||||
}
|
||||
|
||||
// initialised at ModuleReplicator
|
||||
replicator!: LiveSyncAbstractReplicator;
|
||||
// initialised at ModuleFileAccessObsidian
|
||||
storageAccess!: StorageAccess;
|
||||
// initialised at ModuleDatabaseFileAccess
|
||||
databaseFileAccess!: DatabaseFileAccess;
|
||||
// initialised at ModuleFileHandler
|
||||
fileHandler!: ModuleFileHandler;
|
||||
// initialised at ModuleRebuilder
|
||||
rebuilder!: Rebuilder;
|
||||
|
||||
get kvDB() {
|
||||
return this.services.keyValueDB.kvDB;
|
||||
}
|
||||
|
||||
requestCount = reactiveSource(0);
|
||||
@@ -205,6 +241,13 @@ export default class ObsidianLiveSyncPlugin
|
||||
syncStatus: "CLOSED" as DatabaseConnectingStatus,
|
||||
});
|
||||
|
||||
constructor(app: App, manifest: PluginManifest) {
|
||||
super(app, manifest);
|
||||
this.initialiseServices();
|
||||
this.registerModules();
|
||||
this.registerAddOns();
|
||||
}
|
||||
|
||||
private async _startUp() {
|
||||
await this.services.appLifecycle.onLoad();
|
||||
const onReady = this.services.appLifecycle.onReady.bind(this.services.appLifecycle);
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
|
||||
import type { AnyEntry, FilePathWithPrefix, LOG_LEVEL } from "@lib/common/types";
|
||||
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 { __$checkInstanceBinding } from "@lib/dev/checks";
|
||||
import { stripAllPrefixes } from "@lib/string_and_binary/path";
|
||||
import { createInstanceLogFunction } from "@/lib/src/services/lib/logUtils";
|
||||
|
||||
export abstract class AbstractModule {
|
||||
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
||||
if (typeof msg === "string" && level !== LOG_LEVEL_NOTICE) {
|
||||
msg = `[${this.constructor.name}]\u{200A} ${msg}`;
|
||||
_log = createInstanceLogFunction(this.constructor.name, this.services.API);
|
||||
get services() {
|
||||
if (!this.core._services) {
|
||||
throw new Error("Services are not ready yet.");
|
||||
}
|
||||
// console.log(msg);
|
||||
Logger(msg, level, key);
|
||||
};
|
||||
return this.core._services;
|
||||
}
|
||||
|
||||
addCommand = this.services.API.addCommand.bind(this.services.API);
|
||||
registerView = this.services.API.registerWindow.bind(this.services.API);
|
||||
@@ -73,10 +74,6 @@ export abstract class AbstractModule {
|
||||
return this.testDone();
|
||||
}
|
||||
|
||||
get services() {
|
||||
return this.core._services;
|
||||
}
|
||||
|
||||
isMainReady() {
|
||||
return this.services.appLifecycle.isReady();
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { $msg } from "../../lib/src/common/i18n";
|
||||
import { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||
import { initializeStores } from "../../common/stores.ts";
|
||||
import { AbstractModule } from "../AbstractModule.ts";
|
||||
import { LiveSyncManagers } from "../../lib/src/managers/LiveSyncManagers.ts";
|
||||
import type { LiveSyncCore } from "../../main.ts";
|
||||
|
||||
export class ModuleLocalDatabaseObsidian extends AbstractModule {
|
||||
_everyOnloadStart(): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
private async _openDatabase(): Promise<boolean> {
|
||||
if (this.localDatabase != null) {
|
||||
await this.localDatabase.close();
|
||||
}
|
||||
const vaultName = this.services.vault.getVaultName();
|
||||
this._log($msg("moduleLocalDatabase.logWaitingForReady"));
|
||||
const getDB = () => this.core.localDatabase.localDatabase;
|
||||
const getSettings = () => this.core.settings;
|
||||
this.core.managers = new LiveSyncManagers({
|
||||
get database() {
|
||||
return getDB();
|
||||
},
|
||||
getActiveReplicator: () => this.core.replicator,
|
||||
id2path: this.services.path.id2path.bind(this.services.path),
|
||||
// path2id: this.core.$$path2id.bind(this.core),
|
||||
path2id: this.services.path.path2id.bind(this.services.path),
|
||||
get settings() {
|
||||
return getSettings();
|
||||
},
|
||||
});
|
||||
this.core.localDatabase = new LiveSyncLocalDB(vaultName, this.core);
|
||||
|
||||
initializeStores(vaultName);
|
||||
return await this.localDatabase.initializeDatabase();
|
||||
}
|
||||
|
||||
_isDatabaseReady(): boolean {
|
||||
return this.localDatabase != null && this.localDatabase.isReady;
|
||||
}
|
||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||
services.database.isDatabaseReady.setHandler(this._isDatabaseReady.bind(this));
|
||||
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||
services.database.openDatabase.setHandler(this._openDatabase.bind(this));
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { AbstractModule } from "../AbstractModule";
|
||||
import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||
import type { LiveSyncCore } from "../../main";
|
||||
import { ExtraSuffixIndexedDB } from "../../lib/src/common/types";
|
||||
|
||||
export class ModulePouchDB extends AbstractModule {
|
||||
_createPouchDBInstance<T extends object>(
|
||||
name?: string,
|
||||
options?: PouchDB.Configuration.DatabaseConfiguration
|
||||
): PouchDB.Database<T> {
|
||||
const optionPass = options ?? {};
|
||||
if (this.settings.useIndexedDBAdapter) {
|
||||
optionPass.adapter = "indexeddb";
|
||||
//@ts-ignore :missing def
|
||||
optionPass.purged_infos_limit = 1;
|
||||
return new PouchDB(name + ExtraSuffixIndexedDB, optionPass);
|
||||
}
|
||||
return new PouchDB(name, optionPass);
|
||||
}
|
||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||
services.database.createPouchDBInstance.setHandler(this._createPouchDBInstance.bind(this));
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,10 @@ Are you sure you wish to proceed?`;
|
||||
await this.services.setting.realiseSetting();
|
||||
await this.resetLocalDatabase();
|
||||
await delay(1000);
|
||||
await this.services.database.openDatabase();
|
||||
await this.services.database.openDatabase({
|
||||
databaseEvents: this.services.databaseEvents,
|
||||
replicator: this.services.replicator,
|
||||
});
|
||||
// this.core.isReady = true;
|
||||
this.services.appLifecycle.markIsReady();
|
||||
if (makeLocalChunkBeforeSync) {
|
||||
|
||||
@@ -146,10 +146,5 @@ export class ModuleTargetFilter extends AbstractModule {
|
||||
services.vault.isTargetFile.addHandler(this._isTargetFileByLocalDB.bind(this));
|
||||
services.vault.isTargetFile.addHandler(this._isTargetFileFinal.bind(this));
|
||||
services.setting.onSettingRealised.addHandler(this.refreshSettings.bind(this));
|
||||
// services.vault.isTargetFile.use((ctx, next) => {
|
||||
// const [fileName, keepFileCheckList] = ctx.args;
|
||||
// const file = getS
|
||||
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +393,13 @@ export class ModuleInitializerFile extends AbstractModule {
|
||||
ignoreSuspending: boolean = false
|
||||
): Promise<boolean> {
|
||||
this.services.appLifecycle.resetIsReady();
|
||||
if (!reopenDatabase || (await this.services.database.openDatabase())) {
|
||||
if (
|
||||
!reopenDatabase ||
|
||||
(await this.services.database.openDatabase({
|
||||
databaseEvents: this.services.databaseEvents,
|
||||
replicator: this.services.replicator,
|
||||
}))
|
||||
) {
|
||||
if (this.localDatabase.isReady) {
|
||||
await this.services.vault.scanVault(showingNotice, ignoreSuspending);
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
import { delay, yieldMicrotask } from "octagonal-wheels/promises";
|
||||
import { OpenKeyValueDatabase } from "../../common/KeyValueDB.ts";
|
||||
import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||
import { AbstractModule } from "../AbstractModule.ts";
|
||||
import type { LiveSyncCore } from "../../main.ts";
|
||||
import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase";
|
||||
import type { InjectableServiceHub } from "@/lib/src/services/InjectableServices.ts";
|
||||
import type { ObsidianDatabaseService } from "../services/ObsidianServices.ts";
|
||||
|
||||
export class ModuleKeyValueDB extends AbstractModule {
|
||||
async tryCloseKvDB() {
|
||||
try {
|
||||
await this.core.kvDB?.close();
|
||||
return true;
|
||||
} catch (e) {
|
||||
this._log("Failed to close KeyValueDB", LOG_LEVEL_VERBOSE);
|
||||
this._log(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async openKeyValueDB(): Promise<boolean> {
|
||||
await delay(10);
|
||||
try {
|
||||
await this.tryCloseKvDB();
|
||||
await delay(10);
|
||||
await yieldMicrotask();
|
||||
this.core.kvDB = await OpenKeyValueDatabase(this.services.vault.getVaultName() + "-livesync-kv");
|
||||
await yieldMicrotask();
|
||||
await delay(100);
|
||||
} catch (e) {
|
||||
this.core.kvDB = undefined!;
|
||||
this._log("Failed to open KeyValueDB", LOG_LEVEL_NOTICE);
|
||||
this._log(e, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
async _onDBUnload(db: LiveSyncLocalDB) {
|
||||
if (this.core.kvDB) await this.core.kvDB.close();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
async _onDBClose(db: LiveSyncLocalDB) {
|
||||
if (this.core.kvDB) await this.core.kvDB.close();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
private async _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||
if (!(await this.openKeyValueDB())) {
|
||||
return false;
|
||||
}
|
||||
this.core.simpleStore = this.services.database.openSimpleStore<any>("os");
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
_getSimpleStore<T>(kind: string) {
|
||||
const getDB = () => this.core.kvDB;
|
||||
const prefix = `${kind}-`;
|
||||
return {
|
||||
get: async (key: string): Promise<T> => {
|
||||
return await getDB().get(`${prefix}${key}`);
|
||||
},
|
||||
set: async (key: string, value: any): Promise<void> => {
|
||||
await getDB().set(`${prefix}${key}`, value);
|
||||
},
|
||||
delete: async (key: string): Promise<void> => {
|
||||
await getDB().del(`${prefix}${key}`);
|
||||
},
|
||||
keys: async (
|
||||
from: string | undefined,
|
||||
to: string | undefined,
|
||||
count?: number | undefined
|
||||
): Promise<string[]> => {
|
||||
const ret = await getDB().keys(
|
||||
IDBKeyRange.bound(`${prefix}${from || ""}`, `${prefix}${to || ""}`),
|
||||
count
|
||||
);
|
||||
return ret
|
||||
.map((e) => e.toString())
|
||||
.filter((e) => e.startsWith(prefix))
|
||||
.map((e) => e.substring(prefix.length));
|
||||
},
|
||||
db: Promise.resolve(getDB()),
|
||||
} satisfies SimpleStore<T>;
|
||||
}
|
||||
_everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||
return this.openKeyValueDB();
|
||||
}
|
||||
|
||||
async _everyOnResetDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||
try {
|
||||
const kvDBKey = "queued-files";
|
||||
await this.core.kvDB.del(kvDBKey);
|
||||
// localStorage.removeItem(lsKey);
|
||||
await this.core.kvDB.destroy();
|
||||
await yieldMicrotask();
|
||||
this.core.kvDB = await OpenKeyValueDatabase(this.services.vault.getVaultName() + "-livesync-kv");
|
||||
await delay(100);
|
||||
} catch (e) {
|
||||
this.core.kvDB = undefined!;
|
||||
this._log("Failed to reset KeyValueDB", LOG_LEVEL_NOTICE);
|
||||
this._log(e, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||
services.databaseEvents.onUnloadDatabase.addHandler(this._onDBUnload.bind(this));
|
||||
services.databaseEvents.onCloseDatabase.addHandler(this._onDBClose.bind(this));
|
||||
services.databaseEvents.onDatabaseInitialisation.addHandler(this._everyOnInitializeDatabase.bind(this));
|
||||
services.databaseEvents.onResetDatabase.addHandler(this._everyOnResetDatabase.bind(this));
|
||||
(services.database as ObsidianDatabaseService).openSimpleStore.setHandler(this._getSimpleStore.bind(this));
|
||||
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import type { LiveSyncCore } from "../../main.ts";
|
||||
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||
|
||||
export class ModuleExtraSyncObsidian extends AbstractObsidianModule {
|
||||
deviceAndVaultName: string = "";
|
||||
|
||||
_getDeviceAndVaultName(): string {
|
||||
return this.deviceAndVaultName;
|
||||
}
|
||||
_setDeviceAndVaultName(name: string): void {
|
||||
this.deviceAndVaultName = name;
|
||||
}
|
||||
|
||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||
services.setting.getDeviceAndVaultName.setHandler(this._getDeviceAndVaultName.bind(this));
|
||||
services.setting.setDeviceAndVaultName.setHandler(this._setDeviceAndVaultName.bind(this));
|
||||
}
|
||||
}
|
||||
@@ -39,19 +39,22 @@ import {
|
||||
isValidFilenameInDarwin,
|
||||
isValidFilenameInWidows,
|
||||
} from "@/lib/src/string_and_binary/path.ts";
|
||||
import { MARK_LOG_SEPARATOR } from "@/lib/src/services/lib/logUtils.ts";
|
||||
|
||||
// This module cannot be a core module because it depends on the Obsidian UI.
|
||||
|
||||
// DI the log again.
|
||||
const recentLogEntries = reactiveSource<LogEntry[]>([]);
|
||||
setGlobalLogFunction((message: any, level?: number, key?: string) => {
|
||||
const globalLogFunction = (message: any, level?: number, key?: string) => {
|
||||
const messageX =
|
||||
message instanceof Error
|
||||
? new LiveSyncError("[Error Logged]: " + message.message, { cause: message })
|
||||
: message;
|
||||
const entry = { message: messageX, level, key } as LogEntry;
|
||||
recentLogEntries.value = [...recentLogEntries.value, entry];
|
||||
});
|
||||
};
|
||||
|
||||
setGlobalLogFunction(globalLogFunction);
|
||||
let recentLogs = [] as string[];
|
||||
|
||||
function addLog(log: string) {
|
||||
@@ -304,9 +307,9 @@ export class ModuleLog extends AbstractObsidianModule {
|
||||
// const recent = logMessages.value;
|
||||
const newMsg = message;
|
||||
let newLog = this.settings?.showOnlyIconsOnEditor ? "" : status;
|
||||
const moduleTagEnd = newLog.indexOf(`]\u{200A}`);
|
||||
const moduleTagEnd = newLog.indexOf(`]${MARK_LOG_SEPARATOR}`);
|
||||
if (moduleTagEnd != -1) {
|
||||
newLog = newLog.substring(moduleTagEnd + 2);
|
||||
newLog = newLog.substring(moduleTagEnd + MARK_LOG_SEPARATOR.length + 1);
|
||||
}
|
||||
|
||||
this.statusBar?.setText(newMsg.split("\n")[0]);
|
||||
@@ -493,6 +496,7 @@ export class ModuleLog extends AbstractObsidianModule {
|
||||
}
|
||||
}
|
||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||
services.API.addLog.setHandler(globalLogFunction);
|
||||
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||
|
||||
@@ -126,7 +126,10 @@ export class ModuleLiveSyncMain extends AbstractModule {
|
||||
await this.saveSettings();
|
||||
}
|
||||
localStorage.setItem(lsKey, `${VER}`);
|
||||
await this.services.database.openDatabase();
|
||||
await this.services.database.openDatabase({
|
||||
databaseEvents: this.services.databaseEvents,
|
||||
replicator: this.services.replicator,
|
||||
});
|
||||
// this.core.$$realizeSettingSyncMode = this.core.$$realizeSettingSyncMode.bind(this);
|
||||
// this.$$parseReplicationResult = this.$$parseReplicationResult.bind(this);
|
||||
// this.$$replicate = this.$$replicate.bind(this);
|
||||
|
||||
92
src/modules/services/ObsidianAPIService.ts
Normal file
92
src/modules/services/ObsidianAPIService.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { InjectableAPIService } from "@/lib/src/services/implements/injectable/InjectableAPIService";
|
||||
import type { ObsidianServiceContext } from "@/lib/src/services/implements/obsidian/ObsidianServiceContext";
|
||||
import { Platform, type Command, type ViewCreator } from "obsidian";
|
||||
import { ObsHttpHandler } from "../essentialObsidian/APILib/ObsHttpHandler";
|
||||
|
||||
// All Services will be migrated to be based on Plain Services, not Injectable Services.
|
||||
// This is a migration step.
|
||||
|
||||
export class ObsidianAPIService extends InjectableAPIService<ObsidianServiceContext> {
|
||||
_customHandler: ObsHttpHandler | undefined;
|
||||
getCustomFetchHandler(): ObsHttpHandler {
|
||||
if (!this._customHandler) this._customHandler = new ObsHttpHandler(undefined, undefined);
|
||||
return this._customHandler;
|
||||
}
|
||||
|
||||
async showWindow(viewType: string): Promise<void> {
|
||||
const leaves = this.app.workspace.getLeavesOfType(viewType);
|
||||
if (leaves.length == 0) {
|
||||
await this.app.workspace.getLeaf(true).setViewState({
|
||||
type: viewType,
|
||||
active: true,
|
||||
});
|
||||
} else {
|
||||
await leaves[0].setViewState({
|
||||
type: viewType,
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
if (leaves.length > 0) {
|
||||
await this.app.workspace.revealLeaf(leaves[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private get app() {
|
||||
return this.context.app;
|
||||
}
|
||||
|
||||
getPlatform(): string {
|
||||
if (Platform.isAndroidApp) {
|
||||
return "android-app";
|
||||
} else if (Platform.isIosApp) {
|
||||
return "ios";
|
||||
} else if (Platform.isMacOS) {
|
||||
return "macos";
|
||||
} else if (Platform.isMobileApp) {
|
||||
return "mobile-app";
|
||||
} else if (Platform.isMobile) {
|
||||
return "mobile";
|
||||
} else if (Platform.isSafari) {
|
||||
return "safari";
|
||||
} else if (Platform.isDesktop) {
|
||||
return "desktop";
|
||||
} else if (Platform.isDesktopApp) {
|
||||
return "desktop-app";
|
||||
} else {
|
||||
return "unknown-obsidian";
|
||||
}
|
||||
}
|
||||
override isMobile(): boolean {
|
||||
//@ts-ignore : internal API
|
||||
return this.app.isMobile;
|
||||
}
|
||||
override getAppID(): string {
|
||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||
}
|
||||
override getAppVersion(): string {
|
||||
const navigatorString = globalThis.navigator?.userAgent ?? "";
|
||||
const match = navigatorString.match(/obsidian\/([0-9]+\.[0-9]+\.[0-9]+)/);
|
||||
if (match && match.length >= 2) {
|
||||
return match[1];
|
||||
}
|
||||
return "0.0.0";
|
||||
}
|
||||
|
||||
override getPluginVersion(): string {
|
||||
return this.context.plugin.manifest.version;
|
||||
}
|
||||
|
||||
addCommand<TCommand extends Command>(command: TCommand): TCommand {
|
||||
return this.context.plugin.addCommand(command) as TCommand;
|
||||
}
|
||||
|
||||
registerWindow(type: string, factory: ViewCreator): void {
|
||||
return this.context.plugin.registerView(type, factory);
|
||||
}
|
||||
addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement {
|
||||
return this.context.plugin.addRibbonIcon(icon, title, callback);
|
||||
}
|
||||
registerProtocolHandler(action: string, handler: (params: Record<string, string>) => any): void {
|
||||
return this.context.plugin.registerObsidianProtocolHandler(action, handler);
|
||||
}
|
||||
}
|
||||
11
src/modules/services/ObsidianDatabaseService.ts
Normal file
11
src/modules/services/ObsidianDatabaseService.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { initializeStores } from "@/common/stores";
|
||||
|
||||
import { InjectableDatabaseService } from "@/lib/src/services/implements/injectable/InjectableDatabaseService";
|
||||
import type { ObsidianServiceContext } from "@/lib/src/services/implements/obsidian/ObsidianServiceContext";
|
||||
|
||||
export class ObsidianDatabaseService extends InjectableDatabaseService<ObsidianServiceContext> {
|
||||
override onOpenDatabase(vaultName: string): Promise<void> {
|
||||
initializeStores(vaultName);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ import { ObsidianServiceContext } from "@/lib/src/services/implements/obsidian/O
|
||||
import type { ServiceInstances } from "@/lib/src/services/ServiceHub";
|
||||
import type ObsidianLiveSyncPlugin from "@/main";
|
||||
import {
|
||||
ObsidianAPIService,
|
||||
ObsidianConflictService,
|
||||
ObsidianDatabaseService,
|
||||
ObsidianFileProcessingService,
|
||||
ObsidianReplicationService,
|
||||
ObsidianReplicatorService,
|
||||
@@ -15,7 +13,10 @@ import {
|
||||
ObsidianTestService,
|
||||
ObsidianDatabaseEventService,
|
||||
ObsidianConfigService,
|
||||
ObsidianKeyValueDBService,
|
||||
} from "./ObsidianServices";
|
||||
import { ObsidianDatabaseService } from "./ObsidianDatabaseService";
|
||||
import { ObsidianAPIService } from "./ObsidianAPIService";
|
||||
import { ObsidianAppLifecycleService } from "./ObsidianAppLifecycleService";
|
||||
import { ObsidianPathService } from "./ObsidianPathService";
|
||||
import { ObsidianVaultService } from "./ObsidianVaultService";
|
||||
@@ -30,7 +31,6 @@ export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceCont
|
||||
const API = new ObsidianAPIService(context);
|
||||
const appLifecycle = new ObsidianAppLifecycleService(context);
|
||||
const conflict = new ObsidianConflictService(context);
|
||||
const database = new ObsidianDatabaseService(context);
|
||||
const fileProcessing = new ObsidianFileProcessingService(context);
|
||||
const replication = new ObsidianReplicationService(context);
|
||||
const replicator = new ObsidianReplicatorService(context);
|
||||
@@ -45,6 +45,16 @@ export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceCont
|
||||
const path = new ObsidianPathService(context, {
|
||||
settingService: setting,
|
||||
});
|
||||
const database = new ObsidianDatabaseService(context, {
|
||||
path: path,
|
||||
vault: vault,
|
||||
setting: setting,
|
||||
});
|
||||
const keyValueDB = new ObsidianKeyValueDBService(context, {
|
||||
appLifecycle: appLifecycle,
|
||||
databaseEvents: databaseEvents,
|
||||
vault: vault,
|
||||
});
|
||||
const config = new ObsidianConfigService(context, vault);
|
||||
const ui = new ObsidianUIService(context, {
|
||||
appLifecycle,
|
||||
@@ -70,6 +80,7 @@ export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceCont
|
||||
path: path,
|
||||
API: API,
|
||||
config: config,
|
||||
keyValueDB: keyValueDB,
|
||||
} satisfies Required<ServiceInstances<ObsidianServiceContext>>;
|
||||
|
||||
super(context, serviceInstancesToInit);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { InjectableAPIService } from "@lib/services/implements/injectable/InjectableAPIService";
|
||||
import { InjectableConflictService } from "@lib/services/implements/injectable/InjectableConflictService";
|
||||
import { InjectableDatabaseEventService } from "@lib/services/implements/injectable/InjectableDatabaseEventService";
|
||||
import { InjectableDatabaseService } from "@lib/services/implements/injectable/InjectableDatabaseService";
|
||||
import { InjectableFileProcessingService } from "@lib/services/implements/injectable/InjectableFileProcessingService";
|
||||
import { InjectableRemoteService } from "@lib/services/implements/injectable/InjectableRemoteService";
|
||||
import { InjectableReplicationService } from "@lib/services/implements/injectable/InjectableReplicationService";
|
||||
@@ -11,105 +9,8 @@ import { InjectableTestService } from "@lib/services/implements/injectable/Injec
|
||||
import { InjectableTweakValueService } from "@lib/services/implements/injectable/InjectableTweakValueService";
|
||||
import { ConfigServiceBrowserCompat } from "@lib/services/implements/browser/ConfigServiceBrowserCompat";
|
||||
import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext.ts";
|
||||
import { Platform } from "@/deps";
|
||||
import type { SimpleStore } from "@/lib/src/common/utils";
|
||||
import type { IDatabaseService } from "@/lib/src/services/base/IService";
|
||||
import { handlers } from "@/lib/src/services/lib/HandlerUtils";
|
||||
import { ObsHttpHandler } from "../essentialObsidian/APILib/ObsHttpHandler";
|
||||
import type { Command, ViewCreator } from "obsidian";
|
||||
import { KeyValueDBService } from "@/lib/src/services/base/KeyValueDBService";
|
||||
|
||||
// All Services will be migrated to be based on Plain Services, not Injectable Services.
|
||||
// This is a migration step.
|
||||
|
||||
export class ObsidianAPIService extends InjectableAPIService<ObsidianServiceContext> {
|
||||
_customHandler: ObsHttpHandler | undefined;
|
||||
getCustomFetchHandler(): ObsHttpHandler {
|
||||
if (!this._customHandler) this._customHandler = new ObsHttpHandler(undefined, undefined);
|
||||
return this._customHandler;
|
||||
}
|
||||
|
||||
async showWindow(viewType: string): Promise<void> {
|
||||
const leaves = this.app.workspace.getLeavesOfType(viewType);
|
||||
if (leaves.length == 0) {
|
||||
await this.app.workspace.getLeaf(true).setViewState({
|
||||
type: viewType,
|
||||
active: true,
|
||||
});
|
||||
} else {
|
||||
await leaves[0].setViewState({
|
||||
type: viewType,
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
if (leaves.length > 0) {
|
||||
await this.app.workspace.revealLeaf(leaves[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private get app() {
|
||||
return this.context.app;
|
||||
}
|
||||
|
||||
getPlatform(): string {
|
||||
if (Platform.isAndroidApp) {
|
||||
return "android-app";
|
||||
} else if (Platform.isIosApp) {
|
||||
return "ios";
|
||||
} else if (Platform.isMacOS) {
|
||||
return "macos";
|
||||
} else if (Platform.isMobileApp) {
|
||||
return "mobile-app";
|
||||
} else if (Platform.isMobile) {
|
||||
return "mobile";
|
||||
} else if (Platform.isSafari) {
|
||||
return "safari";
|
||||
} else if (Platform.isDesktop) {
|
||||
return "desktop";
|
||||
} else if (Platform.isDesktopApp) {
|
||||
return "desktop-app";
|
||||
} else {
|
||||
return "unknown-obsidian";
|
||||
}
|
||||
}
|
||||
override isMobile(): boolean {
|
||||
//@ts-ignore : internal API
|
||||
return this.app.isMobile;
|
||||
}
|
||||
override getAppID(): string {
|
||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||
}
|
||||
override getAppVersion(): string {
|
||||
const navigatorString = globalThis.navigator?.userAgent ?? "";
|
||||
const match = navigatorString.match(/obsidian\/([0-9]+\.[0-9]+\.[0-9]+)/);
|
||||
if (match && match.length >= 2) {
|
||||
return match[1];
|
||||
}
|
||||
return "0.0.0";
|
||||
}
|
||||
|
||||
override getPluginVersion(): string {
|
||||
return this.context.plugin.manifest.version;
|
||||
}
|
||||
|
||||
addCommand<TCommand extends Command>(command: TCommand): TCommand {
|
||||
return this.context.plugin.addCommand(command) as TCommand;
|
||||
}
|
||||
|
||||
registerWindow(type: string, factory: ViewCreator): void {
|
||||
return this.context.plugin.registerView(type, factory);
|
||||
}
|
||||
addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement {
|
||||
return this.context.plugin.addRibbonIcon(icon, title, callback);
|
||||
}
|
||||
registerProtocolHandler(action: string, handler: (params: Record<string, string>) => any): void {
|
||||
return this.context.plugin.registerObsidianProtocolHandler(action, handler);
|
||||
}
|
||||
}
|
||||
export class ObsidianDatabaseService extends InjectableDatabaseService<ObsidianServiceContext> {
|
||||
openSimpleStore = handlers<IDatabaseService>().binder("openSimpleStore") as (<T>(
|
||||
kind: string
|
||||
) => SimpleStore<T>) & { setHandler: (handler: IDatabaseService["openSimpleStore"], override?: boolean) => void };
|
||||
}
|
||||
export class ObsidianDatabaseEventService extends InjectableDatabaseEventService<ObsidianServiceContext> {}
|
||||
|
||||
// InjectableReplicatorService
|
||||
@@ -129,3 +30,5 @@ export class ObsidianTweakValueService extends InjectableTweakValueService<Obsid
|
||||
// InjectableTestService
|
||||
export class ObsidianTestService extends InjectableTestService<ObsidianServiceContext> {}
|
||||
export class ObsidianConfigService extends ConfigServiceBrowserCompat<ObsidianServiceContext> {}
|
||||
|
||||
export class ObsidianKeyValueDBService extends KeyValueDBService<ObsidianServiceContext> {}
|
||||
|
||||
27
updates.md
27
updates.md
@@ -3,13 +3,37 @@ Since 19th July, 2025 (beta1 in 0.25.0-beta1, 13th July, 2025)
|
||||
|
||||
The head note of 0.25 is now in [updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md). Because 0.25 got a lot of updates, thankfully, compatibility is kept and we do not need breaking changes! In other words, when get enough stabled. The next version will be v1.0.0. Even though it my hope.
|
||||
|
||||
## 0.25.43-patched-3
|
||||
|
||||
16th February, 2026
|
||||
|
||||
### Refactored
|
||||
|
||||
- Now following properties of `ObsidianLiveSyncPlugin` belong to each service:
|
||||
- property : service
|
||||
- `localDatabase` : `services.database`
|
||||
- `managers` : `services.database`
|
||||
- `simpleStore` : `services.keyValueDB`
|
||||
- `kvDB`: `services.keyValueDB`
|
||||
- Initialising modules, addOns, and services are now explicitly separated in the `_startUp` function of the main plug-in class.
|
||||
- LiveSyncLocalDB now depends more explicitly on specified services, not the whole `ServiceHub`.
|
||||
- New service `keyValueDB` has been added. This had been separated from the `database` service.
|
||||
- Non-trivial modules, such as `ModuleExtraSyncObsidian` (which only holds deviceAndVaultName), are simply implemented in the service.
|
||||
- Add `logUtils` for unifying logging method injection and formatting. This utility is able to accept the API service for log writing.
|
||||
- `ModuleKeyValueDB` has been removed, and its functionality is now implemented in the `keyValueDB` service.
|
||||
- `ModulePouchDB` and `ModuleLocalDatabaseObsidian` have been removed, and their functionality is now implemented in the `database` service.
|
||||
- Please be aware that you have overridden createPouchDBInstance or something by dynamic binding; you should now override the createPouchDBInstance in the database service instead of using the module.
|
||||
- You can refer to the `DirectFileManipulatorV2` for an example of how to override the createPouchDBInstance function in the database service.
|
||||
|
||||
|
||||
## 0.25.43-patched-2
|
||||
|
||||
14th February, 2026
|
||||
|
||||
### Fixed
|
||||
|
||||
- Application LifeCycle has now started in Main, not ServiceHub.
|
||||
- Indeed, ServiceHub cannot be known other things in main have got ready, so it is quite natural to start the lifecycle in main.
|
||||
- Indeed, ServiceHub cannot be known other things in main have got ready, so it is quite natural to start the lifecycle in main.
|
||||
|
||||
## 0.25.43-patched-1
|
||||
|
||||
@@ -29,6 +53,7 @@ If this cannot be stable, I will revert to 0.24.43 and try again.
|
||||
- VaultService.isTargetFile is now using multiple checkers instead of a single function.
|
||||
- This change allows better separation of concerns and easier extension in the future.
|
||||
- Application LifeCycle has now started in ServiceHub, not ObsidianMenuModule.
|
||||
|
||||
- It was in a QUITE unexpected place..., isn't it?
|
||||
- Instead of, we should call `await this.services.appLifecycle.onReady()` in other platforms.
|
||||
- As in the browser platform, it will be called at `DOMContentLoaded` event.
|
||||
|
||||
Reference in New Issue
Block a user