using Microsoft.AspNet.SignalR.Client; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks.Dataflow; namespace Communicator { public class UISignalRClient : ICommunicator { private string _connectionUrl; private string _hubName; private HubConnection? _hubConnection; private IHubProxy? _hubProxy; private readonly BufferBlock> _changedDataItems; private readonly CancellationTokenSource _cancellationTokenSource; private ICommunicatorProvider? _provider; private bool disposedValue; public UISignalRClient() { _connectionUrl = "http://localhost:9999/NewUI"; _hubName = "UIHub"; _changedDataItems = new(); _cancellationTokenSource = new(); Task processReceivedDataTask = new(ProcessReceivedData); processReceivedDataTask.Start(); } public bool Initialize(ICommunicatorProvider provider) { ArgumentNullException.ThrowIfNull(provider, nameof(provider)); _provider = provider; if (_hubConnection is not null) { return true; } try { _hubConnection = new HubConnection(_connectionUrl); _hubConnection.StateChanged += OnStateChanged; _hubProxy = _hubConnection.CreateHubProxy(_hubName); _hubProxy.On>(nameof(ReceiveAllDataItems), ReceiveAllDataItems); _hubProxy.On>(nameof(ReceiveChangedDataItems), ReceiveChangedDataItems); _hubConnection.Start().Wait(); return true; } catch (Exception) { return false; } } private void ReceiveAllDataItems(Dictionary dataItems) { if (dataItems.Count <= 0) { return; } _provider?.NotifyAllDataReceived(dataItems); } private void ReceiveChangedDataItems(Dictionary dataItems) { if (dataItems.Count <= 0) { return; } foreach (var item in dataItems) { _changedDataItems.Post(item); } } private async void ProcessReceivedData() { while (await _changedDataItems.OutputAvailableAsync() && !_cancellationTokenSource.IsCancellationRequested) { var item = await _changedDataItems.ReceiveAsync(); _provider?.NotifyDataChanged(item.Key, item.Value); } } private void OnStateChanged(StateChange obj) { //TODO: } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: dispose managed state (managed objects) if (_hubConnection is not null) { _hubConnection.StateChanged -= OnStateChanged; _hubConnection.Dispose(); _changedDataItems.Complete(); _cancellationTokenSource.Cancel(); _cancellationTokenSource.Dispose(); } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer // TODO: set large fields to null disposedValue = true; } } // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources // ~SignalRClient() // { // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Dispose(disposing: false); // } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } } }