mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-09-23 11:07:06 +00:00
Use host preparation for TURN connection settings
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import TurnConfiguration from "@/features/P2PSync/TurnConfiguration.svelte";
|
||||
import { validateIceServerSourceConfiguration } from "@/integrations/iceServerSources";
|
||||
import { validateManagedTurnSettings } from "@/integrations/turnSettings";
|
||||
// import { delay } from "octagonal-wheels/promises";
|
||||
import DialogHeader from "@/modules/services/LiveSyncUI/components/DialogHeader.svelte";
|
||||
import Guidance from "@/modules/services/LiveSyncUI/components/Guidance.svelte";
|
||||
@@ -101,14 +101,14 @@
|
||||
async function checkConnection() {
|
||||
try {
|
||||
processing = true;
|
||||
const sourceError = validateIceServerSourceConfiguration(syncSetting.P2P_iceServerSource);
|
||||
const sourceError = validateManagedTurnSettings(syncSetting);
|
||||
if (sourceError) return sourceError;
|
||||
const trialRemoteSetting = generateSetting();
|
||||
const admission = connectionProbe;
|
||||
if (!admission) {
|
||||
throw new Error("The P2P Setup connection probe is not available.");
|
||||
}
|
||||
const result = await coordinateP2PSetupConnectionProbe(admission, trialRemoteSetting, async () => {
|
||||
const result = await coordinateP2PSetupConnectionProbe(admission, trialRemoteSetting, async (signallingSettings) => {
|
||||
const map = new Map<string, unknown>();
|
||||
const store = {
|
||||
get: (key: string) => {
|
||||
@@ -136,7 +136,7 @@
|
||||
const env: ReplicatorHostEnv = {
|
||||
events: context.context.events,
|
||||
translate: context.context.translate,
|
||||
settings: trialRemoteSetting,
|
||||
settings: signallingSettings,
|
||||
processReplicatedDocs: async (_docs: PouchDB.Core.ExistingDocument<EntryDoc>[]) => {
|
||||
return;
|
||||
},
|
||||
@@ -207,7 +207,7 @@
|
||||
}
|
||||
}
|
||||
function commit() {
|
||||
error = validateIceServerSourceConfiguration(syncSetting.P2P_iceServerSource) ?? "";
|
||||
error = validateManagedTurnSettings(syncSetting) ?? "";
|
||||
if (error) return;
|
||||
const setting = pickP2PSyncSettings(generateSetting());
|
||||
setResult(setting);
|
||||
@@ -221,7 +221,7 @@
|
||||
syncSetting.P2P_roomID.trim() !== "" &&
|
||||
syncSetting.P2P_passphrase.trim() !== "" &&
|
||||
(syncSetting.P2P_DevicePeerName ?? "").trim() !== "" &&
|
||||
validateIceServerSourceConfiguration(syncSetting.P2P_iceServerSource) === undefined
|
||||
validateManagedTurnSettings(syncSetting) === undefined
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
type P2PConnectionProbeAdmission,
|
||||
type P2PConnectionProbeSettings,
|
||||
} from "@vrtmrz/livesync-commonlib/p2p";
|
||||
import { P2PConnectionPaths, type P2PSyncSetting } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
|
||||
export type P2PSetupConnectionProbeResult =
|
||||
| { readonly ok: true }
|
||||
@@ -20,12 +21,25 @@ export interface P2PSetupConnectionProbe {
|
||||
}
|
||||
|
||||
/** Interpret the stable P2P owner's admission without constructing transport eagerly. */
|
||||
export async function coordinateP2PSetupConnectionProbe(
|
||||
export async function coordinateP2PSetupConnectionProbe<T extends P2PConnectionProbeSettings>(
|
||||
admission: P2PConnectionProbeAdmission,
|
||||
trialSettings: P2PConnectionProbeSettings,
|
||||
runOwnedTrial: () => Promise<P2PSetupConnectionProbeResult>
|
||||
trialSettings: T,
|
||||
runOwnedTrial: (settings: T) => Promise<P2PSetupConnectionProbeResult>
|
||||
): Promise<P2PSetupConnectionProbeResult> {
|
||||
const settlement = await admission.run(trialSettings, runOwnedTrial);
|
||||
const settlement = await admission.run(trialSettings, () => {
|
||||
// This trial checks signalling only; TURN allocation belongs to an actual connection.
|
||||
const settings: T & Partial<P2PSyncSetting> = { ...trialSettings };
|
||||
delete settings.P2P_managedType;
|
||||
delete settings.P2P_managedId;
|
||||
delete settings.P2P_managedToken;
|
||||
delete settings.P2P_iceServers;
|
||||
delete settings.P2P_iceServersExpiresAt;
|
||||
settings.P2P_turnServers = "";
|
||||
settings.P2P_turnUsername = "";
|
||||
settings.P2P_turnCredential = "";
|
||||
settings.P2P_connectionPath = P2PConnectionPaths.Automatic;
|
||||
return runOwnedTrial(settings);
|
||||
});
|
||||
if (settlement.status === "observed-active") return { ok: true };
|
||||
if (settlement.status === "blocked") {
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { ACTIVE_P2P_RELAY_BINDING_CONFLICT, type P2PConnectionProbeAdmission } from "@vrtmrz/livesync-commonlib/p2p";
|
||||
import { DEFAULT_SETTINGS, P2PConnectionPaths } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import {
|
||||
coordinateP2PSetupConnectionProbe,
|
||||
probeP2PSetupConnection,
|
||||
@@ -7,6 +8,40 @@ import {
|
||||
} from "./p2pSetupConnectionProbe";
|
||||
|
||||
describe("P2P setup connection probe", () => {
|
||||
it("constructs a signalling-only trial when the draft selects managed TURN", async () => {
|
||||
const settings = {
|
||||
...DEFAULT_SETTINGS,
|
||||
P2P_managedType: "CF",
|
||||
P2P_managedId: "test-key",
|
||||
P2P_managedToken: "test-token",
|
||||
P2P_iceServers: [
|
||||
{ urls: "turn:temporary.example.test", username: "issued-user", credential: "issued-password" },
|
||||
],
|
||||
P2P_iceServersExpiresAt: 123456789,
|
||||
P2P_turnServers: "turn:unused.example.test:3478",
|
||||
P2P_turnUsername: "unused-user",
|
||||
P2P_turnCredential: "unused-password",
|
||||
P2P_connectionPath: P2PConnectionPaths.Relay,
|
||||
};
|
||||
const admission: P2PConnectionProbeAdmission = {
|
||||
run: async (_settings, trial) => ({ status: "trial", result: await trial() }),
|
||||
};
|
||||
const result = await coordinateP2PSetupConnectionProbe(admission, settings, async (trial = settings) => {
|
||||
expect(trial.P2P_managedType).toBeUndefined();
|
||||
expect(trial.P2P_managedToken).toBeUndefined();
|
||||
expect(trial.P2P_iceServers).toBeUndefined();
|
||||
expect(trial.P2P_iceServersExpiresAt).toBeUndefined();
|
||||
expect(trial.P2P_turnServers).toBe("");
|
||||
expect(trial.P2P_turnUsername).toBe("");
|
||||
expect(trial.P2P_turnCredential).toBe("");
|
||||
expect(trial.P2P_connectionPath).toBe(P2PConnectionPaths.Automatic);
|
||||
return { ok: true };
|
||||
});
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(settings.P2P_managedToken).toBe("test-token");
|
||||
expect(settings.P2P_connectionPath).toBe(P2PConnectionPaths.Relay);
|
||||
});
|
||||
|
||||
it("uses a compatible active signalling connection without constructing a trial", async () => {
|
||||
const runOwnedTrial = vi.fn(async (): Promise<P2PSetupConnectionProbeResult> => ({ ok: true }));
|
||||
const admission: P2PConnectionProbeAdmission = {
|
||||
|
||||
Reference in New Issue
Block a user