// same as previous but should not deliver the message // because the second subscriber has also the same filter public async Task Test_DeliverAtLeastOnce_Delayed2() { var hub = new MetaPubSub(); bool timeoutException = false; // first subscriber which will not process the message due to its filter hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); // second subscriber which will subscribe after the message has been published var t = Task.Run(async() => { await Task.Delay(50); hub.Subscribe <MyMessage>(OnMyMessageHandler2, OnMyMessagePredicate); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler2); }); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 100 }; try { // the message has a timeout and can wait until the second subscriber come await hub.Publish(message); } catch (TimeoutException) { timeoutException = true; } Assert.IsTrue(timeoutException); Assert.IsTrue(message.DeliveredCount == 0); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); }
// Should deliver if message is filtered at first and DeliverAtLeastOnce = true but Timeout > 0 and // after the message has published a new subscriber arrived public async Task Test_DeliverAtLeastOnce_Delayed() { var hub = new MetaPubSub(); // first subscriber which will not process the message due to its filter hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); // second subscriber which will subscribe after the message has been published // also with filter, will not process the message var t = Task.Run(async() => { await Task.Delay(50); hub.Subscribe <MyMessage>(OnMyMessageHandler2, OnMyMessagePredicate); }); // third subscriber which will subscribe after the message has been published var t2 = Task.Run(async() => { await Task.Delay(70); hub.Subscribe <MyMessage>(OnMyMessageHandler3); }); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 200000 }; // the message has a timeout and can wait until the second subscriber come await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 1); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); //hub.Unsubscribe<MyMessage>(OnMyMessageHandler2); //hub.Unsubscribe<MyMessage>(OnMyMessageHandler3); }
// subscribed twice but delivered only once public async Task Basic() { var hub = new MetaPubSub(); await Task.Run(() => { for (int i = 0; i < 10_000; i++) { var subscriber = new MySubscriber(); //await Task.Delay(50); hub.Subscribe <MyMessage>(subscriber.Handler); } }); int totalDeliveryCount1 = 0; var t1 = Task.Run(async() => { for (int i = 0; i < 1000; i++) { var subscriber = new MySubscriber(); hub.Subscribe <MyEvent>(subscriber.Handler); var message = new MyMessage(); await hub.Publish(message); totalDeliveryCount1 += message.DeliveredCount; await hub.Unsubscribe <MyEvent>(subscriber.Handler); } }); int totalDeliveryCount2 = 0; var t2 = Task.Run(async() => { for (int i = 0; i < 1000; i++) { var subscriber = new MySubscriber(); hub.Subscribe <MyMessage>(subscriber.Handler); var message = new MyMessage(); await hub.Publish(message); totalDeliveryCount2 += message.DeliveredCount; await hub.Unsubscribe <MyMessage>(subscriber.Handler); } }); await Task.WhenAll(t1, t2); Assert.IsTrue(totalDeliveryCount1 > (10_000 * 1000) && totalDeliveryCount1 < (10_000 * 1000 + 1000)); Assert.IsTrue(totalDeliveryCount2 == 10_000 * 1000 + 1000); }
public HideezServiceController(EventLogger log, MetaPubSub hub) { try { _log = log; _hub = hub; _hub.Subscribe <ClosingEvent>(OnClosing); _serviceStateRefreshTimer = new Timer(2000); _serviceStateRefreshTimer.Elapsed += ServiceStateCheckTimer_Elapsed; _serviceStateRefreshTimer.AutoReset = true; _serviceStateRefreshTimer.Start(); var controller = new ServiceController(SERVICE_NAME); // Will trigger ArgumentException if service is not installed var st = controller.Status; // Will trigger InvalidOperationException if service is not installed _serviceController = controller; if (IsServiceRunning) { StopService(); _restartServiceOnExit = true; } } catch (InvalidOperationException) { // The most probable reason is that service is not installed. It is ok. } catch (ArgumentException) { // The most probable reason is that service is not installed. It is ok. } }
static void RunServer() { var nLog = LogManager.GetLogger("MetaPubSub"); logger = new NLogAdapter(nLog); hub = new MetaPubSub(logger); // Servers started on the Windows process with elevated permissions need to // set up security to allow non-elevated processes to access the pipe. // Otherwise just use hub.StartServer("Meta") call hub.StartServer("Meta", () => { var pipeSecurity = new PipeSecurity(); pipeSecurity.AddAccessRule(new PipeAccessRule( new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), PipeAccessRights.FullControl, AccessControlType.Allow)); var pipe = new NamedPipeServerStream("Meta", PipeDirection.InOut, 32, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 4096, 4096, pipeSecurity); return(pipe); }); hub.Subscribe <PingCommand>(OnPing); }
public async Task Test_Schedule() { var hub = new MetaPubSub(); bool received = false; Task Handler(MyMessage x) { received = true; return(Task.CompletedTask); } hub.Subscribe <MyMessage>(Handler); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 100 }; hub.Schedule(message, 100); await Task.Delay(50); Assert.IsFalse(received); GC.Collect(); await Task.Delay(60); Assert.IsTrue(received); }
// timeout to wait for a subscriber - your message can be queued and wait until someone subscribed and processed it public async Task DeliverAtLeastOnceDelayedExample() { var hub = new MetaPubSub(); // a subscriber that will subscribe after the message has been published var t = Task.Run(async() => { await Task.Delay(1500); Console.WriteLine($"Subscribed to MyMessage at {DateTime.Now:HH:mm:ss.fff}"); hub.Subscribe <MyMessage>(OnMyMessage); }); // the message has the 10 seconds timeout and can wait until the subscriber come var message = new MyMessage { DeliverAtLeastOnce = true, // this must be set to true WaitForSubscriberTimeout = 10_000 }; Console.WriteLine($"Start publishing and awaiting at {DateTime.Now:HH:mm:ss.fff}"); // this method will wait until the subscriber receives the message or until timeout expired (10 seconds) await hub.Publish(message); Console.WriteLine($"End awaiting at {DateTime.Now:HH:mm:ss.fff}"); await hub.Unsubscribe <MyMessage>(OnMyMessage); }
// at least once delivery check async Task AtLeastOnceDeliveryExample() { var hub = new MetaPubSub(); var message = new MyMessage { // if this not set, NoSubscribersException will not be thrown DeliverAtLeastOnce = true }; try { // publishing a message when no one is subscribed await hub.Publish(message); } catch (NoSubscribersException ex) { // no one is listening Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } hub.Subscribe <MyMessage>(OnMyMessage); await hub.Publish(message); await hub.Unsubscribe <MyMessage>(OnMyMessage); }
static void Main(string[] args) { RunServer(); Console.Write(">"); string line; while ((line = Console.ReadLine()) != "exit") { try { if (line == "stop") { hub.StopServer(); } else if (line == "start") { hub.StartServer("Meta"); hub.Subscribe <PingCommand>(OnPing); } } catch (Exception ex) { logger.Error(ex); } Console.Write(">"); } }
public ConnectionManagerViewModel(EventLogger log, MetaPubSub hub) { _log = log; _hub = hub; _hub.Subscribe <ConnectDeviceCommand>(OnConnectDeviceCommand); _hub.Subscribe <StartDiscoveryCommand>(OnStartDiscoveryCommand); _hub.Subscribe <EnterBootCommand>(OnEnterBootCommand); _hub.Subscribe <DeviceWipedEvent>(OnDeviceWipedEvent); var commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); var bondsFilePath = Path.Combine(commonAppData, @"Hideez\bonds"); // ConnectionManager ============================ _connectionManager = new BleConnectionManager(log, bondsFilePath); _connectionManager.AdapterStateChanged += ConnectionManager_AdapterStateChanged; _connectionManager.AdvertismentReceived += ConnectionManager_AdvertismentReceived; // DeviceManager ============================ _deviceManager = new BleDeviceManager(log, _connectionManager); }
async Task BasicExample() { // hub creation var hub = new MetaPubSub(); // subscribing to MyMessage hub.Subscribe <MyMessage>(OnMyMessage); // publishing a message await hub.Publish(new MyMessage()); // unsubscribing await hub.Unsubscribe <MyMessage>(OnMyMessage); }
public MainWindowViewModel(MetaPubSub hub) { // default value -33 is to much and picks up devices from very far SdkConfig.TapProximityUnlockThreshold = -29; SdkConfig.ConnectDeviceTimeout = 5_000; SdkConfig.DeviceInitializationTimeout = 5_000; _hub = hub; _log = new EventLogger("Maintenance"); _hub.Subscribe <AdvertismentReceivedEvent>(OnAdvertismentReceived); _hub.Subscribe <DeviceConnectedEvent>(OnDeviceConnected); _hub.Subscribe <ClosingEvent>(OnClosing); ConnectionManager = new ConnectionManagerViewModel(_log, _hub); HideezServiceController = new HideezServiceController(_log, _hub); SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; if (IsFirmwareSelected) { _hub.Publish(new StartDiscoveryCommand()); } }
// subscribed twice but delivered only once public async Task Basic() { var hub = new MetaPubSub(); var message = new MyMessage(); await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 0); hub.Subscribe <MyMessage>(OnMyMessageHandler); hub.Subscribe <MyMessage>(OnMyMessageHandler); message = new MyMessage(); await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 1); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); message = new MyMessage(); await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 0); }
// exceptions handling - all exceptions raised when a message processing by subscribers can be caught by the publisher as an AggregateException async Task ExceptionHandlingExample() { var hub = new MetaPubSub(); try { var message = new MyMessage { DeliverAtLeastOnce = true, }; // publishing a message when no one subscribed - NoSubscribersException //await hub.Publish(message); // publishing a message when no one subscribed and Timeout > 0 - TimeoutException //message.Timeout = 100; //await hub.Publish(message); hub.Subscribe <MyMessage>(OnMyMessageHandlerWithException); // publishing a message await hub.Publish(message); } catch (NoSubscribersException ex) { // No one is subscribed to this message and (message.DeliverAtLeastOnce == true and message.Timeout == 0) Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } catch (TimeoutException ex) { // No one is subscribed to this message and (message.DeliverAtLeastOnce == true and message.Timeout > 0) Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } catch (AggregateException ex) { // All exceptions raised when a message processing by subscribers // can be caught by the publisher as an AggregateException. // If some of the subscribers throw an exception, other subscribers // continues to process the message. Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); foreach (var innerEx in ex.InnerExceptions) { Console.WriteLine($"\tInner Exception {innerEx.GetType()}: {innerEx.Message}"); } } await hub.Unsubscribe <MyMessage>(OnMyMessageHandlerWithException); }
public async Task Test_MultiProcess() { var hub = new MetaPubSub(); Task Handler(MyMessage x) { hub.Publish(new MyEvent() { SomeId = x.SomeId }); return(Task.CompletedTask); } hub.Subscribe <MyMessage>(Handler); var t1 = Task.Run(async() => { for (int i = 0; i < 100; i++) { var message = new MyMessage { SomeId = i, ResponseTimeout = 1000 }; var res = await hub.Process <MyEvent>(message, x => x.SomeId == i); Assert.IsNotNull(res); Assert.IsTrue(res.SomeId == i); } }); var t2 = Task.Run(async() => { for (int i = 100; i < 200; i++) { var message = new MyMessage { SomeId = i, ResponseTimeout = 1000 }; var res = await hub.Process <MyEvent>(message, x => x.SomeId == i); Assert.IsNotNull(res); Assert.IsTrue(res.SomeId == i); } }); await Task.WhenAll(t1, t2); }
public async Task Test_Process() { var hub = new MetaPubSub(); Task Handler(MyMessage x) { hub.Publish(new MyEvent()); return(Task.CompletedTask); } hub.Subscribe <MyMessage>(Handler); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true, Timeout = 100 }; var res = await hub.Process <MyEvent>(message, 100); Assert.IsNotNull(res); }
public async Task Predicate() { var hub = new MetaPubSub(); hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info }; await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 0); message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Error }; await hub.Publish(message); Assert.IsTrue(message.DeliveredCount == 1); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); }
// scheduling a message - your message can be queued and published after a time delay public async Task ScheduleExample() { var hub = new MetaPubSub(); hub.Subscribe <MyMessage>(OnMyMessage); var message = new MyMessage { DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 1500 }; // The message will be published after 3 seconds delay and after that, it can wait another 500 ms for a subscriber. // When using Schedule method there is no way to receive NoSubscriberException or AggregateException. hub.Schedule(message, millisecondsDelay: 3000); Console.WriteLine($"Message scheduled at {DateTime.Now:HH:mm:ss.fff}, delay - 3 sec"); // waiting before unsubscribing await Task.Delay(3500); await hub.Unsubscribe <MyMessage>(OnMyMessage); }
// request-response pattern - send a message and wait for the response as a single awaitable method, without need to Subscribe/Unsubscribe to the response message public static async Task ProcessExample() { var hub = new MetaPubSub(); // This handler should be placed somewhere in another module. // It processes MyMessage and publishes a MyEvent as a result. Task Handler(MyMessage x) { hub.Publish(new MyEvent()); return(Task.CompletedTask); } hub.Subscribe <MyMessage>(Handler); try { // This method will publish MyMessage and wait for MyEvent one second. // If the event will not arrive in a specified timeout the TimeoutException will be thrown. var message = new MyMessage { DeliverAtLeastOnce = true, WaitForSubscriberTimeout = 100, ResponseTimeout = 1_000 }; MyEvent res = await hub.Process <MyEvent>(message); Console.WriteLine($"Received MyEvent at {DateTime.Now:HH:mm:ss.fff}"); } catch (NoSubscribersException ex) { // no one is listening Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } catch (TimeoutException ex) { Console.WriteLine($"Exception {ex.GetType()}: {ex.Message}"); } }
public async Task Test_Process() { var hub = new MetaPubSub(); Task Handler(MyMessage x) { Task.Run(async() => { await Task.Delay(10); await hub.Publish(new MyEvent()); }); return(Task.CompletedTask); } hub.Subscribe <MyMessage>(Handler); var message = new MyMessage { ResponseTimeout = 2000 }; var res = await hub.Process <MyEvent>(message); Assert.IsNotNull(res); }
// Should get the NoSubscribersException if message is filtered and DeliverAtLeastOnce = true public async Task Test_DeliverAtLeastOnce_Filtered() { var hub = new MetaPubSub(); bool noSubscriberException = false; hub.Subscribe <MyMessage>(OnMyMessageHandler, OnMyMessagePredicate); var message = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info, DeliverAtLeastOnce = true }; try { await hub.Publish(message); } catch (NoSubscribersException) { noSubscriberException = true; } Assert.IsTrue(noSubscriberException); Assert.IsTrue(message.DeliveredCount == 0); await hub.Unsubscribe <MyMessage>(OnMyMessageHandler); }
// message filtering - you can define a predicate to subscribe only those messages you want to process async Task MessageFilteringExample() { var hub = new MetaPubSub(); // subscribing to MyMessage with a predicate that selects only error and critical messages hub.Subscribe <MyMessage>(OnMyMessage, m => m.LogSeverity == MetaLogErrorSeverity.Error || m.LogSeverity == MetaLogErrorSeverity.Critical); // this message will be filtered and not handled var message1 = new MyMessage { LogSeverity = MetaLogErrorSeverity.Info }; await hub.Publish(message1); // this message will be handled var message2 = new MyMessage { LogSeverity = MetaLogErrorSeverity.Error }; await hub.Publish(message2); }