diff --git a/ui/src/utils/moqPeerSettings.ts b/ui/src/utils/moqPeerSettings.ts new file mode 100644 index 00000000..890c42e2 --- /dev/null +++ b/ui/src/utils/moqPeerSettings.ts @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: © 2025 StreamKit Contributors +// +// SPDX-License-Identifier: MPL-2.0 + +import { load } from 'js-yaml'; + +export interface MoqPeerSettings { + gatewayPath?: string; + inputBroadcast?: string; + outputBroadcast?: string; +} + +type ParsedNode = { + kind?: string; + params?: { + gateway_path?: string; + input_broadcast?: string; + output_broadcast?: string; + }; +}; + +type ParsedYaml = { + nodes?: Record; +}; + +/** + * Extracts moq_peer settings from a pipeline YAML string. + * Looks for any node with kind 'transport::moq::peer' and returns its + * gateway_path, input_broadcast, and output_broadcast parameters. + * + * @param yamlContent - The YAML string to parse + * @returns MoqPeerSettings if a moq_peer node is found, null otherwise + */ +export function extractMoqPeerSettings(yamlContent: string): MoqPeerSettings | null { + try { + const parsed = load(yamlContent) as ParsedYaml; + + if (!parsed || typeof parsed !== 'object' || !parsed.nodes) { + return null; + } + + // Find the first node with kind 'transport::moq::peer' + for (const nodeConfig of Object.values(parsed.nodes)) { + if (nodeConfig.kind === 'transport::moq::peer' && nodeConfig.params) { + return { + gatewayPath: nodeConfig.params.gateway_path, + inputBroadcast: nodeConfig.params.input_broadcast, + outputBroadcast: nodeConfig.params.output_broadcast, + }; + } + } + + return null; + } catch { + return null; + } +} + +/** + * Updates a URL's path with a new path while preserving the protocol, host, and port. + * + * @param baseUrl - The original URL string + * @param newPath - The new path to set + * @returns The updated URL string, or the original if parsing fails + */ +export function updateUrlPath(baseUrl: string, newPath: string): string { + try { + const url = new URL(baseUrl); + url.pathname = newPath; + return url.toString(); + } catch { + // If URL parsing fails, try a simple path replacement + // Handle URLs like "https://example.com:4545/moq" -> "https://example.com:4545/moq/transcoder" + const match = baseUrl.match(/^(https?:\/\/[^/]+)(\/.*)?$/); + if (match) { + return match[1] + newPath; + } + return baseUrl; + } +} diff --git a/ui/src/views/StreamView.tsx b/ui/src/views/StreamView.tsx index f91454a3..8065dae4 100644 --- a/ui/src/views/StreamView.tsx +++ b/ui/src/views/StreamView.tsx @@ -17,6 +17,7 @@ import { createSession } from '@/services/sessions'; import { useSchemaStore, ensureSchemasLoaded } from '@/stores/schemaStore'; import type { Event } from '@/types/types'; import { getLogger } from '@/utils/logger'; +import { extractMoqPeerSettings, updateUrlPath } from '@/utils/moqPeerSettings'; import { orderSamplePipelinesSystemFirst } from '@/utils/samplePipelineOrdering'; import { useStreamStore } from '../stores/streamStore'; @@ -505,9 +506,25 @@ const StreamView: React.FC = () => { if (template) { viewState.setSelectedTemplateId(templateId); viewState.setPipelineYaml(template.yaml); + + // Auto-adjust connection settings based on moq_peer node in the pipeline + const moqSettings = extractMoqPeerSettings(template.yaml); + if (moqSettings) { + // Update gateway URL path if specified + if (moqSettings.gatewayPath && serverUrl) { + setServerUrl(updateUrlPath(serverUrl, moqSettings.gatewayPath)); + } + // Update broadcast names if specified + if (moqSettings.inputBroadcast) { + setInputBroadcast(moqSettings.inputBroadcast); + } + if (moqSettings.outputBroadcast) { + setOutputBroadcast(moqSettings.outputBroadcast); + } + } } }, - [viewState] + [viewState, serverUrl, setServerUrl, setInputBroadcast, setOutputBroadcast] ); // Handle session creation