| File: src\Aspire.Tray\Common\IAppHostClient.cs | Web Access |
| Project: src\tests\Aspire.Tray.Tests\Aspire.Tray.Tests.csproj (Aspire.Tray.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Aspire.Tray; internal interface IAppHostClient { IAsyncEnumerable<AppHostSnapshot> WatchAsync(CancellationToken cancellationToken); Task<StopResult> StopAsync(AppHostId id, CancellationToken cancellationToken); Task<StartResult> StartAsync(string appHostPath, CancellationToken cancellationToken); } internal readonly record struct AppHostId(string AppHostPath, int AppHostPid, long? ProcessStartTimeUnixMilliseconds) { // Identity matching follows the platform, but paths also reach menus, the clipboard, // and CLI arguments. Keep their original casing rather than storing an uppercased key. public bool Equals(AppHostId other) => TrayAppHostPath.Comparer.Equals(AppHostPath, other.AppHostPath) && AppHostPid == other.AppHostPid && ProcessStartTimeUnixMilliseconds == other.ProcessStartTimeUnixMilliseconds; public override int GetHashCode() { var hash = new HashCode(); hash.Add(AppHostPath, TrayAppHostPath.Comparer); hash.Add(AppHostPid); hash.Add(ProcessStartTimeUnixMilliseconds); return hash.ToHashCode(); } } internal enum DiscoveryState { Connecting, Live, Disconnected, Incompatible, LimitExceeded } internal sealed record AppHostSnapshot(IReadOnlyList<AppHostInfo> AppHosts, DiscoveryState Discovery); internal enum StopOutcome { Stopped, NotFound, Ambiguous, IdentityMismatch, IdentityUnavailable, Failed, TimedOut, Incompatible } internal sealed record StopResult(StopOutcome Outcome, int? ExitCode); internal enum StartOutcome { Started, NotFound, Failed, TimedOut } internal sealed record StartResult(StartOutcome Outcome, int? ExitCode); internal sealed record AppHostMenuItem( AppHostId Id, string Title, string Subtitle, string DisplayName, bool CanOpenDashboard, bool CanStop, bool IsStopping, string? Error) { public bool IsPinned { get; init; } public bool CanStart { get; init; } public bool IsStarting { get; init; } public bool IsRunning { get; init; } = true; public AppHostHealth Health { get; init; } } internal sealed record TrayViewState( DiscoveryState Discovery, IReadOnlyList<AppHostMenuItem> AppHosts, string Status) { public IReadOnlyList<AppHostMenuItem> RecentAppHosts { get; init; } = []; public bool CanClearRecent { get; init; } public bool HasActiveAppHosts { get; init; } = AppHosts.Any(host => host.IsRunning || host.IsStarting); public bool ShowStatus { get; init; } = AppHosts.Count == 0 || Discovery != DiscoveryState.Live || AppHosts.Any(host => host.Error is not null); }