diff --git a/PubSub.Tests/CoreHubTests.cs b/PubSub.Tests/CoreHubTests.cs index d6f9b5a..b1423c0 100644 --- a/PubSub.Tests/CoreHubTests.cs +++ b/PubSub.Tests/CoreHubTests.cs @@ -226,6 +226,32 @@ public void PubSubUnsubDirectlyToHub() // assert Assert.AreEqual(10, callCount); } + + [TestMethod] + public void PubSubWithToken() + { + var callCount = 0; + string token1 = "token1"; + string token2 = "token2"; + _hub.Subscribe((b) => { callCount++;},token1); + _hub.Subscribe((i)=>callCount++,token2); + + _hub.Publish(true); //There is no token with "" + _hub.Publish(true, token2); //There is no token2 with bool + _hub.Publish(true, token1); //should be true + + Assert.AreEqual(1, callCount); + _hub.Publish(42, token2); //should be true + Assert.AreEqual(2, callCount); + + _hub.Unsubscribe(); //This shouldn't unsubscribe anything + Assert.AreEqual(_hub._handlers.Count, 2); + + _hub.Unsubscribe(token1); //This should unsubscribe token1 + Assert.AreEqual(_hub._handlers.Count, 1); + + + } } public class Event diff --git a/PubSub.Tests/IocExtensionsTests.cs b/PubSub.Tests/IocExtensionsTests.cs index 34c070c..d86545e 100644 --- a/PubSub.Tests/IocExtensionsTests.cs +++ b/PubSub.Tests/IocExtensionsTests.cs @@ -9,8 +9,8 @@ public class IocExtensionsTests private IPubSubPipelineFactory pubSubFactory; private ISubscriber subscriber; private IPublisher publisher; - private object sender; - private object preservedSender; + private string sender; + private string preservedSender; [TestInitialize] public void Setup() @@ -18,8 +18,8 @@ public void Setup() pubSubFactory = new PubSubPipelineFactory(); subscriber = pubSubFactory.GetSubscriber(); publisher = pubSubFactory.GetPublisher(); - sender = new object(); - preservedSender = new object(); + sender = "sender"; + preservedSender = "preservedSender"; } [TestMethod] diff --git a/PubSub/Core/Hub.cs b/PubSub/Core/Hub.cs index 37592a2..13bf30c 100644 --- a/PubSub/Core/Hub.cs +++ b/PubSub/Core/Hub.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace PubSub @@ -13,10 +14,15 @@ public class Hub private static Hub _default; public static Hub Default => _default ?? (_default = new Hub()); - - public void Publish(T data = default(T)) + /// + /// + /// + /// + /// The object we want to publish + /// A token that we will filter on. + public void Publish(T data = default, string token = "") { - foreach (var handler in GetAliveHandlers()) + foreach (Handler handler in GetAliveHandlers(token)) { switch (handler.Action) { @@ -30,9 +36,9 @@ public class Hub } } - public async Task PublishAsync(T data = default(T)) + public async Task PublishAsync(T data = default, string token = "") { - foreach (var handler in GetAliveHandlers()) + foreach (var handler in GetAliveHandlers(token)) { switch (handler.Action) { @@ -51,40 +57,40 @@ public class Hub /// /// /// - public void Subscribe(Action handler) + /// + public void Subscribe(Action handler, string token = "") { - Subscribe(this, handler); + Subscribe(this, handler, token); } - public void Subscribe(object subscriber, Action handler) + public void Subscribe(object subscriber, Action handler, string token = "") { - SubscribeDelegate(subscriber, handler); + SubscribeDelegate(subscriber, handler, token); } - public void Subscribe(Func handler) + public void Subscribe(Func handler, string token = "") { - Subscribe(this, handler); + Subscribe(this, handler, token); } - public void Subscribe(object subscriber, Func handler) + public void Subscribe(object subscriber, Func handler, string token = "") { - SubscribeDelegate(subscriber, handler); + SubscribeDelegate(subscriber, handler, token); } /// /// Allow unsubscribing directly to this Hub. /// - public void Unsubscribe() + public void Unsubscribe(string token = "") { - Unsubscribe(this); + Unsubscribe(this, token); } - public void Unsubscribe(object subscriber) + public void Unsubscribe(object subscriber, string token = "") { lock (_locker) { - var query = _handlers.Where(a => !a.Sender.IsAlive || - a.Sender.Target.Equals(subscriber)); + var query = _handlers.Where(a => !a.Sender.IsAlive || a.Sender.Target.Equals(subscriber) && a.Token == token); foreach (var h in query.ToList()) _handlers.Remove(h); @@ -105,18 +111,16 @@ public void Unsubscribe() /// /// /// - public void Unsubscribe(Action handler) + public void Unsubscribe(Action handler, string token = "") { - Unsubscribe(this, handler); + Unsubscribe(this, handler, token); } - public void Unsubscribe(object subscriber, Action handler = null) + public void Unsubscribe(object subscriber, Action handler = null, string token = "") { lock (_locker) { - var query = _handlers.Where(a => !a.Sender.IsAlive || - a.Sender.Target.Equals(subscriber) && a.Type == typeof(T)); - + var query = _handlers.Where(a => !a.Sender.IsAlive || (a.Sender.Target.Equals(subscriber) && a.Type == typeof(T) && a.Token == token)); if (handler != null) query = query.Where(a => a.Action.Equals(handler)); @@ -125,19 +129,19 @@ public void Unsubscribe(object subscriber, Action handler = null) } } - public bool Exists() + public bool Exists(string token = "") { - return Exists(this); + return Exists(this, token); } - public bool Exists(object subscriber) + public bool Exists(object subscriber, string token = "") { lock (_locker) { foreach (var h in _handlers) { if (Equals(h.Sender.Target, subscriber) && - typeof(T) == h.Type) + typeof(T) == h.Type && h.Token == token) { return true; } @@ -147,7 +151,7 @@ public bool Exists(object subscriber) return false; } - public bool Exists(object subscriber, Action handler) + public bool Exists(object subscriber, Action handler, string token = "") { lock (_locker) { @@ -155,7 +159,7 @@ public bool Exists(object subscriber, Action handler) { if (Equals(h.Sender.Target, subscriber) && typeof(T) == h.Type && - h.Action.Equals(handler)) + h.Action.Equals(handler) && h.Token.Equals(token)) { return true; } @@ -165,13 +169,14 @@ public bool Exists(object subscriber, Action handler) return false; } - private void SubscribeDelegate(object subscriber, Delegate handler) + private void SubscribeDelegate(object subscriber, Delegate handler, string token) { var item = new Handler { Action = handler, Sender = new WeakReference(subscriber), - Type = typeof(T) + Type = typeof(T), + Token = token }; lock (_locker) @@ -180,10 +185,13 @@ private void SubscribeDelegate(object subscriber, Delegate handler) } } - private IEnumerable GetAliveHandlers() + private IEnumerable GetAliveHandlers(string token) { PruneHandlers(); - return _handlers.Where(h => h.Type.GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); + lock (_locker) + { + return _handlers.Where(h => h.Type.GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()) && h.Token == token); + } } private void PruneHandlers() @@ -203,6 +211,8 @@ internal class Handler public Delegate Action { get; set; } public WeakReference Sender { get; set; } public Type Type { get; set; } + public string Token { get; set; } = ""; + } } } \ No newline at end of file diff --git a/PubSub/Ioc/Implementation/Publisher.cs b/PubSub/Ioc/Implementation/Publisher.cs index 80575eb..ebc6a16 100644 --- a/PubSub/Ioc/Implementation/Publisher.cs +++ b/PubSub/Ioc/Implementation/Publisher.cs @@ -9,6 +9,6 @@ public Publisher( Hub hub ) this.hub = hub; } - public void Publish(T data) => hub.Publish(data); + public void Publish(T data, string token) => hub.Publish(data, token); } } \ No newline at end of file diff --git a/PubSub/Ioc/Implementation/Subscriber.cs b/PubSub/Ioc/Implementation/Subscriber.cs index 7227879..6753df8 100644 --- a/PubSub/Ioc/Implementation/Subscriber.cs +++ b/PubSub/Ioc/Implementation/Subscriber.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; namespace PubSub { @@ -6,21 +7,21 @@ public class Subscriber : ISubscriber { private readonly Hub hub; - public Subscriber( Hub hub ) + public Subscriber(Hub hub) { this.hub = hub; } - public bool Exists( object subscriber ) => hub.Exists( subscriber ); + public bool Exists(object subscriber, string token) => hub.Exists(subscriber, token); - public bool Exists( object subscriber, Action handler ) => hub.Exists( subscriber, handler ); + public bool Exists(object subscriber, Action handler, string token) => hub.Exists(subscriber, handler, token); - public void Subscribe( object subscriber, Action handler ) => hub.Subscribe( subscriber, handler ); + public void Subscribe(object subscriber, Action handler, string token) => hub.Subscribe(subscriber, handler, token); - public void Unsubscribe( object subscriber ) => hub.Unsubscribe( subscriber ); + public void Unsubscribe(object subscriber, string token = "") => hub.Unsubscribe(subscriber, token); - public void Unsubscribe( object subscriber ) => hub.Unsubscribe( subscriber, (Action) null ); + public void Unsubscribe(object subscriber, string token) => hub.Unsubscribe(subscriber, (Action)null, token); - public void Unsubscribe( object subscriber, Action handler ) => hub.Unsubscribe( subscriber, handler ); + public void Unsubscribe(object subscriber, Action handler, string token) => hub.Unsubscribe(subscriber, handler, token); } } \ No newline at end of file diff --git a/PubSub/Ioc/Interfaces/IPublisher.cs b/PubSub/Ioc/Interfaces/IPublisher.cs index 447cdf3..f18ce36 100644 --- a/PubSub/Ioc/Interfaces/IPublisher.cs +++ b/PubSub/Ioc/Interfaces/IPublisher.cs @@ -2,6 +2,6 @@ { public interface IPublisher { - void Publish(T data); + void Publish(T data, string token = ""); } } \ No newline at end of file diff --git a/PubSub/Ioc/Interfaces/ISubscriber.cs b/PubSub/Ioc/Interfaces/ISubscriber.cs index 47ae4f7..15be73b 100644 --- a/PubSub/Ioc/Interfaces/ISubscriber.cs +++ b/PubSub/Ioc/Interfaces/ISubscriber.cs @@ -4,11 +4,11 @@ namespace PubSub { public interface ISubscriber { - bool Exists( object subscriber ); - bool Exists( object subscriber, Action handler ); - void Subscribe( object subscriber, Action handler ); - void Unsubscribe( object subscriber ); - void Unsubscribe( object subscriber ); - void Unsubscribe( object subscriber, Action handler ); + bool Exists( object subscriber, string token = "" ); + bool Exists( object subscriber, Action handler, string token = ""); + void Subscribe( object subscriber, Action handler, string token =""); + void Unsubscribe( object subscriber, string token = ""); + void Unsubscribe( object subscriber, string token = ""); + void Unsubscribe( object subscriber, Action handler, string token = ""); } } \ No newline at end of file