Browse Source

The first version of SignalR Client

SenGao 1 week ago
parent
commit
a3e606f8c3

+ 13 - 0
FurnaceNewWorld/Communication/Communicator/Communicator.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0-windows</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNet.SignalR.Client" />
+  </ItemGroup>
+
+</Project>

+ 15 - 0
FurnaceNewWorld/Communication/Communicator/ICommunicator.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Communicator
+{
+    public interface ICommunicator : IDisposable
+    {
+        bool Initialize();
+        void SubscribeDataItem(string dataKey, Action<object> callback);
+        void UnsubscribeDataItem(string dataKey, Action<object> callback);
+    }
+}

+ 148 - 0
FurnaceNewWorld/Communication/Communicator/UISignalRClient.cs

@@ -0,0 +1,148 @@
+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<KeyValuePair<string, object>> _changedDataItems;
+        private readonly CancellationTokenSource _cancellationTokenSource;
+
+        private readonly ConcurrentDictionary<string,List<Action<object>>> _subscribedKeys;
+
+        private bool disposedValue;
+
+        public UISignalRClient()
+        {
+            _connectionUrl = "http://localhost:9999/NewUI";
+            _hubName = "UIHub";
+
+            _changedDataItems = new BufferBlock<KeyValuePair<string, object>>();
+            _cancellationTokenSource = new CancellationTokenSource();
+            _subscribedKeys = new ConcurrentDictionary<string, List<Action<object>>>();
+            Task.Run(() =>
+            {
+                ProcessReceivedData();
+            });
+        }
+
+        public bool Initialize()
+        {
+            try
+            {
+                if (_hubConnection is not null)
+                {
+                    return true;
+                }
+
+                _hubConnection = new HubConnection(_connectionUrl);
+                _hubConnection.StateChanged += OnStateChanged;
+
+                _hubProxy = _hubConnection.CreateHubProxy(_hubName);
+                _hubProxy.On<Dictionary<string, object>>("ReceiveChangedDataItems", items =>
+                {
+                    if(items.Count<=0)
+                    {
+                        return;
+                    }
+
+                    foreach (var item in items)
+                    {
+                        _changedDataItems.Post(item);
+                    }
+                });
+
+
+                return true;
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+        }
+
+        public void SubscribeDataItem(string dataKey, Action<object> callback)
+        {
+            if(!_subscribedKeys.ContainsKey(dataKey))
+            {
+                _subscribedKeys.TryAdd(dataKey, new List<Action<object>>());
+            }
+            _subscribedKeys[dataKey].Add(callback);
+        }
+
+        public void UnsubscribeDataItem(string dataKey, Action<object> callback)
+        {
+            if( _subscribedKeys.ContainsKey(dataKey))
+            {
+                _subscribedKeys[dataKey].Remove(callback);
+            }
+        }
+
+        private async void ProcessReceivedData()
+        {
+            while (await _changedDataItems.OutputAvailableAsync() && !_cancellationTokenSource.IsCancellationRequested)
+            {
+                var item = await _changedDataItems.ReceiveAsync();
+                if (!_subscribedKeys.ContainsKey(item.Key))
+                {
+                    continue;
+                }
+
+                foreach (var action in _subscribedKeys[item.Key])
+                {
+                    action?.Invoke(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);
+        }
+    }
+}

+ 10 - 9
FurnaceNewWorld/Directory.Packages.props

@@ -1,11 +1,12 @@
 <Project>
-    <PropertyGroup>
-        <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
-    </PropertyGroup>
-    <ItemGroup>
-        <PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
-        <PackageVersion Include="Mapster" Version="7.4.0" />
-        <PackageVersion Include="Prism.DryIoc" Version="9.0.537" />
-        <PackageVersion Include="System.IO.Ports" Version="9.0.9" />
-    </ItemGroup>
+  <PropertyGroup>
+    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
+    <PackageVersion Include="Mapster" Version="7.4.0" />
+    <PackageVersion Include="Microsoft.AspNet.SignalR.Client" Version="2.4.3" />
+    <PackageVersion Include="Prism.DryIoc" Version="9.0.537" />
+    <PackageVersion Include="System.IO.Ports" Version="9.0.9" />
+  </ItemGroup>
 </Project>

+ 3 - 0
FurnaceNewWorld/FurnaceNewWorld.slnx

@@ -1,4 +1,7 @@
 <Solution>
+  <Folder Name="/Communication/">
+    <Project Path="Communication/Communicator/Communicator.csproj" Id="327c6f92-1340-4c8e-9e21-70737d759e84" />
+  </Folder>
   <Folder Name="/Data/">
     <Project Path="Data/DataVM/DataVM.csproj" Id="c5464eea-9d32-4a07-b009-f602be5eb5ff" />
   </Folder>

+ 0 - 4
FurnaceNewWorld/FurnaceNewWorld/FurnaceNewWorld.csproj

@@ -26,8 +26,4 @@
 	  <ProjectReference Include="..\UIModules\ModuleBase\ModuleBase.csproj" />
 	</ItemGroup>
 
-	<ItemGroup>
-	  <Folder Include="Resources\" />
-	</ItemGroup>
-
 </Project>

+ 1 - 1
FurnaceNewWorld/UIModules/SummaryModule/Pops/N2Purge/N2PurgeSelectorViewModel.cs

@@ -23,7 +23,7 @@ partial class N2PurgeSelectorViewModel : ObservableObject, IPopAware
     {
     }
 
-    public void OnPop(object state)
+    public void OnPop(object? state)
     {
         this.Mode = "N2 Purge Mode";
     }