1- using System . Collections . Generic ;
2- using System . Linq ;
3- using HandyIpc . Exceptions ;
1+ using System . Collections . Concurrent ;
2+ using System . Threading ;
3+ using System . Threading . Tasks ;
44
55namespace HandyIpc . Core
66{
77 public class NotifierManager
88 {
99 private readonly object _locker = new ( ) ;
1010 private readonly ISerializer _serializer ;
11- private readonly Dictionary < string , Notifier > _notifiers = new ( ) ;
11+ private readonly ConcurrentDictionary < string , Notifier > _notifiers = new ( ) ;
1212
1313 public NotifierManager ( ISerializer serializer )
1414 {
@@ -17,65 +17,50 @@ public NotifierManager(ISerializer serializer)
1717
1818 public void Publish < T > ( string name , T args )
1919 {
20- lock ( _locker )
20+ if ( _notifiers . TryGetValue ( name , out Notifier notifier ) )
2121 {
22- if ( _notifiers . TryGetValue ( name , out Notifier notifier ) )
23- {
24- notifier . Publish ( _serializer . Serialize ( args ) ) ;
25- }
22+ notifier . Push ( _serializer . Serialize ( args ) ) ;
2623 }
2724 }
2825
2926 public void Subscribe ( string name , int processId , IConnection connection )
3027 {
31- lock ( _locker )
32- {
33- if ( ! _notifiers . ContainsKey ( name ) )
34- {
35- _notifiers . Add ( name , new Notifier ( ) ) ;
36- }
37-
38- var notifier = _notifiers [ name ] ;
39- notifier . Subscribe ( processId , connection ) ;
40- }
28+ Notifier notifier = _notifiers . GetOrAdd ( name , _ => new Notifier ( ) ) ;
29+ notifier . Subscribe ( processId , connection ) ;
4130 }
4231
4332 public void Unsubscribe ( string name , int processId )
4433 {
45- lock ( _locker )
34+ if ( _notifiers . TryGetValue ( name , out Notifier notifier ) )
4635 {
47- if ( _notifiers . TryGetValue ( name , out Notifier notifier ) )
48- {
49- notifier . Unsubscribe ( processId ) ;
50- }
36+ notifier . Unsubscribe ( processId ) ;
5137 }
5238 }
5339
5440 private class Notifier
5541 {
56- private readonly Dictionary < int , IConnection > _connections = new ( ) ;
42+ private readonly ConcurrentDictionary < int , IConnection > _connections = new ( ) ;
43+ private readonly BlockingCollection < byte [ ] > _queue = new ( ) ;
44+
45+ private CancellationTokenSource ? _source ;
5746
58- public void Publish ( byte [ ] bytes )
47+ public Notifier ( ) => Start ( ) ;
48+
49+ public void Push ( byte [ ] bytes )
5950 {
60- var connections = _connections . ToArray ( ) ;
61- foreach ( var item in connections )
51+ if ( _connections . IsEmpty )
6252 {
63- int processId = item . Key ;
64- IConnection connection = item . Value ;
53+ _source ? . Cancel ( ) ;
54+ _source = null ;
55+ return ;
56+ }
6557
66- try
67- {
68- byte [ ] result = connection . Invoke ( bytes ) ;
69- if ( ! result . IsUnit ( ) )
70- {
71- throw new IpcException ( ) ;
72- }
73- }
74- catch
75- {
76- Unsubscribe ( processId ) ;
77- }
58+ if ( _source is null or { IsCancellationRequested : true } )
59+ {
60+ Start ( ) ;
7861 }
62+
63+ _queue . Add ( bytes ) ;
7964 }
8065
8166 public void Subscribe ( int processId , IConnection connection )
@@ -85,13 +70,50 @@ public void Subscribe(int processId, IConnection connection)
8570
8671 public void Unsubscribe ( int processId )
8772 {
88- if ( _connections . TryGetValue ( processId , out IConnection connection ) )
73+ if ( _connections . TryRemove ( processId , out IConnection connection ) )
8974 {
90- _connections . Remove ( processId ) ;
9175 // Send a signal to notify end this connection.
9276 connection . Dispose ( ) ;
9377 }
9478 }
79+
80+ private void Start ( )
81+ {
82+ while ( _queue . TryTake ( out _ ) )
83+ {
84+ // Clear history queue.
85+ }
86+
87+ _source = new CancellationTokenSource ( ) ;
88+ Task . Run ( ( ) => Publish ( _source . Token ) ) ;
89+ }
90+
91+ private void Publish ( CancellationToken token )
92+ {
93+ while ( ! token . IsCancellationRequested )
94+ {
95+ byte [ ] bytes = _queue . Take ( token ) ;
96+ var connections = _connections . ToArray ( ) ;
97+ foreach ( var item in connections )
98+ {
99+ int processId = item . Key ;
100+ IConnection connection = item . Value ;
101+
102+ try
103+ {
104+ byte [ ] result = connection . Invoke ( bytes ) ;
105+ if ( ! result . IsUnit ( ) )
106+ {
107+ Unsubscribe ( processId ) ;
108+ }
109+ }
110+ catch
111+ {
112+ Unsubscribe ( processId ) ;
113+ }
114+ }
115+ }
116+ }
95117 }
96118 }
97119}
0 commit comments