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); }
// cancellation token support - you can cancel scheduling or waiting for the message public static async Task CancellationExample() { var hub = new MetaPubSub(); var cts = new CancellationTokenSource(); // publish an event after 100 ms var t = Task.Run(async() => { await Task.Delay(100); await hub.Publish(new MyEvent()); }); // cancel waiting after 50 ms var t2 = Task.Run(async() => { await Task.Delay(50); cts.Cancel(); }); try { var res = await hub.When <MyEvent>(millisecondsTimeout : 200, match : null, cts.Token); } catch (OperationCanceledException) { Console.WriteLine("Waiting for MyEvent has been canceled"); } }
public async Task EnumerateDevices_QuickReconnect_DevicesCollectionEnumerated() { var devices = new List <DeviceDTO>(); IMetaPubSub messenger = GetMessenger(); IDeviceManager deviceManager = GetDeviceManager(messenger); IMetaPubSub hub = new MetaPubSub(); hub.StartServer("Test3"); int devicesCount = 1000; for (int i = 0; i < devicesCount; i++) { devices.Add(GetRandomDeviceDTO()); } var connectionTask = Task.Factory.StartNew(() => { messenger.TryConnectToServer("Test3"); deviceManager = GetDeviceManager(messenger, devices); }); var disconnectionTask = Task.Factory.StartNew(messenger.DisconnectFromServer); var reconnectionTask = Task.Factory.StartNew(() => messenger.TryConnectToServer("Test3")); await Task.WhenAll(connectionTask, disconnectionTask, reconnectionTask); await Task.Delay(2000); Assert.AreEqual(devicesCount, deviceManager.Devices.Count()); }
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. } }
// 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); }
public async Task EnumerateDevices_FluctuatingServiceConnection_DevicesEnumerated() { var devices = new List <DeviceDTO>(); IMetaPubSub messenger = GetMessenger(); IMetaPubSub hub = new MetaPubSub(); hub.StartServer("Test1"); int devicesCount = 100; for (int i = 0; i < devicesCount; i++) { devices.Add(GetRandomDeviceDTO()); } int serviceReconnectsCount = 10; for (int i = 0; i < serviceReconnectsCount; i++) { await messenger.TryConnectToServer("Test1"); IDeviceManager deviceManager = GetDeviceManager(messenger, devices); await Task.Delay(200); Assert.AreEqual(devicesCount, deviceManager.Devices.Count()); await messenger.DisconnectFromServer(); await Task.Delay(200); Assert.AreEqual(0, deviceManager.Devices.Count()); } }
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_Cancel_When() { var hub = new MetaPubSub(); var cts = new CancellationTokenSource(); // publish an event after 100 ms var t = Task.Run(async() => { await Task.Delay(100); await hub.Publish(new MyEvent()); }); // cancel waiting after 50 ms var t2 = Task.Run(async() => { await Task.Delay(50); cts.Cancel(); }); bool exception = false; try { var res = await hub.When <MyEvent>(200, null, cts.Token); Assert.IsTrue(false); } catch (OperationCanceledException) { exception = true; } Assert.IsTrue(exception); }
public async Task Test_When() { var hub = new MetaPubSub(); var t = Task.Run(async() => { await Task.Delay(50); await hub.Publish(new MyEvent()); }); var res = await hub.When <MyEvent>(100); Assert.IsNotNull(res); bool timeoutException = false; try { res = await hub.When <MyEvent>(100); } catch (TimeoutException) { timeoutException = true; } Assert.IsTrue(timeoutException); }
// 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); }
public async Task EnumerateDevices_ClearDevices_DevicesCollectionCleared() { var devices = new List <DeviceDTO>(); IMetaPubSub messenger = GetMessenger(); IMetaPubSub hub = new MetaPubSub(); hub.StartServer("Test2"); await messenger.TryConnectToServer("Test2"); IDeviceManager deviceManager = GetDeviceManager(messenger); int devicesCount = 1000; for (int i = 0; i < devicesCount; i++) { devices.Add(GetRandomDeviceDTO()); } await messenger.PublishOnServer(new DevicesCollectionChangedMessage(devices.ToArray())); await messenger.DisconnectFromServer(); await Task.Delay(200); Assert.AreEqual(0, deviceManager.Devices.Count()); }
MetaPubSub CreateServerHub(string pipeName = null) { pipeName ??= Guid.NewGuid().ToString(); var serverHub = new MetaPubSub(); serverHub.StartServer(pipeName); return(serverHub); }
public RemoteDevicePubSubManager(IMetaPubSub messenger, ILog log) : base(nameof(RemoteDevicePubSubManager), log) { RemoteConnectionPubSub = new MetaPubSub(new MetaPubSubLogger(new NLogWrapper())); PipeName = "HideezRemoteDevicePipe_" + Guid.NewGuid().ToString(); _messenger = messenger; InitializePubSub(); }
// 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 DeviceViewModel(string mac, bool isBonded, MetaPubSub hub) { RegisterDependencies(); _hub = hub; _mac = mac; _isBonded = isBonded; _longOperation.StateChanged += (object sender, EventArgs e) => { NotifyPropertyChanged(nameof(InProgress)); NotifyPropertyChanged(nameof(Progress)); }; }
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); }
// subscribes on server and receives a message public async Task SendMessageToClient() { var pipeName = Guid.NewGuid().ToString(); var clientConnectedEvent = new ManualResetEventSlim(); var @event = new ManualResetEventSlim(); int recvCount = 0; Task Handler(MyMessage x) { if (++recvCount == 10) { @event.Set(); } return(Task.CompletedTask); } // creating remote hub var t = Task.Run(async() => { var hub = new MetaPubSub(); hub.StartServer(pipeName); // wait for the subscriber clientConnectedEvent.Wait(5000); // publishing a message at the remote hub for (int i = 0; i < 10; i++) { await hub.Publish(new MyMessage()); } }); // local hub creation var hub = new MetaPubSub(); await hub.ConnectToServer(pipeName); await hub.SubscribeOnServer <MyMessage>(Handler); // delay allowing the server to process the subscription request await Task.Delay(100); clientConnectedEvent.Set(); @event.Wait(5000); // unsubscribing await hub.Unsubscribe <MyMessage>(Handler); Assert.IsTrue(@event.IsSet && recvCount == 10); }
// 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); }
static async void RunClient() { try { // local hub creation hub = new MetaPubSub(); // connecting the remote server await hub.ConnectToServer("Meta"); // subscribing await hub.SubscribeOnServer <PingCommand>(OnPingCommand); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
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); }
async Task BasicExample() { int count = 0; Task Handler(MyMessage x) { count++; return(Task.CompletedTask); } // Creating the server hub. // The server and the client hubs should be created in separate processes, // this example is for demo only. var serverHub = new MetaPubSub(); // Starting the hub as a server named 'Meta'. serverHub.StartServer("Meta"); // Client hub creation. There are can be several hubs connected to the same server. var clientHub = new MetaPubSub(); // Connecting to the remote server. await clientHub.ConnectToServer("Meta"); // Subscribing to MyMessage on the server and locally at the same time. await clientHub.SubscribeOnServer <MyMessage>(Handler); // The server publishes a message. await serverHub.Publish(new MyMessage()); // Client hub publishes a message and it will be received locally without being sent to the server. await clientHub.Publish(new MyMessage()); // Client hub sends a message to the server where it will be published and sent back. await clientHub.PublishOnServer(new MyMessage()); // All three messages should be received. Debug.Assert(count == 3); // Unsubscribing both on the server-side and locally. await clientHub.Unsubscribe <MyMessage>(Handler); }
public async Task NoSubscribersException() { var pipeName = Guid.NewGuid().ToString(); var clientConnectedEvent = new ManualResetEventSlim(); var @event = new ManualResetEventSlim(); // creating remote hub var t = Task.Run(async() => { var hub = new MetaPubSub(); hub.StartServer(pipeName); // wait for the subscriber clientConnectedEvent.Wait(5000); try { // publishing a message at the remote hub await hub.Publish(new MyMessage() { DeliverAtLeastOnce = true }); } catch (NoSubscribersException) { @event.Set(); } }); // local hub creation var hub = new MetaPubSub(); await hub.ConnectToServer(pipeName); // delay allowing the server process the connection await Task.Delay(100); clientConnectedEvent.Set(); @event.Wait(5000); Assert.IsTrue(@event.IsSet); }
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); }
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); }