Files
ThingsGateway/src/Foundation/ThingsGateway.Foundation/Channel/DDP/DDPUdpSessionChannel.cs
2025-10-18 23:14:55 +08:00

194 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using PooledAwait;
using System.Collections.Concurrent;
using System.Net;
using System.Runtime.CompilerServices;
using ThingsGateway.NewLife;
using TouchSocket.Resources;
namespace ThingsGateway.Foundation;
/// <summary>
/// Udp通道
/// </summary>
public class DDPUdpSessionChannel : UdpSessionChannel, IClientChannel, IDtuUdpSessionChannel
{
public DDPUdpSessionChannel(IChannelOptions channelOptions) : base(channelOptions)
{
}
protected override void LoadConfig(TouchSocketConfig config)
{
base.LoadConfig(config);
// 如果当前实例的配置不为空,则将配置应用到适配器
if (Config != null)
{
DDPAdapter.Config(Config);
}
if (DDPAdapter.Owner != null)
{
DDPAdapter.OnLoaded(this);
}
DDPAdapter.SendCallBackAsync = base.ProtectedDefaultSendAsync;
DataHandlingAdapter.SendCallBackAsync = DefaultSendAsync;
}
protected Task DefaultSendAsync(EndPoint endPoint, ReadOnlyMemory<byte> memory, CancellationToken token)
{
if (TryGetId(endPoint, out var id))
{
return DDPAdapter.SendInputAsync(endPoint, new DDPSend(memory, id, false), token);
}
else
{
throw new ClientNotFindException();
}
}
private DeviceUdpDataHandleAdapter<DDPUdpMessage> DDPAdapter = new();
public EndPoint DefaultEndpoint => RemoteIPHost?.EndPoint;
NonBlockingDictionary<string, WaitLock> WaitLocks { get; } = new();
public override WaitLock GetLock(string key)
{
if (key.IsNullOrEmpty()) return WaitLock;
return WaitLocks.GetOrAdd(key, (a) => new WaitLock(nameof(DDPUdpSessionChannel), WaitLock.MaxCount));
}
public override Task<Result> StopAsync(CancellationToken token)
{
WaitLocks.ForEach(a => a.Value.SafeDispose());
WaitLocks.Clear();
return base.StopAsync(token);
}
protected override ValueTask<bool> OnUdpReceiving(UdpReceiveingEventArgs e)
{
var byteBlock = e.Memory;
var endPoint = e.EndPoint;
if (!DDPAdapter.TryParseRequest(endPoint, byteBlock, out var message))
return EasyValueTask.FromResult(true);
return OnUdpReceiving(this, endPoint, message);
static async PooledValueTask<bool> OnUdpReceiving(DDPUdpSessionChannel @this, EndPoint endPoint, DDPUdpMessage message)
{
if (message != null)
{
if (message.IsSuccess)
{
var id = $"ID={message.Id}";
if (message.Type == 0x09)
{
if (@this.DataHandlingAdapter == null)
{
await @this.OnUdpReceived(new UdpReceivedDataEventArgs(endPoint, message.Content, default)).ConfigureAwait(false);
}
else
{
await @this.DataHandlingAdapter.ReceivedInputAsync(endPoint, message.Content).ConfigureAwait(false);
}
return true;
}
else
{
if (message.Type == 0x01)
{
bool log = false;
//注册ID
if (!@this.IdDict.TryAdd(endPoint, id))
{
@this.IdDict[endPoint] = id;
}
else
{
log = true;
}
if (!@this.EndPointDcit.TryAdd(id, endPoint))
{
@this.EndPointDcit[id] = endPoint;
}
else
{
log = true;
}
//发送成功
await @this.DDPAdapter.SendInputAsync(endPoint, new DDPSend(ReadOnlyMemory<byte>.Empty, id, false, 0x81), @this.ClosedToken).ConfigureAwait(false);
if (log)
@this.Logger?.Info(string.Format(AppResource.DtuConnected, id));
}
else if (message.Type == 0x02)
{
await @this.DDPAdapter.SendInputAsync(endPoint, new DDPSend(ReadOnlyMemory<byte>.Empty, id, false, 0x82), @this.ClosedToken).ConfigureAwait(false);
@this.Logger?.Info(string.Format(AppResource.DtuDisconnecting, id));
await Task.Delay(100).ConfigureAwait(false);
@this.IdDict.TryRemove(endPoint, out _);
@this.EndPointDcit.TryRemove(id, out _);
}
}
}
}
return true;
}
}
#region Throw
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ThrowIfCannotSendRequestInfo()
{
if (DataHandlingAdapter?.CanSendRequestInfo != true)
{
throw new NotSupportedException(TouchSocketResource.CannotSendRequestInfo);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ThrowIfClientNotConnected()
{
if (Online)
{
return;
}
throw new ClientNotConnectedException();
}
#endregion Throw
InternalConcurrentDictionary<EndPoint, string> IdDict { get; set; } = new();
InternalConcurrentDictionary<string, EndPoint> EndPointDcit { get; set; } = new();
public bool TryGetId(EndPoint endPoint, out string id)
{
return IdDict.TryGetValue(endPoint, out id);
}
public bool TryGetEndPoint(string id, out EndPoint endPoint)
{
return EndPointDcit.TryGetValue(id, out endPoint);
}
}