diff --git a/docs/p2p_sync_updates_2026.md b/docs/p2p_sync_updates_2026.md index 34dc9de..b6f3903 100644 --- a/docs/p2p_sync_updates_2026.md +++ b/docs/p2p_sync_updates_2026.md @@ -20,15 +20,21 @@ Once you have saved the settings, return to the **P2P Status Pane** and click th ## 3. Real-time Control The status pane in the right sidebar provides granular control over your synchronisation: +- **Active P2P Remote (new):** P2P now has its own active remote selection, separate from the normal active remote for database replication. Use the combo box next to the cog icon to choose which P2P remote configuration is active for P2P features. +- **Create P2P Remote (new):** Use the **+** button to open the P2P setup dialogue and create a dedicated P2P remote configuration. This is recommended when no P2P active remote has been selected yet. +- **Selection required (new):** If no P2P active remote is selected, the pane asks for selection before P2P target-related changes are saved. + - **Signalling Status:** Shows if you are connected to the relay (🟢 Online). - **Live-push (Broadcast):** Toggle "Broadcast changes" to notify other peers whenever you make an edit. -- **Watch:** Enable "Watch" on specific peers to automatically pull changes when they broadcast. This creates a "LiveSync-like" experience. -- **Sync (🔄/🔁):** Mark specific peers as **sync targets**. Peers marked here will be included when you run the **"P2P: Sync with targets"** command (see section 5). Click the button next to a peer to toggle it on (🔄, highlighted) or off (🔁). This setting is persisted in your configuration. +- **Replicate now (🔄):** Start immediate bidirectional replication with a visible peer (Pull, then Push). +- **Watch (🔔/🔕):** Enable "Watch" on specific peers to automatically pull changes when they broadcast. This creates a "LiveSync-like" experience. +- **Sync target (🔗/⛓️‍💥):** Mark specific peers as **sync targets**. Peers marked here will be included when you run the **"P2P: Sync with targets"** command (see section 5). Click the button next to a peer to toggle it on (🔗, highlighted) or off (⛓️‍💥). This setting is persisted in your configuration. ## 4. Replication Dialogue If you want to synchronise with a specific peer manually, use the **Replication** command or button. This opens the **Replication Dialogue** listing available devices. Inside the dialogue, the **Server Status** card at the top confirms you are still connected while performing the sync. +The status card now shows a stable **Room ID suffix** above **Peer ID**. The Room ID suffix is better for identifying your P2P group, while Peer ID may change between connections. Two actions are available per peer: diff --git a/manifest.json b/manifest.json index 91eb189..70f2561 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { - "id": "obsidian-livesync", - "name": "Self-hosted LiveSync", - "version": "0.25.63", - "minAppVersion": "1.7.2", - "description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", - "author": "vorotamoroz", - "authorUrl": "https://github.com/vrtmrz", - "isDesktopOnly": false + "id": "obsidian-livesync", + "name": "Self-hosted LiveSync", + "version": "0.25.64", + "minAppVersion": "1.7.2", + "description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", + "author": "vorotamoroz", + "authorUrl": "https://github.com/vrtmrz", + "isDesktopOnly": false } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 68c1113..cf13e0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-livesync", - "version": "0.25.63", + "version": "0.25.64", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-livesync", - "version": "0.25.63", + "version": "0.25.64", "license": "MIT", "dependencies": { "@aws-sdk/client-s3": "^3.808.0", diff --git a/package.json b/package.json index 4fd1805..e38acd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-livesync", - "version": "0.25.63", + "version": "0.25.64", "description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.", "main": "main.js", "type": "module", diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte b/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte index 9dd7c8e..948a20e 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte @@ -5,20 +5,21 @@ AcceptedStatus, ConnectionStatus, type PeerStatus, - } from "../../../lib/src/replication/trystero/P2PReplicatorPaneCommon"; - import type { LiveSyncTrysteroReplicator } from "../../../lib/src/replication/trystero/LiveSyncTrysteroReplicator"; + } from "@lib/replication/trystero/P2PReplicatorPaneCommon"; + import type { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator"; import PeerStatusRow from "../P2PReplicator/PeerStatusRow.svelte"; - import { EVENT_LAYOUT_READY, eventHub } from "../../../common/events"; + import { EVENT_LAYOUT_READY, eventHub } from "@/common/events"; import { type PeerInfo, type P2PServerInfo, EVENT_SERVER_STATUS, EVENT_REQUEST_STATUS, EVENT_P2P_REPLICATOR_STATUS, - } from "../../../lib/src/replication/trystero/TrysteroReplicatorP2PServer"; - import { type P2PReplicatorStatus } from "../../../lib/src/replication/trystero/TrysteroReplicator"; - import { $msg as _msg } from "../../../lib/src/common/i18n"; - import { SETTING_KEY_P2P_DEVICE_NAME } from "../../../lib/src/common/types"; + } from "@lib/replication/trystero/TrysteroReplicatorP2PServer"; + import { type P2PReplicatorStatus } from "@lib/replication/trystero/TrysteroReplicator"; + import { $msg as _msg } from "@lib/common/i18n"; + import { SETTING_KEY_P2P_DEVICE_NAME } from "@lib/common/types"; + import { generateP2PRoomId } from "@lib/common/utils"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; interface Props { @@ -148,6 +149,7 @@ eventHub.emitEvent(EVENT_REQUEST_STATUS); return () => { r(); + rx(); r2(); r3(); }; @@ -216,18 +218,8 @@ function useDefaultRelay() { eRelay = DEFAULT_SETTINGS.P2P_relays; } - function _generateRandom() { - return (Math.floor(Math.random() * 1000) + 1000).toString().substring(1); - } - function generateRandom(length: number) { - let buf = ""; - while (buf.length < length) { - buf += "-" + _generateRandom(); - } - return buf.substring(1, length); - } function chooseRandom() { - eRoomId = generateRandom(12) + "-" + Math.random().toString(36).substring(2, 5); + eRoomId = generateP2PRoomId(); } async function openServer() { @@ -251,7 +243,7 @@ setting?: boolean; }; return initialDialogStatus; - } catch (e) { + } catch { return {}; } }; diff --git a/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte b/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte index 980aed4..4d53651 100644 --- a/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PServerStatusCard.svelte @@ -8,17 +8,22 @@ EVENT_REQUEST_STATUS, EVENT_P2P_REPLICATOR_STATUS, } from "@lib/replication/trystero/TrysteroReplicatorP2PServer"; + import { EVENT_SETTING_SAVED } from "@lib/events/coreEvents"; import type { LiveSyncTrysteroReplicator } from "@/lib/src/replication/trystero/LiveSyncTrysteroReplicator"; import type { P2PReplicatorStatus } from "@/lib/src/replication/trystero/TrysteroReplicator"; + import { extractP2PRoomSuffix } from "@/lib/src/common/utils"; + import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; interface Props { liveSyncReplicator: LiveSyncTrysteroReplicator; showBroadcastToggle?: boolean; + core?: LiveSyncBaseCore; } - let { liveSyncReplicator, showBroadcastToggle = true }: Props = $props(); + let { liveSyncReplicator, showBroadcastToggle = true, core }: Props = $props(); let serverInfo = $state(undefined); let replicatorStatus = $state(undefined); + let roomSuffix = $state(extractP2PRoomSuffix(core?.services.setting.currentSettings()?.P2P_roomID ?? "")); async function requestServerStatus() { await Promise.resolve(liveSyncReplicator.requestStatus()); @@ -46,10 +51,14 @@ onMount(() => { const unsubscribe = eventHub.onEvent(EVENT_SERVER_STATUS, (status) => { serverInfo = status; + roomSuffix = extractP2PRoomSuffix(status?.roomId ?? ""); }); const unsubscribeStatus = eventHub.onEvent(EVENT_P2P_REPLICATOR_STATUS, (status) => { replicatorStatus = status; }); + const unsubscribeSettings = eventHub.onEvent(EVENT_SETTING_SAVED, (settings) => { + roomSuffix = extractP2PRoomSuffix(settings?.P2P_roomID ?? ""); + }); fireAndForget(async () => { await delay(100); @@ -59,6 +68,7 @@ return () => { unsubscribe(); unsubscribeStatus(); + unsubscribeSettings(); }; }); @@ -85,6 +95,13 @@ {#if serverInfo} +
+ Room ID suffix: + + {roomSuffix || "-"} + +
+
Peer ID: @@ -162,6 +179,12 @@ text-overflow: ellipsis; } + .room-suffix-display { + font-family: monospace; + font-size: 0.85rem; + font-weight: 600; + } + .broadcast-row { align-items: center; margin-top: 0.25rem; diff --git a/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte b/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte index fc148f8..aeeee48 100644 --- a/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PServerStatusPane.svelte @@ -1,6 +1,6 @@

P2P Status

- +
+
+ + +
+ +
- + {#if !canEditP2PSettings()} +

Please select an active P2P remote configuration to change P2P sync targets.

+ {/if} + +
@@ -225,6 +457,15 @@ {getAcceptanceStatus(peer)} +
SYNC @@ -249,9 +491,10 @@ class="emoji-button {isSyncTarget(peer.name) ? 'is-watching' : ''}" title={isSyncTarget(peer.name) ? 'Sync target \u2014 click to remove' : 'Set as sync target'} aria-label={isSyncTarget(peer.name) ? 'Remove sync target' : 'Set sync target'} + disabled={!canEditP2PSettings()} onclick={() => toggleSyncTarget(peer)} > - {isSyncTarget(peer.name) ? '🔄' : '🔁'} + {isSyncTarget(peer.name) ? '🔗' : '⛓️‍💥'}
{:else}
@@ -345,6 +588,37 @@ gap: 0.5rem; } + .pane-header-actions { + display: flex; + align-items: center; + gap: 0.4rem; + min-width: 0; + } + + .remote-picker-wrap { + display: inline-flex; + gap: 0.3rem; + align-items: center; + min-width: 0; + } + + .remote-picker { + max-width: 14rem; + min-width: 8rem; + height: 1.9rem; + border: 1px solid var(--divider-color); + border-radius: 0.4rem; + background-color: var(--interactive-normal); + color: var(--text-normal); + padding: 0 0.45rem; + } + + .warning-line { + margin: -0.2rem 0 0; + font-size: 0.82rem; + color: var(--text-warning); + } + .pane-header h2 { margin: 0; font-size: 1.1rem; @@ -511,7 +785,7 @@ } .accepted-row { - grid-template-columns: 1fr auto; + grid-template-columns: 1fr auto auto; } .decision-label { diff --git a/src/lib b/src/lib index 07e287c..a0af792 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 07e287c53122a09300f916b5679826e2d1d75b5a +Subproject commit a0af792b48e6e7a5b14d7ee932b81796b65bd497 diff --git a/src/modules/features/SetupWizard/dialogs/SetupRemoteP2P.svelte b/src/modules/features/SetupWizard/dialogs/SetupRemoteP2P.svelte index 64a794f..cd2020e 100644 --- a/src/modules/features/SetupWizard/dialogs/SetupRemoteP2P.svelte +++ b/src/modules/features/SetupWizard/dialogs/SetupRemoteP2P.svelte @@ -1,13 +1,13 @@