From 3963f7c971143cd95121467722b724eba7ea41fd Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Wed, 18 Mar 2026 11:49:41 +0100 Subject: [PATCH] Refactored: P2P replicator has been refactored to be a little roust and easier to understand. --- .../P2PReplicator/P2PReplicatorPaneView.ts | 6 +- src/lib | 2 +- src/main.ts | 28 +++---- src/serviceFeatures/useP2PReplicatorUI.ts | 76 +++++++++++++++++++ 4 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 src/serviceFeatures/useP2PReplicatorUI.ts diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts b/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts index d96445f..5ab5031 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts +++ b/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts @@ -9,7 +9,7 @@ import { LOG_LEVEL_NOTICE, REMOTE_P2P } from "@lib/common/types.ts"; import { Logger } from "@lib/common/logger.ts"; import { EVENT_P2P_PEER_SHOW_EXTRA_MENU, type PeerStatus } from "@lib/replication/trystero/P2PReplicatorPaneCommon.ts"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts"; -import type { UseP2PReplicatorResult } from "@lib/replication/trystero/P2PReplicatorCore.ts"; +import type { P2PPaneParams } from "@/lib/src/replication/trystero/UseP2PReplicatorResult"; export const VIEW_TYPE_P2P = "p2p-replicator"; function addToList(item: string, list: string) { @@ -32,7 +32,7 @@ function removeFromList(item: string, list: string) { export class P2PReplicatorPaneView extends SvelteItemView { core: LiveSyncBaseCore; - private _p2pResult: UseP2PReplicatorResult; + private _p2pResult: P2PPaneParams; override icon = "waypoints"; title: string = ""; override navigation = false; @@ -123,7 +123,7 @@ And you can also drop the local database to rebuild from the remote device.`, await this.core.services.setting.applyPartial(currentSetting, true); } m?: Menu; - constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2pResult: UseP2PReplicatorResult) { + constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2pResult: P2PPaneParams) { super(leaf); this.core = core; this._p2pResult = p2pResult; diff --git a/src/lib b/src/lib index 94e44e8..202038d 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 94e44e8a03b4d079f874c09b9ec60e43b7d35c58 +Subproject commit 202038d19eeb19df76b6804bcd0ea784896ce257 diff --git a/src/main.ts b/src/main.ts index b1f9374..ab89820 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,9 +14,7 @@ import { ModuleObsidianGlobalHistory } from "./modules/features/ModuleGlobalHist import { ModuleIntegratedTest } from "./modules/extras/ModuleIntegratedTest.ts"; import { ModuleReplicateTest } from "./modules/extras/ModuleReplicateTest.ts"; import { LocalDatabaseMaintenance } from "./features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts"; -import { P2PReplicatorPaneView, VIEW_TYPE_P2P } from "./features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts"; -import { useP2PReplicator } from "@lib/replication/trystero/P2PReplicatorCore.ts"; -import type { InjectableServiceHub } from "./lib/src/services/implements/injectable/InjectableServiceHub.ts"; +import type { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub.ts"; import { ObsidianServiceHub } from "./modules/services/ObsidianServiceHub.ts"; import { ServiceRebuilder } from "@lib/serviceModules/Rebuilder.ts"; import { ServiceDatabaseFileAccess } from "@/serviceModules/DatabaseFileAccess.ts"; @@ -27,20 +25,23 @@ import { FileAccessObsidian } from "./serviceModules/FileAccessObsidian.ts"; import { StorageEventManagerObsidian } from "./managers/StorageEventManagerObsidian.ts"; import type { ServiceModules } from "./types.ts"; import { setNoticeClass } from "@lib/mock_and_interop/wrapper.ts"; -import type { ObsidianServiceContext } from "./lib/src/services/implements/obsidian/ObsidianServiceContext.ts"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext.ts"; import { LiveSyncBaseCore } from "./LiveSyncBaseCore.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"; -import { useOfflineScanner } from "./lib/src/serviceFeatures/offlineScanner.ts"; -import { useCheckRemoteSize } from "./lib/src/serviceFeatures/checkRemoteSize.ts"; +import { useOfflineScanner } from "@lib/serviceFeatures/offlineScanner.ts"; +import { useCheckRemoteSize } from "@lib/serviceFeatures/checkRemoteSize.ts"; import { useRedFlagFeatures } from "./serviceFeatures/redFlag.ts"; import { useSetupProtocolFeature } from "./serviceFeatures/setupObsidian/setupProtocol.ts"; import { useSetupQRCodeFeature } from "@lib/serviceFeatures/setupObsidian/qrCode"; import { useSetupURIFeature } from "@lib/serviceFeatures/setupObsidian/setupUri"; import { useSetupManagerHandlersFeature } from "./serviceFeatures/setupObsidian/setupManagerHandlers.ts"; +import { useP2PReplicatorFeature } from "@lib/replication/trystero/useP2PReplicatorFeature.ts"; +import { useP2PReplicatorCommands } from "@lib/replication/trystero/useP2PReplicatorCommands.ts"; +import { useP2PReplicatorUI } from "./serviceFeatures/useP2PReplicatorUI.ts"; export type LiveSyncCore = LiveSyncBaseCore; export default class ObsidianLiveSyncPlugin extends Plugin { core: LiveSyncCore; @@ -136,10 +137,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin { const serviceHub = new ObsidianServiceHub(this); - // Capture useP2PReplicator result so it can be passed to the P2PReplicator addon - // TODO: Dependency fix: bit hacky - let p2pReplicatorResult: ReturnType | undefined; - this.core = new LiveSyncBaseCore( serviceHub, (core, serviceHub) => { @@ -184,10 +181,13 @@ export default class ObsidianLiveSyncPlugin extends Plugin { useOfflineScanner(core); useRedFlagFeatures(core); useCheckRemoteSize(core); - p2pReplicatorResult = useP2PReplicator(core, [ - VIEW_TYPE_P2P, - (leaf: any) => new P2PReplicatorPaneView(leaf, core, p2pReplicatorResult!), - ]); + // p2pReplicatorResult = useP2PReplicator(core, [ + // VIEW_TYPE_P2P, + // (leaf: any) => new P2PReplicatorPaneView(leaf, core, p2pReplicatorResult!), + // ]); + const replicator = useP2PReplicatorFeature(core); + useP2PReplicatorCommands(core, replicator); + useP2PReplicatorUI(core, core, replicator); } ); } diff --git a/src/serviceFeatures/useP2PReplicatorUI.ts b/src/serviceFeatures/useP2PReplicatorUI.ts new file mode 100644 index 0000000..bfe042d --- /dev/null +++ b/src/serviceFeatures/useP2PReplicatorUI.ts @@ -0,0 +1,76 @@ +import { eventHub, EVENT_REQUEST_OPEN_P2P } from "@/common/events"; +import { reactiveSource } from "octagonal-wheels/dataobject/reactive_v2"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { type UseP2PReplicatorResult } from "@/lib/src/replication/trystero/UseP2PReplicatorResult"; +import { P2PLogCollector } from "@/lib/src/replication/trystero/P2PLogCollector"; +import { P2PReplicatorPaneView, VIEW_TYPE_P2P } from "@/features/P2PSync/P2PReplicator/P2PReplicatorPaneView"; +import type { LiveSyncCore } from "@/main"; + +/** + * ServiceFeature: P2P Replicator lifecycle management. + * Binds a LiveSyncTrysteroReplicator to the host's lifecycle events, + * following the same middleware style as useOfflineScanner. + * + * @param viewTypeAndFactory Optional [viewType, factory] pair for registering the P2P pane view. + * When provided, also registers commands and ribbon icon via services.API. + */ + +export function useP2PReplicatorUI( + host: NecessaryServices< + | "API" + | "appLifecycle" + | "setting" + | "vault" + | "database" + | "databaseEvents" + | "keyValueDB" + | "replication" + | "config" + | "UI" + | "replicator", + never + >, + core: LiveSyncCore, + replicator: UseP2PReplicatorResult +) { + // const env: LiveSyncTrysteroReplicatorEnv = { services: host.services as any }; + const getReplicator = () => replicator.replicator; + const p2pLogCollector = new P2PLogCollector(); + const storeP2PStatusLine = reactiveSource(""); + p2pLogCollector.p2pReplicationLine.onChanged((line) => { + storeP2PStatusLine.value = line.value; + }); + + // Register view, commands and ribbon if a view factory is provided + const viewType = VIEW_TYPE_P2P; + const factory = (leaf: any) => { + return new P2PReplicatorPaneView(leaf, core, { + replicator: getReplicator(), + p2pLogCollector, + storeP2PStatusLine, + }); + }; + const openPane = () => host.services.API.showWindow(viewType); + host.services.API.registerWindow(viewType, factory); + + host.services.appLifecycle.onInitialise.addHandler(() => { + eventHub.onEvent(EVENT_REQUEST_OPEN_P2P, () => { + void openPane(); + }); + + host.services.API.addCommand({ + id: "open-p2p-replicator", + name: "P2P Sync : Open P2P Replicator", + callback: () => { + void openPane(); + }, + }); + + host.services.API.addRibbonIcon("waypoints", "P2P Replicator", () => { + void openPane(); + })?.addClass?.("livesync-ribbon-replicate-p2p"); + + return Promise.resolve(true); + }); + return { replicator: getReplicator(), p2pLogCollector, storeP2PStatusLine }; +}