Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ csharp_preserve_single_line_blocks = true
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
[*.cs]
# Add file header
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/
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/
csharp_style_namespace_declarations = file_scoped:suggestion
csharp_style_expression_bodied_local_functions = true:silent
csharp_using_directive_placement = outside_namespace:silent
Expand Down
1 change: 1 addition & 0 deletions BootstrapBlazor.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ Global
{01007B10-7C3C-4136-83FF-981CA39AD3D4} = {7B29E81D-92DE-46C8-8EDC-1B48C8F12BC2}
{835C8BA9-A9CC-4EA0-9002-34A20F8B2E86} = {B6A98ADE-D26A-4D0B-8978-AB7AC915F5AE}
{30C57119-C564-401C-AE3A-6203E2733E1A} = {FF1089BE-C704-4374-B629-C57C08E1798F}
{98054DCC-A9AB-CB11-798F-424112EC8639} = {7B29E81D-92DE-46C8-8EDC-1B48C8F12BC2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5EB1960-6F30-4CE1-B375-EAE1F787D6FF}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>9.0.0</Version>
<Version>9.0.1</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

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

/// <summary>
/// <inheritdoc/>
/// </summary>
public IDataPackageHandler? DataPackageHandler { get; set; }

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand All @@ -33,10 +29,7 @@ public virtual async ValueTask HandlerAsync(ReadOnlyMemory<byte> data, Cancellat
{
if (DataPackageHandler != null)
{
if (DataPackageHandler.ReceivedCallBack == null)
{
DataPackageHandler.ReceivedCallBack = OnHandlerReceivedCallBack;
}
DataPackageHandler.ReceivedCallBack ??= OnHandlerReceivedCallBack;

// 如果存在数据处理器则调用其处理方法
await DataPackageHandler.HandlerAsync(data, token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ public interface IDataPackageAdapter
/// issues.</remarks>
Func<ReadOnlyMemory<byte>, ValueTask>? ReceivedCallBack { get; set; }

/// <summary>
/// Gets the handler responsible for processing data packages.
/// </summary>
IDataPackageHandler? DataPackageHandler { get; }

/// <summary>
/// Asynchronously receives data from a source and processes it.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>9.0.0</Version>
<Version>9.0.1</Version>
</PropertyGroup>

<PropertyGroup>
<PackageTags>BootstrapBlazor Socket</PackageTags>
<PackageTags>BootstrapBlazor Socket TcpClient</PackageTags>
<Description>BootstrapBlazor extensions of TcpSocket</Description>
</PropertyGroup>

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

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

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

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

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

private static readonly Dictionary<ITcpSocketClient, List<(IDataPackageAdapter Adapter, Func<ReadOnlyMemory<byte>, ValueTask> Callback)>> _cache = [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Consider thread safety for the static _cache dictionary.

Since _cache is modified and read by multiple extension methods, this can cause race conditions in multi-threaded use. Use a thread-safe collection like ConcurrentDictionary or implement locking to prevent concurrent access issues.


/// <summary>
/// 增加 <see cref="ITcpSocketClient"/> 数据适配器及其对应的回调方法
/// </summary>
/// <param name="client"></param>
/// <param name="adapter"></param>
/// <param name="callback"></param>
public static void AddDataPackageAdapter(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<ReadOnlyMemory<byte>, ValueTask> callback)
{
if (_cache.TryGetValue(client, out var list))
{
list.Add((adapter, cb));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Variable 'cb' is used before its declaration.

'cb' is referenced in list.Add and _cache.Add before it is declared as an async local function, which will cause a compilation error. Please declare 'cb' before using it.

}
else
{
_cache.Add(client, [(adapter, cb)]);
}

client.ReceivedCallBack += cb;
Comment on lines +64 to +73
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Callback removal logic may not match added callbacks.

Since the callback added is a wrapper function, direct comparison with the original callback may fail. Store and compare the actual delegate instance used in ReceivedCallBack to ensure correct removal.


// 设置 DataPackageAdapter 的回调函数
adapter.ReceivedCallBack = callback;

async ValueTask cb(ReadOnlyMemory<byte> buffer)
{
// 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
await adapter.HandlerAsync(buffer);
}
}

/// <summary>
/// 移除 <see cref="ITcpSocketClient"/> 数据适配器及其对应的回调方法
/// </summary>
/// <param name="client"></param>
/// <param name="callback"></param>
public static void RemoveDataPackageAdapter(this ITcpSocketClient client, Func<ReadOnlyMemory<byte>, ValueTask> callback)
{
if (_cache.TryGetValue(client, out var list))
{
var items = list.Where(i => i.Adapter.ReceivedCallBack == callback).ToList();
foreach (var c in items)
{
client.ReceivedCallBack -= c.Callback;
list.Remove(c);
}
}
}

/// <summary>
/// Configures the specified <see cref="ITcpSocketClient"/> to use the provided <see cref="IDataPackageAdapter"/>
/// for processing received data and sets a callback to handle processed data.
Expand All @@ -67,6 +115,16 @@ public static ValueTask<bool> ConnectAsync(this ITcpSocketClient client, string
/// containing the processed data and returns a <see cref="ValueTask"/>.</param>
public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<ReadOnlyMemory<byte>, ValueTask> callback)
{
// 释放缓存
if (_cache.TryGetValue(client, out var list))
{
foreach (var (Adapter, Callback) in list)
{
client.ReceivedCallBack -= Callback;
}
list.Clear();
}

// 设置 ITcpSocketClient 的回调函数
client.ReceivedCallBack = async buffer =>
{
Expand All @@ -75,7 +133,18 @@ public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPack
};

// 设置 DataPackageAdapter 的回调函数
adapter.ReceivedCallBack = buffer => callback(buffer);
adapter.ReceivedCallBack = callback;
}

/// <summary>
/// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
/// </summary>
/// <param name="client"><see cref="ITcpSocketClient"/> 实例</param>
/// <param name="handler"><see cref="IDataPackageHandler"/> 数据处理实例</param>
/// <param name="callback">回调方法</param>
public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPackageHandler handler, Func<ReadOnlyMemory<byte>, ValueTask> callback)
{
client.SetDataPackageAdapter(new DataPackageAdapter(handler), callback);
}

/// <summary>
Expand All @@ -92,6 +161,16 @@ public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPack
/// <param name="callback">The callback function to be invoked with the converted entity.</param>
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageAdapter adapter, IDataConverter<TEntity> socketDataConverter, Func<TEntity?, Task> callback)
{
// 释放缓存
if (_cache.TryGetValue(client, out var list))
{
foreach (var (Adapter, Callback) in list)
{
client.ReceivedCallBack -= Callback;
}
list.Clear();
}

// 设置 ITcpSocketClient 的回调函数
client.ReceivedCallBack = async buffer =>
{
Expand All @@ -111,6 +190,19 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
};
}

/// <summary>
/// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="client"></param>
/// <param name="handler"></param>
/// <param name="socketDataConverter"></param>
/// <param name="callback"></param>
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageHandler handler, IDataConverter<TEntity> socketDataConverter, Func<TEntity?, Task> callback)
{
client.SetDataPackageAdapter(new DataPackageAdapter(handler), socketDataConverter, callback);
}

/// <summary>
/// Configures the specified <see cref="ITcpSocketClient"/> to use a custom data package adapter and callback
/// function.
Expand All @@ -126,6 +218,16 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
/// <param name="callback">The callback function to invoke with the processed entity of type <typeparamref name="TEntity"/>.</param>
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageAdapter adapter, Func<TEntity?, Task> callback)
{
// 释放缓存
if (_cache.TryGetValue(client, out var list))
{
foreach (var (Adapter, Callback) in list)
{
client.ReceivedCallBack -= Callback;
}
list.Clear();
}

// 设置 ITcpSocketClient 的回调函数
client.ReceivedCallBack = async buffer =>
{
Expand Down Expand Up @@ -163,6 +265,17 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
}
}

/// <summary>
/// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
/// </summary>
/// <param name="client"><see cref="ITcpSocketClient"/> 实例</param>
/// <param name="handler"><see cref="IDataPackageHandler"/> 数据处理实例</param>
/// <param name="callback">回调方法</param>
public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client, IDataPackageHandler handler, Func<TEntity?, Task> callback)
{
client.SetDataPackageAdapter(new DataPackageAdapter(handler), callback);
}

private static void SetDataAdapterCallback<TEntity>(this IDataPackageAdapter adapter, IDataConverter<TEntity> converter, Func<TEntity?, Task> callback)
{
adapter.ReceivedCallBack = async buffer =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

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

Expand Down Expand Up @@ -48,7 +48,6 @@ public static IPAddress ConvertToIPAddress(string ipString)
}

[ExcludeFromCodeCoverage]

[UnsupportedOSPlatform("browser")]
private static IPAddress IPAddressByHostName => Dns.GetHostAddresses(Dns.GetHostName(), AddressFamily.InterNetwork).FirstOrDefault() ?? IPAddress.Any;

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

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

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

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

Expand Down
Loading