Skip to content

Commit 65d85ce

Browse files
committed
refactor: 实现 INetworkMonitorService 逻辑
1 parent 4d58915 commit 65d85ce

File tree

8 files changed

+181
-126
lines changed

8 files changed

+181
-126
lines changed

src/BootstrapBlazor/Components/NetworkMonitor/NetworkMonitor.cs

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/BootstrapBlazor/Components/NetworkMonitor/NetworkMonitorIndicator.razor

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,3 @@
2222
</div>
2323
</Template>
2424
</Popover>
25-
26-
<NetworkMonitor OnNetworkStateChanged="OnNetworkStateChanged" Indicators="@_indicators"></NetworkMonitor>

src/BootstrapBlazor/Components/NetworkMonitor/NetworkMonitorIndicator.razor.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace BootstrapBlazor.Components;
1313
/// <remarks>This component allows you to configure the text, placement, and trigger behavior of a tooltip that
1414
/// appears when interacting with the network monitor indicator. The tooltip can be customized to provide additional
1515
/// information to users.</remarks>
16-
public partial class NetworkMonitorIndicator
16+
public partial class NetworkMonitorIndicator : IDisposable
1717
{
1818
/// <summary>
1919
/// 获得/设置 Popover 弹窗标题 默认为 null
@@ -37,8 +37,10 @@ public partial class NetworkMonitorIndicator
3737
[Inject, NotNull]
3838
private IStringLocalizer<NetworkMonitorIndicator>? Localizer { get; set; }
3939

40+
[Inject, NotNull]
41+
private INetworkMonitorService? NetworkMonitorService { get; set; }
42+
4043
private NetworkMonitorState _state = new();
41-
private readonly List<string> _indicators = [];
4244
private string _networkTypeString = "";
4345
private string _downlinkString = "";
4446
private string _rttString = "";
@@ -53,11 +55,11 @@ public partial class NetworkMonitorIndicator
5355
/// <summary>
5456
/// <inheritdoc/>
5557
/// </summary>
56-
protected override void OnInitialized()
58+
protected override async Task OnInitializedAsync()
5759
{
58-
base.OnInitialized();
60+
await base.OnInitializedAsync();
5961

60-
_indicators.Add(Id);
62+
await NetworkMonitorService.RegisterStateChangedCallback(this, OnNetworkStateChanged);
6163
}
6264

6365
/// <summary>
@@ -69,6 +71,7 @@ protected override void OnParametersSet()
6971

7072
Trigger ??= "hover focus";
7173
Title ??= Localizer["Title"];
74+
7275
_networkTypeString = Localizer["NetworkType"];
7376
_downlinkString = Localizer["Downlink"];
7477
_rttString = Localizer["RTT"];
@@ -80,4 +83,22 @@ private Task OnNetworkStateChanged(NetworkMonitorState state)
8083
StateHasChanged();
8184
return Task.CompletedTask;
8285
}
86+
87+
private void Dispose(bool disposing)
88+
{
89+
if (disposing)
90+
{
91+
NetworkMonitorService.UnregisterStateChangedCallback(this);
92+
}
93+
}
94+
95+
/// <summary>
96+
/// <inheritdoc/>
97+
/// </summary>
98+
/// <exception cref="NotImplementedException"></exception>
99+
public void Dispose()
100+
{
101+
Dispose(true);
102+
GC.SuppressFinalize(this);
103+
}
83104
}

src/BootstrapBlazor/Components/NetworkMonitor/NetworkMonitorState.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ namespace BootstrapBlazor.Components;
1010
/// </summary>
1111
public class NetworkMonitorState
1212
{
13-
/// <summary>
14-
/// Gets or sets a value indicating whether the network is online
15-
/// </summary>
16-
public bool IsOnline { get; set; }
17-
1813
/// <summary>
1914
/// Gets or sets the current network type
2015
/// </summary>

src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public static IServiceCollection AddBootstrapBlazor(this IServiceCollection serv
9393
services.TryAddScoped<IMediaDevices, DefaultMediaDevices>();
9494
services.TryAddScoped<IVideoDevice, DefaultVideoDevice>();
9595
services.TryAddScoped<IAudioDevice, DefaultAudioDevice>();
96+
services.TryAddScoped<INetworkMonitorService, DefaultNetowrkMonitorService>();
9697
services.AddScoped<TabItemTextOptions>();
9798
services.AddScoped<DialogService>();
9899
services.AddScoped<MaskService>();

src/BootstrapBlazor/Services/DefaultNetworkMonitorService.cs

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,110 @@
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
55

6+
using System.Collections.Concurrent;
7+
68
namespace BootstrapBlazor.Components;
79

810
/// <summary>
911
/// 网络状态服务
1012
/// </summary>
11-
class DefaultNetowrkMonitorService(IJSRuntime jSRuntime)
13+
class DefaultNetowrkMonitorService : INetworkMonitorService, IAsyncDisposable
1214
{
1315
[NotNull]
1416
private JSModule? _module = null;
17+
[NotNull]
18+
private JSModule? _networkModule = null;
19+
private readonly IJSRuntime _runtime;
20+
private readonly DotNetObjectReference<DefaultNetowrkMonitorService> _interop;
21+
private readonly ConcurrentDictionary<IComponent, Func<NetworkMonitorState, Task>> _callbacks = new();
22+
private bool _init = false;
23+
private readonly SemaphoreSlim _semaphoreSlim = new(1, 1);
1524

16-
private Task<JSModule> LoadModule() => jSRuntime.LoadUtility();
25+
public DefaultNetowrkMonitorService(IJSRuntime jsRuntime)
26+
{
27+
_runtime = jsRuntime;
28+
_interop = DotNetObjectReference.Create(this);
29+
}
30+
31+
private Task<JSModule> LoadModule() => _runtime.LoadUtility();
1732

1833
/// <summary>
19-
/// 获取剪切板数据方法
34+
/// <inheritdoc/>
2035
/// </summary>
2136
public async Task<NetworkMonitorState> GetNetworkMonitorState(CancellationToken token = default)
2237
{
2338
_module ??= await LoadModule();
2439
return await _module.InvokeAsync<NetworkMonitorState?>("getNetworkInfo", token) ?? new();
2540
}
41+
42+
/// <summary>
43+
/// <inheritdoc/>
44+
/// </summary>
45+
/// <param name="component"></param>
46+
/// <param name="callback"></param>
47+
public async Task RegisterStateChangedCallback(IComponent component, Func<NetworkMonitorState, Task> callback)
48+
{
49+
_callbacks.AddOrUpdate(component, key => callback, (k, v) => callback);
50+
51+
if (!_init)
52+
{
53+
await _semaphoreSlim.WaitAsync();
54+
if (!_init)
55+
{
56+
_init = true;
57+
58+
_networkModule ??= await _runtime.LoadModuleByName("net");
59+
await _networkModule.InvokeVoidAsync("init", new
60+
{
61+
Invoke = _interop,
62+
OnNetworkStateChangedCallback = nameof(TriggerNetworkStateChanged)
63+
});
64+
}
65+
_semaphoreSlim.Release();
66+
}
67+
}
68+
69+
/// <summary>
70+
/// <inheritdoc/>
71+
/// </summary>
72+
/// <param name="component"></param>
73+
public void UnregisterStateChangedCallback(IComponent component)
74+
{
75+
_callbacks.TryRemove(component, out _);
76+
}
77+
78+
/// <summary>
79+
/// JSInvoke 回调方法
80+
/// </summary>
81+
/// <returns></returns>
82+
[JSInvokable]
83+
public async Task TriggerNetworkStateChanged(NetworkMonitorState state)
84+
{
85+
foreach (var callback in _callbacks.Values)
86+
{
87+
if (callback != null)
88+
{
89+
await callback(state);
90+
}
91+
}
92+
}
93+
94+
/// <summary>
95+
/// <inheritdoc/>
96+
/// </summary>
97+
/// <returns></returns>
98+
public async ValueTask DisposeAsync()
99+
{
100+
if (_module != null)
101+
{
102+
await _module.DisposeAsync();
103+
_module = null;
104+
}
105+
if (_networkModule != null)
106+
{
107+
await _networkModule.DisposeAsync();
108+
_networkModule = null;
109+
}
110+
_interop?.Dispose();
111+
}
26112
}

src/BootstrapBlazor/Services/INetworkMonitorService.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,32 @@
66
namespace BootstrapBlazor.Components;
77

88
/// <summary>
9-
///
9+
/// Defines a service for monitoring network state and retrieving the current network monitor status.
1010
/// </summary>
1111
public interface INetworkMonitorService
1212
{
13+
/// <summary>
14+
/// Retrieves the current state of the network monitor.
15+
/// </summary>
16+
/// <param name="token">A cancellation token that can be used to cancel the operation.</param>
17+
/// <returns>A task representing the asynchronous operation. The task result contains the current <see
18+
/// cref="NetworkMonitorState"/>.</returns>
19+
Task<NetworkMonitorState> GetNetworkMonitorState(CancellationToken token = default);
1320

21+
/// <summary>
22+
/// Registers a callback to be invoked when the network monitor state changes.
23+
/// </summary>
24+
/// <remarks>The callback is executed asynchronously whenever the network monitor detects a change in
25+
/// state. Ensure that the callback function is thread-safe and handles any exceptions that may occur during
26+
/// execution.</remarks>
27+
/// <param name="component">The component that will be associated with the callback. Cannot be null.</param>
28+
/// <param name="callback">A function to be called when the network monitor state changes. The function receives the new state and returns
29+
/// a task. Cannot be null.</param>
30+
Task RegisterStateChangedCallback(IComponent component, Func<NetworkMonitorState, Task> callback);
31+
32+
/// <summary>
33+
/// Unregisters a previously registered callback for state changes on the specified component.
34+
/// </summary>
35+
/// <param name="component">The component for which the state change callback should be unregistered. Cannot be null.</param>
36+
void UnregisterStateChangedCallback(IComponent component);
1437
}

0 commit comments

Comments
 (0)