添加IAsyncDisposable
This commit is contained in:
@@ -683,36 +683,20 @@ public class MachineInfo : IExtend
|
||||
if (dic.TryGetValue("MemTotal", out var str) && !str.IsNullOrEmpty())
|
||||
Memory = (UInt64)str.TrimEnd(" kB").ToLong();
|
||||
|
||||
/*
|
||||
指标 含义 是否可回收
|
||||
MemTotal 系统总物理内存 ❌ 固定值
|
||||
MemFree 完全未使用的内存(不含缓存/缓冲区) ✅ 100% 可用
|
||||
MemAvailable 内核估计的可用内存(含可回收缓存和缓冲区) ✅ 最权威的保守估计
|
||||
Cached 文件系统缓存(Page Cache),可完全回收 ✅ 100% 可回收
|
||||
SReclaimable Slab 缓存中可回收的部分(如 dentry/inode) ✅ 大部分可回收(80%~90%)
|
||||
Buffers 磁盘块缓存(现代内核中值较小,可回收) ✅ 可回收
|
||||
Slab 内核对象缓存总大小(含可回收和不可回收部分) ⚠️ 需区分 SReclaimable
|
||||
SwapCached 被缓存到 Swap 的内存(可回收,但性能较差) ✅ 可回收但不建议依赖
|
||||
ulong ma = 0;
|
||||
if (dic.TryGetValue("MemAvailable", out str) && !str.IsNullOrEmpty())
|
||||
{
|
||||
ma = (UInt64)(str.TrimEnd(" kB").ToLong());
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
var ma = (UInt64)(dic["MemAvailable"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||
//低于3.14内核的版本用 free+cache
|
||||
var mf = (UInt64)(dic["MemFree"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||
var mc = (UInt64)(dic["Cached"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||
var bf = (UInt64)(dic["Buffers"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||
|
||||
if (dic.TryGetValue("SReclaimable", out str) && !str.IsNullOrEmpty())
|
||||
{
|
||||
var sr = (UInt64)(str?.TrimEnd(" kB").ToLong() ?? 0);
|
||||
mf += (ulong)(sr * 0.9);
|
||||
}
|
||||
if (dic.TryGetValue("Buffers", out str) && !str.IsNullOrEmpty())
|
||||
{
|
||||
var bf = (UInt64)(str?.TrimEnd(" kB").ToLong() ?? 0);
|
||||
mf += bf;
|
||||
}
|
||||
mf += mc;
|
||||
var free = mf + mc + bf;
|
||||
|
||||
AvailableMemory = ma > mf ? ma : mf;
|
||||
AvailableMemory = ma > free ? ma : free;
|
||||
}
|
||||
|
||||
// A2/A4温度获取,Buildroot,CPU温度和主板温度
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.10.1</PluginVersion>
|
||||
<ProPluginVersion>10.10.1</ProPluginVersion>
|
||||
<DefaultVersion>10.10.2</DefaultVersion>
|
||||
<PluginVersion>10.10.2</PluginVersion>
|
||||
<ProPluginVersion>10.10.2</ProPluginVersion>
|
||||
<DefaultVersion>10.10.3</DefaultVersion>
|
||||
<AuthenticationVersion>2.9.29</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.9.29</SourceGeneratorVersion>
|
||||
<NET8Version>8.0.18</NET8Version>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;netstandard2.0;net6.0;</TargetFrameworks>
|
||||
<TargetFrameworks>net462;netstandard2.0;net6.0;net8.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -134,6 +134,7 @@ public abstract class TcpServiceChannelBase<TClient> : TcpService<TClient>, ITcp
|
||||
|
||||
protected override void SafetyDispose(bool disposing)
|
||||
{
|
||||
m_transport?.SafeCancel();
|
||||
m_transport?.SafeDispose();
|
||||
base.SafetyDispose(disposing);
|
||||
}
|
||||
|
@@ -204,6 +204,7 @@ public class UdpSessionChannel : UdpSession, IClientChannel
|
||||
/// <inheritdoc/>
|
||||
protected override void SafetyDispose(bool disposing)
|
||||
{
|
||||
m_transport?.SafeCancel();
|
||||
m_transport?.SafeDispose();
|
||||
WaitHandlePool.SafeDispose();
|
||||
base.SafetyDispose(disposing);
|
||||
|
@@ -24,7 +24,7 @@ namespace ThingsGateway.Foundation;
|
||||
/// <summary>
|
||||
/// 协议基类
|
||||
/// </summary>
|
||||
public abstract class DeviceBase : DisposableObject, IDevice
|
||||
public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IChannel Channel { get; private set; }
|
||||
@@ -585,13 +585,6 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (!this.DisposedValue)
|
||||
{
|
||||
await Task.Delay(timeout, Channel.ClosedToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
return new MessageBase(ex);
|
||||
}
|
||||
var result = waitData.Check();
|
||||
@@ -1041,6 +1034,56 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
if (Channel != null)
|
||||
{
|
||||
Channel.Starting.Remove(ChannelStarting);
|
||||
Channel.Stoped.Remove(ChannelStoped);
|
||||
Channel.Started.Remove(ChannelStarted);
|
||||
Channel.Stoping.Remove(ChannelStoping);
|
||||
Channel.ChannelReceived.Remove(ChannelReceived);
|
||||
|
||||
if (Channel.Collects.Count == 1)
|
||||
{
|
||||
if (Channel is ITcpServiceChannel tcpServiceChannel)
|
||||
{
|
||||
tcpServiceChannel.Clients.ForEach(a => a.WaitHandlePool.SafeDispose());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//只关闭,不释放
|
||||
await Channel.CloseAsync().ConfigureAwait(false);
|
||||
if (Channel is IClientChannel client)
|
||||
{
|
||||
client.WaitHandlePool.SafeDispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Channel is ITcpServiceChannel tcpServiceChannel && this is IDtu dtu)
|
||||
{
|
||||
if (tcpServiceChannel.TryGetClient($"ID={dtu.DtuId}", out var client))
|
||||
{
|
||||
client.WaitHandlePool?.SafeDispose();
|
||||
await client.CloseAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Channel.Collects.Remove(this);
|
||||
}
|
||||
|
||||
_deviceLogger?.TryDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public virtual Action<IPluginManager> ConfigurePlugins(TouchSocketConfig config)
|
||||
{
|
||||
@@ -1058,4 +1101,5 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
return a => { };
|
||||
}
|
||||
public abstract ValueTask<OperResult<ReadOnlyMemory<byte>>> ReadAsync(object state, CancellationToken cancellationToken = default);
|
||||
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation;
|
||||
/// <summary>
|
||||
/// 协议设备接口
|
||||
/// </summary>
|
||||
public interface IDevice : IDisposable, IDisposableObject
|
||||
public interface IDevice : IDisposable, IDisposableObject, IAsyncDisposable
|
||||
{
|
||||
#region 属性
|
||||
|
||||
|
@@ -0,0 +1,73 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway;
|
||||
|
||||
|
||||
public static class DisposableExtensions
|
||||
{
|
||||
#region IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// 安全性释放(不用判断对象是否为空)。不会抛出任何异常。
|
||||
/// </summary>
|
||||
/// <param name="dis"></param>
|
||||
/// <returns>释放状态,当对象为<see langword="null"/>,或者已被释放时,均会返回<see cref="Result.Success"/>,只有实际在释放时遇到异常时,才显示其他状态。</returns>
|
||||
public static async Task<Result> SafeDisposeAsync(this IAsyncDisposable dis)
|
||||
{
|
||||
if (dis == default)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
try
|
||||
{
|
||||
await dis.DisposeAsync().ConfigureAwait(false);
|
||||
return Result.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.FromException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion IDisposable
|
||||
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 安全地取消 <see cref="CancellationTokenSource"/>,并返回操作结果。
|
||||
/// </summary>
|
||||
/// <param name="tokenSource">要取消的 <see cref="CancellationTokenSource"/>。</param>
|
||||
/// <returns>一个 <see cref="Result"/> 对象,表示操作的结果。</returns>
|
||||
public static async Task<Result> SafeCancelAsync(this CancellationTokenSource tokenSource)
|
||||
{
|
||||
if (tokenSource is null)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
try
|
||||
{
|
||||
await tokenSource.CancelAsync().ConfigureAwait(false);
|
||||
return Result.Success;
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return Result.Disposed;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.FromException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
@@ -9,6 +9,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
#pragma warning disable CA1851
|
||||
|
||||
public static class PackHelpers
|
||||
{
|
||||
|
@@ -0,0 +1,109 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 具有释放的对象。内部实现了<see cref="GC.SuppressFinalize(object)"/>,但不包括析构函数相关。
|
||||
/// </summary>
|
||||
public abstract partial class AsyncAndSyncDisposableObject :
|
||||
IDisposableObject,
|
||||
IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断当前对象是否已经被释放。
|
||||
/// 如果已经被释放,则抛出<see cref="ObjectDisposedException"/>异常。
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">当对象已经被释放时抛出此异常</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected void ThrowIfDisposed()
|
||||
{
|
||||
// 检查对象是否已经被释放
|
||||
if (this.m_disposedValue)
|
||||
{
|
||||
// 如果对象已被释放,抛出ObjectDisposedException异常
|
||||
throw new ObjectDisposedException($"The object instance with type {this.GetType().FullName} has been released");
|
||||
}
|
||||
}
|
||||
|
||||
private int m_count = 0;
|
||||
private int m_asyncCount = 0;
|
||||
/// <summary>
|
||||
/// 判断是否已释放。
|
||||
/// </summary>
|
||||
private volatile bool m_disposedValue;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool DisposedValue => this.m_disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// 处置资源
|
||||
/// </summary>
|
||||
/// <param name="disposing">一个值,表示是否释放托管资源</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// 标记当前对象为已处置状态
|
||||
this.m_disposedValue = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Interlocked.Increment(ref this.m_count) == 1)
|
||||
{
|
||||
this.Dispose(disposing: true);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处置资源
|
||||
/// </summary>
|
||||
/// <param name="disposing">一个值,表示是否释放托管资源</param>
|
||||
protected virtual Task DisposeAsync(bool disposing)
|
||||
{
|
||||
// 标记当前对象为已处置状态
|
||||
this.m_disposedValue = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Interlocked.Increment(ref this.m_count) == 1)
|
||||
//{
|
||||
// this.Dispose(disposing: true);
|
||||
//}
|
||||
|
||||
if (Interlocked.Increment(ref this.m_asyncCount) == 1)
|
||||
{
|
||||
await this.DisposeAsync(disposing: true).ConfigureAwait(false);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 具有释放的对象。内部实现了<see cref="GC.SuppressFinalize(object)"/>,但不包括析构函数相关。
|
||||
/// </summary>
|
||||
public abstract partial class AsyncDisposableObject :
|
||||
//IDisposableObject,
|
||||
IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断当前对象是否已经被释放。
|
||||
/// 如果已经被释放,则抛出<see cref="ObjectDisposedException"/>异常。
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">当对象已经被释放时抛出此异常</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected void ThrowIfDisposed()
|
||||
{
|
||||
// 检查对象是否已经被释放
|
||||
if (this.m_disposedValue)
|
||||
{
|
||||
// 如果对象已被释放,抛出ObjectDisposedException异常
|
||||
throw new ObjectDisposedException($"The object instance with type {this.GetType().FullName} has been released");
|
||||
}
|
||||
}
|
||||
|
||||
private int m_asyncCount = 0;
|
||||
/// <summary>
|
||||
/// 判断是否已释放。
|
||||
/// </summary>
|
||||
private volatile bool m_disposedValue;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool DisposedValue => this.m_disposedValue;
|
||||
|
||||
///// <summary>
|
||||
///// 处置资源
|
||||
///// </summary>
|
||||
///// <param name="disposing">一个值,表示是否释放托管资源</param>
|
||||
//protected virtual void Dispose(bool disposing)
|
||||
//{
|
||||
// // 标记当前对象为已处置状态
|
||||
// this.m_disposedValue = true;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
///// </summary>
|
||||
//public void Dispose()
|
||||
//{
|
||||
// if (this.DisposedValue)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (Interlocked.Increment(ref this.m_count) == 1)
|
||||
// {
|
||||
// this.Dispose(disposing: true);
|
||||
// }
|
||||
// GC.SuppressFinalize(this);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 处置资源
|
||||
/// </summary>
|
||||
/// <param name="disposing">一个值,表示是否释放托管资源</param>
|
||||
protected virtual Task DisposeAsync(bool disposing)
|
||||
{
|
||||
// 标记当前对象为已处置状态
|
||||
this.m_disposedValue = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Interlocked.Increment(ref this.m_count) == 1)
|
||||
//{
|
||||
// this.Dispose(disposing: true);
|
||||
//}
|
||||
|
||||
if (Interlocked.Increment(ref this.m_asyncCount) == 1)
|
||||
{
|
||||
await this.DisposeAsync(disposing: true).ConfigureAwait(false);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
@@ -54,7 +54,7 @@ public class AsyncReadWriteLock
|
||||
{
|
||||
var cancellationTokenSource = _cancellationTokenSource;
|
||||
_cancellationTokenSource = new();
|
||||
await cancellationTokenSource.CancelAsync().ConfigureAwait(false); // 取消读取
|
||||
await cancellationTokenSource.SafeCancelAsync().ConfigureAwait(false); // 取消读取
|
||||
cancellationTokenSource.SafeDispose();
|
||||
}
|
||||
|
||||
|
@@ -59,10 +59,10 @@ public abstract class BusinessBaseWithCacheAlarm : BusinessBaseWithCache
|
||||
|
||||
await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
GlobalData.AlarmChangedEvent -= AlarmValueChange;
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
/// <summary>
|
||||
/// 当报警值发生变化时触发此事件处理方法。该方法内部会检查是否需要进行报警上传,如果需要,则调用 <see cref="AlarmChange(AlarmVariable)"/> 方法。
|
||||
|
@@ -130,7 +130,7 @@ public abstract class BusinessBaseWithCacheInterval : BusinessBaseWithCache
|
||||
/// <summary>
|
||||
/// 释放资源方法
|
||||
/// </summary>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
// 解绑事件
|
||||
GlobalData.AlarmChangedEvent -= AlarmValueChange;
|
||||
@@ -142,7 +142,7 @@ public abstract class BusinessBaseWithCacheInterval : BusinessBaseWithCache
|
||||
_memoryDevModelQueue.Clear();
|
||||
_memoryVarModelQueue.Clear();
|
||||
_memoryVarModelsQueue.Clear();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -47,10 +47,11 @@ public abstract class CollectFoundationBase : CollectBase
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
FoundationDevice?.Dispose();
|
||||
base.Dispose(disposing);
|
||||
if (FoundationDevice != null)
|
||||
await FoundationDevice.SafeDisposeAsync().ConfigureAwait(false);
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
}
|
||||
/// <summary>
|
||||
/// 开始通讯执行的方法
|
||||
|
@@ -26,11 +26,12 @@ namespace ThingsGateway.Gateway.Application;
|
||||
/// <summary>
|
||||
/// 插件基类
|
||||
/// </summary>
|
||||
public abstract class DriverBase : DisposableObject, IDriver
|
||||
public abstract class DriverBase : AsyncDisposableObject, IDriver
|
||||
{
|
||||
/// <inheritdoc cref="DriverBase"/>
|
||||
public DriverBase()
|
||||
{
|
||||
|
||||
Localizer = App.CreateLocalizerByType(typeof(DriverBase))!;
|
||||
}
|
||||
|
||||
@@ -312,38 +313,44 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
|
||||
protected abstract List<IScheduledTask> ProtectedGetTasks(CancellationToken cancellationToken);
|
||||
|
||||
protected object stopLock = new();
|
||||
protected WaitLock stopLock = new(nameof(DriverBase));
|
||||
/// <summary>
|
||||
/// 已停止任务,释放插件
|
||||
/// </summary>
|
||||
internal virtual void Stop()
|
||||
internal virtual async Task StopAsync()
|
||||
{
|
||||
if (!DisposedValue)
|
||||
{
|
||||
lock (stopLock)
|
||||
await stopLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
if (!DisposedValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 执行资源释放操作
|
||||
Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录 Dispose 方法执行失败的错误信息
|
||||
LogMessage?.LogError(ex, "Dispose");
|
||||
}
|
||||
|
||||
// 执行资源释放操作
|
||||
await this.SafeDisposeAsync().ConfigureAwait(false);
|
||||
|
||||
// 记录设备线程已停止的信息
|
||||
LogMessage?.LogInformation(string.Format(AppResource.DeviceTaskStop, DeviceName));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录 Dispose 方法执行失败的错误信息
|
||||
LogMessage?.LogError(ex, "Dispose");
|
||||
}
|
||||
finally
|
||||
{
|
||||
stopLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
if (TaskSchedulerLoop != null)
|
||||
{
|
||||
lock (TaskSchedulerLoop)
|
||||
|
@@ -14,7 +14,7 @@ using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application
|
||||
{
|
||||
public interface IDriver : IDisposable
|
||||
public interface IDriver : IAsyncDisposable
|
||||
{
|
||||
bool DisposedValue { get; }
|
||||
ChannelRuntime CurrentChannel { get; }
|
||||
|
@@ -17,6 +17,7 @@ using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
#pragma warning disable CS0649
|
||||
|
||||
/// <summary>
|
||||
/// 通道表
|
||||
|
@@ -17,6 +17,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
#pragma warning disable CS0649
|
||||
|
||||
/// <summary>
|
||||
/// 设备表
|
||||
|
@@ -16,6 +16,7 @@ using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
#pragma warning disable CS0649
|
||||
|
||||
/// <summary>
|
||||
/// 设备变量表
|
||||
|
@@ -12,9 +12,10 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
using ThingsGateway.Common.Extension;
|
||||
using ThingsGateway.Gateway.Application.Extensions;
|
||||
using ThingsGateway.NewLife;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +45,7 @@ internal sealed class AlarmTask : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
StopTask();
|
||||
scheduledTask?.TryDispose();
|
||||
scheduledTask?.SafeDispose();
|
||||
}
|
||||
|
||||
#region 核心实现
|
||||
|
@@ -43,7 +43,7 @@ internal sealed class ChannelThreadManage : IChannelThreadManage
|
||||
{
|
||||
if (!DeviceThreadManages.TryRemove(channelId, out var deviceThreadManage)) return;
|
||||
|
||||
await deviceThreadManage.DisposeAsync().ConfigureAwait(false);
|
||||
await deviceThreadManage.SafeDisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -326,7 +326,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
{
|
||||
try
|
||||
{
|
||||
await oldCts.CancelAsync().ConfigureAwait(false);
|
||||
await oldCts.SafeCancelAsync().ConfigureAwait(false);
|
||||
oldCts.SafeDispose();
|
||||
}
|
||||
catch
|
||||
@@ -340,7 +340,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
CancellationTokenSources.TryAdd(driver.DeviceId, cts);
|
||||
|
||||
_ = Task.Factory.StartNew((state) => DriverStart(state, token), driver, token, TaskCreationOptions.None, TaskScheduler.Default);
|
||||
}).ConfigureAwait(false);
|
||||
}, App.HostApplicationLifetime.ApplicationStopping).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -393,45 +393,48 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
try
|
||||
{
|
||||
ConcurrentList<VariableRuntime> saveVariableRuntimes = new();
|
||||
deviceIds.ParallelForEach((deviceId) =>
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
// 查找具有指定设备ID的驱动程序对象
|
||||
if (Drivers.TryRemove(deviceId, out var driver))
|
||||
{
|
||||
driver.CurrentDevice.SetDeviceStatus(now, false, "Communication connection has been removed");
|
||||
if (IsCollectChannel == true)
|
||||
{
|
||||
foreach (var a in driver.IdVariableRuntimes)
|
||||
{
|
||||
a.Value.SetValue(a.Value.Value, now, false);
|
||||
a.Value.SetErrorMessage("Communication connection has been removed");
|
||||
if (a.Value.SaveValue && !a.Value.DynamicVariable)
|
||||
{
|
||||
saveVariableRuntimes.Add(a.Value);
|
||||
}
|
||||
}
|
||||
await deviceIds.ParallelForEachAsync(async (deviceId, cancellationToken) =>
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
// 查找具有指定设备ID的驱动程序对象
|
||||
if (Drivers.TryRemove(deviceId, out var driver))
|
||||
{
|
||||
driver.CurrentDevice.SetDeviceStatus(now, false, "Communication connection has been removed");
|
||||
if (IsCollectChannel == true)
|
||||
{
|
||||
foreach (var a in driver.IdVariableRuntimes)
|
||||
{
|
||||
a.Value.SetValue(a.Value.Value, now, false);
|
||||
a.Value.SetErrorMessage("Communication connection has been removed");
|
||||
if (a.Value.SaveValue && !a.Value.DynamicVariable)
|
||||
{
|
||||
saveVariableRuntimes.Add(a.Value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 取消驱动程序的操作
|
||||
if (CancellationTokenSources.TryRemove(deviceId, out var token))
|
||||
{
|
||||
if (token != null)
|
||||
{
|
||||
driver.Stop();
|
||||
token.Cancel();
|
||||
token.Dispose();
|
||||
}
|
||||
}
|
||||
// 取消驱动程序的操作
|
||||
if (CancellationTokenSources.TryRemove(deviceId, out var token))
|
||||
{
|
||||
if (token != null)
|
||||
{
|
||||
await token.SafeCancelAsync().ConfigureAwait(false);
|
||||
token.SafeDispose();
|
||||
if (driver != null)
|
||||
{
|
||||
await driver.StopAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DriverTasks.TryRemove(deviceId, out var task))
|
||||
{
|
||||
task.Stop();
|
||||
}
|
||||
});
|
||||
if (DriverTasks.TryRemove(deviceId, out var task))
|
||||
{
|
||||
task.Stop();
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
|
||||
@@ -796,7 +799,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
Disposed = true;
|
||||
try
|
||||
{
|
||||
await CancellationTokenSource.CancelAsync().ConfigureAwait(false);
|
||||
await CancellationTokenSource.SafeCancelAsync().ConfigureAwait(false);
|
||||
CancellationTokenSource.SafeDispose();
|
||||
GlobalData.DeviceStatusChangeEvent -= GlobalData_DeviceStatusChangeEvent;
|
||||
await NewDeviceLock.WaitAsync().ConfigureAwait(false);
|
||||
|
@@ -78,7 +78,7 @@ internal sealed class GatewayMonitorHostedService : BackgroundService, IGatewayM
|
||||
|
||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await ChannelThreadManage.DisposeAsync().ConfigureAwait(false);
|
||||
await ChannelThreadManage.SafeDisposeAsync().ConfigureAwait(false);
|
||||
await base.StopAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@@ -312,10 +312,10 @@ internal sealed class RedundancyTask : IRpcDriver, IAsyncDisposable
|
||||
{
|
||||
await StopTaskAsync().ConfigureAwait(false);
|
||||
TextLogger?.TryDispose();
|
||||
scheduledTask?.TryDispose();
|
||||
scheduledTask?.SafeDispose();
|
||||
|
||||
_tcpDmtpService?.TryDispose();
|
||||
_tcpDmtpClient?.TryDispose();
|
||||
_tcpDmtpService?.SafeDispose();
|
||||
_tcpDmtpClient?.SafeDispose();
|
||||
_tcpDmtpService = null;
|
||||
_tcpDmtpClient = null;
|
||||
}
|
||||
|
@@ -78,12 +78,12 @@ internal sealed class PluginService : IPluginService
|
||||
|
||||
public Type GetDebugUI(string pluginName)
|
||||
{
|
||||
using var driver = GetDriver(pluginName);
|
||||
var driver = GetDriver(pluginName);
|
||||
return driver?.DriverDebugUIType;
|
||||
}
|
||||
public Type GetAddressUI(string pluginName)
|
||||
{
|
||||
using var driver = GetDriver(pluginName);
|
||||
var driver = GetDriver(pluginName);
|
||||
return driver?.DriverVariableAddressUIType;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,6 @@ internal sealed class PluginService : IPluginService
|
||||
{
|
||||
string cacheKey = $"{nameof(PluginService)}_{nameof(GetDriverMethodInfos)}_{CultureInfo.CurrentUICulture.Name}";
|
||||
// 如果未提供驱动基类对象,则尝试根据插件名称获取驱动对象
|
||||
var dispose = driver == null; // 标记是否需要释放驱动对象
|
||||
driver ??= GetDriver(pluginName); // 如果未提供驱动对象,则根据插件名称获取驱动对象
|
||||
|
||||
// 检查插件名称是否为空或null
|
||||
@@ -183,10 +182,10 @@ internal sealed class PluginService : IPluginService
|
||||
}
|
||||
|
||||
// 如果未从缓存中获取到指定插件的属性信息,则尝试从驱动基类对象中获取
|
||||
return SetDriverMethodInfosCache(driver, pluginName, cacheKey, dispose); // 获取并设置属性信息缓存
|
||||
return SetDriverMethodInfosCache(driver, pluginName, cacheKey); // 获取并设置属性信息缓存
|
||||
|
||||
// 用于设置驱动方法信息缓存的内部方法
|
||||
List<DriverMethodInfo> SetDriverMethodInfosCache(IDriver driver, string pluginName, string cacheKey, bool dispose)
|
||||
List<DriverMethodInfo> SetDriverMethodInfosCache(IDriver driver, string pluginName, string cacheKey)
|
||||
{
|
||||
// 获取驱动对象的方法信息,并筛选出带有 DynamicMethodAttribute 特性的方法
|
||||
var dependencyPropertyWithInfos = driver.GetType().GetMethods()?.SelectMany(it =>
|
||||
@@ -206,10 +205,6 @@ internal sealed class PluginService : IPluginService
|
||||
var result = dependencyPropertyWithInfos.ToList();
|
||||
App.CacheService.HashAdd(cacheKey, pluginName, result);
|
||||
|
||||
// 如果是通过方法内部创建的驱动对象,则在方法执行完成后释放该驱动对象
|
||||
if (dispose)
|
||||
driver.SafeDispose();
|
||||
|
||||
// 返回获取到的属性信息字典
|
||||
return result;
|
||||
}
|
||||
@@ -228,7 +223,6 @@ internal sealed class PluginService : IPluginService
|
||||
{
|
||||
string cacheKey = $"{nameof(PluginService)}_{nameof(GetDriverPropertyTypes)}_{CultureInfo.CurrentUICulture.Name}";
|
||||
|
||||
var dispose = driver == null;
|
||||
driver ??= GetDriver(pluginName); // 如果 driver 为 null, 获取驱动实例
|
||||
// 检查插件名称是否为空或空字符串
|
||||
if (!pluginName.IsNullOrEmpty())
|
||||
@@ -245,17 +239,15 @@ internal sealed class PluginService : IPluginService
|
||||
}
|
||||
// 如果缓存中不存在该插件的数据,则重新获取并缓存
|
||||
|
||||
return (SetCache(driver, pluginName, cacheKey, dispose), driver.DriverProperties, driver.DriverPropertyUIType); // 调用 SetCache 方法进行缓存并返回结果
|
||||
return (SetCache(driver, pluginName, cacheKey), driver.DriverProperties, driver.DriverPropertyUIType); // 调用 SetCache 方法进行缓存并返回结果
|
||||
|
||||
// 定义 SetCache 方法,用于设置缓存并返回
|
||||
IEnumerable<IEditorItem> SetCache(IDriver driver, string pluginName, string cacheKey, bool dispose)
|
||||
IEnumerable<IEditorItem> SetCache(IDriver driver, string pluginName, string cacheKey)
|
||||
{
|
||||
var editorItems = PluginServiceUtil.GetEditorItems(driver.DriverProperties?.GetType()).ToList();
|
||||
// 将结果存入缓存中,键为插件名称
|
||||
App.CacheService.HashAdd(cacheKey, pluginName, editorItems);
|
||||
// 如果 dispose 参数为 true,则释放 driver 对象
|
||||
if (dispose)
|
||||
driver.SafeDispose();
|
||||
|
||||
return editorItems;
|
||||
}
|
||||
}
|
||||
@@ -291,7 +283,6 @@ internal sealed class PluginService : IPluginService
|
||||
|
||||
{
|
||||
string cacheKey = $"{nameof(PluginService)}_{nameof(GetVariablePropertyTypes)}_{CultureInfo.CurrentUICulture.Name}";
|
||||
var dispose = businessBase == null;
|
||||
businessBase ??= (BusinessBase)GetDriver(pluginName); // 如果 driver 为 null, 获取驱动实例
|
||||
|
||||
var data = App.CacheService.HashGetAll<List<IEditorItem>>(cacheKey);
|
||||
@@ -309,8 +300,6 @@ internal sealed class PluginService : IPluginService
|
||||
// 将结果存入缓存中,键为插件名称
|
||||
App.CacheService.HashAdd(cacheKey, pluginName, editorItems);
|
||||
// 如果 dispose 参数为 true,则释放 driver 对象
|
||||
if (dispose)
|
||||
businessBase.SafeDispose();
|
||||
return editorItems;
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ public class TimeIntervalTriggerNode : TextNode, ITriggerNode, IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
_task?.Stop();
|
||||
_task.TryDispose();
|
||||
_task?.TryDispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
@@ -468,7 +468,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel))
|
||||
{
|
||||
var pluginKey = channel?.PluginName;
|
||||
using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey);
|
||||
var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey);
|
||||
return new KeyValuePair<string, VariablePropertyBase>(pluginKey, businessBase.VariablePropertys);
|
||||
}
|
||||
return new KeyValuePair<string, VariablePropertyBase>(string.Empty, null);
|
||||
@@ -500,7 +500,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel))
|
||||
{
|
||||
var pluginKey = channel?.PluginName;
|
||||
using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey);
|
||||
var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey);
|
||||
return new KeyValuePair<string, VariablePropertyBase>(pluginKey, businessBase.VariablePropertys);
|
||||
}
|
||||
return new KeyValuePair<string, VariablePropertyBase>(string.Empty, null);
|
||||
|
@@ -30,7 +30,7 @@ public static class VariableServiceHelpers
|
||||
if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel))
|
||||
{
|
||||
var pluginKey = channel?.PluginName;
|
||||
using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey);
|
||||
var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey);
|
||||
return new KeyValuePair<string, VariablePropertyBase>(pluginKey, businessBase.VariablePropertys);
|
||||
}
|
||||
return new KeyValuePair<string, VariablePropertyBase>(string.Empty, null);
|
||||
|
@@ -9,6 +9,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Dlt645;
|
||||
#pragma warning disable CA1851
|
||||
|
||||
internal static class PackHelper
|
||||
{
|
||||
|
@@ -11,6 +11,7 @@
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
|
||||
namespace ThingsGateway.Foundation.Modbus;
|
||||
#pragma warning disable CA1851
|
||||
|
||||
/// <summary>
|
||||
/// PackHelper
|
||||
|
@@ -155,7 +155,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
foreach (var item in ModbusServer01ByteBlocks)
|
||||
{
|
||||
@@ -177,7 +177,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress
|
||||
ModbusServer02ByteBlocks.Clear();
|
||||
ModbusServer03ByteBlocks.Clear();
|
||||
ModbusServer04ByteBlocks.Clear();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<Import Project="..\..\PackNuget.props" />
|
||||
<Import Project="..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;netstandard2.0;net6.0;</TargetFrameworks>
|
||||
<TargetFrameworks>net462;netstandard2.0;net6.0;net8.0;</TargetFrameworks>
|
||||
<Description>工业设备通讯协议-OpcDa协议</Description>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<DocumentationFile></DocumentationFile>
|
||||
|
@@ -28,7 +28,7 @@ public delegate void LogEventHandler(byte level, object sender, string message,
|
||||
/// <summary>
|
||||
/// OpcUaMaster
|
||||
/// </summary>
|
||||
public class OpcUaMaster : IDisposable
|
||||
public class OpcUaMaster : IDisposable, IAsyncDisposable
|
||||
{
|
||||
#region 属性,变量等
|
||||
|
||||
@@ -405,6 +405,18 @@ public class OpcUaMaster : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接。
|
||||
/// </summary>
|
||||
public async Task DisconnectAsync()
|
||||
{
|
||||
await PrivateDisconnectAsync().ConfigureAwait(false);
|
||||
// disconnect any existing session.
|
||||
if (m_session != null)
|
||||
{
|
||||
m_session = null;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -412,7 +424,12 @@ public class OpcUaMaster : IDisposable
|
||||
_variableDicts?.Clear();
|
||||
_subscriptionDicts?.Clear();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await DisconnectAsync().ConfigureAwait(false);
|
||||
_variableDicts?.Clear();
|
||||
_subscriptionDicts?.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取变量说明
|
||||
/// </summary>
|
||||
@@ -865,7 +882,7 @@ public class OpcUaMaster : IDisposable
|
||||
{
|
||||
return;
|
||||
}
|
||||
PrivateDisconnect();
|
||||
await PrivateDisconnectAsync().ConfigureAwait(false);
|
||||
if (LastServerUrl != serverUrl)
|
||||
{
|
||||
_variableDicts.Clear();
|
||||
@@ -944,6 +961,29 @@ public class OpcUaMaster : IDisposable
|
||||
DoConnectComplete(false);
|
||||
}
|
||||
}
|
||||
private async Task PrivateDisconnectAsync()
|
||||
{
|
||||
bool state = m_session?.Connected == true;
|
||||
|
||||
if (m_reConnectHandler != null)
|
||||
{
|
||||
try { m_reConnectHandler.Dispose(); } catch { }
|
||||
m_reConnectHandler = null;
|
||||
}
|
||||
if (m_session != null)
|
||||
{
|
||||
m_session.KeepAlive -= Session_KeepAlive;
|
||||
await m_session.CloseAsync(10000).ConfigureAwait(false);
|
||||
m_session.Dispose();
|
||||
m_session = null;
|
||||
}
|
||||
|
||||
if (state)
|
||||
{
|
||||
Log(2, null, "Disconnected");
|
||||
DoConnectComplete(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 连接
|
||||
|
||||
@@ -1376,5 +1416,7 @@ public class OpcUaMaster : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion 私有方法
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.SiemensS7;
|
||||
#pragma warning disable CA1851
|
||||
|
||||
internal static class PackHelper
|
||||
{
|
||||
|
@@ -417,13 +417,15 @@ public partial class SiemensS7Master : DeviceBase
|
||||
//本地TSAP
|
||||
if (SiemensS7Type == SiemensTypeEnum.S200 || SiemensS7Type == SiemensTypeEnum.S200Smart)
|
||||
{
|
||||
ISO_CR[13] = BitConverter.GetBytes(LocalTSAP)[1];
|
||||
ISO_CR[14] = BitConverter.GetBytes(LocalTSAP)[0];
|
||||
var data = s7BitConverter.GetBytes(LocalTSAP);
|
||||
ISO_CR[13] = data[0];
|
||||
ISO_CR[14] = data[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ISO_CR[16] = BitConverter.GetBytes(LocalTSAP)[1];
|
||||
ISO_CR[17] = BitConverter.GetBytes(LocalTSAP)[0];
|
||||
var data = s7BitConverter.GetBytes(LocalTSAP);
|
||||
ISO_CR[16] = data[0];
|
||||
ISO_CR[17] = data[1];
|
||||
}
|
||||
}
|
||||
if (Rack > 0 || Slot > 0)
|
||||
|
@@ -49,10 +49,10 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariable, ID
|
||||
|
||||
private SqlSugarClient _db;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_db?.TryDispose();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
|
||||
|
@@ -51,10 +51,10 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable, IDBH
|
||||
|
||||
protected override BusinessPropertyWithCacheInterval _businessPropertyWithCacheInterval => _driverPropertys;
|
||||
private SqlSugarClient _db;
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_db?.TryDispose();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
public async Task<SqlSugarPagedList<IDBHistoryValue>> GetDBHistoryValuePagesAsync(DBHistoryValuePageInput input)
|
||||
{
|
||||
|
@@ -47,10 +47,10 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheAlarm, IDBHistoryAla
|
||||
/// <returns></returns>
|
||||
public override bool IsConnected() => success;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_db?.TryDispose();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
protected override Task ProtectedStartAsync(CancellationToken cancellationToken)
|
||||
|
@@ -53,10 +53,10 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariable,
|
||||
|
||||
protected override BusinessPropertyWithCacheInterval _businessPropertyWithCacheInterval => _driverPropertys;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_db?.TryDispose();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
|
||||
|
@@ -10,8 +10,6 @@
|
||||
|
||||
using ThingsGateway.Gateway.Application;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Plugin.Dlt645;
|
||||
|
||||
/// <summary>
|
||||
@@ -52,7 +50,8 @@ public class Dlt645_2007Master : CollectFoundationBase
|
||||
|
||||
var plc = _plc;
|
||||
_plc = new();
|
||||
plc?.SafeDispose();
|
||||
if (plc != null)
|
||||
await plc.SafeDisposeAsync().ConfigureAwait(false);
|
||||
|
||||
//载入配置
|
||||
_plc.DtuId = _driverPropertys.DtuId;
|
||||
|
@@ -73,7 +73,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScriptAll
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -83,7 +83,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScriptAll
|
||||
{
|
||||
}
|
||||
_producer?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
protected override Task ProtectedExecuteAsync(object? state, CancellationToken cancellationToken)
|
||||
|
@@ -11,8 +11,6 @@
|
||||
using ThingsGateway.Debug;
|
||||
using ThingsGateway.Gateway.Application;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
|
||||
/// <summary>
|
||||
@@ -65,7 +63,8 @@ public class ModbusMaster : CollectFoundationBase
|
||||
ArgumentNullException.ThrowIfNull(channel);
|
||||
var plc = _plc;
|
||||
_plc = new();
|
||||
plc?.SafeDispose();
|
||||
if (plc != null)
|
||||
await plc.SafeDisposeAsync().ConfigureAwait(false);
|
||||
//载入配置
|
||||
_plc.DataFormat = _driverPropertys.DataFormat;
|
||||
_plc.DtuId = _driverPropertys.DtuId;
|
||||
|
@@ -92,7 +92,8 @@ public class ModbusSlave : BusinessBase
|
||||
ArgumentNullException.ThrowIfNull(channel);
|
||||
var plc = _plc;
|
||||
_plc = new();
|
||||
plc?.SafeDispose();
|
||||
if (plc != null)
|
||||
await plc.SafeDisposeAsync().ConfigureAwait(false);
|
||||
//载入配置
|
||||
_plc.DataFormat = _driverPropertys.DataFormat;
|
||||
_plc.IsStringReverseByteWord = _driverPropertys.IsStringReverseByteWord;
|
||||
@@ -137,13 +138,14 @@ public class ModbusSlave : BusinessBase
|
||||
);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
ModbusVariables?.Clear();
|
||||
ModbusVariableQueue?.Clear();
|
||||
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
if (_plc != null)
|
||||
await _plc.SafeDisposeAsync().ConfigureAwait(false);
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected override async Task ProtectedExecuteAsync(object? state, CancellationToken cancellationToken)
|
||||
|
@@ -150,18 +150,17 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScriptAll
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
_ = Task.Run(async () =>
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
|
||||
if (_mqttClient != null)
|
||||
{
|
||||
if (_mqttClient != null)
|
||||
{
|
||||
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
|
||||
_mqttClient.SafeDispose();
|
||||
}
|
||||
_mqttClient = null;
|
||||
});
|
||||
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
|
||||
_mqttClient.SafeDispose();
|
||||
}
|
||||
_mqttClient = null;
|
||||
|
||||
}
|
||||
|
||||
protected override async Task ProtectedStartAsync(CancellationToken cancellationToken)
|
||||
|
@@ -505,8 +505,8 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScriptAll
|
||||
|
||||
private async ValueTask<OperResult> TryMqttClientAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if(DisposedValue|| _mqttClient==null) return new OperResult("MqttClient is disposed");
|
||||
|
||||
if (DisposedValue || _mqttClient == null) return new OperResult("MqttClient is disposed");
|
||||
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.Success;
|
||||
return await Client().ConfigureAwait(false);
|
||||
|
@@ -38,11 +38,16 @@ public partial class MqttCollect : CollectBase
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_mqttClient?.SafeDispose();
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
if (_mqttClient != null)
|
||||
{
|
||||
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
|
||||
_mqttClient.SafeDispose();
|
||||
}
|
||||
_mqttClient = null;
|
||||
TopicItemDict?.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public override string GetAddressDescription()
|
||||
|
@@ -66,9 +66,9 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScriptAll
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
if (_mqttServer != null)
|
||||
{
|
||||
_mqttServer.ClientDisconnectedAsync -= MqttServer_ClientDisconnectedAsync;
|
||||
|
@@ -84,14 +84,14 @@ public class OpcDaMaster : CollectBase
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
if (_plc != null)
|
||||
_plc.DataChangedHandler -= DataChangedHandler;
|
||||
_plc?.SafeDispose();
|
||||
|
||||
VariableAddresDicts?.Clear();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
public override string GetAddressDescription()
|
||||
|
@@ -70,7 +70,7 @@ public class OpcUaMaster : CollectBase
|
||||
{
|
||||
plc.DataChangedHandler -= DataChangedHandler;
|
||||
plc.LogEvent -= _plc_LogEvent;
|
||||
plc.SafeDispose();
|
||||
await plc.SafeDisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_plc.LogEvent += _plc_LogEvent;
|
||||
@@ -88,19 +88,18 @@ public class OpcUaMaster : CollectBase
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
if (_plc != null)
|
||||
{
|
||||
_plc.DataChangedHandler -= DataChangedHandler;
|
||||
_plc.LogEvent -= _plc_LogEvent;
|
||||
|
||||
_plc.Disconnect();
|
||||
_plc.SafeDispose();
|
||||
await _plc.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
VariableAddresDicts?.Clear();
|
||||
base.Dispose(disposing);
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override string GetAddressDescription()
|
||||
@@ -301,7 +300,8 @@ public class OpcUaMaster : CollectBase
|
||||
{
|
||||
try
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
if (_plc != null)
|
||||
await _plc.DisconnectAsync().ConfigureAwait(false);
|
||||
await base.AfterVariablesChangedAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
|
@@ -175,13 +175,13 @@ public partial class OpcUaServer : BusinessBase
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
||||
UaDispose();
|
||||
CollectVariableRuntimes?.Clear();
|
||||
IdVariableRuntimes?.Clear();
|
||||
base.Dispose(disposing);
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
|
||||
protected override async Task ProtectedStartAsync(CancellationToken cancellationToken)
|
||||
|
@@ -119,7 +119,7 @@ public partial class OpcUaMaster : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
_plc.Disconnect();
|
||||
await _plc.DisconnectAsync().ConfigureAwait(false);
|
||||
LogPath = _plc?.GetHashCode().ToLong().GetDebugLogPath();
|
||||
await GetOpc().ConnectAsync(CancellationToken.None);
|
||||
}
|
||||
|
@@ -12,8 +12,6 @@ using RabbitMQ.Client;
|
||||
|
||||
using ThingsGateway.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Plugin.RabbitMQ;
|
||||
|
||||
/// <summary>
|
||||
@@ -53,11 +51,13 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScriptAll
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_channel?.SafeDispose();
|
||||
_connection?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
if (_channel != null)
|
||||
await _channel.SafeDisposeAsync().ConfigureAwait(false);
|
||||
if (_connection != null)
|
||||
await _connection.SafeDisposeAsync().ConfigureAwait(false);
|
||||
await base.DisposeAsync(disposing).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected override async Task ProtectedExecuteAsync(object? state, CancellationToken cancellationToken)
|
||||
|
@@ -60,7 +60,8 @@ public class SiemensS7Master : CollectFoundationBase
|
||||
|
||||
var plc = _plc;
|
||||
_plc = new();
|
||||
plc?.SafeDispose();
|
||||
if (plc != null)
|
||||
await plc.SafeDisposeAsync().ConfigureAwait(false);
|
||||
|
||||
//载入配置
|
||||
_plc.DataFormat = _driverPropertys.DataFormat;
|
||||
|
Reference in New Issue
Block a user