Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make some types non-generic #1237

Merged
merged 2 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/Aspire.Dashboard/Components/Pages/Resources.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ public partial class Resources : ComponentBase, IDisposable
private IEnumerable<EnvironmentVariableViewModel>? SelectedEnvironmentVariables { get; set; }
private string? SelectedResourceName { get; set; }

private static ViewModelMonitor<ResourceViewModel> GetViewModelMonitor(IDashboardViewModelService dashboardViewModelService)
=> dashboardViewModelService.GetResources();

private bool Filter(ResourceViewModel resource)
=> ((resource.ResourceType == "Project" && _areProjectsVisible) ||
(resource.ResourceType == "Container" && _areContainersVisible) ||
Expand Down Expand Up @@ -78,7 +75,7 @@ private void HandleTypeFilterTypeChanged()
protected override void OnInitialized()
{
_applicationUnviewedErrorCounts = TelemetryRepository.GetApplicationUnviewedErrorLogsCount();
var viewModelMonitor = GetViewModelMonitor(DashboardViewModelService);
var viewModelMonitor = DashboardViewModelService.GetResources();
var resources = viewModelMonitor.Snapshot;
var watch = viewModelMonitor.Watch;
foreach (var resource in resources)
Expand Down
7 changes: 4 additions & 3 deletions src/Aspire.Dashboard/Model/IDashboardViewModelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ public interface IDashboardViewModelService
{
string ApplicationName { get; }

ViewModelMonitor<ResourceViewModel> GetResources();
ViewModelMonitor GetResources();
}

public record ViewModelMonitor<TViewModel>(List<TViewModel> Snapshot, IAsyncEnumerable<ResourceChanged<TViewModel>> Watch)
where TViewModel : ResourceViewModel;
public record ViewModelMonitor(
List<ResourceViewModel> Snapshot,
IAsyncEnumerable<ResourceChange> Watch);
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@

namespace Aspire.Dashboard.Model;

public sealed record ResourceChanged<T>(ObjectChangeType ObjectChangeType, T Resource)
where T : class;
public sealed record ResourceChange(ObjectChangeType ObjectChangeType, ResourceViewModel Resource);
17 changes: 9 additions & 8 deletions src/Aspire.Hosting/Dashboard/DashboardViewModelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ internal sealed partial class DashboardViewModelService : IDashboardViewModelSer
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly CancellationToken _cancellationToken;

// Private channels, for decoupling producer/consumer and serialising updates.
private readonly Channel<(WatchEventType, string, CustomResource?)> _kubernetesChangesChannel;
private readonly Channel<ResourceChange> _resourceViewModelChangesChannel;

private readonly Dictionary<string, Container> _containersMap = [];
private readonly Dictionary<string, Executable> _executablesMap = [];
private readonly Dictionary<string, Service> _servicesMap = [];
Expand All @@ -40,9 +43,7 @@ internal sealed partial class DashboardViewModelService : IDashboardViewModelSer
private readonly ConcurrentDictionary<string, List<EnvVar>> _additionalEnvVarsMap = [];
private readonly HashSet<string> _containersWithTaskStarted = [];

private readonly Channel<ResourceChanged<ResourceViewModel>> _resourceViewModelChangesChannel;

private readonly ViewModelProcessor<ResourceViewModel> _resourceViewModelProcessor;
private readonly ViewModelProcessor _resourceViewModelProcessor;

public DashboardViewModelService(
DistributedApplicationModel applicationModel, KubernetesService kubernetesService, IHostEnvironment hostEnvironment, ILoggerFactory loggerFactory)
Expand All @@ -52,23 +53,23 @@ public DashboardViewModelService(
_applicationName = ComputeApplicationName(hostEnvironment.ApplicationName);
_logger = loggerFactory.CreateLogger<DashboardViewModelService>();
_cancellationToken = _cancellationTokenSource.Token;

_kubernetesChangesChannel = Channel.CreateUnbounded<(WatchEventType, string, CustomResource?)>();
_resourceViewModelChangesChannel = Channel.CreateUnbounded<ResourceChange>();

RunWatchTask<Executable>();
RunWatchTask<Service>();
RunWatchTask<Endpoint>();
RunWatchTask<Container>();

_resourceViewModelChangesChannel = Channel.CreateUnbounded<ResourceChanged<ResourceViewModel>>();

Task.Run(ProcessKubernetesChanges);

_resourceViewModelProcessor = new ViewModelProcessor<ResourceViewModel>(_resourceViewModelChangesChannel, _cancellationToken);
_resourceViewModelProcessor = new ViewModelProcessor(_resourceViewModelChangesChannel, _cancellationToken);
}

public string ApplicationName => _applicationName;

public ViewModelMonitor<ResourceViewModel> GetResources() => _resourceViewModelProcessor.GetResourceMonitor();
public ViewModelMonitor GetResources() => _resourceViewModelProcessor.GetMonitor();

private void RunWatchTask<T>()
where T : CustomResource
Expand Down Expand Up @@ -290,7 +291,7 @@ private async Task ProcessServiceChange(WatchEventType watchEventType, Service s
private async Task WriteChange(ResourceViewModel resourceViewModel, ObjectChangeType changeType = ObjectChangeType.Modified)
{
await _resourceViewModelChangesChannel.Writer.WriteAsync(
new ResourceChanged<ResourceViewModel>(changeType, resourceViewModel), _cancellationToken)
new ResourceChange(changeType, resourceViewModel), _cancellationToken)
.ConfigureAwait(false);
}

Expand Down
46 changes: 23 additions & 23 deletions src/Aspire.Hosting/Dashboard/ViewModelProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,76 +6,76 @@

namespace Aspire.Hosting.Dashboard;

internal sealed class ViewModelProcessor<TViewModel>
where TViewModel : ResourceViewModel
internal sealed class ViewModelProcessor
{
private readonly object _syncLock = new();
private readonly Channel<ResourceChanged<TViewModel>> _incomingChannel;
private readonly Channel<ResourceChange> _incomingChannel;
private readonly CancellationToken _cancellationToken;
private readonly Dictionary<string, TViewModel> _snapshot = [];
private readonly List<Channel<ResourceChanged<TViewModel>>> _subscribedChannels = [];
private readonly Dictionary<string, ResourceViewModel> _snapshot = [];
private readonly List<Channel<ResourceChange>> _subscribedChannels = [];

public ViewModelProcessor(Channel<ResourceChanged<TViewModel>> incomingChannel, CancellationToken cancellationToken)
public ViewModelProcessor(Channel<ResourceChange> incomingChannel, CancellationToken cancellationToken)
{
_incomingChannel = incomingChannel;
_cancellationToken = cancellationToken;

Task.Run(ProcessChanges, cancellationToken);
}

public ViewModelMonitor<TViewModel> GetResourceMonitor()
public ViewModelMonitor GetMonitor()
{
lock (_syncLock)
{
var snapshot = _snapshot.Values.ToList();
var channel = Channel.CreateUnbounded<ResourceChanged<TViewModel>>();
var channel = Channel.CreateUnbounded<ResourceChange>();
_subscribedChannels.Add(channel);
var enumerable = new ChangeEnumerable(channel, RemoveChannel);

return new ViewModelMonitor<TViewModel>(snapshot, enumerable);
return new ViewModelMonitor(
Snapshot: _snapshot.Values.ToList(),
Watch: new ChangeEnumerable(channel, RemoveChannel));
}
}

private void RemoveChannel(Channel<ResourceChanged<TViewModel>> channel)
private void RemoveChannel(Channel<ResourceChange> channel)
{
lock (_syncLock)
{
_subscribedChannels.Remove(channel);
}
}

private sealed class ChangeEnumerable : IAsyncEnumerable<ResourceChanged<TViewModel>>
private sealed class ChangeEnumerable : IAsyncEnumerable<ResourceChange>
{
private readonly Channel<ResourceChanged<TViewModel>> _channel;
private readonly Action<Channel<ResourceChanged<TViewModel>>> _disposeAction;
private readonly Channel<ResourceChange> _channel;
private readonly Action<Channel<ResourceChange>> _disposeAction;

public ChangeEnumerable(Channel<ResourceChanged<TViewModel>> channel, Action<Channel<ResourceChanged<TViewModel>>> disposeAction)
public ChangeEnumerable(Channel<ResourceChange> channel, Action<Channel<ResourceChange>> disposeAction)
{
_channel = channel;
_disposeAction = disposeAction;
}

public IAsyncEnumerator<ResourceChanged<TViewModel>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
public IAsyncEnumerator<ResourceChange> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new ChangeEnumerator(_channel, _disposeAction, cancellationToken);
}
}

private sealed class ChangeEnumerator : IAsyncEnumerator<ResourceChanged<TViewModel>>
private sealed class ChangeEnumerator : IAsyncEnumerator<ResourceChange>
{
private readonly Channel<ResourceChanged<TViewModel>> _channel;
private readonly Action<Channel<ResourceChanged<TViewModel>>> _disposeAction;
private readonly Channel<ResourceChange> _channel;
private readonly Action<Channel<ResourceChange>> _disposeAction;
private readonly CancellationToken _cancellationToken;

public ChangeEnumerator(
Channel<ResourceChanged<TViewModel>> channel, Action<Channel<ResourceChanged<TViewModel>>> disposeAction, CancellationToken cancellationToken)
Channel<ResourceChange> channel, Action<Channel<ResourceChange>> disposeAction, CancellationToken cancellationToken)
{
_channel = channel;
_disposeAction = disposeAction;
_cancellationToken = cancellationToken;
Current = default!;
}

public ResourceChanged<TViewModel> Current { get; private set; }
public ResourceChange Current { get; private set; }

public ValueTask DisposeAsync()
{
Expand All @@ -96,7 +96,7 @@ private async Task ProcessChanges()
{
await foreach (var change in _incomingChannel.Reader.ReadAllAsync(_cancellationToken))
{
List<Channel<ResourceChanged<TViewModel>>> outgoingChannels;
List<Channel<ResourceChange>> outgoingChannels;
lock (_syncLock)
{
var resource = change.Resource;
Expand Down