diff --git a/src/LiveSyncBaseCore.ts b/src/LiveSyncBaseCore.ts index 27df933d..12168bec 100644 --- a/src/LiveSyncBaseCore.ts +++ b/src/LiveSyncBaseCore.ts @@ -37,6 +37,7 @@ import { usePrepareDatabaseForUse } from "@vrtmrz/livesync-commonlib/compat/serv import type { Constructor } from "@vrtmrz/livesync-commonlib/compat/common/utils.type"; import { CAPABILITY_NOT_APPLICABLE, + CENTRAL_REMOTE_REPLICATION_READINESS, defineReplicatorProviderDefinitions, supportedOpenReplicationContinuous, supportedOpenReplicationOneShot, @@ -158,6 +159,7 @@ export class LiveSyncBaseCore< [REMOTE_COUCHDB]: { kind: REMOTE_COUCHDB, diagnosticName: "CouchDB", + readiness: CENTRAL_REMOTE_REPLICATION_READINESS, isConfigured: (settings) => settings.remoteType === REMOTE_COUCHDB && !!settings.couchDB_URI?.trim() && @@ -171,6 +173,7 @@ export class LiveSyncBaseCore< [REMOTE_MINIO]: { kind: REMOTE_MINIO, diagnosticName: "Object Storage", + readiness: CENTRAL_REMOTE_REPLICATION_READINESS, isConfigured: (settings) => settings.remoteType === REMOTE_MINIO && !!settings.endpoint?.trim() && !!settings.bucket?.trim(), create: (_settings) => Promise.resolve(new LiveSyncJournalReplicator(this)), diff --git a/src/apps/webpeer/src/P2PCheckSession.ts b/src/apps/webpeer/src/P2PCheckSession.ts index 2c49569b..3ff3356a 100644 --- a/src/apps/webpeer/src/P2PCheckSession.ts +++ b/src/apps/webpeer/src/P2PCheckSession.ts @@ -53,7 +53,7 @@ export class P2PCheckSession { try { await runtime.start(); - await runtime.currentReplicator.makeSureOpened(); + await runtime.p2p.transportLifecycle.connect(); } catch (error) { await this.stop(); throw error; diff --git a/src/apps/webpeer/src/WebPeerRuntime.ts b/src/apps/webpeer/src/WebPeerRuntime.ts index 4aa323bc..c6e7d433 100644 --- a/src/apps/webpeer/src/WebPeerRuntime.ts +++ b/src/apps/webpeer/src/WebPeerRuntime.ts @@ -3,10 +3,9 @@ import { compatGlobal } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvFu import { EVENT_LAYOUT_READY } from "@vrtmrz/livesync-commonlib/compat/events/coreEvents"; import type { PeerStatus } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/P2PReplicatorPaneCommon"; import { P2PLogCollector } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/P2PLogCollector"; -import type { LiveSyncTrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/LiveSyncTrysteroReplicator"; -import type { UseP2PReplicatorResult } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/UseP2PReplicatorResult"; import { useP2PReplicatorFeature } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/useP2PReplicatorFeature"; import { ServiceContext, type LiveSyncEventHub } from "@vrtmrz/livesync-commonlib/context"; +import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import { unique } from "octagonal-wheels/collection"; import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase"; @@ -48,7 +47,7 @@ function removeFromList(item: string, list: string): string { export class WebPeerRuntime { readonly context: ServiceContext; readonly services: LiveSyncBrowserServiceHub; - readonly p2p: UseP2PReplicatorResult; + readonly p2p: P2PServiceViews; readonly p2pLogCollector: P2PLogCollector; readonly paneHost: P2PReplicatorPaneHost; @@ -87,10 +86,6 @@ export class WebPeerRuntime { return this.context.events; } - get currentReplicator(): LiveSyncTrysteroReplicator { - return this.p2p.replicator; - } - get settings(): P2PSyncSetting { return this.services.setting.currentSettings(); } @@ -119,9 +114,7 @@ export class WebPeerRuntime { } this.services.appLifecycle.markIsReady(); this.events.emitEvent(EVENT_LAYOUT_READY); - if (this.settings.P2P_AutoStart && this.settings.P2P_Enabled) { - compatGlobal.setTimeout(() => void this.currentReplicator.open(), 100); - } + await this.services.appLifecycle.onResumed(); return this; } @@ -151,12 +144,12 @@ export class WebPeerRuntime { this.menu = new Menu() .addItem((item) => item.setTitle("📥 Only fetch").onClick(async () => { - await this.currentReplicator.replicateFrom(peer.peerId); + await this.p2p.targetedTransfer.pullFromPeer(peer.peerId); }) ) .addItem((item) => item.setTitle("📤 Only send").onClick(async () => { - await this.currentReplicator.requestSynchroniseToPeer(peer.peerId); + await this.p2p.targetedTransfer.requestPushToPeer(peer.peerId); }) ) .addSeparator() diff --git a/src/features/P2PSync/P2PReplicator/P2POpenReplicationModal.ts b/src/features/P2PSync/P2PReplicator/P2POpenReplicationModal.ts index fba0d767..b3b527aa 100644 --- a/src/features/P2PSync/P2PReplicator/P2POpenReplicationModal.ts +++ b/src/features/P2PSync/P2PReplicator/P2POpenReplicationModal.ts @@ -1,7 +1,7 @@ import { App, Modal } from "@/deps.ts"; import P2POpenReplicationPane from "./P2POpenReplicationPane.svelte"; import { mount, unmount } from "svelte"; -import type { LiveSyncTrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/LiveSyncTrysteroReplicator"; +import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; export type P2POpenReplicationModalCallback = { onSync: (peerId: string) => Promise; @@ -9,7 +9,7 @@ export type P2POpenReplicationModalCallback = { }; export class P2POpenReplicationModal extends Modal { - liveSyncReplicator: LiveSyncTrysteroReplicator; + p2p: P2PServiceViews; callback?: P2POpenReplicationModalCallback; component?: ReturnType; showResult: boolean; @@ -19,7 +19,7 @@ export class P2POpenReplicationModal extends Modal { constructor( app: App, - liveSyncReplicator: LiveSyncTrysteroReplicator, + p2p: P2PServiceViews, callback?: P2POpenReplicationModalCallback, showResult: boolean = false, title: string = "P2P Replication", @@ -27,7 +27,7 @@ export class P2POpenReplicationModal extends Modal { rebuildMode: boolean = false ) { super(app); - this.liveSyncReplicator = liveSyncReplicator; + this.p2p = p2p; this.callback = callback; this.showResult = showResult; this.title = title; @@ -57,7 +57,7 @@ export class P2POpenReplicationModal extends Modal { this.component = mount(P2POpenReplicationPane, { target: contentEl, props: { - liveSyncReplicator: this.liveSyncReplicator, + p2p: this.p2p, onSync: (peerId: string) => this.onSync(peerId), onSyncAndClose: (peerId: string) => this.onSyncAndClose(peerId), onClose: () => this.close(), diff --git a/src/features/P2PSync/P2PReplicator/P2POpenReplicationPane.svelte b/src/features/P2PSync/P2PReplicator/P2POpenReplicationPane.svelte index 64b0821b..618c20f9 100644 --- a/src/features/P2PSync/P2PReplicator/P2POpenReplicationPane.svelte +++ b/src/features/P2PSync/P2PReplicator/P2POpenReplicationPane.svelte @@ -9,13 +9,13 @@ // import type { TrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicator"; import { LOG_LEVEL_NOTICE, LOG_LEVEL_INFO } from "@vrtmrz/livesync-commonlib/compat/common/types"; import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger"; - import type { LiveSyncTrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/LiveSyncTrysteroReplicator"; + import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import { delay, fireAndForget } from "octagonal-wheels/promises"; import P2PServerStatusCard from "./P2PServerStatusCard.svelte"; import { $msg as translateMessage } from "@/common/translation"; interface Props { - liveSyncReplicator: LiveSyncTrysteroReplicator; + p2p: P2PServiceViews; onSync: (_peerId: string) => Promise; onSyncAndClose: (_peerId: string) => Promise; onClose: () => void; @@ -23,15 +23,14 @@ rebuildMode?: boolean; } - let { onSync, onSyncAndClose, onClose, showResult, liveSyncReplicator, rebuildMode = false }: Props = $props(); - const getLiveSyncReplicator = () => liveSyncReplicator; + let { onSync, onSyncAndClose, onClose, showResult, p2p, rebuildMode = false }: Props = $props(); let serverInfo = $state(undefined); let syncingPeerId = $state(null); const logLevel = $derived(showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO); async function requestServerStatus() { - await liveSyncReplicator.requestStatus(); + p2p.diagnostics.requestStatus(); eventHub.emitEvent(EVENT_REQUEST_STATUS); } onMount(() => { @@ -73,7 +72,7 @@ async function disconnect() { try { - await liveSyncReplicator.close(); + await p2p.transportLifecycle.disconnect(); Logger("Signalling connection closed.", logLevel); } catch (e) { Logger(`Failed to close signalling connection: ${e instanceof Error ? e.message : String(e)}`, logLevel); @@ -100,7 +99,7 @@
- +

{translateMessage("Available Peers")}

diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicationUI.ts b/src/features/P2PSync/P2PReplicator/P2PReplicationUI.ts index 39cf4a62..65bc7c3e 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicationUI.ts +++ b/src/features/P2PSync/P2PReplicator/P2PReplicationUI.ts @@ -2,6 +2,7 @@ import type { App } from "@/deps.ts"; import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger"; import { LOG_LEVEL_NOTICE, LOG_LEVEL_INFO } from "@vrtmrz/livesync-commonlib/compat/common/types"; import type { LiveSyncTrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/LiveSyncTrysteroReplicator"; +import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import { P2POpenReplicationModal } from "./P2POpenReplicationModal"; /** @@ -15,8 +16,8 @@ import { P2POpenReplicationModal } from "./P2POpenReplicationModal"; */ export function createOpenReplicationUI( app: App -): (replicator: LiveSyncTrysteroReplicator) => (showResult: boolean) => Promise { - return (replicator: LiveSyncTrysteroReplicator) => +): (replicator: LiveSyncTrysteroReplicator, p2p: P2PServiceViews) => (showResult: boolean) => Promise { + return (replicator: LiveSyncTrysteroReplicator, p2p: P2PServiceViews) => (showResult: boolean): Promise => { const logLevel = showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO; return new Promise((resolve) => { @@ -57,7 +58,7 @@ export function createOpenReplicationUI( }; const modal = new P2POpenReplicationModal( app, - replicator, + p2p, { onSync: (peerId: string) => synchronise(peerId, false), onSyncAndClose: (peerId: string) => synchronise(peerId, true), @@ -85,8 +86,8 @@ export function createOpenReplicationUI( */ export function createOpenRebuildUI( app: App -): (replicator: LiveSyncTrysteroReplicator) => (showResult: boolean) => Promise { - return (replicator: LiveSyncTrysteroReplicator) => +): (replicator: LiveSyncTrysteroReplicator, p2p: P2PServiceViews) => (showResult: boolean) => Promise { + return (replicator: LiveSyncTrysteroReplicator, p2p: P2PServiceViews) => (showResult: boolean): Promise => { const logLevel = showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO; return new Promise((resolve) => { @@ -132,7 +133,7 @@ export function createOpenRebuildUI( const modal = new P2POpenReplicationModal( app, - replicator, + p2p, { onSync: doRebuild, onSyncAndClose: doRebuild, diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicationUI.unit.spec.ts b/src/features/P2PSync/P2PReplicator/P2PReplicationUI.unit.spec.ts index 86ad37e0..252e8255 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicationUI.unit.spec.ts +++ b/src/features/P2PSync/P2PReplicator/P2PReplicationUI.unit.spec.ts @@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const modalState = vi.hoisted(() => ({ instances: [] as Array<{ + p2p: unknown; callback: { onSync: (peerId: string) => Promise; onSyncAndClose: (peerId: string) => Promise; @@ -15,18 +16,20 @@ vi.mock("@/deps.ts", () => ({ App: class {} })); vi.mock("./P2POpenReplicationModal", () => ({ P2POpenReplicationModal: class { + p2p; callback; onClosed; open = vi.fn(); constructor( _app: unknown, - _replicator: unknown, + p2p: unknown, callback: (typeof modalState.instances)[number]["callback"], _showResult: boolean, _title?: string, onClosed?: () => void ) { + this.p2p = p2p; this.callback = callback; this.onClosed = onClosed; modalState.instances.push(this); @@ -46,15 +49,21 @@ function createReplicator() { } as any; } +function createP2PServiceViews() { + return { transportLifecycle: {}, diagnostics: {} } as any; +} + describe("createOpenReplicationUI", () => { beforeEach(() => { modalState.instances.length = 0; }); it("settles a cancelled peer-selection session when the modal closes", async () => { - const session = createOpenReplicationUI({} as any)(createReplicator())(true); + const p2p = createP2PServiceViews(); + const session = createOpenReplicationUI({} as any)(createReplicator(), p2p)(true); const modal = modalState.instances[0]; + expect(modal.p2p).toBe(p2p); expect(modal.onClosed).toBeTypeOf("function"); modal.onClosed?.(); @@ -63,7 +72,7 @@ describe("createOpenReplicationUI", () => { it("keeps repeated synchronisation inside the session boundary until the modal closes", async () => { const replicator = createReplicator(); - const session = createOpenReplicationUI({} as any)(replicator)(true); + const session = createOpenReplicationUI({} as any)(replicator, createP2PServiceViews())(true); const modal = modalState.instances[0]; let settled = false; void session.finally(() => { @@ -91,7 +100,7 @@ describe("createOpenReplicationUI", () => { finishPull = resolve; }) ); - const session = createOpenReplicationUI({} as any)(replicator)(true); + const session = createOpenReplicationUI({} as any)(replicator, createP2PServiceViews())(true); const modal = modalState.instances[0]; let settled = false; void session.finally(() => { @@ -111,7 +120,7 @@ describe("createOpenReplicationUI", () => { it("closes the P2P connection after a successful sync-and-close action", async () => { const replicator = createReplicator(); - const session = createOpenReplicationUI({} as any)(replicator)(true); + const session = createOpenReplicationUI({} as any)(replicator, createP2PServiceViews())(true); const modal = modalState.instances[0]; await modal.callback.onSyncAndClose("peer-a"); @@ -143,7 +152,7 @@ describe("createOpenRebuildUI", () => { finishPull = resolve; }) ); - const session = createOpenRebuildUI({} as any)(replicator)(true); + const session = createOpenRebuildUI({} as any)(replicator, createP2PServiceViews())(true); const modal = modalState.instances[0]; let settled = false; void session.finally(() => { @@ -166,7 +175,7 @@ describe("createOpenRebuildUI", () => { it("does not complete Fetch when the rebuild dialogue closes without selecting a peer", async () => { const replicator = createReplicator(); - const session = createOpenRebuildUI({} as any)(replicator)(true); + const session = createOpenRebuildUI({} as any)(replicator, createP2PServiceViews())(true); const modal = modalState.instances[0]; modal.onClosed?.(); diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte b/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte index a059c2b0..f8bf13ab 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte @@ -13,7 +13,6 @@ type PeerInfo, type P2PServerInfo, EVENT_SERVER_STATUS, - EVENT_REQUEST_STATUS, EVENT_P2P_REPLICATOR_STATUS, } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicatorP2PServer"; import type { P2PReplicatorStatus } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicator"; @@ -29,7 +28,6 @@ let services = $derived(host.services); let events = $derived(services.context.events); const currentSettings = () => services.setting.currentSettings() as P2PSyncSetting; - const currentReplicator = () => host.p2p.replicator; const initialSettings = { ...currentSettings() } as P2PSyncSetting; let settings = $state(initialSettings); @@ -146,7 +144,7 @@ replicatorInfo = status; }); applyLoadSettings(currentSettings(), true); - events.emitEvent(EVENT_REQUEST_STATUS); + host.p2p.diagnostics.requestStatus(); return () => { r(); rx(); @@ -223,16 +221,16 @@ } async function openServer() { - await currentReplicator().open(); + await host.p2p.transportLifecycle.connect(); } async function closeServer() { - await currentReplicator().close(); + await host.p2p.transportLifecycle.disconnect(); } function startBroadcasting() { - currentReplicator().enableBroadcastChanges(); + host.p2p.changeRelay.enableBroadcastChanges(); } function stopBroadcasting() { - currentReplicator().disableBroadcastChanges(); + host.p2p.changeRelay.disableBroadcastChanges(); } const initialDialogStatusKey = `p2p-dialog-status`; diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneHost.ts b/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneHost.ts index 0118aa4b..3204e2dd 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneHost.ts +++ b/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneHost.ts @@ -1,12 +1,20 @@ import type { RequiredServices } from "@vrtmrz/livesync-commonlib/compat/interfaces/ServiceModule"; +import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import type { PeerStatus } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/P2PReplicatorPaneCommon"; -import type { UseP2PReplicatorResult } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/UseP2PReplicatorResult"; -export type P2PReplicatorHandle = Pick; +/** + * The shared pane only needs the contracts which represent its visible + * actions. In particular, it must not receive the compatibility Replicator + * facade, whose lifecycle methods can bypass the stable P2P service owner. + */ +export type P2PReplicatorPaneP2P = Pick< + P2PServiceViews, + "transportLifecycle" | "peerDirectory" | "peerAdmission" | "targetedTransfer" | "changeRelay" | "diagnostics" +>; /** Host capabilities consumed by the shared P2P pane. */ export interface P2PReplicatorPaneHost { readonly services: RequiredServices<"API" | "config" | "setting" | "vault">; - readonly p2p: P2PReplicatorHandle; + readonly p2p: P2PReplicatorPaneP2P; readonly showPeerMenu?: (peer: PeerStatus, event: MouseEvent) => void; } diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts b/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts index 99671f81..2b9e1d84 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts +++ b/src/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.ts @@ -8,7 +8,7 @@ import { LOG_LEVEL_NOTICE, REMOTE_P2P } from "@vrtmrz/livesync-commonlib/compat/ import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger"; import type { PeerStatus } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/P2PReplicatorPaneCommon"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts"; -import type { P2PPaneParams } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/UseP2PReplicatorResult"; +import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; export const VIEW_TYPE_P2P = "p2p-replicator"; function addToList(item: string, list: string) { @@ -31,7 +31,7 @@ function removeFromList(item: string, list: string) { export class P2PReplicatorPaneView extends SvelteItemView { core: LiveSyncBaseCore; - private _p2pResult: P2PPaneParams; + private _p2p: P2PServiceViews; override icon = "waypoints"; title: string = ""; override navigation = false; @@ -39,21 +39,18 @@ export class P2PReplicatorPaneView extends SvelteItemView { override getIcon(): string { return "waypoints"; } - get replicator() { - return this._p2pResult.replicator; - } async replicateFrom(peer: PeerStatus) { - await this.replicator.replicateFrom(peer.peerId); + await this._p2p.targetedTransfer.pullFromPeer(peer.peerId); } async replicateTo(peer: PeerStatus) { - await this.replicator.requestSynchroniseToPeer(peer.peerId); + await this._p2p.targetedTransfer.requestPushToPeer(peer.peerId); } async getRemoteConfig(peer: PeerStatus) { Logger( `Requesting remote config for ${peer.name}. Please input the passphrase on the remote device`, LOG_LEVEL_NOTICE ); - const remoteConfig = await this.replicator.getRemoteConfig(peer.peerId); + const remoteConfig = await this._p2p.configurationExchange.getRemoteConfiguration(peer.peerId); if (remoteConfig) { Logger(`Remote config for ${peer.name} is retrieved successfully`); const DROP = "Yes, and drop local database"; @@ -122,10 +119,10 @@ 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: P2PPaneParams) { + constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2p: P2PServiceViews) { super(leaf); this.core = core; - this._p2pResult = p2pResult; + this._p2p = p2p; } private showPeerMenu(peer: PeerStatus, event: MouseEvent): void { @@ -187,7 +184,7 @@ And you can also drop the local database to rebuild from the remote device.`, props: { host: { services: this.core.services, - p2p: this._p2pResult, + p2p: this._p2p, showPeerMenu: (peer: PeerStatus, event: MouseEvent) => this.showPeerMenu(peer, event), }, }, diff --git a/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte b/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte index caa5cd42..13e7a244 100644 --- a/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte @@ -9,19 +9,19 @@ EVENT_P2P_REPLICATOR_STATUS, } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicatorP2PServer"; import { EVENT_SETTING_SAVED } from "@vrtmrz/livesync-commonlib/compat/events/coreEvents"; - import type { LiveSyncTrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/LiveSyncTrysteroReplicator"; + import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import type { P2PReplicatorStatus } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicator"; import { extractP2PRoomSuffix } from "@vrtmrz/livesync-commonlib/compat/common/utils"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; import { $msg as translateMessage } from "@/common/translation"; interface Props { - getLiveSyncReplicator: () => LiveSyncTrysteroReplicator; + p2p: P2PServiceViews; showBroadcastToggle?: boolean; core?: LiveSyncBaseCore; } - let { getLiveSyncReplicator, showBroadcastToggle = true, core }: Props = $props(); + let { p2p, showBroadcastToggle = true, core }: Props = $props(); let serverInfo = $state(undefined); let replicatorStatus = $state(undefined); // Later setting changes arrive through EVENT_SETTING_SAVED; these values only seed local state at mount time. @@ -31,25 +31,25 @@ let useDiagRTC = $state(initialSettings?.P2P_useDiagRTC ?? false); async function requestServerStatus() { - await Promise.resolve(getLiveSyncReplicator().requestStatus()); + p2p.diagnostics.requestStatus(); eventHub.emitEvent(EVENT_REQUEST_STATUS); } async function onOpenConnection() { - await getLiveSyncReplicator().makeSureOpened(); + await p2p.transportLifecycle.connect(); await requestServerStatus(); } async function onDisconnect() { - await getLiveSyncReplicator().close(); + await p2p.transportLifecycle.disconnect(); await requestServerStatus(); } function toggleBroadcast() { if (replicatorStatus?.isBroadcasting) { - getLiveSyncReplicator().disableBroadcastChanges(); + p2p.changeRelay.disableBroadcastChanges(); } else { - getLiveSyncReplicator().enableBroadcastChanges(); + p2p.changeRelay.enableBroadcastChanges(); } } diff --git a/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte b/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte index 3171cf72..09530814 100644 --- a/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte @@ -8,7 +8,7 @@ EVENT_P2P_REPLICATOR_PROGRESS, type P2PServerInfo, } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicatorP2PServer"; - import type { LiveSyncTrysteroReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/LiveSyncTrysteroReplicator"; + import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import type { P2PReplicatorStatus, P2PReplicationReport } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/TrysteroReplicator"; import { delay, fireAndForget } from "octagonal-wheels/promises"; import P2PServerStatusCard from "./P2PServerStatusCard.svelte"; @@ -33,11 +33,11 @@ } from "./p2pPeerSettings"; interface Props { - getLiveSyncReplicator: () => LiveSyncTrysteroReplicator; + p2p: P2PServiceViews; core: LiveSyncBaseCore; } - let { getLiveSyncReplicator, core }: Props = $props(); + let { p2p, core }: Props = $props(); let serverInfo = $state(undefined); let replicatorInfo = $state(undefined); let decidingPeerId = $state(null); @@ -121,7 +121,7 @@ } async function requestServerStatus() { - await getLiveSyncReplicator().requestStatus(); + p2p.diagnostics.requestStatus(); eventHub.emitEvent(EVENT_REQUEST_STATUS); } @@ -296,7 +296,7 @@ ) { decidingPeerId = peer.peerId; try { - await getLiveSyncReplicator().makeDecision({ + await p2p.peerAdmission.makeDecision({ peerId: peer.peerId, name: peer.name, decision, @@ -311,7 +311,7 @@ async function revokeDecision(peer: P2PServerInfo["knownAdvertisements"][number]) { decidingPeerId = peer.peerId; try { - await getLiveSyncReplicator().revokeDecision({ + await p2p.peerAdmission.revokeDecision({ peerId: peer.peerId, name: peer.name, }); @@ -324,10 +324,7 @@ async function startReplication(peer: P2PServerInfo["knownAdvertisements"][number]) { replicatingPeerId = peer.peerId; try { - const pullResult = await getLiveSyncReplicator().replicateFrom(peer.peerId, true); - if (pullResult?.ok) { - await getLiveSyncReplicator().requestSynchroniseToPeer(peer.peerId); - } + await p2p.targetedTransfer.synchroniseWithPeer(peer.peerId, true); await requestServerStatus(); } finally { replicatingPeerId = null; @@ -347,9 +344,9 @@ return; } if (isWatching(peerId)) { - getLiveSyncReplicator().unwatchPeer(peerId); + p2p.changeRelay.unwatchPeer(peerId); } else { - getLiveSyncReplicator().watchPeer(peerId); + p2p.changeRelay.watchPeer(peerId); } } @@ -455,7 +452,7 @@

{/if} - +
diff --git a/src/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.ts b/src/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.ts index e10cfad9..0a5eed05 100644 --- a/src/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.ts +++ b/src/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.ts @@ -2,21 +2,21 @@ import { WorkspaceLeaf } from "@/deps.ts"; import { mount } from "svelte"; import { SvelteItemView } from "@/common/SvelteItemView.ts"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts"; -import type { P2PPaneParams } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/UseP2PReplicatorResult"; +import type { P2PServiceViews } from "@vrtmrz/livesync-commonlib/p2p"; import P2PServerStatusPane from "./P2PServerStatusPane.svelte"; export const VIEW_TYPE_P2P_SERVER_STATUS = "p2p-server-status"; export class P2PServerStatusPaneView extends SvelteItemView { core: LiveSyncBaseCore; - private _p2pResult: P2PPaneParams; + private readonly p2p: P2PServiceViews; override icon = "waypoints"; override navigation = false; - constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2pResult: P2PPaneParams) { + constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2p: P2PServiceViews) { super(leaf); this.core = core; - this._p2pResult = p2pResult; + this.p2p = p2p; } override getIcon(): string { @@ -35,7 +35,7 @@ export class P2PServerStatusPaneView extends SvelteItemView { return mount(P2PServerStatusPane, { target, props: { - getLiveSyncReplicator: () => this._p2pResult.replicator, + p2p: this.p2p, core: this.core, }, }); diff --git a/src/features/P2PSync/P2PReplicator/PeerStatusRow.svelte b/src/features/P2PSync/P2PReplicator/PeerStatusRow.svelte index 1ad8bb68..d9f58a0b 100644 --- a/src/features/P2PSync/P2PReplicator/PeerStatusRow.svelte +++ b/src/features/P2PSync/P2PReplicator/PeerStatusRow.svelte @@ -1,17 +1,16 @@