33using RxTelegram . Bot . Interface . InlineMode ;
44using RxTelegram . Bot . Interface . Payments ;
55using RxTelegram . Bot . Interface . Setup ;
6+ using RxTelegram . Bot . Utils . Rx ;
67using System ;
78using System . Collections . Generic ;
89using System . Linq ;
@@ -17,11 +18,14 @@ namespace RxTelegram.Bot.Api;
1718
1819public sealed class UpdateDistributor : IUpdateManager , IDisposable
1920{
20- private IObservable < Update > _tracker ;
2121
2222 #region Observable Update properties
23- private Dictionary < UpdateType , UpdateTypeInfo > _updateInfos = new Dictionary < UpdateType , UpdateTypeInfo > ( ) ;
24- private UpdateTypeInfo _update = new UpdateTypeInfo ( ) ;
23+ private readonly Dictionary < UpdateType , UpdateTypeInfo > _updateInfos ;
24+ private readonly UpdateTypeInfo _updateInfo ;
25+ private readonly IEnumerable < UpdateType > _trackedTypes ;
26+ private readonly ReactiveProperty < IObservable < Update > > _tracker ;
27+ private bool _isDisposed = false ;
28+ private readonly object _lock ;
2529 public IObservable < CallbackQuery > CallbackQuery => Selector ( UpdateType . CallbackQuery , _update => _update . CallbackQuery ) ;
2630 public IObservable < Message > ChannelPost => Selector ( UpdateType . ChannelPost , _update => _update . ChannelPost ) ;
2731 public IObservable < ChatBoostUpdated > ChatBoost => Selector ( UpdateType . ChatBoost , _update => _update . ChatBoost ) ;
@@ -38,9 +42,7 @@ public sealed class UpdateDistributor : IUpdateManager, IDisposable
3842 public IObservable < PreCheckoutQuery > PreCheckoutQuery => Selector ( UpdateType . PreCheckoutQuery , _update => _update . PreCheckoutQuery ) ;
3943 public IObservable < ChatBoostRemoved > RemovedChatBoost => Selector ( UpdateType . RemovedChatBoost , _update => _update . RemovedChatBoost ) ;
4044 public IObservable < ShippingQuery > ShippingQuery => Selector ( UpdateType . ShippingQuery , _update => _update . ShippingQuery ) ;
41- public IObservable < Update > Update => ( IObservable < Update > ) ( _update . Observer ??= new UpdateSubject < Update > ( x => x ,
42- onSubscribe : AddGeneralListener ,
43- onDispose : RemoveGeneralListener ) ) ;
45+ public IObservable < Update > Update => Selector ( null , _update => _update ) ;
4446 #endregion
4547
4648#if NETSTANDARD2_1
@@ -65,101 +67,85 @@ public sealed class UpdateDistributor : IUpdateManager, IDisposable
6567#endif
6668 public UpdateDistributor ( IObservable < Update > updateTracker )
6769 {
70+ _lock = new ( ) ;
6871 _updateInfos = Enum . GetValues ( typeof ( UpdateType ) )
6972 . Cast < UpdateType > ( )
7073 . ToDictionary ( x => x , _ => new UpdateTypeInfo ( ) ) ;
71- Set ( updateTracker ) ;
72- }
7374
74- private void AddGeneralListener ( )
75- {
76- ++ _update . Listeners ;
75+ _updateInfo = new UpdateTypeInfo ( ) ;
7776
78- ( _tracker as ITrackerSetup ) ? . Set ( null ) ;
77+ _trackedTypes = _updateInfos . Where ( x => x . Value . Listeners != 0 )
78+ . Select ( x => x . Key ) ;
7979
80- _update . Subscription ??= _tracker . Subscribe ( _update . Observer ) ;
80+ _tracker = new ReactiveProperty < IObservable < Update > > ( updateTracker ) ;
81+ Set ( updateTracker ) ;
8182 }
82- private void AddListener ( UpdateType type )
83+ private void AddListener ( UpdateType ? type )
8384 {
84- var updateType = _updateInfos [ type ] ;
85- ++ updateType . Listeners ;
86-
87- UpdateTrackerTypes ( ) ;
85+ lock ( _lock )
86+ {
87+ var info = GetInfo ( type ) ;
88+ ++ info . Listeners ;
8889
89- updateType . Subscription ??= _tracker . Subscribe ( updateType . Observer ) ;
90+ if ( info . Listeners != 1 ) return ;
91+ UpdateTrackerTypes ( ) ;
92+ }
9093 }
91- private void RemoveGeneralListener ( )
92- {
93- -- _update . Listeners ;
94- _update . Subscription ? . Dispose ( ) ;
95- _update . Subscription = null ;
94+ private UpdateTypeInfo GetInfo ( UpdateType ? type )
95+ => type == null ? _updateInfo : _updateInfos [ ( UpdateType ) type ] ;
9696
97- UpdateTrackerTypes ( ) ;
98- }
99- private void RemoveListener ( UpdateType type )
97+ private void RemoveListener ( UpdateType ? type )
10098 {
101- var updateType = _updateInfos [ type ] ;
102- -- updateType . Listeners ;
103- _update . Subscription ? . Dispose ( ) ;
104- _update . Subscription = null ;
99+ lock ( _lock )
100+ {
101+ var info = GetInfo ( type ) ;
102+ -- info . Listeners ;
103+ if ( info . Listeners != 0 ) return ;
105104
106- UpdateTrackerTypes ( ) ;
105+ UpdateTrackerTypes ( ) ;
106+ }
107107 }
108- public IObservable < T > Selector < T > ( UpdateType updateType , Func < Update , T > propertySelector )
108+ public IObservable < T > Selector < T > ( UpdateType ? type , Func < Update , T > propertySelector )
109+ where T : class
109110 {
110- var info = _updateInfos [ updateType ] ;
111- if ( info . Observer != null )
112- return ( IObservable < T > ) info ;
113-
114- var subject = new UpdateSubject < T > ( propertySelector ,
115- onSubscribe : ( ) => AddListener ( updateType ) ,
116- onDispose : ( ) => RemoveListener ( updateType ) ) ;
117- info . Observer = subject ;
118- info . Subscription = _tracker . Subscribe ( info . Observer ) ;
119- return subject ;
111+ return _tracker . Switch ( ) . Select ( propertySelector )
112+ . Where ( x => x != null )
113+ . DoOnSubscribe ( ( ) => AddListener ( type ) )
114+ . Finally ( ( ) => RemoveListener ( type ) ) ;
120115 }
116+
121117 public void Set ( IObservable < Update > tracker )
122118 {
123- //Setup current tracker to listen all messages before change to a new one
124- ( _tracker as ITrackerSetup ) ? . Set ( null ) ;
125- DisposeTrackerSubcription ( ) ;
126- _tracker = tracker ;
119+ // Configure the current tracker to listen for all types of updates
120+ // before switching to a new one
121+ ( _tracker . Current as ITrackerSetup ) ? . Set ( null ) ;
122+
123+ _tracker . OnNext ( tracker ) ;
127124 UpdateTrackerTypes ( ) ;
128- SubscribeToTracker ( ) ;
129125 }
130- public void DisposeTrackerSubcription ( )
131- {
132- _update . Subscription ? . Dispose ( ) ;
133- foreach ( var info in _updateInfos . Values )
134- info . Subscription ? . Dispose ( ) ;
135- }
136- public void SubscribeToTracker ( )
126+ private void UpdateTrackerTypes ( )
137127 {
138- if ( _update . Observer != null )
139- _update . Subscription = _tracker . Subscribe ( _update . Observer ) ;
140- foreach ( var info in _updateInfos . Values . Where ( x => x . Observer != null ) )
141- info . Subscription = _tracker . Subscribe ( info . Observer ) ;
128+ if ( _tracker . Current is not ITrackerSetup setup ) return ;
129+
130+ setup . Set ( _updateInfo . Listeners != 0 || ! _trackedTypes . Any ( ) ?
131+ null : _trackedTypes ) ;
142132 }
143- private void UpdateTrackerTypes ( )
133+
134+ public void Dispose ( ) => Dispose ( true ) ;
135+ void Dispose ( bool explicitDisposing )
144136 {
145- if ( _tracker is not ITrackerSetup ) return ;
137+ if ( _isDisposed ) return ;
146138
147- IEnumerable < UpdateType > types = null ;
148- if ( _update . Listeners == 0 )
149- {
150- types = _updateInfos . Where ( x => x . Value . Listeners != 0 ) . Select ( x => x . Key ) ;
151- if ( ! types . Any ( ) )
152- types = null ;
153- }
154- ( _tracker as ITrackerSetup ) . Set ( types ) ;
139+ if ( explicitDisposing )
140+ _tracker . Dispose ( ) ;
141+
142+ _isDisposed = true ;
155143 }
156144
157- public void Dispose ( ) => DisposeTrackerSubcription ( ) ;
145+ ~ UpdateDistributor ( ) => Dispose ( false ) ;
158146
159- private class UpdateTypeInfo
147+ sealed private class UpdateTypeInfo
160148 {
161149 public int Listeners { get ; set ; } = 0 ;
162- public IObserver < Update > Observer { get ; set ; } = null ;
163- public IDisposable Subscription { get ; set ; } = null ;
164150 }
165151}
0 commit comments