11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System . Collections . Immutable ;
45using System . Threading . Channels ;
56using Aspire . Dashboard . Model ;
67
@@ -13,7 +14,7 @@ internal sealed class ViewModelProcessor<TViewModel>
1314 private readonly Channel < ResourceChanged < TViewModel > > _incomingChannel ;
1415 private readonly CancellationToken _cancellationToken ;
1516 private readonly Dictionary < string , TViewModel > _snapshot = [ ] ;
16- private readonly List < Channel < ResourceChanged < TViewModel > > > _subscribedChannels = [ ] ;
17+ private ImmutableHashSet < Channel < ResourceChanged < TViewModel > > > _outgoingChannels = [ ] ;
1718
1819 public ViewModelProcessor ( Channel < ResourceChanged < TViewModel > > incomingChannel , CancellationToken cancellationToken )
1920 {
@@ -28,18 +29,15 @@ public ViewModelMonitor<TViewModel> GetResourceMonitor()
2829 {
2930 var snapshot = _snapshot . Values . ToList ( ) ;
3031 var channel = Channel . CreateUnbounded < ResourceChanged < TViewModel > > ( ) ;
31- _subscribedChannels . Add ( channel ) ;
32+ ImmutableInterlocked . Update ( ref _outgoingChannels , static ( set , channel ) => set . Add ( channel ) , channel ) ;
3233 var enumerable = new ChangeEnumerable ( channel , RemoveChannel ) ;
3334
3435 return new ViewModelMonitor < TViewModel > ( snapshot , enumerable ) ;
3536 }
36- }
3737
38- private void RemoveChannel ( Channel < ResourceChanged < TViewModel > > channel )
39- {
40- lock ( _syncLock )
38+ void RemoveChannel ( Channel < ResourceChanged < TViewModel > > channel )
4139 {
42- _subscribedChannels . Remove ( channel ) ;
40+ ImmutableInterlocked . Update ( ref _outgoingChannels , static ( set , channel ) => set . Remove ( channel ) , channel ) ;
4341 }
4442 }
4543
@@ -96,11 +94,11 @@ private async Task ProcessChanges()
9694 {
9795 await foreach ( var change in _incomingChannel . Reader . ReadAllAsync ( _cancellationToken ) )
9896 {
99- List < Channel < ResourceChanged < TViewModel > > > outgoingChannels ;
97+ var ( changeType , resource ) = change ;
98+
10099 lock ( _syncLock )
101100 {
102- var resource = change . Resource ;
103- switch ( change . ObjectChangeType )
101+ switch ( changeType )
104102 {
105103 case ObjectChangeType . Added :
106104 _snapshot . Add ( resource . Name , resource ) ;
@@ -114,11 +112,9 @@ private async Task ProcessChanges()
114112 _snapshot . Remove ( resource . Name ) ;
115113 break ;
116114 }
117-
118- outgoingChannels = _subscribedChannels . ToList ( ) ;
119115 }
120116
121- foreach ( var channel in outgoingChannels )
117+ foreach ( var channel in _outgoingChannels )
122118 {
123119 await channel . Writer . WriteAsync ( change , _cancellationToken ) . ConfigureAwait ( false ) ;
124120 }
0 commit comments