| File: Terminal\DefaultTerminalConnectionResolver.cs | Web Access |
| Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Dashboard.Model; using Hex1b; namespace Aspire.Dashboard.Terminal; /// <summary> /// Resolves per-replica HMP v1 producer streams from the live resource /// snapshots in <see cref="IDashboardClient"/>. The dashboard receives /// the consumer UDS path inside each replica snapshot's properties; this /// resolver looks up the requested resource by its unique instance name and /// connects to the matching local socket. /// </summary> /// <remarks> /// <para>The path itself is included in the gRPC stream from the AppHost. In Aspire's /// single-user, single-machine local-dev scenario the path is not a privileged /// secret (the user already controls the AppHost process and can read or write /// anything in its temp directory), but the path never reaches the browser via /// the terminal WebSocket because the proxy takes only /// a <c>resource</c> instance identifier.</para> /// <para>The resolver opens only the transport. The WebSocket handler owns /// the HMP1 consumer and its per-browser HWT1 presentation lifetime.</para> /// </remarks> internal sealed class DefaultTerminalConnectionResolver : ITerminalConnectionResolver { private readonly IDashboardClient _client; public DefaultTerminalConnectionResolver(IDashboardClient client) { _client = client ?? throw new ArgumentNullException(nameof(client)); } public async Task<Stream?> ConnectAsync(string resourceName, CancellationToken cancellationToken) { if (!_client.IsEnabled) { return null; } var match = _client.GetResource(resourceName); if (match is null || !match.HasTerminal()) { return null; } if (!match.TryGetTerminalConsumerUdsPath(out var udsPath)) { return null; } return await Hmp1Transports.ConnectUnixSocket(udsPath, cancellationToken).ConfigureAwait(false); } }