Enhance P2P synchronization features and UI improvements

This commit is contained in:
vorotamoroz
2026-05-16 23:50:08 +09:00
parent f0628a0d2c
commit 9a90256a8a
7 changed files with 122 additions and 26 deletions

View File

@@ -57,16 +57,16 @@
}
async function handleSyncAndClose(peerId: string) {
try {
syncingPeerId = peerId;
Logger(`Starting sync and close with ${peerId}`, logLevel);
await onSyncAndClose(peerId);
Logger(`Sync and close completed with ${peerId}`, logLevel);
} catch (e) {
Logger(`Error during sync and close: ${e instanceof Error ? e.message : String(e)}`, logLevel);
} finally {
syncingPeerId = null;
}
fireAndForget(async () => {
try {
Logger(`Starting sync with ${peerId}`, logLevel);
await onSync(peerId);
Logger(`Sync completed with ${peerId}`, logLevel);
} catch (e) {
Logger(`Error during sync: ${e instanceof Error ? e.message : String(e)}`, logLevel);
}
});
onClose();
}
async function disconnect(){
try {
@@ -103,7 +103,7 @@
/>
<div class="peers-section">
<h3>Available Devices</h3>
<h3>Available Peers</h3>
{#if serverInfo && serverInfo.knownAdvertisements.length > 0}
<div class="peers-list">
{#each serverInfo.knownAdvertisements as peer (peer.peerId)}
@@ -133,7 +133,7 @@
disabled={syncingPeerId !== null}
onclick={() => handleSyncAndClose(peer.peerId)}
>
{syncingPeerId === peer.peerId ? "Syncing..." : "Sync & Close"}
Start Sync &amp; Close
</button>
</div>
</div>
@@ -181,6 +181,7 @@
.peer-item {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-items: center;
padding: 0.75rem;
background-color: var(--background-secondary);
@@ -234,9 +235,9 @@
}
.peer-actions {
flex-wrap: wrap;
display: flex;
gap: 0.5rem;
flex-shrink: 0;
}
.btn {

View File

@@ -12,17 +12,32 @@
import type { P2PReplicatorStatus, P2PReplicationReport } from "@/lib/src/replication/trystero/TrysteroReplicator";
import { delay, fireAndForget } from "octagonal-wheels/promises";
import P2PServerStatusCard from "./P2PServerStatusCard.svelte";
import { EVENT_SETTING_SAVED } from "@lib/events/coreEvents";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore";
interface Props {
liveSyncReplicator: LiveSyncTrysteroReplicator;
core: LiveSyncBaseCore;
}
let { liveSyncReplicator }: Props = $props();
let { liveSyncReplicator, core }: Props = $props();
let serverInfo = $state<P2PServerInfo | undefined>(undefined);
let replicatorInfo = $state<P2PReplicatorStatus | undefined>(undefined);
let decidingPeerId = $state<string | null>(null);
let communicatingUntil = $state<Record<string, number>>({});
const COMMUNICATION_HOLD_MS = 2500;
let syncOnReplicationSetting = $state(
core.services.setting.currentSettings()?.P2P_SyncOnReplication ?? ""
);
function addToList(item: string, list: string): string {
const items = list.split(",").map((e) => e.trim()).filter((e) => e);
if (!items.includes(item)) items.push(item);
return items.join(",");
}
function removeFromList(item: string, list: string): string {
return list.split(",").map((e) => e.trim()).filter((e) => e && e !== item).join(",");
}
function markCommunicating(peerId: string) {
const expiry = Date.now() + COMMUNICATION_HOLD_MS;
@@ -60,6 +75,10 @@
}
});
const unsubscribeSettings = eventHub.onEvent(EVENT_SETTING_SAVED, (settings) => {
syncOnReplicationSetting = settings?.P2P_SyncOnReplication ?? "";
});
fireAndForget(async () => {
await delay(100);
await requestServerStatus();
@@ -69,6 +88,7 @@
unsubscribe();
unsubscribeReplicatorStatus();
unsubscribeReplicatorProgress();
unsubscribeSettings();
};
});
@@ -145,6 +165,22 @@
const isHeldCommunicating = (communicatingUntil[peerId] ?? 0) > Date.now();
return isLiveCommunicating || isHeldCommunicating;
}
function isSyncTarget(peerName: string) {
return syncOnReplicationSetting
.split(",")
.map((e) => e.trim())
.filter((e) => e)
.includes(peerName);
}
async function toggleSyncTarget(peer: P2PServerInfo["knownAdvertisements"][number]) {
const currentValue = core.services.setting.currentSettings()?.P2P_SyncOnReplication ?? "";
const newValue = isSyncTarget(peer.name)
? removeFromList(peer.name, currentValue)
: addToList(peer.name, currentValue);
await core.services.setting.applyPartial({ P2P_SyncOnReplication: newValue }, true);
}
</script>
<div class="p2p-container">
@@ -207,8 +243,17 @@
>
{isWatching(peer.peerId) ? '👁' : '👁‍🗨'}
</button>
</div>
{:else}
</div> <div class="decision-row watch-row">
<span class="decision-label">SYNC</span>
<button
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'}
onclick={() => toggleSyncTarget(peer)}
>
{isSyncTarget(peer.name) ? '🔄' : '🔁'}
</button>
</div> {:else}
<div class="decision-status">
<span class="badge status-chip {getAcceptanceStatusClass(peer)}">
{getAcceptanceStatus(peer)}

View File

@@ -36,6 +36,7 @@ export class P2PServerStatusPaneView extends SvelteItemView {
target,
props: {
liveSyncReplicator: this._p2pResult.replicator,
core: this.core,
},
});
}