Skip to content

Commit e4236c0

Browse files
authored
feat(TcpSocket): support multiple DataPackageAdapter (#542)
* chore: 更新 License 信息 * chore: 更新解决方案 * chore: 增加 AddDataPackageAdapter 方法 * chore: bump version 9.0.1-beta02 * refactor: 精简代码 * feat: 增加缓存 * refactor: bump version 9.0.1 * doc: 代码格式化 * refactor: 增加缓存控制 * chore: 更新 tag 标签 * chore: bump version 9.0.1 * test: 更新单元测试 * refactor: 增加 SetDataPackageAdapter 方法 * test: 增加 AddDataPackageAdapter 单元测试 * test: 增加 SetDataPackageAdapter 单元测试 * test: 增加泛型单元测试
1 parent 46bea10 commit e4236c0

17 files changed

Lines changed: 257 additions & 56 deletions

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ csharp_preserve_single_line_blocks = true
216216
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
217217
[*.cs]
218218
# Add file header
219-
file_header_template = Copyright (c) Argo Zhang (argo@163.com). All rights reserved.\nLicensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\nWebsite: https://www.blazor.zone or https://argozhang.github.io/
219+
file_header_template = Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.\nLicensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\nWebsite: https://www.blazor.zone or https://argozhang.github.io/
220220
csharp_style_namespace_declarations = file_scoped:suggestion
221221
csharp_style_expression_bodied_local_functions = true:silent
222222
csharp_using_directive_placement = outside_namespace:silent

BootstrapBlazor.Extensions.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ Global
647647
{01007B10-7C3C-4136-83FF-981CA39AD3D4} = {7B29E81D-92DE-46C8-8EDC-1B48C8F12BC2}
648648
{835C8BA9-A9CC-4EA0-9002-34A20F8B2E86} = {B6A98ADE-D26A-4D0B-8978-AB7AC915F5AE}
649649
{30C57119-C564-401C-AE3A-6203E2733E1A} = {FF1089BE-C704-4374-B629-C57C08E1798F}
650+
{98054DCC-A9AB-CB11-798F-424112EC8639} = {7B29E81D-92DE-46C8-8EDC-1B48C8F12BC2}
650651
EndGlobalSection
651652
GlobalSection(ExtensibilityGlobals) = postSolution
652653
SolutionGuid = {D5EB1960-6F30-4CE1-B375-EAE1F787D6FF}

src/extensions/BootstrapBlazor.Socket/BootstrapBlazor.Socket.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<Version>9.0.0</Version>
4+
<Version>9.0.1</Version>
55
</PropertyGroup>
66

77
<PropertyGroup>

src/extensions/BootstrapBlazor.Socket/DataAdapter/DataPackageAdapter.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
1+
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33
// Website: https://www.blazor.zone or https://argozhang.github.io/
44

@@ -7,22 +7,18 @@ namespace BootstrapBlazor.DataAdapters;
77
/// <summary>
88
/// Provides a base implementation for adapting data packages between different systems or formats.
99
/// </summary>
10+
/// <param name="DataPackageHandler"><see cref="IDataPackageHandler"/> 实例</param>
1011
/// <remarks>This abstract class serves as a foundation for implementing custom data package adapters. It defines
1112
/// common methods for sending, receiving, and handling data packages, as well as a property for accessing the
1213
/// associated data package handler. Derived classes should override the virtual methods to provide specific behavior
1314
/// for handling data packages.</remarks>
14-
public class DataPackageAdapter : IDataPackageAdapter
15+
public class DataPackageAdapter(IDataPackageHandler? DataPackageHandler = null) : IDataPackageAdapter
1516
{
1617
/// <summary>
1718
/// <inheritdoc/>
1819
/// </summary>
1920
public Func<ReadOnlyMemory<byte>, ValueTask>? ReceivedCallBack { get; set; }
2021

21-
/// <summary>
22-
/// <inheritdoc/>
23-
/// </summary>
24-
public IDataPackageHandler? DataPackageHandler { get; set; }
25-
2622
/// <summary>
2723
/// <inheritdoc/>
2824
/// </summary>
@@ -33,10 +29,7 @@ public virtual async ValueTask HandlerAsync(ReadOnlyMemory<byte> data, Cancellat
3329
{
3430
if (DataPackageHandler != null)
3531
{
36-
if (DataPackageHandler.ReceivedCallBack == null)
37-
{
38-
DataPackageHandler.ReceivedCallBack = OnHandlerReceivedCallBack;
39-
}
32+
DataPackageHandler.ReceivedCallBack ??= OnHandlerReceivedCallBack;
4033

4134
// 如果存在数据处理器则调用其处理方法
4235
await DataPackageHandler.HandlerAsync(data, token);

src/extensions/BootstrapBlazor.Socket/DataAdapter/IDataPackageAdapter.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ public interface IDataPackageAdapter
2020
/// issues.</remarks>
2121
Func<ReadOnlyMemory<byte>, ValueTask>? ReceivedCallBack { get; set; }
2222

23-
/// <summary>
24-
/// Gets the handler responsible for processing data packages.
25-
/// </summary>
26-
IDataPackageHandler? DataPackageHandler { get; }
27-
2823
/// <summary>
2924
/// Asynchronously receives data from a source and processes it.
3025
/// </summary>

src/extensions/BootstrapBlazor.TcpSocket/BootstrapBlazor.TcpSocket.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<Version>9.0.0</Version>
4+
<Version>9.0.1</Version>
55
</PropertyGroup>
66

77
<PropertyGroup>
8-
<PackageTags>BootstrapBlazor Socket</PackageTags>
8+
<PackageTags>BootstrapBlazor Socket TcpClient</PackageTags>
99
<Description>BootstrapBlazor extensions of TcpSocket</Description>
1010
</PropertyGroup>
1111

src/extensions/BootstrapBlazor.TcpSocket/DefaultTcpSocketClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
1+
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33
// Website: https://www.blazor.zone or https://argozhang.github.io/
44

src/extensions/BootstrapBlazor.TcpSocket/DefaultTcpSocketClientProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
1+
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33
// Website: https://www.blazor.zone or https://argozhang.github.io/
44

src/extensions/BootstrapBlazor.TcpSocket/DefaultTcpSocketFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
1+
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33
// Website: https://www.blazor.zone or https://argozhang.github.io/
44

src/extensions/BootstrapBlazor.TcpSocket/Extensions/ITcpSocketClientExtensions.cs

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
2-
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3-
// See the LICENSE file in the project root for more information.
4-
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
1+
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
54

65
using Microsoft.Extensions.DependencyInjection;
76
using Microsoft.Extensions.Options;
@@ -52,6 +51,55 @@ public static ValueTask<bool> ConnectAsync(this ITcpSocketClient client, string
5251
return client.ConnectAsync(endPoint, token);
5352
}
5453

54+
private static readonly Dictionary<ITcpSocketClient, List<(IDataPackageAdapter Adapter, Func<ReadOnlyMemory<byte>, ValueTask> Callback)>> _cache = [];
55+
56+
/// <summary>
57+
/// 增加 <see cref="ITcpSocketClient"/> 数据适配器及其对应的回调方法
58+
/// </summary>
59+
/// <param name="client"></param>
60+
/// <param name="adapter"></param>
61+
/// <param name="callback"></param>
62+
public static void AddDataPackageAdapter(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<ReadOnlyMemory<byte>, ValueTask> callback)
63+
{
64+
if (_cache.TryGetValue(client, out var list))
65+
{
66+
list.Add((adapter, cb));
67+
}
68+
else
69+
{
70+
_cache.Add(client, [(adapter, cb)]);
71+
}
72+
73+
client.ReceivedCallBack += cb;
74+
75+
// 设置 DataPackageAdapter 的回调函数
76+
adapter.ReceivedCallBack = callback;
77+
78+
async ValueTask cb(ReadOnlyMemory<byte> buffer)
79+
{
80+
// 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
81+
await adapter.HandlerAsync(buffer);
82+
}
83+
}
84+
85+
/// <summary>
86+
/// 移除 <see cref="ITcpSocketClient"/> 数据适配器及其对应的回调方法
87+
/// </summary>
88+
/// <param name="client"></param>
89+
/// <param name="callback"></param>
90+
public static void RemoveDataPackageAdapter(this ITcpSocketClient client, Func<ReadOnlyMemory<byte>, ValueTask> callback)
91+
{
92+
if (_cache.TryGetValue(client, out var list))
93+
{
94+
var items = list.Where(i => i.Adapter.ReceivedCallBack == callback).ToList();
95+
foreach (var c in items)
96+
{
97+
client.ReceivedCallBack -= c.Callback;
98+
list.Remove(c);
99+
}
100+
}
101+
}
102+
55103
/// <summary>
56104
/// Configures the specified <see cref="ITcpSocketClient"/> to use the provided <see cref="IDataPackageAdapter"/>
57105
/// for processing received data and sets a callback to handle processed data.
@@ -67,6 +115,16 @@ public static ValueTask<bool> ConnectAsync(this ITcpSocketClient client, string
67115
/// containing the processed data and returns a <see cref="ValueTask"/>.</param>
68116
public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<ReadOnlyMemory<byte>, ValueTask> callback)
69117
{
118+
// 释放缓存
119+
if (_cache.TryGetValue(client, out var list))
120+
{
121+
foreach (var (Adapter, Callback) in list)
122+
{
123+
client.ReceivedCallBack -= Callback;
124+
}
125+
list.Clear();
126+
}
127+
70128
// 设置 ITcpSocketClient 的回调函数
71129
client.ReceivedCallBack = async buffer =>
72130
{
@@ -75,7 +133,18 @@ public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPack
75133
};
76134

77135
// 设置 DataPackageAdapter 的回调函数
78-
adapter.ReceivedCallBack = buffer => callback(buffer);
136+
adapter.ReceivedCallBack = callback;
137+
}
138+
139+
/// <summary>
140+
/// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
141+
/// </summary>
142+
/// <param name="client"><see cref="ITcpSocketClient"/> 实例</param>
143+
/// <param name="handler"><see cref="IDataPackageHandler"/> 数据处理实例</param>
144+
/// <param name="callback">回调方法</param>
145+
public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPackageHandler handler, Func<ReadOnlyMemory<byte>, ValueTask> callback)
146+
{
147+
client.SetDataPackageAdapter(new DataPackageAdapter(handler), callback);
79148
}
80149

81150
/// <summary>
@@ -92,6 +161,16 @@ public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPack
92161
/// <param name="callback">The callback function to be invoked with the converted entity.</param>
93162
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageAdapter adapter, IDataConverter<TEntity> socketDataConverter, Func<TEntity?, Task> callback)
94163
{
164+
// 释放缓存
165+
if (_cache.TryGetValue(client, out var list))
166+
{
167+
foreach (var (Adapter, Callback) in list)
168+
{
169+
client.ReceivedCallBack -= Callback;
170+
}
171+
list.Clear();
172+
}
173+
95174
// 设置 ITcpSocketClient 的回调函数
96175
client.ReceivedCallBack = async buffer =>
97176
{
@@ -111,6 +190,19 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
111190
};
112191
}
113192

193+
/// <summary>
194+
/// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
195+
/// </summary>
196+
/// <typeparam name="TEntity"></typeparam>
197+
/// <param name="client"></param>
198+
/// <param name="handler"></param>
199+
/// <param name="socketDataConverter"></param>
200+
/// <param name="callback"></param>
201+
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageHandler handler, IDataConverter<TEntity> socketDataConverter, Func<TEntity?, Task> callback)
202+
{
203+
client.SetDataPackageAdapter(new DataPackageAdapter(handler), socketDataConverter, callback);
204+
}
205+
114206
/// <summary>
115207
/// Configures the specified <see cref="ITcpSocketClient"/> to use a custom data package adapter and callback
116208
/// function.
@@ -126,6 +218,16 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
126218
/// <param name="callback">The callback function to invoke with the processed entity of type <typeparamref name="TEntity"/>.</param>
127219
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<TEntity?, Task> callback)
128220
{
221+
// 释放缓存
222+
if (_cache.TryGetValue(client, out var list))
223+
{
224+
foreach (var (Adapter, Callback) in list)
225+
{
226+
client.ReceivedCallBack -= Callback;
227+
}
228+
list.Clear();
229+
}
230+
129231
// 设置 ITcpSocketClient 的回调函数
130232
client.ReceivedCallBack = async buffer =>
131233
{
@@ -163,6 +265,17 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
163265
}
164266
}
165267

268+
/// <summary>
269+
/// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
270+
/// </summary>
271+
/// <param name="client"><see cref="ITcpSocketClient"/> 实例</param>
272+
/// <param name="handler"><see cref="IDataPackageHandler"/> 数据处理实例</param>
273+
/// <param name="callback">回调方法</param>
274+
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageHandler handler, Func<TEntity?, Task> callback)
275+
{
276+
client.SetDataPackageAdapter(new DataPackageAdapter(handler), callback);
277+
}
278+
166279
private static void SetDataAdapterCallback<TEntity>(this IDataPackageAdapter adapter, IDataConverter<TEntity> converter, Func<TEntity?, Task> callback)
167280
{
168281
adapter.ReceivedCallBack = async buffer =>

0 commit comments

Comments
 (0)