mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-11-04 09:33:58 +08:00 
			
		
		
		
	Compare commits
	
		
			22 Commits
		
	
	
		
			10.11.31.0
			...
			10.11.56.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					35e1ffa3e9 | ||
| 
						 | 
					4921642151 | ||
| 
						 | 
					d71ee29da8 | ||
| 
						 | 
					901aa2d59f | ||
| 
						 | 
					764957c014 | ||
| 
						 | 
					0e3898218b | ||
| 
						 | 
					61f13cef3c | ||
| 
						 | 
					0b663d9e01 | ||
| 
						 | 
					6c95c6209f | ||
| 
						 | 
					4d223d2622 | ||
| 
						 | 
					e8d7e91b64 | ||
| 
						 | 
					8175f541ec | ||
| 
						 | 
					0adbdb926b | ||
| 
						 | 
					42adee9980 | ||
| 
						 | 
					427a7404bc | ||
| 
						 | 
					3658199e0a | ||
| 
						 | 
					82eedee50a | ||
| 
						 | 
					6a18fc3e06 | ||
| 
						 | 
					c37e314ed6 | ||
| 
						 | 
					a937a85d90 | ||
| 
						 | 
					35dd4ae9d3 | ||
| 
						 | 
					0b829ac85c | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -364,8 +364,5 @@ FodyWeavers.xsd
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/src/*Pro*/
 | 
					/src/*Pro*/
 | 
				
			||||||
/src/*Pro*
 | 
					/src/*Pro*
 | 
				
			||||||
/src/**/*Pro*
 | 
					 | 
				
			||||||
/src/*pro*
 | 
					 | 
				
			||||||
/src/*pro*/
 | 
					 | 
				
			||||||
/src/ThingsGateway.Server/Configuration/GiteeOAuthSettings.json
 | 
					/src/ThingsGateway.Server/Configuration/GiteeOAuthSettings.json
 | 
				
			||||||
/src/.idea/
 | 
					/src/.idea/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<div class="tg-table h-100">
 | 
					<div class="tg-table h-100">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <Table TItem="TItem" IsBordered="true" IsStriped="true" TableSize="TableSize.Compact" IsMultipleSelect="IsMultipleSelect" @ref="Instance" SearchTemplate="SearchTemplate"
 | 
					    <Table TItem="TItem" IsBordered="true" IsStriped="true" TableSize="TableSize.Compact" SelectedRows=SelectedRows SelectedRowsChanged=privateSelectedRowsChanged IsMultipleSelect="IsMultipleSelect" @ref="Instance" SearchTemplate="SearchTemplate"
 | 
				
			||||||
           DataService="DataService" CreateItemCallback="CreateItemCallback!"
 | 
					           DataService="DataService" CreateItemCallback="CreateItemCallback!"
 | 
				
			||||||
           IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText" ShowSearchButton="ShowSearchButton" BeforeShowEditDialogCallback="BeforeShowEditDialogCallback!"
 | 
					           IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText" ShowSearchButton="ShowSearchButton" DisableEditButtonCallback="DisableEditButtonCallback" DisableDeleteButtonCallback="DisableDeleteButtonCallback" BeforeShowEditDialogCallback=" BeforeShowEditDialogCallback!"
 | 
				
			||||||
           IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender
 | 
					           IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender
 | 
				
			||||||
           ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton
 | 
					           ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton
 | 
				
			||||||
           ShowEmpty="ShowEmpty" EmptyText="@EmptyText" EmptyImage="@($"{WebsiteConst.DefaultResourceUrl}images/empty.svg")" SortString="@SortString" EditDialogSize="EditDialogSize"
 | 
					           ShowEmpty="ShowEmpty" EmptyText="@EmptyText" EmptyImage="@($"{WebsiteConst.DefaultResourceUrl}images/empty.svg")" SortString="@SortString" EditDialogSize="EditDialogSize"
 | 
				
			||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
           ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo
 | 
					           ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo
 | 
				
			||||||
           SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton ExportButtonText=@ExportButtonText
 | 
					           SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton ExportButtonText=@ExportButtonText
 | 
				
			||||||
           ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode
 | 
					           ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode
 | 
				
			||||||
           ShowExportCsvButton=@ShowExportCsvButton SelectedRowsChanged=SelectedRowsChanged ShowCardView=ShowCardView
 | 
					           ShowExportCsvButton=@ShowExportCsvButton ShowCardView=ShowCardView
 | 
				
			||||||
           FixedExtendButtonsColumn=FixedExtendButtonsColumn FixedMultipleColumn=FixedMultipleColumn FixedDetailRowHeaderColumn=FixedDetailRowHeaderColumn FixedLineNoColumn=FixedLineNoColumn
 | 
					           FixedExtendButtonsColumn=FixedExtendButtonsColumn FixedMultipleColumn=FixedMultipleColumn FixedDetailRowHeaderColumn=FixedDetailRowHeaderColumn FixedLineNoColumn=FixedLineNoColumn
 | 
				
			||||||
           IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval
 | 
					           IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval
 | 
				
			||||||
           AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh
 | 
					           AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh
 | 
				
			||||||
@@ -29,7 +29,7 @@
 | 
				
			|||||||
           ShowMultiFilterHeader=ShowMultiFilterHeader
 | 
					           ShowMultiFilterHeader=ShowMultiFilterHeader
 | 
				
			||||||
           ShowFilterHeader=ShowFilterHeader
 | 
					           ShowFilterHeader=ShowFilterHeader
 | 
				
			||||||
           ShowColumnList=ShowColumnList ExtendButtonColumnWidth="@ExtendButtonColumnWidth"
 | 
					           ShowColumnList=ShowColumnList ExtendButtonColumnWidth="@ExtendButtonColumnWidth"
 | 
				
			||||||
           CustomerSearchModel="CustomerSearchModel" SelectedRows="SelectedRows" ModelEqualityComparer="ModelEqualityComparer!"
 | 
					           CustomerSearchModel="CustomerSearchModel" ModelEqualityComparer="ModelEqualityComparer!"
 | 
				
			||||||
           ShowExtendEditButtonCallback="ShowExtendEditButtonCallback!" ShowExtendDeleteButtonCallback="ShowExtendDeleteButtonCallback!"
 | 
					           ShowExtendEditButtonCallback="ShowExtendEditButtonCallback!" ShowExtendDeleteButtonCallback="ShowExtendDeleteButtonCallback!"
 | 
				
			||||||
           DisableExtendEditButton="DisableExtendEditButton!" DisableExtendDeleteButton="DisableExtendDeleteButton!"
 | 
					           DisableExtendEditButton="DisableExtendEditButton!" DisableExtendDeleteButton="DisableExtendDeleteButton!"
 | 
				
			||||||
           DisableExtendEditButtonCallback="DisableExtendEditButtonCallback!" DisableExtendDeleteButtonCallback="DisableExtendDeleteButtonCallback!"
 | 
					           DisableExtendEditButtonCallback="DisableExtendEditButtonCallback!" DisableExtendDeleteButtonCallback="DisableExtendDeleteButtonCallback!"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,24 @@ namespace ThingsGateway.Admin.Razor;
 | 
				
			|||||||
[CascadingTypeParameter(nameof(TItem))]
 | 
					[CascadingTypeParameter(nameof(TItem))]
 | 
				
			||||||
public partial class AdminTable<TItem> where TItem : class, new()
 | 
					public partial class AdminTable<TItem> where TItem : class, new()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc cref="Table{TItem}.SelectedRows"/>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public List<TItem> SelectedRows { get; set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task privateSelectedRowsChanged(List<TItem> items)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        SelectedRows = items;
 | 
				
			||||||
 | 
					        if (SelectedRowsChanged.HasDelegate)
 | 
				
			||||||
 | 
					            await SelectedRowsChanged.InvokeAsync(items);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.DoubleClickToEdit"/>
 | 
					    /// <inheritdoc cref="Table{TItem}.DoubleClickToEdit"/>
 | 
				
			||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public bool DoubleClickToEdit { get; set; } = false;
 | 
					    public bool DoubleClickToEdit { get; set; } = false;
 | 
				
			||||||
@@ -210,14 +228,6 @@ public partial class AdminTable<TItem> where TItem : class, new()
 | 
				
			|||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public RenderFragment<TItem>? SearchTemplate { get; set; }
 | 
					    public RenderFragment<TItem>? SearchTemplate { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.SelectedRows"/>
 | 
					 | 
				
			||||||
    [Parameter]
 | 
					 | 
				
			||||||
    public List<TItem>? SelectedRows { get; set; } = new List<TItem>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
 | 
					 | 
				
			||||||
    [Parameter]
 | 
					 | 
				
			||||||
    public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.SetRowClassFormatter"/>
 | 
					    /// <inheritdoc cref="Table{TItem}.SetRowClassFormatter"/>
 | 
				
			||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public Func<TItem, string?>? SetRowClassFormatter { get; set; }
 | 
					    public Func<TItem, string?>? SetRowClassFormatter { get; set; }
 | 
				
			||||||
@@ -266,6 +276,15 @@ public partial class AdminTable<TItem> where TItem : class, new()
 | 
				
			|||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public bool ShowExportButton { get; set; } = false;
 | 
					    public bool ShowExportButton { get; set; } = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc cref="Table{TItem}.DisableEditButtonCallback"/>
 | 
				
			||||||
 | 
					    public Func<List<TItem>, bool> DisableEditButtonCallback { get; set; } = (list) =>
 | 
				
			||||||
 | 
					    list.Count != 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc cref="Table{TItem}.DisableDeleteButtonCallback"/>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public Func<List<TItem>, bool> DisableDeleteButtonCallback { get; set; } = (list) =>
 | 
				
			||||||
 | 
					    list.Count <= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.ShowExportCsvButton"/>
 | 
					    /// <inheritdoc cref="Table{TItem}.ShowExportCsvButton"/>
 | 
				
			||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public bool ShowExportCsvButton { get; set; } = false;
 | 
					    public bool ShowExportCsvButton { get; set; } = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
 | 
							<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
 | 
				
			||||||
		<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
 | 
							<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
 | 
				
			||||||
		<PackageReference Include="BootstrapBlazor" Version="9.10.0" />
 | 
							<PackageReference Include="BootstrapBlazor" Version="9.10.1" />
 | 
				
			||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.Diagnostics;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.NewLife.Log;
 | 
					using ThingsGateway.NewLife.Log;
 | 
				
			||||||
using ThingsGateway.NewLife.Reflection;
 | 
					using ThingsGateway.NewLife.Reflection;
 | 
				
			||||||
@@ -76,7 +75,7 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        _timer.TryDispose();
 | 
					        _timer.TryDispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WriteLog($"Dispose {typeof(T).FullName} FreeCount={FreeCount:n0} BusyCount={BusyCount:n0} Total={Total:n0}");
 | 
					        WriteLog($"Dispose {typeof(T).FullName} FreeCount={FreeCount:n0} BusyCount={BusyCount:n0}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Clear();
 | 
					        Clear();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -112,10 +111,6 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public virtual T Get()
 | 
					    public virtual T Get()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var sw = Log == null || Log == Logger.Null ? null : Stopwatch.StartNew();
 | 
					 | 
				
			||||||
        Interlocked.Increment(ref _Total);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var success = false;
 | 
					 | 
				
			||||||
        Item? pi = null;
 | 
					        Item? pi = null;
 | 
				
			||||||
        do
 | 
					        do
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -123,8 +118,6 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
            if (_free.TryPop(out pi) || _free2.TryDequeue(out pi))
 | 
					            if (_free.TryPop(out pi) || _free2.TryDequeue(out pi))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Interlocked.Decrement(ref _FreeCount);
 | 
					                Interlocked.Decrement(ref _FreeCount);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                success = true;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -150,8 +143,6 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
                WriteLog("Acquire Create Free={0} Busy={1}", FreeCount, count + 1);
 | 
					                WriteLog("Acquire Create Free={0} Busy={1}", FreeCount, count + 1);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Interlocked.Increment(ref _NewCount);
 | 
					 | 
				
			||||||
                success = false;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 借出时如果不可用,再次借取
 | 
					            // 借出时如果不可用,再次借取
 | 
				
			||||||
@@ -164,17 +155,6 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
        _busy.TryAdd(pi.Value, pi);
 | 
					        _busy.TryAdd(pi.Value, pi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Interlocked.Increment(ref _BusyCount);
 | 
					        Interlocked.Increment(ref _BusyCount);
 | 
				
			||||||
        if (success) Interlocked.Increment(ref _Success);
 | 
					 | 
				
			||||||
        if (sw != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sw.Stop();
 | 
					 | 
				
			||||||
            var ms = sw.Elapsed.TotalMilliseconds;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (Cost < 0.001)
 | 
					 | 
				
			||||||
                Cost = ms;
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                Cost = (Cost * 3 + ms) / 4;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return pi.Value;
 | 
					        return pi.Value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -200,7 +180,6 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
#if DEBUG
 | 
					#if DEBUG
 | 
				
			||||||
            WriteLog("Return Error");
 | 
					            WriteLog("Return Error");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            Interlocked.Increment(ref _ReleaseCount);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -210,13 +189,11 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
        // 是否可用
 | 
					        // 是否可用
 | 
				
			||||||
        if (!OnReturn(value))
 | 
					        if (!OnReturn(value))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Interlocked.Increment(ref _ReleaseCount);
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (value is DisposeBase db && db.Disposed)
 | 
					        if (value is DisposeBase db && db.Disposed)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Interlocked.Increment(ref _ReleaseCount);
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -373,39 +350,14 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var ncount = _NewCount;
 | 
					        if (count > 0)
 | 
				
			||||||
        var fcount = _ReleaseCount;
 | 
					 | 
				
			||||||
        if (count > 0 || ncount > 0 || fcount > 0)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Interlocked.Add(ref _NewCount, -ncount);
 | 
					 | 
				
			||||||
            Interlocked.Add(ref _ReleaseCount, -fcount);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var p = Total == 0 ? 0 : (Double)Success / Total;
 | 
					            WriteLog("Release New={6:n0} Release={7:n0} Free={0} Busy={1} 清除过期资源 {2:n0} 项。", FreeCount, BusyCount, count);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            WriteLog("Release New={6:n0} Release={7:n0} Free={0} Busy={1} 清除过期资源 {2:n0} 项。总请求 {3:n0} 次,命中 {4:p2},平均 {5:n2}us", FreeCount, BusyCount, count, Total, p, Cost * 1000, ncount, fcount);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region 统计
 | 
					 | 
				
			||||||
    private Int32 _Total;
 | 
					 | 
				
			||||||
    /// <summary>总请求数</summary>
 | 
					 | 
				
			||||||
    public Int32 Total => _Total;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Int32 _Success;
 | 
					 | 
				
			||||||
    /// <summary>成功数</summary>
 | 
					 | 
				
			||||||
    public Int32 Success => _Success;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>新创建数</summary>
 | 
					 | 
				
			||||||
    private Int32 _NewCount;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>释放数</summary>
 | 
					 | 
				
			||||||
    private Int32 _ReleaseCount;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>平均耗时。单位ms</summary>
 | 
					 | 
				
			||||||
    private Double Cost;
 | 
					 | 
				
			||||||
    #endregion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #region 日志
 | 
					    #region 日志
 | 
				
			||||||
    /// <summary>日志</summary>
 | 
					    /// <summary>日志</summary>
 | 
				
			||||||
    public ILog Log { get; set; } = Logger.Null;
 | 
					    public ILog Log { get; set; } = Logger.Null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,23 +15,19 @@ public class ExpiringDictionary<TKey, TValue> : IDisposable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public void TryAdd(TKey key, TValue value)
 | 
					    public void TryAdd(TKey key, TValue value)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_cleanupTimer.Disposed) throw new ObjectDisposedException(nameof(ExpiringDictionary<TKey, TValue>));
 | 
					 | 
				
			||||||
        _dict.TryAdd(key, value);
 | 
					        _dict.TryAdd(key, value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public bool TryGetValue(TKey key, out TValue value)
 | 
					    public bool TryGetValue(TKey key, out TValue value)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_cleanupTimer.Disposed) throw new ObjectDisposedException(nameof(ExpiringDictionary<TKey, TValue>));
 | 
					 | 
				
			||||||
        return _dict.TryGetValue(key, out value);
 | 
					        return _dict.TryGetValue(key, out value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public TValue GetOrAdd(TKey key, Func<TKey, TValue> func)
 | 
					    public TValue GetOrAdd(TKey key, Func<TKey, TValue> func)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_cleanupTimer.Disposed) throw new ObjectDisposedException(nameof(ExpiringDictionary<TKey, TValue>));
 | 
					 | 
				
			||||||
        return _dict.GetOrAdd(key, func);
 | 
					        return _dict.GetOrAdd(key, func);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public TValue GetOrAdd(TKey key, TValue value)
 | 
					    public TValue GetOrAdd(TKey key, TValue value)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_cleanupTimer.Disposed) throw new ObjectDisposedException(nameof(ExpiringDictionary<TKey, TValue>));
 | 
					 | 
				
			||||||
        return _dict.GetOrAdd(key, value);
 | 
					        return _dict.GetOrAdd(key, value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,6 +106,17 @@ public static class Runtime
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if NET6_0_OR_GREATER
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static Boolean IsSystemd
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        get
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var id = Environment.GetEnvironmentVariable("INVOCATION_ID");
 | 
				
			||||||
 | 
					            return !string.IsNullOrEmpty(id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Boolean? isLegacyWindows;
 | 
					    public static Boolean? isLegacyWindows;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation;
 | 
					namespace ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// JTokenUtil
 | 
					/// JTokenUtil
 | 
				
			||||||
@@ -131,6 +131,63 @@ public static class JTokenUtil
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 把任意对象转换为 JToken。
 | 
				
			||||||
 | 
					    /// 支持 JsonElement、JToken、本地 CLR 类型。
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static JToken GetJTokenFromObj(this object value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (value == null)
 | 
				
			||||||
 | 
					            return JValue.CreateNull();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case JToken jt:
 | 
				
			||||||
 | 
					                return jt;
 | 
				
			||||||
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
 | 
					            case System.Text.Json.JsonElement elem:
 | 
				
			||||||
 | 
					                return elem.ToJToken();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            case string s:
 | 
				
			||||||
 | 
					                return new JValue(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case bool b:
 | 
				
			||||||
 | 
					                return new JValue(b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case int i:
 | 
				
			||||||
 | 
					                return new JValue(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case long l:
 | 
				
			||||||
 | 
					                return new JValue(l);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case double d:
 | 
				
			||||||
 | 
					                return new JValue(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case float f:
 | 
				
			||||||
 | 
					                return new JValue(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case decimal m:
 | 
				
			||||||
 | 
					                return new JValue(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DateTime dt:
 | 
				
			||||||
 | 
					                return new JValue(dt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DateTimeOffset dto:
 | 
				
			||||||
 | 
					                return new JValue(dto);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case Guid g:
 | 
				
			||||||
 | 
					                return new JValue(g);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                // 兜底:用 Newtonsoft 来包装成 JToken
 | 
				
			||||||
 | 
					                return JToken.FromObject(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region json
 | 
					    #region json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://thingsgateway.cn/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Globalization;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Text.Json;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static class JsonElementExtensions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static string GetValue(object src, bool parseBoolNumber = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (src == null)
 | 
				
			||||||
 | 
					            return string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (src)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case string strValue:
 | 
				
			||||||
 | 
					                return strValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case bool boolValue:
 | 
				
			||||||
 | 
					                return boolValue ? parseBoolNumber ? "1" : "True" : parseBoolNumber ? "0" : "False";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonElement elem: // System.Text.Json.JsonElement
 | 
				
			||||||
 | 
					                return elem.ValueKind switch
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    JsonValueKind.String => elem.GetString(),
 | 
				
			||||||
 | 
					                    JsonValueKind.Number => elem.GetRawText(),  // 或 elem.GetDecimal().ToString()
 | 
				
			||||||
 | 
					                    JsonValueKind.True => "1",
 | 
				
			||||||
 | 
					                    JsonValueKind.False => "0",
 | 
				
			||||||
 | 
					                    JsonValueKind.Null => string.Empty,
 | 
				
			||||||
 | 
					                    _ => elem.GetRawText(), // 对象、数组等直接输出 JSON
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return (src).GetJTokenFromObj().ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 将 System.Text.Json.JsonElement 递归转换为 Newtonsoft.Json.Linq.JToken
 | 
				
			||||||
 | 
					    /// - tryParseDates: 是否尝试把字符串解析为 DateTime/DateTimeOffset
 | 
				
			||||||
 | 
					    /// - tryParseGuids: 是否尝试把字符串解析为 Guid
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static JToken ToJToken(this JsonElement element, bool tryParseDates = true, bool tryParseGuids = true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (element.ValueKind)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case JsonValueKind.Object:
 | 
				
			||||||
 | 
					                var obj = new JObject();
 | 
				
			||||||
 | 
					                foreach (var prop in element.EnumerateObject())
 | 
				
			||||||
 | 
					                    obj.Add(prop.Name, prop.Value.ToJToken(tryParseDates, tryParseGuids));
 | 
				
			||||||
 | 
					                return obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonValueKind.Array:
 | 
				
			||||||
 | 
					                var arr = new JArray();
 | 
				
			||||||
 | 
					                foreach (var item in element.EnumerateArray())
 | 
				
			||||||
 | 
					                    arr.Add(item.ToJToken(tryParseDates, tryParseGuids));
 | 
				
			||||||
 | 
					                return arr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonValueKind.String:
 | 
				
			||||||
 | 
					                // 优先按语义尝试解析 Guid / DateTimeOffset / DateTime
 | 
				
			||||||
 | 
					                if (tryParseGuids && element.TryGetGuid(out Guid g))
 | 
				
			||||||
 | 
					                    return new JValue(g);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tryParseDates && element.TryGetDateTimeOffset(out DateTimeOffset dto))
 | 
				
			||||||
 | 
					                    return new JValue(dto);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tryParseDates && element.TryGetDateTime(out DateTime dt))
 | 
				
			||||||
 | 
					                    return new JValue(dt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return new JValue(element.GetString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonValueKind.Number:
 | 
				
			||||||
 | 
					                return NumberElementToJToken(element);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonValueKind.True:
 | 
				
			||||||
 | 
					                return new JValue(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonValueKind.False:
 | 
				
			||||||
 | 
					                return new JValue(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JsonValueKind.Null:
 | 
				
			||||||
 | 
					            case JsonValueKind.Undefined:
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return JValue.CreateNull();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static JToken NumberElementToJToken(JsonElement element)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // 取原始文本(保持原始表示,方便处理超出标准类型范围的数字)
 | 
				
			||||||
 | 
					        string raw = element.GetRawText(); // 例如 "123", "1.23e4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 如果不含小数点或指数,优先尝试整数解析(long / ulong / BigInteger)
 | 
				
			||||||
 | 
					        if (!raw.Contains('.') && !raw.Contains('e') && !raw.Contains('E'))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (long.TryParse(raw, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var l))
 | 
				
			||||||
 | 
					                return new JValue(l);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (ulong.TryParse(raw, NumberStyles.None, CultureInfo.InvariantCulture, out var ul))
 | 
				
			||||||
 | 
					                return new JValue(ul);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (BigInteger.TryParse(raw, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var bi))
 | 
				
			||||||
 | 
					                // BigInteger 可能不被 JValue 直接识别为数字类型,使用 FromObject 保证正确表示
 | 
				
			||||||
 | 
					                return JToken.FromObject(bi);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 含小数或指数,或整数解析失败,尝试 decimal -> double
 | 
				
			||||||
 | 
					        if (decimal.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var dec))
 | 
				
			||||||
 | 
					            return new JValue(dec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (double.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var d))
 | 
				
			||||||
 | 
					            return new JValue(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 最后兜底:把原始文本当字符串返回(极端情况)
 | 
				
			||||||
 | 
					        return new JValue(raw);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 把 JToken 转成“平面”字符串,适合用于日志或写入 CSV 的单元格:
 | 
				
			||||||
 | 
					    /// - string -> 原文
 | 
				
			||||||
 | 
					    /// - bool -> "1"/"0"
 | 
				
			||||||
 | 
					    /// - number -> 原始数字文本
 | 
				
			||||||
 | 
					    /// - date -> ISO 8601 (o)
 | 
				
			||||||
 | 
					    /// - object/array -> 紧凑的 JSON 文本
 | 
				
			||||||
 | 
					    /// - null/undefined -> empty string
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static string JTokenToPlainString(this JToken token)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (token == null || token.Type == JTokenType.Null || token.Type == JTokenType.Undefined)
 | 
				
			||||||
 | 
					            return string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (token.Type)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case JTokenType.String:
 | 
				
			||||||
 | 
					                return token.Value<string>() ?? string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JTokenType.Boolean:
 | 
				
			||||||
 | 
					                return token.Value<bool>() ? "1" : "0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JTokenType.Integer:
 | 
				
			||||||
 | 
					            case JTokenType.Float:
 | 
				
			||||||
 | 
					                // 保持紧凑数字文本(不加引号)
 | 
				
			||||||
 | 
					                return token.ToString(Formatting.None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case JTokenType.Date:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    // Date 类型可能是 DateTime 或 DateTimeOffset
 | 
				
			||||||
 | 
					                    var val = token.Value<object>();
 | 
				
			||||||
 | 
					                    if (val is DateTimeOffset dto) return dto.ToString("o");
 | 
				
			||||||
 | 
					                    if (val is DateTime dt) return dt.ToString("o");
 | 
				
			||||||
 | 
					                    return token.ToString(Formatting.None);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                // 对象/数组等,返回紧凑 JSON 表示
 | 
				
			||||||
 | 
					                return token.ToString(Formatting.None);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -21,6 +21,7 @@ public class Setting : Config<Setting>
 | 
				
			|||||||
    #region 属性
 | 
					    #region 属性
 | 
				
			||||||
    /// <summary>是否启用全局调试。默认启用</summary>
 | 
					    /// <summary>是否启用全局调试。默认启用</summary>
 | 
				
			||||||
    [Description("全局调试。XTrace.Debug")]
 | 
					    [Description("全局调试。XTrace.Debug")]
 | 
				
			||||||
 | 
					    [XmlIgnore, IgnoreDataMember]
 | 
				
			||||||
    public Boolean Debug { get; set; } = true;
 | 
					    public Boolean Debug { get; set; } = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>日志等级,只输出大于等于该级别的日志,All/Debug/Info/Warn/Error/Fatal,默认Info</summary>
 | 
					    /// <summary>日志等级,只输出大于等于该级别的日志,All/Debug/Info/Warn/Error/Fatal,默认Info</summary>
 | 
				
			||||||
@@ -30,6 +31,7 @@ public class Setting : Config<Setting>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// <summary>文件日志目录。默认Log子目录</summary>
 | 
					    /// <summary>文件日志目录。默认Log子目录</summary>
 | 
				
			||||||
    [Description("文件日志目录。默认Log子目录")]
 | 
					    [Description("文件日志目录。默认Log子目录")]
 | 
				
			||||||
 | 
					    [XmlIgnore, IgnoreDataMember]
 | 
				
			||||||
    public String LogPath { get; set; } = "Logs/XLog";
 | 
					    public String LogPath { get; set; } = "Logs/XLog";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>日志文件上限。超过上限后拆分新日志文件,默认5MB,0表示不限制大小</summary>
 | 
					    /// <summary>日志文件上限。超过上限后拆分新日志文件,默认5MB,0表示不限制大小</summary>
 | 
				
			||||||
@@ -42,6 +44,7 @@ public class Setting : Config<Setting>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// <summary>日志文件格式。默认{0:yyyy_MM_dd}.log,支持日志等级如 {1}_{0:yyyy_MM_dd}.log</summary>
 | 
					    /// <summary>日志文件格式。默认{0:yyyy_MM_dd}.log,支持日志等级如 {1}_{0:yyyy_MM_dd}.log</summary>
 | 
				
			||||||
    [Description("日志文件格式。默认{0:yyyy_MM_dd}.log,支持日志等级如 {1}_{0:yyyy_MM_dd}.log")]
 | 
					    [Description("日志文件格式。默认{0:yyyy_MM_dd}.log,支持日志等级如 {1}_{0:yyyy_MM_dd}.log")]
 | 
				
			||||||
 | 
					    [XmlIgnore, IgnoreDataMember]
 | 
				
			||||||
    public String LogFileFormat { get; set; } = "{0:yyyy_MM_dd}.log";
 | 
					    public String LogFileFormat { get; set; } = "{0:yyyy_MM_dd}.log";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>日志行格式。默认Time|ThreadId|Kind|Name|Message,还支持Level</summary>
 | 
					    /// <summary>日志行格式。默认Time|ThreadId|Kind|Name|Message,还支持Level</summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
 | 
							<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
 | 
				
			||||||
		<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
 | 
							<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
 | 
				
			||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
@namespace ThingsGateway.Razor
 | 
					@namespace ThingsGateway.Razor
 | 
				
			||||||
@typeparam TItem
 | 
					@typeparam TItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<Table TItem="TItem" IsBordered="true" IsStriped="true" IsMultipleSelect="IsMultipleSelect" @ref="Instance" TableSize=TableSize SearchTemplate=SearchTemplate
 | 
					<Table TItem="TItem" IsBordered="true" IsStriped="true" IsMultipleSelect="IsMultipleSelect" @ref="Instance" TableSize=TableSize SearchTemplate=SearchTemplate SelectedRows=SelectedRows SelectedRowsChanged=privateSelectedRowsChanged 
 | 
				
			||||||
       IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText"
 | 
					       IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText"
 | 
				
			||||||
       IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender
 | 
					       IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender
 | 
				
			||||||
       ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton
 | 
					       ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton
 | 
				
			||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
       ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo
 | 
					       ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo
 | 
				
			||||||
       SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton  
 | 
					       SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton  
 | 
				
			||||||
       ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode
 | 
					       ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode
 | 
				
			||||||
       ShowExportCsvButton=@ShowExportCsvButton SelectedRowsChanged=SelectedRowsChanged ShowCardView=ShowCardView
 | 
					       ShowExportCsvButton=@ShowExportCsvButton ShowCardView=ShowCardView
 | 
				
			||||||
       FixedExtendButtonsColumn IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval
 | 
					       FixedExtendButtonsColumn IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval
 | 
				
			||||||
       AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh
 | 
					       AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh
 | 
				
			||||||
       AllowResizing=@AllowResizing ExportButtonDropdownTemplate=ExportButtonDropdownTemplate
 | 
					       AllowResizing=@AllowResizing ExportButtonDropdownTemplate=ExportButtonDropdownTemplate
 | 
				
			||||||
@@ -24,7 +24,7 @@
 | 
				
			|||||||
       ShowMultiFilterHeader=ShowMultiFilterHeader
 | 
					       ShowMultiFilterHeader=ShowMultiFilterHeader
 | 
				
			||||||
       ShowFilterHeader=ShowFilterHeader
 | 
					       ShowFilterHeader=ShowFilterHeader
 | 
				
			||||||
       ShowColumnList=ShowColumnList ExtendButtonColumnWidth="@ExtendButtonColumnWidth"
 | 
					       ShowColumnList=ShowColumnList ExtendButtonColumnWidth="@ExtendButtonColumnWidth"
 | 
				
			||||||
       CustomerSearchModel="CustomerSearchModel" SelectedRows="SelectedRows" ModelEqualityComparer="ModelEqualityComparer!"
 | 
					       CustomerSearchModel="CustomerSearchModel" ModelEqualityComparer="ModelEqualityComparer!"
 | 
				
			||||||
       ShowExtendEditButtonCallback="ShowExtendEditButtonCallback!" ShowExtendDeleteButtonCallback="ShowExtendDeleteButtonCallback!"
 | 
					       ShowExtendEditButtonCallback="ShowExtendEditButtonCallback!" ShowExtendDeleteButtonCallback="ShowExtendDeleteButtonCallback!"
 | 
				
			||||||
       DisableExtendEditButton="DisableExtendEditButton!" DisableExtendDeleteButton="DisableExtendDeleteButton!"
 | 
					       DisableExtendEditButton="DisableExtendEditButton!" DisableExtendDeleteButton="DisableExtendDeleteButton!"
 | 
				
			||||||
       DisableExtendEditButtonCallback="DisableExtendEditButtonCallback!" DisableExtendDeleteButtonCallback="DisableExtendDeleteButtonCallback!"
 | 
					       DisableExtendEditButtonCallback="DisableExtendEditButtonCallback!" DisableExtendDeleteButtonCallback="DisableExtendDeleteButtonCallback!"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,23 @@ namespace ThingsGateway.Razor;
 | 
				
			|||||||
[CascadingTypeParameter(nameof(TItem))]
 | 
					[CascadingTypeParameter(nameof(TItem))]
 | 
				
			||||||
public partial class DefaultTable<TItem> where TItem : class, new()
 | 
					public partial class DefaultTable<TItem> where TItem : class, new()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc cref="Table{TItem}.SelectedRows"/>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public List<TItem> SelectedRows { get; set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task privateSelectedRowsChanged(List<TItem> items)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        SelectedRows = items;
 | 
				
			||||||
 | 
					        if (SelectedRowsChanged.HasDelegate)
 | 
				
			||||||
 | 
					            await SelectedRowsChanged.InvokeAsync(items);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.AllowDragColumn"/>
 | 
					    /// <inheritdoc cref="Table{TItem}.AllowDragColumn"/>
 | 
				
			||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public bool AllowDragColumn { get; set; } = false;
 | 
					    public bool AllowDragColumn { get; set; } = false;
 | 
				
			||||||
@@ -186,14 +203,6 @@ public partial class DefaultTable<TItem> where TItem : class, new()
 | 
				
			|||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public RenderFragment<TItem>? SearchTemplate { get; set; }
 | 
					    public RenderFragment<TItem>? SearchTemplate { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.SelectedRows"/>
 | 
					 | 
				
			||||||
    [Parameter]
 | 
					 | 
				
			||||||
    public List<TItem>? SelectedRows { get; set; } = new List<TItem>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
 | 
					 | 
				
			||||||
    [Parameter]
 | 
					 | 
				
			||||||
    public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc cref="Table{TItem}.SetRowClassFormatter"/>
 | 
					    /// <inheritdoc cref="Table{TItem}.SetRowClassFormatter"/>
 | 
				
			||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public Func<TItem, string?>? SetRowClassFormatter { get; set; }
 | 
					    public Func<TItem, string?>? SetRowClassFormatter { get; set; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@
 | 
				
			|||||||
		<PackageReference Include="CsvHelper" Version="33.1.0" />
 | 
							<PackageReference Include="CsvHelper" Version="33.1.0" />
 | 
				
			||||||
		<PackageReference Include="TDengine.Connector" Version="3.1.9" />
 | 
							<PackageReference Include="TDengine.Connector" Version="3.1.9" />
 | 
				
			||||||
		<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.9.1" />
 | 
							<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.9.1" />
 | 
				
			||||||
		<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.23" />
 | 
							<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.25" />
 | 
				
			||||||
		<PackageReference Include="System.Data.Common" Version="4.3.0" />
 | 
							<PackageReference Include="System.Data.Common" Version="4.3.0" />
 | 
				
			||||||
		<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.1" />
 | 
							<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.1" />
 | 
				
			||||||
		<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
 | 
							<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,17 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<PluginVersion>10.11.31</PluginVersion>
 | 
							<PluginVersion>10.11.56</PluginVersion>
 | 
				
			||||||
		<ProPluginVersion>10.11.31</ProPluginVersion>
 | 
							<ProPluginVersion>10.11.56</ProPluginVersion>
 | 
				
			||||||
		<DefaultVersion>10.11.31</DefaultVersion>
 | 
							<DefaultVersion>10.11.56</DefaultVersion>
 | 
				
			||||||
		<AuthenticationVersion>10.11.3</AuthenticationVersion>
 | 
							<AuthenticationVersion>10.11.5</AuthenticationVersion>
 | 
				
			||||||
		<SourceGeneratorVersion>10.11.3</SourceGeneratorVersion>
 | 
							<SourceGeneratorVersion>10.11.4</SourceGeneratorVersion>
 | 
				
			||||||
		<NET8Version>8.0.19</NET8Version>
 | 
							<NET8Version>8.0.20</NET8Version>
 | 
				
			||||||
		<NET9Version>9.0.8</NET9Version>
 | 
							<NET9Version>9.0.9</NET9Version>
 | 
				
			||||||
		<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
 | 
							<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
 | 
				
			||||||
		<IsTrimmable>false</IsTrimmable>
 | 
							<IsTrimmable>false</IsTrimmable>
 | 
				
			||||||
		<ManagementProPluginVersion>10.11.22</ManagementProPluginVersion>
 | 
							<ManagementProPluginVersion>10.11.36</ManagementProPluginVersion>
 | 
				
			||||||
		<ManagementPluginVersion>10.11.22</ManagementPluginVersion>
 | 
							<ManagementPluginVersion>10.11.36</ManagementPluginVersion>
 | 
				
			||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,6 +68,7 @@ public class ModbusMasterDemo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        bytes = await device.ModbusReadAsync(new ModbusAddress()
 | 
					        bytes = await device.ModbusReadAsync(new ModbusAddress()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            Station = 1,
 | 
				
			||||||
            StartAddress = 0,
 | 
					            StartAddress = 0,
 | 
				
			||||||
            FunctionCode = 3,
 | 
					            FunctionCode = 3,
 | 
				
			||||||
            Length = 10,
 | 
					            Length = 10,
 | 
				
			||||||
@@ -92,6 +93,7 @@ public class ModbusMasterDemo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        write = await device.ModbusRequestAsync(new ModbusAddress()
 | 
					        write = await device.ModbusRequestAsync(new ModbusAddress()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            Station = 1,
 | 
				
			||||||
            StartAddress = 0,
 | 
					            StartAddress = 0,
 | 
				
			||||||
            FunctionCode = 3,
 | 
					            FunctionCode = 3,
 | 
				
			||||||
            MasterWriteDatas = device.ThingsGatewayBitConverter.GetBytes(new double[] { 123.456, 123.456 })
 | 
					            MasterWriteDatas = device.ThingsGatewayBitConverter.GetBytes(new double[] { 123.456, 123.456 })
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ using Newtonsoft.Json.Linq;
 | 
				
			|||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Gateway.Application.Extensions;
 | 
					using ThingsGateway.Gateway.Application.Extensions;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
using ThingsGateway.NewLife.Reflection;
 | 
					using ThingsGateway.NewLife.Reflection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation;
 | 
					namespace ThingsGateway.Foundation;
 | 
				
			||||||
@@ -68,12 +69,12 @@ public abstract class VariableObject
 | 
				
			|||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public virtual JToken GetExpressionsValue(object value, VariableRuntimeProperty variableRuntimeProperty)
 | 
					    public virtual JToken GetExpressionsValue(object value, VariableRuntimeProperty variableRuntimeProperty)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var jToken = JToken.FromObject(value);
 | 
					        var jToken = value.GetJTokenFromObj();
 | 
				
			||||||
        if (!string.IsNullOrEmpty(variableRuntimeProperty.Attribute.WriteExpressions))
 | 
					        if (!string.IsNullOrEmpty(variableRuntimeProperty.Attribute.WriteExpressions))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            object rawdata = jToken.GetObjectFromJToken();
 | 
					            object rawdata = jToken.GetObjectFromJToken();
 | 
				
			||||||
            object data = variableRuntimeProperty.Attribute.WriteExpressions.GetExpressionsResult(rawdata, Device?.Logger);
 | 
					            object data = variableRuntimeProperty.Attribute.WriteExpressions.GetExpressionsResult(rawdata, Device?.Logger);
 | 
				
			||||||
            jToken = JToken.FromObject(data);
 | 
					            jToken = data.GetJTokenFromObj();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return jToken;
 | 
					        return jToken;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,7 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
            for (int i = 0; i < funcs.Count; i++)
 | 
					            for (int i = 0; i < funcs.Count; i++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var func = funcs[i];
 | 
					                var func = funcs[i];
 | 
				
			||||||
 | 
					                if (func == null) continue;
 | 
				
			||||||
                await func.Invoke(clientChannel, e, i == funcs.Count - 1).ConfigureAwait(false);
 | 
					                await func.Invoke(clientChannel, e, i == funcs.Count - 1).ConfigureAwait(false);
 | 
				
			||||||
                if (e.Handled)
 | 
					                if (e.Handled)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -65,6 +66,7 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
                for (int i = 0; i < funcs.Count; i++)
 | 
					                for (int i = 0; i < funcs.Count; i++)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var func = funcs[i];
 | 
					                    var func = funcs[i];
 | 
				
			||||||
 | 
					                    if (func == null) continue;
 | 
				
			||||||
                    var handled = await func.Invoke(clientChannel, i == funcs.Count - 1).ConfigureAwait(false);
 | 
					                    var handled = await func.Invoke(clientChannel, i == funcs.Count - 1).ConfigureAwait(false);
 | 
				
			||||||
                    if (handled)
 | 
					                    if (handled)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -96,19 +98,32 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (channelOptions.MaxClientCount > 0)
 | 
					        if (channelOptions.MaxClientCount > 0)
 | 
				
			||||||
            config.SetMaxCount(channelOptions.MaxClientCount);
 | 
					            config.SetMaxCount(channelOptions.MaxClientCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config.SetTransportOption(new TouchSocket.Sockets.TransportOption()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SendPipeOptions = new System.IO.Pipelines.PipeOptions(
 | 
				
			||||||
 | 
					             minimumSegmentSize: 1024,
 | 
				
			||||||
 | 
					             useSynchronizationContext: false),
 | 
				
			||||||
 | 
					            ReceivePipeOptions = new System.IO.Pipelines.PipeOptions(
 | 
				
			||||||
 | 
					             minimumSegmentSize: 1024,
 | 
				
			||||||
 | 
					                pauseWriterThreshold: 1024 * 1024,
 | 
				
			||||||
 | 
					                resumeWriterThreshold: 1024 * 512,
 | 
				
			||||||
 | 
					                useSynchronizationContext: false)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch (channelType)
 | 
					        switch (channelType)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            case ChannelTypeEnum.TcpClient:
 | 
					            case ChannelTypeEnum.TcpClient:
 | 
				
			||||||
                return config.GetTcpClientWithIPHost(channelOptions);
 | 
					                return config.GetTcpClient(channelOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case ChannelTypeEnum.TcpService:
 | 
					            case ChannelTypeEnum.TcpService:
 | 
				
			||||||
                return config.GetTcpServiceWithBindIPHost(channelOptions);
 | 
					                return config.GetTcpService(channelOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case ChannelTypeEnum.SerialPort:
 | 
					            case ChannelTypeEnum.SerialPort:
 | 
				
			||||||
                return config.GetSerialPortWithOption(channelOptions);
 | 
					                return config.GetSerialPort(channelOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case ChannelTypeEnum.UdpSession:
 | 
					            case ChannelTypeEnum.UdpSession:
 | 
				
			||||||
                return config.GetUdpSessionWithIPHost(channelOptions);
 | 
					                return config.GetUdpSession(channelOptions);
 | 
				
			||||||
            case ChannelTypeEnum.Other:
 | 
					            case ChannelTypeEnum.Other:
 | 
				
			||||||
                channelOptions.Config = config;
 | 
					                channelOptions.Config = config;
 | 
				
			||||||
                OtherChannel otherChannel = new OtherChannel(channelOptions);
 | 
					                OtherChannel otherChannel = new OtherChannel(channelOptions);
 | 
				
			||||||
@@ -123,13 +138,12 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
    /// <param name="config">配置</param>
 | 
					    /// <param name="config">配置</param>
 | 
				
			||||||
    /// <param name="channelOptions">串口配置</param>
 | 
					    /// <param name="channelOptions">串口配置</param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public static SerialPortChannel GetSerialPortWithOption(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
					    private static SerialPortChannel GetSerialPort(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var serialPortOption = channelOptions.Map<SerialPortOption>();
 | 
					        var serialPortOption = channelOptions.Map<SerialPortOption>();
 | 
				
			||||||
        serialPortOption.ThrowIfNull(nameof(SerialPortOption));
 | 
					        serialPortOption.ThrowIfNull(nameof(SerialPortOption));
 | 
				
			||||||
        channelOptions.Config = config;
 | 
					        channelOptions.Config = config;
 | 
				
			||||||
        config.SetSerialPortOption(serialPortOption);
 | 
					        config.SetSerialPortOption(serialPortOption);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        //载入配置
 | 
					        //载入配置
 | 
				
			||||||
        SerialPortChannel serialPortChannel = new SerialPortChannel(channelOptions);
 | 
					        SerialPortChannel serialPortChannel = new SerialPortChannel(channelOptions);
 | 
				
			||||||
        return serialPortChannel;
 | 
					        return serialPortChannel;
 | 
				
			||||||
@@ -142,7 +156,7 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
    /// <param name="channelOptions">通道配置</param>
 | 
					    /// <param name="channelOptions">通道配置</param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    /// <exception cref="ArgumentNullException"></exception>
 | 
					    /// <exception cref="ArgumentNullException"></exception>
 | 
				
			||||||
    public static TcpClientChannel GetTcpClientWithIPHost(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
					    private static TcpClientChannel GetTcpClient(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var remoteUrl = channelOptions.RemoteUrl;
 | 
					        var remoteUrl = channelOptions.RemoteUrl;
 | 
				
			||||||
        var bindUrl = channelOptions.BindUrl;
 | 
					        var bindUrl = channelOptions.BindUrl;
 | 
				
			||||||
@@ -164,7 +178,7 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
    /// <param name="channelOptions">通道配置</param>
 | 
					    /// <param name="channelOptions">通道配置</param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    /// <exception cref="ArgumentNullException"></exception>
 | 
					    /// <exception cref="ArgumentNullException"></exception>
 | 
				
			||||||
    public static IChannel GetTcpServiceWithBindIPHost(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
					    private static IChannel GetTcpService(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var bindUrl = channelOptions.BindUrl;
 | 
					        var bindUrl = channelOptions.BindUrl;
 | 
				
			||||||
        bindUrl.ThrowIfNull(nameof(bindUrl));
 | 
					        bindUrl.ThrowIfNull(nameof(bindUrl));
 | 
				
			||||||
@@ -192,7 +206,7 @@ public static class ChannelOptionsExtensions
 | 
				
			|||||||
    /// <param name="channelOptions">通道配置</param>
 | 
					    /// <param name="channelOptions">通道配置</param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    /// <exception cref="ArgumentNullException"></exception>
 | 
					    /// <exception cref="ArgumentNullException"></exception>
 | 
				
			||||||
    public static UdpSessionChannel GetUdpSessionWithIPHost(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
					    private static UdpSessionChannel GetUdpSession(this TouchSocketConfig config, IChannelOptions channelOptions)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var remoteUrl = channelOptions.RemoteUrl;
 | 
					        var remoteUrl = channelOptions.RemoteUrl;
 | 
				
			||||||
        var bindUrl = channelOptions.BindUrl;
 | 
					        var bindUrl = channelOptions.BindUrl;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ public interface IChannel : ISetupConfigObject, IDisposable, IClosableClient, IC
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public ChannelEventHandler Stoping { get; }
 | 
					    public ChannelEventHandler Stoping { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue);
 | 
					    void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@ public interface IClientChannel : IChannel, ISender, IClient, IClientSender, IOn
 | 
				
			|||||||
    WaitHandlePool<MessageBase> WaitHandlePool { get; }
 | 
					    WaitHandlePool<MessageBase> WaitHandlePool { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WaitLock GetLock(string key);
 | 
					    WaitLock GetLock(string key);
 | 
				
			||||||
 | 
					    void LogSeted(bool logSeted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 设置数据处理适配器
 | 
					    /// 设置数据处理适配器
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,11 @@ namespace ThingsGateway.Foundation;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class OtherChannel : SetupConfigObject, IClientChannel
 | 
					public class OtherChannel : SetupConfigObject, IClientChannel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    ~OtherChannel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SingleStreamDataHandlingAdapter m_dataHandlingAdapter;
 | 
					    private SingleStreamDataHandlingAdapter m_dataHandlingAdapter;
 | 
				
			||||||
    public DataHandlingAdapter ReadOnlyDataHandlingAdapter => m_dataHandlingAdapter;
 | 
					    public DataHandlingAdapter ReadOnlyDataHandlingAdapter => m_dataHandlingAdapter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,19 +34,9 @@ public class OtherChannel : SetupConfigObject, IClientChannel
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
					    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
				
			||||||
    public void SetDataHandlingAdapterLogger(ILog log)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (_deviceDataHandleAdapter != ReadOnlyDataHandlingAdapter && ReadOnlyDataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _deviceDataHandleAdapter = handleAdapter;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (_deviceDataHandleAdapter != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _deviceDataHandleAdapter.Logger = log;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
 | 
					
 | 
				
			||||||
 | 
					    public void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var pool = WaitHandlePool;
 | 
					        var pool = WaitHandlePool;
 | 
				
			||||||
        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
					        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
				
			||||||
@@ -73,7 +68,7 @@ public class OtherChannel : SetupConfigObject, IClientChannel
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 等待池
 | 
					    /// 等待池
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(0, ushort.MaxValue);
 | 
					    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(1, ushort.MaxValue - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public WaitLock WaitLock => ChannelOptions.WaitLock;
 | 
					    public WaitLock WaitLock => ChannelOptions.WaitLock;
 | 
				
			||||||
@@ -83,15 +78,29 @@ public class OtherChannel : SetupConfigObject, IClientChannel
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    //private readonly WaitLock _connectLock = new WaitLock();
 | 
					    //private readonly WaitLock _connectLock = new WaitLock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private IDeviceDataHandleAdapter _deviceDataHandleAdapter;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private bool logSet;
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public void SetDataHandlingAdapterLogger(ILog log)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!logSet && ReadOnlyDataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            logSet = true;
 | 
				
			||||||
 | 
					            handleAdapter.Logger = log;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public void SetDataHandlingAdapter(DataHandlingAdapter adapter)
 | 
					    public void SetDataHandlingAdapter(DataHandlingAdapter adapter)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
					        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
				
			||||||
            SetAdapter(singleStreamDataHandlingAdapter);
 | 
					            SetAdapter(singleStreamDataHandlingAdapter);
 | 
				
			||||||
        if (adapter is IDeviceDataHandleAdapter deviceDataHandleAdapter)
 | 
					
 | 
				
			||||||
            _deviceDataHandleAdapter = deviceDataHandleAdapter;
 | 
					        logSet = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public void LogSeted(bool logSeted)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        logSet = logSeted;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 设置数据处理适配器。
 | 
					    /// 设置数据处理适配器。
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,10 @@ namespace ThingsGateway.Foundation;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class SerialPortChannel : SerialPortClient, IClientChannel
 | 
					public class SerialPortChannel : SerialPortClient, IClientChannel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    ~SerialPortChannel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    public SerialPortChannel(IChannelOptions channelOptions)
 | 
					    public SerialPortChannel(IChannelOptions channelOptions)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ChannelOptions = channelOptions;
 | 
					        ChannelOptions = channelOptions;
 | 
				
			||||||
@@ -27,7 +31,7 @@ public class SerialPortChannel : SerialPortClient, IClientChannel
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
					    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
 | 
					    public void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var pool = WaitHandlePool;
 | 
					        var pool = WaitHandlePool;
 | 
				
			||||||
        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
					        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
				
			||||||
@@ -47,16 +51,15 @@ public class SerialPortChannel : SerialPortClient, IClientChannel
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public DataHandlingAdapter ReadOnlyDataHandlingAdapter => ProtectedDataHandlingAdapter;
 | 
					    public DataHandlingAdapter ReadOnlyDataHandlingAdapter => ProtectedDataHandlingAdapter;
 | 
				
			||||||
    private IDeviceDataHandleAdapter _deviceDataHandleAdapter;
 | 
					
 | 
				
			||||||
 | 
					    private bool logSet;
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public void SetDataHandlingAdapterLogger(ILog log)
 | 
					    public void SetDataHandlingAdapterLogger(ILog log)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_deviceDataHandleAdapter != ProtectedDataHandlingAdapter && ProtectedDataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
					        if (!logSet && ProtectedDataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _deviceDataHandleAdapter = handleAdapter;
 | 
					            logSet = true;
 | 
				
			||||||
        }
 | 
					            handleAdapter.Logger = log;
 | 
				
			||||||
        if (_deviceDataHandleAdapter != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _deviceDataHandleAdapter.Logger = log;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
@@ -64,10 +67,16 @@ public class SerialPortChannel : SerialPortClient, IClientChannel
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
					        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
				
			||||||
            SetAdapter(singleStreamDataHandlingAdapter);
 | 
					            SetAdapter(singleStreamDataHandlingAdapter);
 | 
				
			||||||
        if (adapter is IDeviceDataHandleAdapter deviceDataHandleAdapter)
 | 
					
 | 
				
			||||||
            _deviceDataHandleAdapter = deviceDataHandleAdapter;
 | 
					        logSet = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void LogSeted(bool logSeted)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        logSet = logSeted;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public ChannelEventHandler Started { get; } = new();
 | 
					    public ChannelEventHandler Started { get; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -82,7 +91,7 @@ public class SerialPortChannel : SerialPortClient, IClientChannel
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 等待池
 | 
					    /// 等待池
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(0, ushort.MaxValue);
 | 
					    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(1, ushort.MaxValue - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public WaitLock WaitLock => ChannelOptions.WaitLock;
 | 
					    public WaitLock WaitLock => ChannelOptions.WaitLock;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,10 @@ namespace ThingsGateway.Foundation;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class TcpClientChannel : TcpClient, IClientChannel
 | 
					public class TcpClientChannel : TcpClient, IClientChannel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    ~TcpClientChannel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public TcpClientChannel(IChannelOptions channelOptions)
 | 
					    public TcpClientChannel(IChannelOptions channelOptions)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -24,22 +28,19 @@ public class TcpClientChannel : TcpClient, IClientChannel
 | 
				
			|||||||
        ResetSign();
 | 
					        ResetSign();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
					    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
				
			||||||
    public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
 | 
					    public void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var pool = WaitHandlePool;
 | 
					        var pool = WaitHandlePool;
 | 
				
			||||||
        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
					        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
				
			||||||
        pool?.CancelAll();
 | 
					        pool?.CancelAll();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private IDeviceDataHandleAdapter _deviceDataHandleAdapter;
 | 
					    private bool logSet;
 | 
				
			||||||
    public void SetDataHandlingAdapterLogger(ILog log)
 | 
					    public void SetDataHandlingAdapterLogger(ILog log)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_deviceDataHandleAdapter != DataHandlingAdapter && DataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
					        if (!logSet && DataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _deviceDataHandleAdapter = handleAdapter;
 | 
					            logSet = true;
 | 
				
			||||||
        }
 | 
					            handleAdapter.Logger = log;
 | 
				
			||||||
        if (_deviceDataHandleAdapter != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _deviceDataHandleAdapter.Logger = log;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
@@ -47,8 +48,12 @@ public class TcpClientChannel : TcpClient, IClientChannel
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
					        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
				
			||||||
            SetAdapter(singleStreamDataHandlingAdapter);
 | 
					            SetAdapter(singleStreamDataHandlingAdapter);
 | 
				
			||||||
        if (adapter is IDeviceDataHandleAdapter deviceDataHandleAdapter)
 | 
					
 | 
				
			||||||
            _deviceDataHandleAdapter = deviceDataHandleAdapter;
 | 
					        logSet = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public void LogSeted(bool logSeted)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        logSet = logSeted;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public ChannelReceivedEventHandler ChannelReceived { get; } = new();
 | 
					    public ChannelReceivedEventHandler ChannelReceived { get; } = new();
 | 
				
			||||||
@@ -78,7 +83,7 @@ public class TcpClientChannel : TcpClient, IClientChannel
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 等待池
 | 
					    /// 等待池
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(0, ushort.MaxValue);
 | 
					    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(1, ushort.MaxValue - 1);
 | 
				
			||||||
    public virtual WaitLock GetLock(string key) => WaitLock;
 | 
					    public virtual WaitLock GetLock(string key) => WaitLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,11 @@ namespace ThingsGateway.Foundation;
 | 
				
			|||||||
/// <typeparam name="TClient"></typeparam>
 | 
					/// <typeparam name="TClient"></typeparam>
 | 
				
			||||||
public abstract class TcpServiceChannelBase<TClient> : TcpService<TClient>, ITcpService<TClient> where TClient : TcpSessionClientChannel, new()
 | 
					public abstract class TcpServiceChannelBase<TClient> : TcpService<TClient>, ITcpService<TClient> where TClient : TcpSessionClientChannel, new()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~TcpServiceChannelBase()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public ConcurrentList<IDevice> Collects { get; } = new();
 | 
					    public ConcurrentList<IDevice> Collects { get; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -205,7 +210,7 @@ public class TcpServiceChannel<TClient> : TcpServiceChannelBase<TClient>, IChann
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    public int MinSign { get; private set; } = 0;
 | 
					    public int MinSign { get; private set; } = 0;
 | 
				
			||||||
    public int MaxSign { get; private set; } = ushort.MaxValue;
 | 
					    public int MaxSign { get; private set; } = ushort.MaxValue;
 | 
				
			||||||
    public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
 | 
					    public void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        MinSign = minSign;
 | 
					        MinSign = minSign;
 | 
				
			||||||
        MaxSign = maxSign;
 | 
					        MaxSign = maxSign;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,20 +17,22 @@ namespace ThingsGateway.Foundation;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class TcpSessionClientChannel : TcpSessionClient, IClientChannel
 | 
					public class TcpSessionClientChannel : TcpSessionClient, IClientChannel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    ~TcpSessionClientChannel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public TcpSessionClientChannel()
 | 
					    public TcpSessionClientChannel()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private IDeviceDataHandleAdapter _deviceDataHandleAdapter;
 | 
					    private bool logSet;
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public void SetDataHandlingAdapterLogger(ILog log)
 | 
					    public void SetDataHandlingAdapterLogger(ILog log)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_deviceDataHandleAdapter != DataHandlingAdapter && DataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
					        if (!logSet && DataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _deviceDataHandleAdapter = handleAdapter;
 | 
					            logSet = true;
 | 
				
			||||||
        }
 | 
					            handleAdapter.Logger = log;
 | 
				
			||||||
        if (_deviceDataHandleAdapter != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _deviceDataHandleAdapter.Logger = log;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
@@ -38,10 +40,14 @@ public class TcpSessionClientChannel : TcpSessionClient, IClientChannel
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
					        if (adapter is SingleStreamDataHandlingAdapter singleStreamDataHandlingAdapter)
 | 
				
			||||||
            SetAdapter(singleStreamDataHandlingAdapter);
 | 
					            SetAdapter(singleStreamDataHandlingAdapter);
 | 
				
			||||||
        if (adapter is IDeviceDataHandleAdapter deviceDataHandleAdapter)
 | 
					
 | 
				
			||||||
            _deviceDataHandleAdapter = deviceDataHandleAdapter;
 | 
					        logSet = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
 | 
					    public void LogSeted(bool logSeted)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        logSet = logSeted;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var pool = WaitHandlePool;
 | 
					        var pool = WaitHandlePool;
 | 
				
			||||||
        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
					        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
				
			||||||
@@ -76,7 +82,7 @@ public class TcpSessionClientChannel : TcpSessionClient, IClientChannel
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 等待池
 | 
					    /// 等待池
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public WaitHandlePool<MessageBase> WaitHandlePool { get; private set; } = new(0, ushort.MaxValue);
 | 
					    public WaitHandlePool<MessageBase> WaitHandlePool { get; private set; } = new(1, ushort.MaxValue - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public WaitLock WaitLock { get; internal set; } = new(nameof(TcpSessionClientChannel));
 | 
					    public WaitLock WaitLock { get; internal set; } = new(nameof(TcpSessionClientChannel));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,10 @@ namespace ThingsGateway.Foundation;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class UdpSessionChannel : UdpSession, IClientChannel
 | 
					public class UdpSessionChannel : UdpSession, IClientChannel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    ~UdpSessionChannel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    private readonly WaitLock _connectLock = new WaitLock(nameof(UdpSessionChannel));
 | 
					    private readonly WaitLock _connectLock = new WaitLock(nameof(UdpSessionChannel));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
@@ -26,27 +30,31 @@ public class UdpSessionChannel : UdpSession, IClientChannel
 | 
				
			|||||||
        ResetSign();
 | 
					        ResetSign();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
					    public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
 | 
				
			||||||
    private IDeviceDataHandleAdapter _deviceDataHandleAdapter;
 | 
					    private bool logSet;
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public void SetDataHandlingAdapterLogger(ILog log)
 | 
					    public void SetDataHandlingAdapterLogger(ILog log)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_deviceDataHandleAdapter != DataHandlingAdapter && DataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
					        if (!logSet && DataHandlingAdapter is IDeviceDataHandleAdapter handleAdapter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _deviceDataHandleAdapter = handleAdapter;
 | 
					            logSet = true;
 | 
				
			||||||
        }
 | 
					            handleAdapter.Logger = log;
 | 
				
			||||||
        if (_deviceDataHandleAdapter != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _deviceDataHandleAdapter.Logger = log;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    public void LogSeted(bool logSeted)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        logSet = logSeted;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public void SetDataHandlingAdapter(DataHandlingAdapter adapter)
 | 
					    public void SetDataHandlingAdapter(DataHandlingAdapter adapter)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (adapter is UdpDataHandlingAdapter udpDataHandlingAdapter)
 | 
					        if (adapter is UdpDataHandlingAdapter udpDataHandlingAdapter)
 | 
				
			||||||
            SetAdapter(udpDataHandlingAdapter);
 | 
					            SetAdapter(udpDataHandlingAdapter);
 | 
				
			||||||
        if (adapter is IDeviceDataHandleAdapter deviceDataHandleAdapter)
 | 
					
 | 
				
			||||||
            _deviceDataHandleAdapter = deviceDataHandleAdapter;
 | 
					        logSet = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void ResetSign(int minSign = 1, int maxSign = ushort.MaxValue - 1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var pool = WaitHandlePool;
 | 
					        var pool = WaitHandlePool;
 | 
				
			||||||
        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
					        WaitHandlePool = new WaitHandlePool<MessageBase>(minSign, maxSign);
 | 
				
			||||||
@@ -85,7 +93,7 @@ public class UdpSessionChannel : UdpSession, IClientChannel
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 等待池
 | 
					    /// 等待池
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public WaitHandlePool<MessageBase> WaitHandlePool { get; set; } = new(0, ushort.MaxValue);
 | 
					    public WaitHandlePool<MessageBase> WaitHandlePool { get; internal set; } = new(1, ushort.MaxValue - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public WaitLock WaitLock => ChannelOptions.WaitLock;
 | 
					    public WaitLock WaitLock => ChannelOptions.WaitLock;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -331,34 +331,23 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    public bool AutoConnect { get; protected set; } = true;
 | 
					    public bool AutoConnect { get; protected set; } = true;
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    private async ValueTask<OperResult> SendAsync(ISendMessage sendMessage, IClientChannel channel, CancellationToken token = default)
 | 
					    private async Task SendAsync(ISendMessage sendMessage, IClientChannel channel, CancellationToken token = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					
 | 
				
			||||||
 | 
					        if (SendDelayTime != 0)
 | 
				
			||||||
 | 
					            await Task.Delay(SendDelayTime, token).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (channel is IDtuUdpSessionChannel udpSession)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            EndPoint? endPoint = GetUdpEndpoint();
 | 
				
			||||||
 | 
					            await udpSession.SendAsync(endPoint, sendMessage, token).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (SendDelayTime != 0)
 | 
					 | 
				
			||||||
                await Task.Delay(SendDelayTime, token).ConfigureAwait(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (token.IsCancellationRequested)
 | 
					 | 
				
			||||||
                return new OperResult(new OperationCanceledException());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (channel is IDtuUdpSessionChannel udpSession)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                EndPoint? endPoint = GetUdpEndpoint();
 | 
					 | 
				
			||||||
                await udpSession.SendAsync(endPoint, sendMessage, token).ConfigureAwait(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                await channel.SendAsync(sendMessage, token).ConfigureAwait(false);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return OperResult.Success;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new(ex);
 | 
					            await channel.SendAsync(sendMessage, token).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task BeforeSendAsync(IClientChannel channel, CancellationToken token)
 | 
					    private Task BeforeSendAsync(IClientChannel channel, CancellationToken token)
 | 
				
			||||||
@@ -417,7 +406,8 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
                channelResult.Content.SetDataHandlingAdapterLogger(Logger);
 | 
					                channelResult.Content.SetDataHandlingAdapterLogger(Logger);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return await SendAsync(sendMessage, channelResult.Content, cancellationToken).ConfigureAwait(false);
 | 
					                await SendAsync(sendMessage, channelResult.Content, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                return OperResult.Success;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            finally
 | 
					            finally
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -426,8 +416,6 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!cancellationToken.IsCancellationRequested)
 | 
					 | 
				
			||||||
                await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
 | 
					 | 
				
			||||||
            return new(ex);
 | 
					            return new(ex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -538,7 +526,6 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ObjectPool<ReusableCancellationTokenSource> _reusableTimeouts = new();
 | 
					    private ObjectPool<ReusableCancellationTokenSource> _reusableTimeouts = new();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 发送并等待数据
 | 
					    /// 发送并等待数据
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -548,6 +535,8 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
        int timeout = 3000,
 | 
					        int timeout = 3000,
 | 
				
			||||||
        CancellationToken cancellationToken = default)
 | 
					        CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var waitData = clientChannel.WaitHandlePool.GetWaitDataAsync(out var sign);
 | 
					        var waitData = clientChannel.WaitHandlePool.GetWaitDataAsync(out var sign);
 | 
				
			||||||
        command.Sign = sign;
 | 
					        command.Sign = sign;
 | 
				
			||||||
        WaitLock? waitLock = null;
 | 
					        WaitLock? waitLock = null;
 | 
				
			||||||
@@ -557,13 +546,12 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
            await BeforeSendAsync(clientChannel, cancellationToken).ConfigureAwait(false);
 | 
					            await BeforeSendAsync(clientChannel, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            waitLock = GetWaitLock(clientChannel);
 | 
					            waitLock = GetWaitLock(clientChannel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await waitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 | 
					            await waitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            clientChannel.SetDataHandlingAdapterLogger(Logger);
 | 
					            clientChannel.SetDataHandlingAdapterLogger(Logger);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var sendResult = await SendAsync(command, clientChannel, cancellationToken).ConfigureAwait(false);
 | 
					            await SendAsync(command, clientChannel, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
            if (!sendResult.IsSuccess)
 | 
					 | 
				
			||||||
                return new MessageBase(sendResult);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (waitData.Status == WaitDataStatus.Success)
 | 
					            if (waitData.Status == WaitDataStatus.Success)
 | 
				
			||||||
                return waitData.CompletedData;
 | 
					                return waitData.CompletedData;
 | 
				
			||||||
@@ -573,6 +561,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
            var reusableTimeout = _reusableTimeouts.Get();
 | 
					            var reusableTimeout = _reusableTimeouts.Get();
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var cts = reusableTimeout.GetTokenSource(timeout, cancellationToken, Channel.ClosedToken);
 | 
					                var cts = reusableTimeout.GetTokenSource(timeout, cancellationToken, Channel.ClosedToken);
 | 
				
			||||||
                await waitData.WaitAsync(cts.Token).ConfigureAwait(false);
 | 
					                await waitData.WaitAsync(cts.Token).ConfigureAwait(false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -580,7 +569,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                timeoutStatus = reusableTimeout.TimeoutStatus;
 | 
					                timeoutStatus = reusableTimeout.TimeoutStatus;
 | 
				
			||||||
                return timeoutStatus
 | 
					                return timeoutStatus
 | 
				
			||||||
                    ? new MessageBase(new TimeoutException())
 | 
					                    ? new MessageBase(new TimeoutException()) { ErrorMessage = $"Timeout, sign: {sign}" }
 | 
				
			||||||
                    : new MessageBase(new OperationCanceledException());
 | 
					                    : new MessageBase(new OperationCanceledException());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
@@ -594,9 +583,15 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
                _reusableTimeouts.Return(reusableTimeout);
 | 
					                _reusableTimeouts.Return(reusableTimeout);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return waitData.Status == WaitDataStatus.Success
 | 
					            if (waitData.Status == WaitDataStatus.Success)
 | 
				
			||||||
                ? waitData.CompletedData
 | 
					            {
 | 
				
			||||||
                : new MessageBase(waitData.Check(timeoutStatus));
 | 
					                return waitData.CompletedData;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var operResult = waitData.Check(timeoutStatus);
 | 
				
			||||||
 | 
					                return new MessageBase(operResult) { ErrorMessage = $"{operResult.ErrorMessage}, sign: {sign}" };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -606,6 +601,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            waitLock?.Release();
 | 
					            waitLock?.Release();
 | 
				
			||||||
            waitData?.SafeDispose();
 | 
					            waitData?.SafeDispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -639,7 +635,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
            DataTypeEnum.UInt32 => await ReadUInt32Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					            DataTypeEnum.UInt32 => await ReadUInt32Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
            DataTypeEnum.Int64 => await ReadInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					            DataTypeEnum.Int64 => await ReadInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
            DataTypeEnum.UInt64 => await ReadUInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					            DataTypeEnum.UInt64 => await ReadUInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
            DataTypeEnum.Single => await ReadSingleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					            DataTypeEnum.Float => await ReadSingleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
            DataTypeEnum.Double => await ReadDoubleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					            DataTypeEnum.Double => await ReadDoubleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
            DataTypeEnum.Decimal => await ReadDecimalAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					            DataTypeEnum.Decimal => await ReadDecimalAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
            _ => new OperResult<Array>(string.Format(AppResource.DataTypeNotSupported, dataType)),
 | 
					            _ => new OperResult<Array>(string.Format(AppResource.DataTypeNotSupported, dataType)),
 | 
				
			||||||
@@ -665,7 +661,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
                    DataTypeEnum.UInt32 => await WriteAsync(address, jArray.ToObject<UInt32[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.UInt32 => await WriteAsync(address, jArray.ToObject<UInt32[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Int64 => await WriteAsync(address, jArray.ToObject<Int64[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Int64 => await WriteAsync(address, jArray.ToObject<Int64[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.UInt64 => await WriteAsync(address, jArray.ToObject<UInt64[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.UInt64 => await WriteAsync(address, jArray.ToObject<UInt64[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Single => await WriteAsync(address, jArray.ToObject<Single[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Float => await WriteAsync(address, jArray.ToObject<Single[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Double => await WriteAsync(address, jArray.ToObject<Double[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Double => await WriteAsync(address, jArray.ToObject<Double[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Decimal => await WriteAsync(address, jArray.ToObject<Decimal[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Decimal => await WriteAsync(address, jArray.ToObject<Decimal[]>().AsMemory(), cancellationToken: cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    _ => new OperResult(string.Format(AppResource.DataTypeNotSupported, dataType)),
 | 
					                    _ => new OperResult(string.Format(AppResource.DataTypeNotSupported, dataType)),
 | 
				
			||||||
@@ -684,7 +680,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
                    DataTypeEnum.UInt32 => await WriteAsync(address, value.ToObject<UInt32>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.UInt32 => await WriteAsync(address, value.ToObject<UInt32>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Int64 => await WriteAsync(address, value.ToObject<Int64>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Int64 => await WriteAsync(address, value.ToObject<Int64>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.UInt64 => await WriteAsync(address, value.ToObject<UInt64>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.UInt64 => await WriteAsync(address, value.ToObject<UInt64>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Single => await WriteAsync(address, value.ToObject<Single>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Float => await WriteAsync(address, value.ToObject<Single>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Double => await WriteAsync(address, value.ToObject<Double>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Double => await WriteAsync(address, value.ToObject<Double>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    DataTypeEnum.Decimal => await WriteAsync(address, value.ToObject<Decimal>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
					                    DataTypeEnum.Decimal => await WriteAsync(address, value.ToObject<Decimal>(), bitConverter, cancellationToken).ConfigureAwait(false),
 | 
				
			||||||
                    _ => new OperResult(string.Format(AppResource.DataTypeNotSupported, dataType)),
 | 
					                    _ => new OperResult(string.Format(AppResource.DataTypeNotSupported, dataType)),
 | 
				
			||||||
@@ -874,7 +870,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
    public virtual ValueTask<OperResult> WriteAsync(string address, float value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
 | 
					    public virtual ValueTask<OperResult> WriteAsync(string address, float value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
 | 
					        bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
 | 
				
			||||||
        return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Single, cancellationToken);
 | 
					        return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Float, cancellationToken);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
@@ -947,7 +943,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
    public virtual ValueTask<OperResult> WriteAsync(string address, ReadOnlyMemory<float> value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
 | 
					    public virtual ValueTask<OperResult> WriteAsync(string address, ReadOnlyMemory<float> value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
 | 
					        bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
 | 
				
			||||||
        return WriteAsync(address, bitConverter.GetBytes(value.Span), DataTypeEnum.Single, cancellationToken);
 | 
					        return WriteAsync(address, bitConverter.GetBytes(value.Span), DataTypeEnum.Float, cancellationToken);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
@@ -988,6 +984,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            lock (Channel)
 | 
					            lock (Channel)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Channel.Starting.Remove(ChannelStarting);
 | 
					                Channel.Starting.Remove(ChannelStarting);
 | 
				
			||||||
                Channel.Stoped.Remove(ChannelStoped);
 | 
					                Channel.Stoped.Remove(ChannelStoped);
 | 
				
			||||||
                Channel.Started.Remove(ChannelStarted);
 | 
					                Channel.Started.Remove(ChannelStarted);
 | 
				
			||||||
@@ -1028,6 +1025,11 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Channel.Collects.Remove(this);
 | 
					                Channel.Collects.Remove(this);
 | 
				
			||||||
 | 
					                if (Channel is IClientChannel clientChannel)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    clientChannel.LogSeted(false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        _reusableTimeouts?.SafeDispose();
 | 
					        _reusableTimeouts?.SafeDispose();
 | 
				
			||||||
@@ -1080,6 +1082,12 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Channel.Collects.Remove(this);
 | 
					            Channel.Collects.Remove(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (Channel is IClientChannel clientChannel)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                clientChannel.LogSeted(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _reusableTimeouts?.SafeDispose();
 | 
					        _reusableTimeouts?.SafeDispose();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,12 +45,16 @@ public enum DataTypeEnum
 | 
				
			|||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    UInt64,
 | 
					    UInt64,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <summary>
 | 
				
			||||||
    Single,
 | 
					    /// 大部分人并不认识Single,但都认识Float
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    Float,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    Double,
 | 
					    Double,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    Decimal,
 | 
					    Decimal,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ public static class DataTypeExtensions
 | 
				
			|||||||
            DataTypeEnum.UInt32 => 4,
 | 
					            DataTypeEnum.UInt32 => 4,
 | 
				
			||||||
            DataTypeEnum.Int64 => 8,
 | 
					            DataTypeEnum.Int64 => 8,
 | 
				
			||||||
            DataTypeEnum.UInt64 => 8,
 | 
					            DataTypeEnum.UInt64 => 8,
 | 
				
			||||||
            DataTypeEnum.Single => 4,
 | 
					            DataTypeEnum.Float => 4,
 | 
				
			||||||
            DataTypeEnum.Double => 8,
 | 
					            DataTypeEnum.Double => 8,
 | 
				
			||||||
            DataTypeEnum.Decimal => 16,
 | 
					            DataTypeEnum.Decimal => 16,
 | 
				
			||||||
            _ => 0,
 | 
					            _ => 0,
 | 
				
			||||||
@@ -57,7 +57,7 @@ public static class DataTypeExtensions
 | 
				
			|||||||
            TypeCode.UInt32 => DataTypeEnum.UInt32,
 | 
					            TypeCode.UInt32 => DataTypeEnum.UInt32,
 | 
				
			||||||
            TypeCode.Int64 => DataTypeEnum.Int64,
 | 
					            TypeCode.Int64 => DataTypeEnum.Int64,
 | 
				
			||||||
            TypeCode.UInt64 => DataTypeEnum.UInt64,
 | 
					            TypeCode.UInt64 => DataTypeEnum.UInt64,
 | 
				
			||||||
            TypeCode.Single => DataTypeEnum.Single,
 | 
					            TypeCode.Single => DataTypeEnum.Float,
 | 
				
			||||||
            TypeCode.Double => DataTypeEnum.Double,
 | 
					            TypeCode.Double => DataTypeEnum.Double,
 | 
				
			||||||
            TypeCode.Decimal => DataTypeEnum.Decimal,
 | 
					            TypeCode.Decimal => DataTypeEnum.Decimal,
 | 
				
			||||||
            _ => DataTypeEnum.Object,
 | 
					            _ => DataTypeEnum.Object,
 | 
				
			||||||
@@ -82,7 +82,7 @@ public static class DataTypeExtensions
 | 
				
			|||||||
            DataTypeEnum.UInt32 => typeof(uint),
 | 
					            DataTypeEnum.UInt32 => typeof(uint),
 | 
				
			||||||
            DataTypeEnum.Int64 => typeof(long),
 | 
					            DataTypeEnum.Int64 => typeof(long),
 | 
				
			||||||
            DataTypeEnum.UInt64 => typeof(ulong),
 | 
					            DataTypeEnum.UInt64 => typeof(ulong),
 | 
				
			||||||
            DataTypeEnum.Single => typeof(float),
 | 
					            DataTypeEnum.Float => typeof(float),
 | 
				
			||||||
            DataTypeEnum.Double => typeof(double),
 | 
					            DataTypeEnum.Double => typeof(double),
 | 
				
			||||||
            DataTypeEnum.Decimal => typeof(decimal),
 | 
					            DataTypeEnum.Decimal => typeof(decimal),
 | 
				
			||||||
            _ => typeof(object),
 | 
					            _ => typeof(object),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ using System.Globalization;
 | 
				
			|||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.NewLife.Extension;
 | 
					using ThingsGateway.NewLife.Extension;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Extension.String;
 | 
					namespace ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="$(NET9Version)" />
 | 
							<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="$(NET9Version)" />
 | 
				
			||||||
		<PackageReference Include="TouchSocket" Version="4.0.0-beta.25" />
 | 
							<PackageReference Include="TouchSocket" Version="4.0.0-beta.28" />
 | 
				
			||||||
		<PackageReference Include="TouchSocket.SerialPorts" Version="4.0.0-beta.25" />
 | 
							<PackageReference Include="TouchSocket.SerialPorts" Version="4.0.0-beta.28" />
 | 
				
			||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,7 @@ public static class ThingsGatewayBitConverterExtension
 | 
				
			|||||||
                case DataTypeEnum.UInt64:
 | 
					                case DataTypeEnum.UInt64:
 | 
				
			||||||
                    return byteConverter.GetBytes(value.ToObject<UInt64[]>());
 | 
					                    return byteConverter.GetBytes(value.ToObject<UInt64[]>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case DataTypeEnum.Single:
 | 
					                case DataTypeEnum.Float:
 | 
				
			||||||
                    return byteConverter.GetBytes(value.ToObject<Single[]>());
 | 
					                    return byteConverter.GetBytes(value.ToObject<Single[]>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case DataTypeEnum.Double:
 | 
					                case DataTypeEnum.Double:
 | 
				
			||||||
@@ -107,7 +107,7 @@ public static class ThingsGatewayBitConverterExtension
 | 
				
			|||||||
                case DataTypeEnum.UInt64:
 | 
					                case DataTypeEnum.UInt64:
 | 
				
			||||||
                    return byteConverter.GetBytes(value.ToObject<UInt64>());
 | 
					                    return byteConverter.GetBytes(value.ToObject<UInt64>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case DataTypeEnum.Single:
 | 
					                case DataTypeEnum.Float:
 | 
				
			||||||
                    return byteConverter.GetBytes(value.ToObject<Single>());
 | 
					                    return byteConverter.GetBytes(value.ToObject<Single>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case DataTypeEnum.Double:
 | 
					                case DataTypeEnum.Double:
 | 
				
			||||||
@@ -333,7 +333,7 @@ public static class ThingsGatewayBitConverterExtension
 | 
				
			|||||||
                    return true;
 | 
					                    return true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case DataTypeEnum.Single:
 | 
					            case DataTypeEnum.Float:
 | 
				
			||||||
                if (arrayLength > 1)
 | 
					                if (arrayLength > 1)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var newVal = byteConverter.ToSingle(buffer, index, arrayLength);
 | 
					                    var newVal = byteConverter.ToSingle(buffer, index, arrayLength);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,35 +8,48 @@
 | 
				
			|||||||
//  QQ群:605534569
 | 
					//  QQ群:605534569
 | 
				
			||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Gateway.Application;
 | 
					namespace ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class LinkedCancellationTokenSourceCache : IDisposable
 | 
					public class LinkedCancellationTokenSourceCache : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private CancellationTokenSource? _cachedCts;
 | 
					    private CancellationTokenSource? _cachedCts;
 | 
				
			||||||
    private CancellationToken _token1;
 | 
					    private CancellationToken _token1;
 | 
				
			||||||
    private CancellationToken _token2;
 | 
					    private CancellationToken _token2;
 | 
				
			||||||
 | 
					    private CancellationToken _token3;
 | 
				
			||||||
    private readonly object _lock = new();
 | 
					    private readonly object _lock = new();
 | 
				
			||||||
    ~LinkedCancellationTokenSourceCache()
 | 
					    ~LinkedCancellationTokenSourceCache()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Dispose();
 | 
					        Dispose();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取一个 CancellationTokenSource,它是由两个 token 链接而成的。
 | 
					    /// 获取一个 CancellationTokenSource,它是由两个 token 链接而成的。
 | 
				
			||||||
    /// 会尝试复用之前缓存的 CTS,前提是两个 token 仍然相同且未取消。
 | 
					    /// 会尝试复用之前缓存的 CTS,前提是两个 token 仍然相同且未取消。
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public CancellationTokenSource GetLinkedTokenSource(CancellationToken token1, CancellationToken token2)
 | 
					    public CancellationTokenSource GetLinkedTokenSource(CancellationToken token1, CancellationToken token2, CancellationToken token3 = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        lock (_lock)
 | 
					        lock (_lock)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // 如果缓存的 CTS 已经取消或 Dispose,或者 token 不同,重新创建
 | 
					            // 如果缓存的 CTS 已经取消或 Dispose,或者 token 不同,重新创建
 | 
				
			||||||
            if (_cachedCts?.IsCancellationRequested != false ||
 | 
					            if (_cachedCts?.IsCancellationRequested != false ||
 | 
				
			||||||
                !_token1.Equals(token1) || !_token2.Equals(token2))
 | 
					                !_token1.Equals(token1) || !_token2.Equals(token2) || !_token3.Equals(token3))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
 | 
					                if (_cachedCts?.TryReset() != true)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _cachedCts?.Dispose();
 | 
				
			||||||
 | 
					                    _cachedCts = CancellationTokenSource.CreateLinkedTokenSource(token1, token2, token3);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
                _cachedCts?.Dispose();
 | 
					                _cachedCts?.Dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _cachedCts = CancellationTokenSource.CreateLinkedTokenSource(token1, token2);
 | 
					                _cachedCts = CancellationTokenSource.CreateLinkedTokenSource(token1, token2, token3);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _token1 = token1;
 | 
					                _token1 = token1;
 | 
				
			||||||
                _token2 = token2;
 | 
					                _token2 = token2;
 | 
				
			||||||
 | 
					                _token3 = token3;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return _cachedCts;
 | 
					            return _cachedCts;
 | 
				
			||||||
@@ -18,7 +18,6 @@ using System.Threading;
 | 
				
			|||||||
public sealed class ReusableCancellationTokenSource : IDisposable
 | 
					public sealed class ReusableCancellationTokenSource : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private readonly Timer _timer;
 | 
					    private readonly Timer _timer;
 | 
				
			||||||
    private readonly object _lock = new();
 | 
					 | 
				
			||||||
    private CancellationTokenSource? _cts;
 | 
					    private CancellationTokenSource? _cts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ReusableCancellationTokenSource()
 | 
					    public ReusableCancellationTokenSource()
 | 
				
			||||||
@@ -30,59 +29,29 @@ public sealed class ReusableCancellationTokenSource : IDisposable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private void OnTimeout(object? state)
 | 
					    private void OnTimeout(object? state)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        lock (_lock)
 | 
					        TimeoutStatus = true;
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            TimeoutStatus = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (_cts?.IsCancellationRequested == false)
 | 
					        if (_cts?.IsCancellationRequested == false)
 | 
				
			||||||
                _cts?.Cancel();
 | 
					            _cts?.Cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 获取一个 CTS,并启动超时
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    public CancellationTokenSource GetTokenSource(long timeout, CancellationToken external1 = default)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        lock (_lock)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            TimeoutStatus = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 如果已有 CTS,先 Dispose
 | 
					    private readonly LinkedCancellationTokenSourceCache _linkedCtsCache = new();
 | 
				
			||||||
            _cts?.SafeCancel();
 | 
					 | 
				
			||||||
            _cts?.SafeDispose();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // 创建新的 CTS
 | 
					 | 
				
			||||||
            _cts = CancellationTokenSource.CreateLinkedTokenSource(external1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // 启动 Timer
 | 
					 | 
				
			||||||
            _timer.Change(timeout, Timeout.Infinite);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return _cts;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取一个 CTS,并启动超时
 | 
					    /// 获取一个 CTS,并启动超时
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public CancellationTokenSource GetTokenSource(long timeout, CancellationToken external1 = default, CancellationToken external2 = default, CancellationToken external3 = default)
 | 
					    public CancellationTokenSource GetTokenSource(long timeout, CancellationToken external1 = default, CancellationToken external2 = default, CancellationToken external3 = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        lock (_lock)
 | 
					        TimeoutStatus = false;
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            TimeoutStatus = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 如果已有 CTS,先 Dispose
 | 
					        // 创建新的 CTS
 | 
				
			||||||
            _cts?.SafeCancel();
 | 
					        _cts = _linkedCtsCache.GetLinkedTokenSource(external1, external2, external3);
 | 
				
			||||||
            _cts?.SafeDispose();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 创建新的 CTS
 | 
					        // 启动 Timer
 | 
				
			||||||
            _cts = CancellationTokenSource.CreateLinkedTokenSource(external1, external2, external3);
 | 
					        _timer.Change(timeout, Timeout.Infinite);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 启动 Timer
 | 
					        return _cts;
 | 
				
			||||||
            _timer.Change(timeout, Timeout.Infinite);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return _cts;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,20 +65,15 @@ public sealed class ReusableCancellationTokenSource : IDisposable
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public void Cancel()
 | 
					    public void Cancel()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        lock (_lock)
 | 
					        _cts?.SafeCancel();
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _cts?.SafeCancel();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void Dispose()
 | 
					    public void Dispose()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        lock (_lock)
 | 
					        _cts?.SafeCancel();
 | 
				
			||||||
        {
 | 
					        _cts?.SafeDispose();
 | 
				
			||||||
            _cts?.SafeCancel();
 | 
					        _linkedCtsCache.SafeDispose();
 | 
				
			||||||
            _cts?.SafeDispose();
 | 
					        _timer.SafeDispose();
 | 
				
			||||||
            _timer.SafeDispose();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,5 +106,5 @@ public class BusinessPropertyWithCacheIntervalScript : BusinessPropertyWithCache
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [DynamicProperty]
 | 
					    [DynamicProperty]
 | 
				
			||||||
    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
    public string? BigTextScriptPluginEventDataModel { get; set; }
 | 
					    public virtual string? BigTextScriptPluginEventDataModel { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,15 @@ public abstract partial class CollectBase : DriverBase
 | 
				
			|||||||
    /// 特殊方法
 | 
					    /// 特殊方法
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public List<DriverMethodInfo>? DriverMethodInfos { get; private set; }
 | 
					    public List<DriverMethodInfo>? DriverMethodInfos { get; private set; }
 | 
				
			||||||
 | 
					    protected virtual bool IsRuntimeSourceValid(VariableRuntime a)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //筛选特殊变量地址
 | 
				
			||||||
 | 
					        //1、DeviceStatus
 | 
				
			||||||
 | 
					        return !a.RegisterAddress.Equals(nameof(DeviceRuntime.DeviceStatus), StringComparison.OrdinalIgnoreCase) &&
 | 
				
			||||||
 | 
					        !a.RegisterAddress.Equals("Script", StringComparison.OrdinalIgnoreCase) &&
 | 
				
			||||||
 | 
					        !a.RegisterAddress.Equals("ScriptRead", StringComparison.OrdinalIgnoreCase)
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    public override async Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
 | 
					    public override async Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LogMessage?.LogInformation("Refresh variable");
 | 
					        LogMessage?.LogInformation("Refresh variable");
 | 
				
			||||||
@@ -84,21 +92,13 @@ public abstract partial class CollectBase : DriverBase
 | 
				
			|||||||
            && string.IsNullOrEmpty(it.OtherMethod)
 | 
					            && string.IsNullOrEmpty(it.OtherMethod)
 | 
				
			||||||
            && !string.IsNullOrEmpty(it.RegisterAddress));
 | 
					            && !string.IsNullOrEmpty(it.RegisterAddress));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //筛选特殊变量地址
 | 
					
 | 
				
			||||||
        //1、DeviceStatus
 | 
					 | 
				
			||||||
        Func<VariableRuntime, bool> source = (a =>
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return !a.RegisterAddress.Equals(nameof(DeviceRuntime.DeviceStatus), StringComparison.OrdinalIgnoreCase) &&
 | 
					 | 
				
			||||||
            !a.RegisterAddress.Equals("Script", StringComparison.OrdinalIgnoreCase) &&
 | 
					 | 
				
			||||||
            !a.RegisterAddress.Equals("ScriptRead", StringComparison.OrdinalIgnoreCase)
 | 
					 | 
				
			||||||
            ;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        var now = DateTime.Now;
 | 
					        var now = DateTime.Now;
 | 
				
			||||||
#pragma warning disable CA1851
 | 
					#pragma warning disable CA1851
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            currentDevice.VariableScriptReads = tags.Where(a => !source(a)).Select(a =>
 | 
					            currentDevice.VariableScriptReads = tags.Where(a => !IsRuntimeSourceValid(a)).Select(a =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var data = new VariableScriptRead();
 | 
					                var data = new VariableScriptRead();
 | 
				
			||||||
                data.VariableRuntime = a;
 | 
					                data.VariableRuntime = a;
 | 
				
			||||||
@@ -111,9 +111,9 @@ public abstract partial class CollectBase : DriverBase
 | 
				
			|||||||
            // 如果出现异常,记录日志并初始化 VariableSourceReads 属性为新实例
 | 
					            // 如果出现异常,记录日志并初始化 VariableSourceReads 属性为新实例
 | 
				
			||||||
            currentDevice.VariableScriptReads = new();
 | 
					            currentDevice.VariableScriptReads = new();
 | 
				
			||||||
            LogMessage?.LogWarning(ex, string.Format(AppResource.VariablePackError, ex.Message));
 | 
					            LogMessage?.LogWarning(ex, string.Format(AppResource.VariablePackError, ex.Message));
 | 
				
			||||||
            tags.Where(a => !source(a)).ForEach(a => a.SetValue(null, now, isOnline: false));
 | 
					            tags.Where(a => !IsRuntimeSourceValid(a)).ForEach(a => a.SetValue(null, now, isOnline: false));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        var variableReads = tags.Where(source).ToList();
 | 
					        var variableReads = tags.Where(IsRuntimeSourceValid).ToList();
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // 将打包后的结果存储在当前设备的 VariableSourceReads 属性中
 | 
					            // 将打包后的结果存储在当前设备的 VariableSourceReads 属性中
 | 
				
			||||||
@@ -594,7 +594,7 @@ public abstract partial class CollectBase : DriverBase
 | 
				
			|||||||
                    // 根据写入表达式转换数据
 | 
					                    // 根据写入表达式转换数据
 | 
				
			||||||
                    object data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata, LogMessage);
 | 
					                    object data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata, LogMessage);
 | 
				
			||||||
                    // 将转换后的数据重新赋值给写入信息列表
 | 
					                    // 将转换后的数据重新赋值给写入信息列表
 | 
				
			||||||
                    writeInfoLists[deviceVariable] = JToken.FromObject(data);
 | 
					                    writeInfoLists[deviceVariable] = JTokenUtil.GetJTokenFromObj(data);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (Exception ex)
 | 
					                catch (Exception ex)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -662,7 +662,7 @@ public abstract partial class CollectBase : DriverBase
 | 
				
			|||||||
                    // 根据写入表达式转换数据
 | 
					                    // 根据写入表达式转换数据
 | 
				
			||||||
                    object data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata, LogMessage);
 | 
					                    object data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata, LogMessage);
 | 
				
			||||||
                    // 将转换后的数据重新赋值给写入信息列表
 | 
					                    // 将转换后的数据重新赋值给写入信息列表
 | 
				
			||||||
                    writeInfoLists[deviceVariable] = JToken.FromObject(data);
 | 
					                    writeInfoLists[deviceVariable] = JTokenUtil.GetJTokenFromObj(data);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (Exception ex)
 | 
					                catch (Exception ex)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://thingsgateway.cn/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// 插件配置项
 | 
				
			||||||
 | 
					/// <br></br>
 | 
				
			||||||
 | 
					/// 使用<see cref="DynamicPropertyAttribute"/> 标识所需的配置属性
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class MempryDevicePropertyBase : CollectPropertyBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// <para></para>
 | 
				
			||||||
 | 
					/// 采集插件,继承实现不同PLC通讯
 | 
				
			||||||
 | 
					/// <para></para>
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class MempryDevice : CollectBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private MempryDevicePropertyBase _driverPropertyBase = new MempryDevicePropertyBase();
 | 
				
			||||||
 | 
					    public override CollectPropertyBase CollectProperties => _driverPropertyBase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !Management
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否连接成功
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public override bool IsConnected()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(new List<VariableSourceRead>());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected override bool IsRuntimeSourceValid(VariableRuntime a)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -15,6 +15,8 @@ using Riok.Mapperly.Abstractions;
 | 
				
			|||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.ComponentModel.DataAnnotations;
 | 
					using System.ComponentModel.DataAnnotations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Gateway.Application;
 | 
					namespace ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -409,7 +409,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
 | 
				
			|||||||
                 // 查找具有指定设备ID的驱动程序对象
 | 
					                 // 查找具有指定设备ID的驱动程序对象
 | 
				
			||||||
                 if (Drivers.TryRemove(deviceId, out var driver))
 | 
					                 if (Drivers.TryRemove(deviceId, out var driver))
 | 
				
			||||||
                 {
 | 
					                 {
 | 
				
			||||||
                     driver.CurrentDevice.SetDeviceStatus(now, false, "Communication connection has been removed");
 | 
					                     driver.CurrentDevice.SetDeviceStatus(now, true, "Communication connection has been removed");
 | 
				
			||||||
                     if (IsCollectChannel == true)
 | 
					                     if (IsCollectChannel == true)
 | 
				
			||||||
                     {
 | 
					                     {
 | 
				
			||||||
                         foreach (var a in driver.IdVariableRuntimes)
 | 
					                         foreach (var a in driver.IdVariableRuntimes)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ using ThingsGateway.Blazor.Diagrams.Core;
 | 
				
			|||||||
using ThingsGateway.Blazor.Diagrams.Core.Anchors;
 | 
					using ThingsGateway.Blazor.Diagrams.Core.Anchors;
 | 
				
			||||||
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
 | 
					using ThingsGateway.Blazor.Diagrams.Core.Geometry;
 | 
				
			||||||
using ThingsGateway.Blazor.Diagrams.Core.Models;
 | 
					using ThingsGateway.Blazor.Diagrams.Core.Models;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Gateway.Application;
 | 
					namespace ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +89,7 @@ public static class RuleHelpers
 | 
				
			|||||||
        var propertyInfos = nodeModel.GetType().GetRuntimeProperties().Where(a => a.GetCustomAttribute<ModelValue>() != null);
 | 
					        var propertyInfos = nodeModel.GetType().GetRuntimeProperties().Where(a => a.GetCustomAttribute<ModelValue>() != null);
 | 
				
			||||||
        foreach (var item in propertyInfos)
 | 
					        foreach (var item in propertyInfos)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            jtokens.Add(item.Name, JToken.FromObject(item.GetValue(nodeModel) ?? JValue.CreateNull()));
 | 
					            jtokens.Add(item.Name, (item.GetValue(nodeModel) ?? JValue.CreateNull()).GetJTokenFromObj());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return jtokens;
 | 
					        return jtokens;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
using Newtonsoft.Json.Linq;
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Gateway.Application;
 | 
					namespace ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class NodeInput
 | 
					public class NodeInput
 | 
				
			||||||
@@ -9,7 +11,7 @@ public class NodeInput
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        get
 | 
					        get
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return JToken.FromObject(input);
 | 
					            return (input).GetJTokenFromObj();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
using Newtonsoft.Json.Linq;
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Gateway.Application;
 | 
					namespace ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class NodeOutput
 | 
					public class NodeOutput
 | 
				
			||||||
@@ -9,7 +11,7 @@ public class NodeOutput
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        get
 | 
					        get
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return JToken.FromObject(output);
 | 
					            return (output).GetJTokenFromObj();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,9 +11,9 @@
 | 
				
			|||||||
		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
 | 
							<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
 | 
				
			||||||
		<PackageReference Include="Rougamo.Fody" Version="5.0.1" />
 | 
							<PackageReference Include="Rougamo.Fody" Version="5.0.1" />
 | 
				
			||||||
		<PackageReference Include="System.Linq.Async" Version="6.0.3" />
 | 
							<PackageReference Include="System.Linq.Async" Version="6.0.3" />
 | 
				
			||||||
		<PackageReference Include="TouchSocket.Dmtp" Version="4.0.0-beta.25" />
 | 
							<PackageReference Include="TouchSocket.Dmtp" Version="4.0.0-beta.28" />
 | 
				
			||||||
		<!--<PackageReference Include="TouchSocket.WebApi.Swagger" Version="4.0.0-beta.25" />-->
 | 
							<!--<PackageReference Include="TouchSocket.WebApi.Swagger" Version="4.0.0-beta.28" />-->
 | 
				
			||||||
		<PackageReference Include="TouchSocket.WebApi" Version="4.0.0-beta.25" />
 | 
							<PackageReference Include="TouchSocket.WebApi" Version="4.0.0-beta.28" />
 | 
				
			||||||
		<PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" />
 | 
							<PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" />
 | 
				
			||||||
		<!--<ProjectReference Include="..\..\PluginPro\ThingsGateway.Authentication\ThingsGateway.Authentication.csproj" />-->
 | 
							<!--<ProjectReference Include="..\..\PluginPro\ThingsGateway.Authentication\ThingsGateway.Authentication.csproj" />-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
    /*切换高度*/
 | 
					    /*切换高度*/
 | 
				
			||||||
    .quickactions-list.is-open {
 | 
					    .quickactions-list.is-open {
 | 
				
			||||||
        height: 300px;
 | 
					        height: 200px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.quickactions-header {
 | 
					.quickactions-header {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,18 +76,34 @@ public partial class DeviceRuntimeInfo1 : IDisposable
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        await DialogService.Show(new DialogOption()
 | 
					        var renderFragment = BootstrapDynamicComponent.CreateComponent(driver, new Dictionary<string, object?>()
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            IsScrolling = false,
 | 
					 | 
				
			||||||
            ShowMaximizeButton = true,
 | 
					 | 
				
			||||||
            Size = Size.ExtraExtraLarge,
 | 
					 | 
				
			||||||
            Title = DeviceRuntime.Name,
 | 
					 | 
				
			||||||
            Component = BootstrapDynamicComponent.CreateComponent(driver, new Dictionary<string, object?>()
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            {nameof(IDriverUIBase.Driver),DeviceRuntime.Driver},
 | 
					            {nameof(IDriverUIBase.Driver),DeviceRuntime.Driver},
 | 
				
			||||||
        })
 | 
					        }).Render();
 | 
				
			||||||
        });
 | 
					        if (renderFragment != null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var option = new WinBoxOption()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Title = DeviceRuntime.Name,
 | 
				
			||||||
 | 
					                ContentTemplate = renderFragment,
 | 
				
			||||||
 | 
					                Max = false,
 | 
				
			||||||
 | 
					                Width = "80%",
 | 
				
			||||||
 | 
					                Height = "80%",
 | 
				
			||||||
 | 
					                Top = "0%",
 | 
				
			||||||
 | 
					                Left = "10%",
 | 
				
			||||||
 | 
					                Background = "var(--bb-primary-color)",
 | 
				
			||||||
 | 
					                Overflow = true
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            await WinBoxService.Show(option);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Inject]
 | 
				
			||||||
 | 
					    [NotNull]
 | 
				
			||||||
 | 
					    private WinBoxService? WinBoxService { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [Inject]
 | 
					    [Inject]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,14 @@
 | 
				
			|||||||
                                    @Localizer["Check"]
 | 
					                                    @Localizer["Check"]
 | 
				
			||||||
                                </Button>
 | 
					                                </Button>
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                         <div class="col-12  col-md-12 min-height-500">
 | 
				
			||||||
 | 
					                            <BootstrapLabel Value=@PropertyComponentLocalizer["BigTextScriptPluginEventDataModel"] ShowLabelTooltip="true" />
 | 
				
			||||||
 | 
					                            <CodeEditor IsReadonly=@(!CanWrite) ShowLineNo @bind-Value=@businessProperty.BigTextScriptPluginEventDataModel Language="csharp" Theme="vs-dark" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    </EditTemplate>
 | 
					                    </EditTemplate>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,8 +48,22 @@ public partial class GatewayMonitorPage
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                VariableRuntimes = deviceRuntime.Driver?.IdVariableRuntimes?.Where(a => a.Value != null)
 | 
					                if (deviceRuntime.Driver == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _ = Task.Run(async () =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await Task.Delay(2000);
 | 
				
			||||||
 | 
					                        VariableRuntimes = deviceRuntime.Driver?.IdVariableRuntimes?.Where(a => a.Value != null)
 | 
				
			||||||
.Select(a => a.Value) ?? Enumerable.Empty<VariableRuntime>();
 | 
					.Select(a => a.Value) ?? Enumerable.Empty<VariableRuntime>();
 | 
				
			||||||
 | 
					                        await InvokeAsync(StateHasChanged);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    VariableRuntimes = deviceRuntime.Driver?.IdVariableRuntimes?.Where(a => a.Value != null)
 | 
				
			||||||
 | 
					.Select(a => a.Value) ?? Enumerable.Empty<VariableRuntime>();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ChannelRuntimes = Enumerable.Repeat(deviceRuntime.ChannelRuntime, 1);
 | 
					            ChannelRuntimes = Enumerable.Repeat(deviceRuntime.ChannelRuntime, 1);
 | 
				
			||||||
            DeviceRuntimes = Enumerable.Repeat(deviceRuntime, 1);
 | 
					            DeviceRuntimes = Enumerable.Repeat(deviceRuntime, 1);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,15 +28,7 @@ public partial class VariableRuntimeInfo : IDisposable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    [Parameter]
 | 
					    [Parameter]
 | 
				
			||||||
    public IEnumerable<VariableRuntime>? Items { get; set; } = Enumerable.Empty<VariableRuntime>();
 | 
					    public IEnumerable<VariableRuntime>? Items { get; set; } = Enumerable.Empty<VariableRuntime>();
 | 
				
			||||||
    private IEnumerable<VariableRuntime>? _previousItemsRef;
 | 
					
 | 
				
			||||||
    protected override async Task OnParametersSetAsync()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (!ReferenceEquals(_previousItemsRef, Items))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _previousItemsRef = Items;
 | 
					 | 
				
			||||||
            await Refresh(null);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static void BeforeShowEditDialogCallback(ITableEditDialogOption<VariableRuntime> tableEditDialogOption)
 | 
					    private static void BeforeShowEditDialogCallback(ITableEditDialogOption<VariableRuntime> tableEditDialogOption)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,244 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://kimdiego2098.github.io/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BenchmarkConsoleApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Attributes;
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Diagnosers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Longbow.Modbus;
 | 
				
			||||||
 | 
					using Longbow.TcpSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Net.Sockets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using TouchSocket.Core;
 | 
				
			||||||
 | 
					using TouchSocket.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using IModbusMaster = NModbus.IModbusMaster;
 | 
				
			||||||
 | 
					using ModbusMaster = ThingsGateway.Foundation.Modbus.ModbusMaster;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[MemoryDiagnoser]
 | 
				
			||||||
 | 
					public class ModbusBenchmark : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly List<IModbusClient> _lgbModbusClients = [];
 | 
				
			||||||
 | 
					    private List<ModbusMaster> thingsgatewaymodbuss = new();
 | 
				
			||||||
 | 
					    private List<IModbusMaster> nmodbuss = new();
 | 
				
			||||||
 | 
					    //private List<ModbusTcpNet> modbusTcpNets = new();
 | 
				
			||||||
 | 
					    private List<ModbusTcpMaster> modbusTcpMasters = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ModbusBenchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var clientConfig = new TouchSocket.Core.TouchSocketConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var clientChannel = clientConfig.GetChannel(new ChannelOptions() { ChannelType = ChannelTypeEnum.TcpClient, RemoteUrl = "127.0.0.1:502", MaxConcurrentCount = 10 });
 | 
				
			||||||
 | 
					            var thingsgatewaymodbus = new ModbusMaster()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                //modbus协议格式
 | 
				
			||||||
 | 
					                ModbusType = ModbusTypeEnum.ModbusTcp,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            thingsgatewaymodbus.InitChannel(clientChannel);
 | 
				
			||||||
 | 
					            clientChannel.SetupAsync(clientChannel.Config).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					            clientChannel.Logger.LogLevel = LogLevel.Warning;
 | 
				
			||||||
 | 
					            thingsgatewaymodbus.ConnectAsync(CancellationToken.None).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					            thingsgatewaymodbus.ReadAsync("40001", 100).GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					            thingsgatewaymodbuss.Add(thingsgatewaymodbus);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var factory = new NModbus.ModbusFactory();
 | 
				
			||||||
 | 
					            var nmodbus = factory.CreateMaster(new TcpClient("127.0.0.1", 502));
 | 
				
			||||||
 | 
					            nmodbus.ReadHoldingRegistersAsync(1, 0, 100).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					            nmodbuss.Add(nmodbus);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					        //{
 | 
				
			||||||
 | 
					        //    ModbusTcpNet modbusTcpNet = new();
 | 
				
			||||||
 | 
					        //    modbusTcpNet.IpAddress = "127.0.0.1";
 | 
				
			||||||
 | 
					        //    modbusTcpNet.Port = 502;
 | 
				
			||||||
 | 
					        //    modbusTcpNet.ConnectServer();
 | 
				
			||||||
 | 
					        //    modbusTcpNet.ReadAsync("0", 100).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					        //    modbusTcpNets.Add(modbusTcpNet);
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var client = new ModbusTcpMaster();
 | 
				
			||||||
 | 
					            client.SetupAsync(new TouchSocketConfig()
 | 
				
			||||||
 | 
					    .SetRemoteIPHost("127.0.0.1:502")).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					            client.ConnectAsync(CancellationToken.None).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					            client.ReadHoldingRegistersAsync(0, 100).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					            modbusTcpMasters.Add(client);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sc = new ServiceCollection();
 | 
				
			||||||
 | 
					            sc.AddTcpSocketFactory();
 | 
				
			||||||
 | 
					            sc.AddModbusFactory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var provider = sc.BuildServiceProvider();
 | 
				
			||||||
 | 
					            var factory = provider.GetRequiredService<IModbusFactory>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var client = factory.GetOrCreateTcpMaster();
 | 
				
			||||||
 | 
					                client.ConnectAsync("127.0.0.1", 502).GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					                client.ReadHoldingRegistersAsync(0x01, 0x00, 10).GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _lgbModbusClients.Add(client);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async Task ThingsGateway()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //ModbusAddress addr = new ModbusAddress() { FunctionCode = 3, StartAddress = 0, Length = 100 };
 | 
				
			||||||
 | 
					        List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					        foreach (var thingsgatewaymodbus in thingsgatewaymodbuss)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var result = await thingsgatewaymodbus.ModbusReadAsync(new ModbusAddress() { Station = 1, FunctionCode = 3, StartAddress = 0, Length = 100 }).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                        if (!result.IsSuccess)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            throw new Exception(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff") + result.ToString());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var data = TouchSocketBitConverter.ConvertValues<byte, ushort>(result.Content.Span, EndianType.Little);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async Task LongbowModbus()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					        foreach (var _lgbModbusClient in _lgbModbusClients)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        using var cts = new CancellationTokenSource(3000);
 | 
				
			||||||
 | 
					                        var task = await _lgbModbusClient.ReadHoldingRegistersAsync(1, 0, 100, cts.Token).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async Task TouchSocket()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					        foreach (var modbusTcpMaster in modbusTcpMasters)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var result = await modbusTcpMaster.ReadHoldingRegistersAsync(0, 100).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                        var data = TouchSocketBitConverter.ConvertValues<byte, ushort>(result.Data.Span, EndianType.Little);
 | 
				
			||||||
 | 
					                        if (!result.IsSuccess)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            throw new Exception(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff") + result.ToString());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async Task NModbus4()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					        foreach (var nmodbus in nmodbuss)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var result = await nmodbus.ReadHoldingRegistersAsync(1, 0, 100).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //并发失败
 | 
				
			||||||
 | 
					    //[Benchmark]
 | 
				
			||||||
 | 
					    //public async Task HslCommunication()
 | 
				
			||||||
 | 
					    //{
 | 
				
			||||||
 | 
					    //    List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					    //    foreach (var modbusTcpNet in modbusTcpNets)
 | 
				
			||||||
 | 
					    //    {
 | 
				
			||||||
 | 
					    //        for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					    //        {
 | 
				
			||||||
 | 
					    //            tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					    //            {
 | 
				
			||||||
 | 
					    //                for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					    //                {
 | 
				
			||||||
 | 
					    //                    var result = await modbusTcpNet.ReadAsync("0", 100);
 | 
				
			||||||
 | 
					    //                    if (!result.IsSuccess)
 | 
				
			||||||
 | 
					    //                    {
 | 
				
			||||||
 | 
					    //                        throw new Exception(result.Message);
 | 
				
			||||||
 | 
					    //                    }
 | 
				
			||||||
 | 
					    //                }
 | 
				
			||||||
 | 
					    //            }));
 | 
				
			||||||
 | 
					    //        }
 | 
				
			||||||
 | 
					    //    }
 | 
				
			||||||
 | 
					    //    await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    //}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thingsgatewaymodbuss?.ForEach(a => a.Channel.SafeDispose());
 | 
				
			||||||
 | 
					        thingsgatewaymodbuss?.ForEach(a => a.SafeDispose());
 | 
				
			||||||
 | 
					        nmodbuss?.ForEach(a => a.SafeDispose());
 | 
				
			||||||
 | 
					        //modbusTcpNets?.ForEach(a => a.SafeDispose());
 | 
				
			||||||
 | 
					        _lgbModbusClients?.ForEach(a => a.DisposeAsync().GetAwaiter().GetResult());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://kimdiego2098.github.io/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BenchmarkConsoleApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Attributes;
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Diagnosers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using HslCommunication.Profinet.Siemens;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using S7.Net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.SiemensS7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using TouchSocket.Core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[MemoryDiagnoser]
 | 
				
			||||||
 | 
					public class S7Benchmark : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private List<SiemensS7Master> siemensS7s = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private List<Plc> plcs = new();
 | 
				
			||||||
 | 
					    private List<SiemensS7Net> siemensS7Nets = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public S7Benchmark()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var clientConfig = new TouchSocket.Core.TouchSocketConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var clientChannel = clientConfig.GetChannel(new ChannelOptions() { ChannelType = ChannelTypeEnum.TcpClient, RemoteUrl = "127.0.0.1:102" });
 | 
				
			||||||
 | 
					                var siemensS7 = new SiemensS7Master()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //modbus协议格式
 | 
				
			||||||
 | 
					                    SiemensS7Type = SiemensTypeEnum.S1500
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                siemensS7.InitChannel(clientChannel);
 | 
				
			||||||
 | 
					                clientChannel.SetupAsync(clientChannel.Config).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					                clientChannel.Logger.LogLevel = LogLevel.Warning;
 | 
				
			||||||
 | 
					                siemensS7.ConnectAsync(CancellationToken.None).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					                siemensS7.ReadAsync("M1", 100).GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					                siemensS7s.Add(siemensS7);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var siemensS7Net = new SiemensS7Net(SiemensPLCS.S1500, "127.0.0.1");
 | 
				
			||||||
 | 
					                siemensS7Net.ConnectServer();
 | 
				
			||||||
 | 
					                siemensS7Net.ReadAsync("M0", 100).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					                siemensS7Nets.Add(siemensS7Net);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.ClientCount; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var plc = new Plc(CpuType.S7300, "127.0.0.1", 102, 0, 0);
 | 
				
			||||||
 | 
					                plc.Open();//打开plc连接
 | 
				
			||||||
 | 
					                plc.ReadAsync(DataType.Memory, 1, 0, VarType.Byte, 100).GetFalseAwaitResult();
 | 
				
			||||||
 | 
					                plcs.Add(plc);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async Task S7netplus()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					        foreach (var plc in plcs)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var result = await plc.ReadAsync(DataType.Memory, 1, 0, VarType.Byte, 100);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //并发失败
 | 
				
			||||||
 | 
					    //[Benchmark]
 | 
				
			||||||
 | 
					    //public async Task HslCommunication()
 | 
				
			||||||
 | 
					    //{
 | 
				
			||||||
 | 
					    //    List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					    //    foreach (var siemensS7Net in siemensS7Nets)
 | 
				
			||||||
 | 
					    //    {
 | 
				
			||||||
 | 
					    //        for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					    //        {
 | 
				
			||||||
 | 
					    //            tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					    //            {
 | 
				
			||||||
 | 
					    //                for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					    //                {
 | 
				
			||||||
 | 
					    //                    var result = await siemensS7Net.ReadAsync("M0", 100);
 | 
				
			||||||
 | 
					    //                    if (!result.IsSuccess)
 | 
				
			||||||
 | 
					    //                    {
 | 
				
			||||||
 | 
					    //                        throw new Exception(result.Message);
 | 
				
			||||||
 | 
					    //                    }
 | 
				
			||||||
 | 
					    //                }
 | 
				
			||||||
 | 
					    //            }));
 | 
				
			||||||
 | 
					    //        }
 | 
				
			||||||
 | 
					    //    }
 | 
				
			||||||
 | 
					    //    await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    //}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async Task ThingsGateway()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        SiemensS7Address[] siemensS7Address = [SiemensS7Address.ParseFrom("M1", 100)];
 | 
				
			||||||
 | 
					        List<Task> tasks = new List<Task>();
 | 
				
			||||||
 | 
					        foreach (var siemensS7 in siemensS7s)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0; i < Program.TaskNumberOfItems; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tasks.Add(Task.Run(async () =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < Program.NumberOfItems; i++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var result = await siemensS7.S7ReadAsync(siemensS7Address);
 | 
				
			||||||
 | 
					                        if (!result.IsSuccess)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            throw new Exception(result.ToString());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await Task.WhenAll(tasks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        plcs.ForEach(a => a.SafeDispose());
 | 
				
			||||||
 | 
					        siemensS7Nets.ForEach(a => a.SafeDispose());
 | 
				
			||||||
 | 
					        siemensS7s.ForEach(a => a.Channel.SafeDispose());
 | 
				
			||||||
 | 
					        siemensS7s.ForEach(a => a.SafeDispose());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://kimdiego2098.github.io/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Attributes;
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Diagnosers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[MemoryDiagnoser]
 | 
				
			||||||
 | 
					public class TimeoutBenchmark
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async ValueTask CtsWaitAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        using var otherCts = new CancellationTokenSource();
 | 
				
			||||||
 | 
					        for (int i1 = 0; i1 < 10; i1++)
 | 
				
			||||||
 | 
					            for (int i = 0; i < 10; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                using var ctsTime = new CancellationTokenSource(TimeSpan.FromMilliseconds(10));
 | 
				
			||||||
 | 
					                using var cts = CancellationTokenSource.CreateLinkedTokenSource(ctsTime.Token, otherCts.Token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                await Task.Delay(5, cts.Token).ConfigureAwait(false); // 模拟工作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ObjectPool<ReusableCancellationTokenSource> _reusableTimeouts;
 | 
				
			||||||
 | 
					    [Benchmark]
 | 
				
			||||||
 | 
					    public async ValueTask ReusableTimeoutWaitAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _reusableTimeouts ??= new();
 | 
				
			||||||
 | 
					        using var otherCts = new CancellationTokenSource();
 | 
				
			||||||
 | 
					        for (int i1 = 0; i1 < 10; i1++)
 | 
				
			||||||
 | 
					            for (int i = 0; i < 10; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var _reusableTimeout = _reusableTimeouts.Get();
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    await Task.Delay(5, _reusableTimeout.GetTokenSource(10, otherCts.Token).Token).ConfigureAwait(false); // 模拟工作
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                finally
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _reusableTimeouts.Return(_reusableTimeout);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _reusableTimeouts.Dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/Plugin/ThingsGateway.Foundation.Benchmark/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/Plugin/ThingsGateway.Foundation.Benchmark/Program.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明或在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首页:http://rrqm_home.gitee.io/touchsocket/
 | 
				
			||||||
 | 
					//  交流QQ群:234762506
 | 
				
			||||||
 | 
					//  感谢您的下载和使用
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Configs;
 | 
				
			||||||
 | 
					using BenchmarkDotNet.Running;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BenchmarkConsoleApp
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    internal class Program
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static int ClientCount = 30;
 | 
				
			||||||
 | 
					        public static int TaskNumberOfItems = 30;
 | 
				
			||||||
 | 
					        public static int NumberOfItems = 30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private static async Task Main(string[] args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Console.WriteLine("开始测试前,请先启动ModbusSlave,建议使用本项目自带的ThingsGateway.Debug.Photino软件开启,S7可以用KEPSERVER的S7模拟服务");
 | 
				
			||||||
 | 
					            Console.WriteLine($"多客户端({ClientCount}),多线程({TaskNumberOfItems})并发读取({NumberOfItems})测试,共{ClientCount * TaskNumberOfItems * NumberOfItems}次");
 | 
				
			||||||
 | 
					            await Task.CompletedTask;
 | 
				
			||||||
 | 
					            //ModbusBenchmark modbusBenchmark = new ModbusBenchmark();
 | 
				
			||||||
 | 
					            //System.Diagnostics.Stopwatch stopwatch = new();
 | 
				
			||||||
 | 
					            //stopwatch.Start();
 | 
				
			||||||
 | 
					            //await modbusBenchmark.ThingsGateway();
 | 
				
			||||||
 | 
					            //stopwatch.Stop();
 | 
				
			||||||
 | 
					            //Console.WriteLine($"ThingsGateway耗时:{stopwatch.ElapsedMilliseconds}ms");
 | 
				
			||||||
 | 
					            //stopwatch.Restart();
 | 
				
			||||||
 | 
					            //await modbusBenchmark.TouchSocket();
 | 
				
			||||||
 | 
					            //stopwatch.Stop();
 | 
				
			||||||
 | 
					            //Console.WriteLine($"TouchSocket耗时:{stopwatch.ElapsedMilliseconds}ms");
 | 
				
			||||||
 | 
					            //Console.ReadLine();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //            BenchmarkRunner.Run<TimeoutBenchmark>(
 | 
				
			||||||
 | 
					            //ManualConfig.Create(DefaultConfig.Instance)
 | 
				
			||||||
 | 
					            //.WithOptions(ConfigOptions.DisableOptimizationsValidator)
 | 
				
			||||||
 | 
					            //);
 | 
				
			||||||
 | 
					            BenchmarkRunner.Run<ModbusBenchmark>(
 | 
				
			||||||
 | 
					       ManualConfig.Create(DefaultConfig.Instance)
 | 
				
			||||||
 | 
					           .WithOptions(ConfigOptions.DisableOptimizationsValidator)
 | 
				
			||||||
 | 
					   );
 | 
				
			||||||
 | 
					            //            BenchmarkRunner.Run<S7Benchmark>(
 | 
				
			||||||
 | 
					            //ManualConfig.Create(DefaultConfig.Instance)
 | 
				
			||||||
 | 
					            //.WithOptions(ConfigOptions.DisableOptimizationsValidator)
 | 
				
			||||||
 | 
					            //);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<PropertyGroup>
 | 
				
			||||||
 | 
							<OutputType>Exe</OutputType>
 | 
				
			||||||
 | 
							<TargetFramework>net8.0</TargetFramework>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<AnalysisModeDesign>None</AnalysisModeDesign>
 | 
				
			||||||
 | 
							<AnalysisModeDocumentation>None</AnalysisModeDocumentation>
 | 
				
			||||||
 | 
							<AnalysisModeGlobalization>None</AnalysisModeGlobalization>
 | 
				
			||||||
 | 
							<AnalysisModeInteroperability>None</AnalysisModeInteroperability>
 | 
				
			||||||
 | 
							<AnalysisModeMaintainability>None</AnalysisModeMaintainability>
 | 
				
			||||||
 | 
							<AnalysisModeNaming>None</AnalysisModeNaming>
 | 
				
			||||||
 | 
							<AnalysisModePerformance>None</AnalysisModePerformance>
 | 
				
			||||||
 | 
							<AnalysisModeSingleFile>None</AnalysisModeSingleFile>
 | 
				
			||||||
 | 
							<AnalysisModeReliability>None</AnalysisModeReliability>
 | 
				
			||||||
 | 
							<AnalysisModeSecurity>None</AnalysisModeSecurity>
 | 
				
			||||||
 | 
							<AnalysisModeUsage>None</AnalysisModeUsage>
 | 
				
			||||||
 | 
							<AnalysisModeStyle>None</AnalysisModeStyle>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<TargetFrameworks>net8.0;</TargetFrameworks>
 | 
				
			||||||
 | 
							<LangVersion>13.0</LangVersion>
 | 
				
			||||||
 | 
							<ImplicitUsings>enable</ImplicitUsings>
 | 
				
			||||||
 | 
							<Nullable>enable</Nullable>
 | 
				
			||||||
 | 
							<Authors>Diego</Authors>
 | 
				
			||||||
 | 
							<Company>Diego</Company>
 | 
				
			||||||
 | 
							<Product>Diego</Product>
 | 
				
			||||||
 | 
							<Copyright>版权所有 © 2023-present Diego</Copyright>
 | 
				
			||||||
 | 
							<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl>
 | 
				
			||||||
 | 
							<RepositoryType>Gitee</RepositoryType>
 | 
				
			||||||
 | 
							<GenerateResxSourceIncludeDefaultValues>true</GenerateResxSourceIncludeDefaultValues>
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<PackageReference Remove="Roslynator.Analyzers">
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<PackageReference Include="BenchmarkDotNet" Version="0.15.3" />
 | 
				
			||||||
 | 
							<PackageReference Include="HslCommunication" Version="12.5.1" />
 | 
				
			||||||
 | 
							<PackageReference Include="Longbow.Modbus" Version="9.0.7" />
 | 
				
			||||||
 | 
							<PackageReference Include="NModbus" Version="3.0.81" />
 | 
				
			||||||
 | 
							<PackageReference Include="NModbus.Serial" Version="3.0.81" />
 | 
				
			||||||
 | 
							<PackageReference Include="S7netplus" Version="0.20.0" />
 | 
				
			||||||
 | 
							<!--<PackageReference Include="ThingsGateway.Foundation.Modbus" Version="$(DefaultVersion)" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Foundation.SiemensS7" Version="$(DefaultVersion)" />-->
 | 
				
			||||||
 | 
							<PackageReference Include="TouchSocket.Modbus" Version="4.0.0-beta.28" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\Plugin\ThingsGateway.Foundation.Modbus\ThingsGateway.Foundation.Modbus.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\Plugin\ThingsGateway.Foundation.SiemensS7\ThingsGateway.Foundation.SiemensS7.csproj" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -186,7 +186,7 @@ public class Dlt645_2007Send : ISendMessage
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var lenSpan = writerLenAnchor.Rewind(ref byteBlock, out var length);
 | 
					        var lenSpan = writerLenAnchor.Rewind(ref byteBlock, out var length);
 | 
				
			||||||
        lenSpan.WriteValue<byte>((byte)(length - 1));//数据域长度
 | 
					        lenSpan.WriteValue<byte>((byte)(length));//数据域长度
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int num = 0;
 | 
					        int num = 0;
 | 
				
			||||||
        for (int index = 0; index < byteBlock.WrittenCount - SendHeadCodeIndex; ++index)
 | 
					        for (int index = 0; index < byteBlock.WrittenCount - SendHeadCodeIndex; ++index)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@ public class ModbusRequest
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 站号
 | 
					    /// 站号
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public byte Station { get; set; }
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #endregion Request
 | 
					    #endregion Request
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,7 +69,6 @@ public class ModbusRtuSend : ISendMessage
 | 
				
			|||||||
        else if (wf == 15 || wf == 16)
 | 
					        else if (wf == 15 || wf == 16)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var data = ModbusAddress.MasterWriteDatas.ArrayExpandToLengthEven().Span;
 | 
					            var data = ModbusAddress.MasterWriteDatas.ArrayExpandToLengthEven().Span;
 | 
				
			||||||
            WriterExtension.WriteValue(ref byteBlock, (ushort)(data.Length + 7), EndianType.Big);
 | 
					 | 
				
			||||||
            WriterExtension.WriteValue(ref byteBlock, (byte)ModbusAddress.Station);
 | 
					            WriterExtension.WriteValue(ref byteBlock, (byte)ModbusAddress.Station);
 | 
				
			||||||
            WriterExtension.WriteValue(ref byteBlock, (byte)ModbusAddress.WriteFunctionCode);
 | 
					            WriterExtension.WriteValue(ref byteBlock, (byte)ModbusAddress.WriteFunctionCode);
 | 
				
			||||||
            WriterExtension.WriteValue(ref byteBlock, (ushort)ModbusAddress.StartAddress, EndianType.Big);
 | 
					            WriterExtension.WriteValue(ref byteBlock, (ushort)ModbusAddress.StartAddress, EndianType.Big);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,7 +97,9 @@ public class ModbusSlave : DeviceBase, IModbusAddress
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
 | 
					        return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    protected override void SetChannel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override DataHandlingAdapter GetDataAdapter()
 | 
					    public override DataHandlingAdapter GetDataAdapter()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@
 | 
				
			|||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
 | 
							<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
 | 
				
			||||||
		<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.244" />
 | 
							<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.244" />
 | 
				
			||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.String;
 | 
					using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
using ThingsGateway.Foundation.Modbus;
 | 
					using ThingsGateway.Foundation.Modbus;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using TouchSocket.Core;
 | 
					using TouchSocket.Core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,14 +29,14 @@ public class ModbusTest
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [Theory]
 | 
					    [Theory]
 | 
				
			||||||
    [InlineData("400045", true, "00010000002F01032C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
 | 
					    [InlineData("400045", true, "00020000002F01032C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
 | 
				
			||||||
    [InlineData("300045", true, "00010000002F01042C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
 | 
					    [InlineData("300045", true, "00020000002F01042C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
 | 
				
			||||||
    [InlineData("100045", true, "000100000009010206000000000000")]
 | 
					    [InlineData("100045", true, "000200000009010206000000000000")]
 | 
				
			||||||
    [InlineData("000045", true, "000100000009010106000000000000")]
 | 
					    [InlineData("000045", true, "000200000009010106000000000000")]
 | 
				
			||||||
    [InlineData("400045", false, "0001000000060106002C0001", "1", DataTypeEnum.UInt16)]
 | 
					    [InlineData("400045", false, "0002000000060106002C0001", "1", DataTypeEnum.UInt16)]
 | 
				
			||||||
    [InlineData("000045", false, "0001000000060105002CFF00", "true", DataTypeEnum.Boolean)]
 | 
					    [InlineData("000045", false, "0002000000060105002CFF00", "true", DataTypeEnum.Boolean)]
 | 
				
			||||||
    [InlineData("400045;w=16", false, "0001000000090110002C0001020001", "1", DataTypeEnum.UInt16)]
 | 
					    [InlineData("400045;w=16", false, "0002000000090110002C0001020001", "1", DataTypeEnum.UInt16)]
 | 
				
			||||||
    [InlineData("000045;w=15", false, "000100000008010F002C00010101", "true", DataTypeEnum.Boolean)]
 | 
					    [InlineData("000045;w=15", false, "000200000008010F002C00010101", "true", DataTypeEnum.Boolean)]
 | 
				
			||||||
    public async Task ModbusTcp_ReadWrite_OK(string address, bool read, string data, string writeData = null, DataTypeEnum dataTypeEnum = DataTypeEnum.UInt16)
 | 
					    public async Task ModbusTcp_ReadWrite_OK(string address, bool read, string data, string writeData = null, DataTypeEnum dataTypeEnum = DataTypeEnum.UInt16)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var modbusChannel = new TouchSocketConfig().GetChannel(new ChannelOptions()
 | 
					        var modbusChannel = new TouchSocketConfig().GetChannel(new ChannelOptions()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.String;
 | 
					using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
using ThingsGateway.Foundation.SiemensS7;
 | 
					using ThingsGateway.Foundation.SiemensS7;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using TouchSocket.Core;
 | 
					using TouchSocket.Core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,8 +30,8 @@ public class SiemensS7Test
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [Theory]
 | 
					    [Theory]
 | 
				
			||||||
    [InlineData("M100", true, "03 00 00 1B 02 F0 80 32 03 00 00 00 01 00 02 00 06 00 00 04 01 FF 04 00 10 00 00")]
 | 
					    [InlineData("M100", true, "03 00 00 1B 02 F0 80 32 03 00 00 00 02 00 02 00 06 00 00 04 01 FF 04 00 10 00 00")]
 | 
				
			||||||
    [InlineData("M100", false, "03 00 00 16 02 F0 80 32 03 00 00 00 01 00 02 00 01 00 00 05 01 FF", "1", DataTypeEnum.UInt16)]
 | 
					    [InlineData("M100", false, "03 00 00 16 02 F0 80 32 03 00 00 00 02 00 02 00 01 00 00 05 01 FF", "1", DataTypeEnum.UInt16)]
 | 
				
			||||||
    public async Task SiemensS7_ReadWrite_OK(string address, bool read, string data, string writeData = null, DataTypeEnum dataTypeEnum = DataTypeEnum.UInt16)
 | 
					    public async Task SiemensS7_ReadWrite_OK(string address, bool read, string data, string writeData = null, DataTypeEnum dataTypeEnum = DataTypeEnum.UInt16)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var siemensS7Channel = new TouchSocketConfig().GetChannel(new ChannelOptions()
 | 
					        var siemensS7Channel = new TouchSocketConfig().GetChannel(new ChannelOptions()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,9 +8,8 @@
 | 
				
			|||||||
//  QQ群:605534569
 | 
					//  QQ群:605534569
 | 
				
			||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using ThingsGateway.NewLife.Extension;
 | 
					using ThingsGateway.NewLife.Extension;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
using ThingsGateway.Plugin.QuestDB;
 | 
					using ThingsGateway.Plugin.QuestDB;
 | 
				
			||||||
using ThingsGateway.Plugin.SqlDB;
 | 
					using ThingsGateway.Plugin.SqlDB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,7 +22,7 @@ internal static class Helper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        var dest = new SQLHistoryValue();
 | 
					        var dest = new SQLHistoryValue();
 | 
				
			||||||
        dest.Id = src.Id;
 | 
					        dest.Id = src.Id;
 | 
				
			||||||
        dest.Value = GetValue(src.Value);
 | 
					        dest.Value = JsonElementExtensions.GetValue(src.Value, true);
 | 
				
			||||||
        dest.CreateTime = DateTime.Now;
 | 
					        dest.CreateTime = DateTime.Now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dest.CollectTime = src.CollectTime;
 | 
					        dest.CollectTime = src.CollectTime;
 | 
				
			||||||
@@ -43,7 +42,7 @@ internal static class Helper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        var dest = new SQLHistoryValue();
 | 
					        var dest = new SQLHistoryValue();
 | 
				
			||||||
        dest.Id = src.Id;
 | 
					        dest.Id = src.Id;
 | 
				
			||||||
        dest.Value = GetValue(src.Value);
 | 
					        dest.Value = JsonElementExtensions.GetValue(src.Value, true);
 | 
				
			||||||
        dest.CreateTime = DateTime.Now;
 | 
					        dest.CreateTime = DateTime.Now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dest.CollectTime = src.CollectTime;
 | 
					        dest.CollectTime = src.CollectTime;
 | 
				
			||||||
@@ -121,8 +120,9 @@ internal static class Helper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        var dest = new SQLRealValue();
 | 
					        var dest = new SQLRealValue();
 | 
				
			||||||
        dest.Id = src.Id;
 | 
					        dest.Id = src.Id;
 | 
				
			||||||
        dest.Value = GetValue(src.Value);
 | 
					        dest.Value = JsonElementExtensions.GetValue(src.Value, true);
 | 
				
			||||||
        dest.CollectTime = src.CollectTime;
 | 
					        dest.CollectTime = src.CollectTime;
 | 
				
			||||||
 | 
					        //dest.UpdateTime = DateTime.Now;
 | 
				
			||||||
        dest.DeviceName = src.DeviceName;
 | 
					        dest.DeviceName = src.DeviceName;
 | 
				
			||||||
        dest.IsOnline = src.IsOnline;
 | 
					        dest.IsOnline = src.IsOnline;
 | 
				
			||||||
        dest.Name = src.Name;
 | 
					        dest.Name = src.Name;
 | 
				
			||||||
@@ -145,8 +145,9 @@ internal static class Helper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        var dest = new SQLRealValue();
 | 
					        var dest = new SQLRealValue();
 | 
				
			||||||
        dest.Id = src.Id;
 | 
					        dest.Id = src.Id;
 | 
				
			||||||
        dest.Value = GetValue(src.Value);
 | 
					        dest.Value = JsonElementExtensions.GetValue(src.Value, true);
 | 
				
			||||||
        dest.CollectTime = src.CollectTime;
 | 
					        dest.CollectTime = src.CollectTime;
 | 
				
			||||||
 | 
					        //dest.UpdateTime = DateTime.Now;
 | 
				
			||||||
        dest.DeviceName = src.DeviceName;
 | 
					        dest.DeviceName = src.DeviceName;
 | 
				
			||||||
        dest.IsOnline = src.IsOnline;
 | 
					        dest.IsOnline = src.IsOnline;
 | 
				
			||||||
        dest.Name = src.Name;
 | 
					        dest.Name = src.Name;
 | 
				
			||||||
@@ -172,7 +173,7 @@ internal static class Helper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        var dest = new QuestDBHistoryValue();
 | 
					        var dest = new QuestDBHistoryValue();
 | 
				
			||||||
        dest.Id = src.Id;
 | 
					        dest.Id = src.Id;
 | 
				
			||||||
        dest.Value = GetValue(src.Value);
 | 
					        dest.Value = JsonElementExtensions.GetValue(src.Value, true);
 | 
				
			||||||
        dest.CreateTime = DateTime.UtcNow;
 | 
					        dest.CreateTime = DateTime.UtcNow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime;
 | 
					        dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime;
 | 
				
			||||||
@@ -192,7 +193,7 @@ internal static class Helper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        var dest = new QuestDBHistoryValue();
 | 
					        var dest = new QuestDBHistoryValue();
 | 
				
			||||||
        dest.Id = src.Id;
 | 
					        dest.Id = src.Id;
 | 
				
			||||||
        dest.Value = GetValue(src.Value);
 | 
					        dest.Value = JsonElementExtensions.GetValue(src.Value, true);
 | 
				
			||||||
        dest.CreateTime = DateTime.UtcNow;
 | 
					        dest.CreateTime = DateTime.UtcNow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime;
 | 
					        dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime;
 | 
				
			||||||
@@ -252,26 +253,4 @@ internal static class Helper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static string GetValue(object src)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (src != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (src is string strValue)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return strValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (src is bool boolValue)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return boolValue ? "1" : "0";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return JToken.FromObject(src).ToString();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return string.Empty;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ public class RealDBProducerProperty : BusinessPropertyWithCacheInterval
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 历史表脚本
 | 
					    /// 历史表脚本
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [DynamicProperty(Remark = "必须为间隔上传,才生效")]
 | 
					    [DynamicProperty]
 | 
				
			||||||
    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
    public string? BigTextScriptHistoryTable { get; set; }
 | 
					    public string? BigTextScriptHistoryTable { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,6 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariable
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        _db.DbMaintenance.CreateDatabase();
 | 
					        _db.DbMaintenance.CreateDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //必须为间隔上传
 | 
					 | 
				
			||||||
        if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
 | 
					        if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            DynamicSQLBase? hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
 | 
					            DynamicSQLBase? hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,4 +58,9 @@ public class SQLRealValue : IPrimaryIdEntity
 | 
				
			|||||||
    [AutoGenerateColumn(Order = 22, Visible = true, Sortable = true, Filterable = false)]
 | 
					    [AutoGenerateColumn(Order = 22, Visible = true, Sortable = true, Filterable = false)]
 | 
				
			||||||
    [SugarColumn(ColumnDescription = "采集时间")]
 | 
					    [SugarColumn(ColumnDescription = "采集时间")]
 | 
				
			||||||
    public DateTime CollectTime { get; set; }
 | 
					    public DateTime CollectTime { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //[AutoGenerateColumn(Order = 23, Visible = true, Sortable = true, Filterable = false)]
 | 
				
			||||||
 | 
					    //[SugarColumn(ColumnDescription = "更新时间")]
 | 
				
			||||||
 | 
					    //public DateTime UpdateTime { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -112,7 +112,6 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        _db.DbMaintenance.CreateDatabase();
 | 
					        _db.DbMaintenance.CreateDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //必须为间隔上传
 | 
					 | 
				
			||||||
        if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
 | 
					        if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
 | 
					            var hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,13 +69,13 @@ public class SqlDBProducerProperty : BusinessPropertyWithCacheInterval
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 实时表脚本
 | 
					    /// 实时表脚本
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [DynamicProperty(Remark = "必须为间隔上传,才生效")]
 | 
					    [DynamicProperty]
 | 
				
			||||||
    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
    public string? BigTextScriptRealTable { get; set; }
 | 
					    public string? BigTextScriptRealTable { get; set; }
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 历史表脚本
 | 
					    /// 历史表脚本
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [DynamicProperty(Remark = "必须为间隔上传,才生效")]
 | 
					    [DynamicProperty]
 | 
				
			||||||
    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
    public string? BigTextScriptHistoryTable { get; set; }
 | 
					    public string? BigTextScriptHistoryTable { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,7 +102,6 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariable
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        _db.DbMaintenance.CreateDatabase();
 | 
					        _db.DbMaintenance.CreateDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //必须为间隔上传
 | 
					 | 
				
			||||||
        if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
 | 
					        if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
 | 
					            var hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,13 +8,12 @@
 | 
				
			|||||||
//  QQ群:605534569
 | 
					//  QQ群:605534569
 | 
				
			||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using System.Diagnostics;
 | 
					using System.Diagnostics;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Extension.Generic;
 | 
					using ThingsGateway.Extension.Generic;
 | 
				
			||||||
using ThingsGateway.Foundation;
 | 
					using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
using ThingsGateway.Plugin.DB;
 | 
					using ThingsGateway.Plugin.DB;
 | 
				
			||||||
using ThingsGateway.SqlSugar;
 | 
					using ThingsGateway.SqlSugar;
 | 
				
			||||||
using ThingsGateway.SqlSugar.TDengine;
 | 
					using ThingsGateway.SqlSugar.TDengine;
 | 
				
			||||||
@@ -155,7 +154,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                foreach (var item in variableGroup)
 | 
					                foreach (var item in variableGroup)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    stringBuilder.Append($"""(NOW,"{item.CollectTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}",{item.Id},{item.IsOnline},"{GetValue(item)}"),""");
 | 
					                    stringBuilder.Append($"""(NOW,"{item.CollectTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}",{item.Id},{item.IsOnline},"{JsonElementExtensions.GetValue(item.Value, true)}"),""");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                stringBuilder.Remove(stringBuilder.Length - 1, 1);
 | 
					                stringBuilder.Remove(stringBuilder.Length - 1, 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -174,28 +173,6 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariable
 | 
				
			|||||||
            LogMessage?.Trace($"TableName:{tableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms");
 | 
					            LogMessage?.Trace($"TableName:{tableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private string GetValue(VariableBasicData src)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (src.Value != null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (src.Value is string strValue)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return strValue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (src.Value is bool boolValue)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return boolValue ? "1" : "0";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return JToken.FromObject(src.Value).ToString();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return string.Empty;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #endregion 方法
 | 
					    #endregion 方法
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using Microsoft.Extensions.Localization;
 | 
					using Microsoft.Extensions.Localization;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Modbus;
 | 
					using ThingsGateway.Foundation.Modbus;
 | 
				
			||||||
@@ -114,7 +112,8 @@ public class ModbusSlave : BusinessBase
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await _plc.ConnectAsync(cancellationToken).ConfigureAwait(false);
 | 
					            if (channel.ChannelType == ChannelTypeEnum.TcpService)
 | 
				
			||||||
 | 
					                await _plc.ConnectAsync(cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch
 | 
					        catch
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -184,11 +183,11 @@ public class ModbusSlave : BusinessBase
 | 
				
			|||||||
            var type = variableRuntime.GetPropertyValue(CurrentDevice.Id, nameof(ModbusSlaveVariableProperty.DataType));
 | 
					            var type = variableRuntime.GetPropertyValue(CurrentDevice.Id, nameof(ModbusSlaveVariableProperty.DataType));
 | 
				
			||||||
            if (Enum.TryParse(type, out DataTypeEnum result))
 | 
					            if (Enum.TryParse(type, out DataTypeEnum result))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                await _plc.WriteJTokenAsync(item.Key, JToken.FromObject(variableRuntime.Value), result, cancellationToken).ConfigureAwait(false);
 | 
					                await _plc.WriteJTokenAsync(item.Key, (variableRuntime.Value).GetJTokenFromObj(), result, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                await _plc.WriteJTokenAsync(item.Key, JToken.FromObject(variableRuntime.Value), variableRuntime.DataType, cancellationToken).ConfigureAwait(false);
 | 
					                await _plc.WriteJTokenAsync(item.Key, (variableRuntime.Value).GetJTokenFromObj(), variableRuntime.DataType, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "ThingsGateway.Plugin.Mqtt.MqttClientProperty": {
 | 
					  "ThingsGateway.Plugin.Mqtt.MqttClientProperty": {
 | 
				
			||||||
 | 
					    "BigTextScriptPluginEventDataModel": "BigTextScriptPluginEventDataModel",
 | 
				
			||||||
    "CAFile_BrowserFile": "CAFile",
 | 
					    "CAFile_BrowserFile": "CAFile",
 | 
				
			||||||
    "ClientCertificateFile_BrowserFile": "ClientCertificateFile",
 | 
					    "ClientCertificateFile_BrowserFile": "ClientCertificateFile",
 | 
				
			||||||
    "ClientKeyFile_BrowserFile": "ClientKeyFile",
 | 
					    "ClientKeyFile_BrowserFile": "ClientKeyFile",
 | 
				
			||||||
@@ -40,6 +41,7 @@
 | 
				
			|||||||
    "WebSocketUrl": "WebSocketUrl"
 | 
					    "WebSocketUrl": "WebSocketUrl"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "ThingsGateway.Plugin.Mqtt.MqttServerProperty": {
 | 
					  "ThingsGateway.Plugin.Mqtt.MqttServerProperty": {
 | 
				
			||||||
 | 
					    "BigTextScriptPluginEventDataModel": "BigTextScriptPluginEventDataModel",
 | 
				
			||||||
    "AnonymousEnable": "AnonymousEnable",
 | 
					    "AnonymousEnable": "AnonymousEnable",
 | 
				
			||||||
    "DeviceRpcEnable": "DeviceRpcEnable",
 | 
					    "DeviceRpcEnable": "DeviceRpcEnable",
 | 
				
			||||||
    "IP": "IP",
 | 
					    "IP": "IP",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "ThingsGateway.Plugin.Mqtt.MqttClientProperty": {
 | 
					  "ThingsGateway.Plugin.Mqtt.MqttClientProperty": {
 | 
				
			||||||
 | 
					    "BigTextScriptPluginEventDataModel": "插件事件上传脚本",
 | 
				
			||||||
    "CAFile_BrowserFile": "CA文件",
 | 
					    "CAFile_BrowserFile": "CA文件",
 | 
				
			||||||
    "ClientCertificateFile_BrowserFile": "客户端证书",
 | 
					    "ClientCertificateFile_BrowserFile": "客户端证书",
 | 
				
			||||||
    "ClientKeyFile_BrowserFile": "客户端key文件",
 | 
					    "ClientKeyFile_BrowserFile": "客户端key文件",
 | 
				
			||||||
@@ -40,6 +41,7 @@
 | 
				
			|||||||
    "WebSocketUrl": "WebSocketUrl"
 | 
					    "WebSocketUrl": "WebSocketUrl"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "ThingsGateway.Plugin.Mqtt.MqttServerProperty": {
 | 
					  "ThingsGateway.Plugin.Mqtt.MqttServerProperty": {
 | 
				
			||||||
 | 
					    "BigTextScriptPluginEventDataModel": "插件事件上传脚本",
 | 
				
			||||||
    "AnonymousEnable": "允许匿名登录",
 | 
					    "AnonymousEnable": "允许匿名登录",
 | 
				
			||||||
    "DeviceRpcEnable": "允许Rpc写入",
 | 
					    "DeviceRpcEnable": "允许Rpc写入",
 | 
				
			||||||
    "IP": "IP",
 | 
					    "IP": "IP",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,4 +124,8 @@ public class MqttClientProperty : BusinessPropertyWithCacheIntervalScript
 | 
				
			|||||||
    [DynamicProperty]
 | 
					    [DynamicProperty]
 | 
				
			||||||
    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
    public string? BigTextScriptRpc { get; set; }
 | 
					    public string? BigTextScriptRpc { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [DynamicProperty]
 | 
				
			||||||
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
 | 
					    public override string? BigTextScriptPluginEventDataModel { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,4 +76,8 @@ public class MqttServerProperty : BusinessPropertyWithCacheIntervalScript
 | 
				
			|||||||
    [DynamicProperty]
 | 
					    [DynamicProperty]
 | 
				
			||||||
    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
    public string? BigTextScriptRpc { get; set; }
 | 
					    public string? BigTextScriptRpc { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [DynamicProperty]
 | 
				
			||||||
 | 
					    [AutoGenerateColumn(Visible = true, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false)]
 | 
				
			||||||
 | 
					    public override string? BigTextScriptPluginEventDataModel { get; set; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ using System.Globalization;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.OpcUa;
 | 
					using ThingsGateway.Foundation.OpcUa;
 | 
				
			||||||
using ThingsGateway.Gateway.Application;
 | 
					using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
using ThingsGateway.NewLife.Reflection;
 | 
					using ThingsGateway.NewLife.Reflection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using TouchSocket.Core;
 | 
					using TouchSocket.Core;
 | 
				
			||||||
@@ -300,7 +301,7 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                SetDataType(tag, value);
 | 
					                SetDataType(tag, value);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            var jToken = JToken.FromObject(value);
 | 
					            var jToken = (value).GetJTokenFromObj();
 | 
				
			||||||
            var dataValue = JsonUtils.DecoderObject(
 | 
					            var dataValue = JsonUtils.DecoderObject(
 | 
				
			||||||
               Server.MessageContext,
 | 
					               Server.MessageContext,
 | 
				
			||||||
           tag.DataType,
 | 
					           tag.DataType,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								src/ThingsGateway.ScriptDebug/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/ThingsGateway.ScriptDebug/Program.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://thingsgateway.cn/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.ResponseCompression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Admin.Application;
 | 
				
			||||||
 | 
					using ThingsGateway.DB;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife;
 | 
				
			||||||
 | 
					using ThingsGateway.NewLife.Log;
 | 
				
			||||||
 | 
					using ThingsGateway.SqlSugar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Program
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static async Task Main(string[] args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
 | 
					        await Task.Delay(2000).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										263
									
								
								src/ThingsGateway.ScriptDebug/Test/TestCollectPlugin.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								src/ThingsGateway.ScriptDebug/Test/TestCollectPlugin.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,263 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					//using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					//namespace ThingsGateway.Server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///// <summary>
 | 
				
			||||||
 | 
					///// 插件类,默认实现了<see cref="IDevice"/>接口,继承<see cref="CollectFoundationBase"/> 实现采集插件
 | 
				
			||||||
 | 
					///// </summary>
 | 
				
			||||||
 | 
					//public class TestCollectPlugin : CollectFoundationBase
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 调试UI Type,如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverDebugUIType => base.DriverDebugUIType;
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件属性UI Type,继承<see cref="IPropertyUIBase"/>如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverPropertyUIType => base.DriverPropertyUIType;
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件UI Type,继承<see cref="IDriverUIBase"/>如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverUIType => base.DriverUIType;
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件变量寄存器UI Type,继承<see cref="IAddressUIBase"/>如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverVariableAddressUIType => base.DriverVariableAddressUIType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件配置项,继承<see cref="CollectPropertyBase"/> 返回类实例
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override CollectPropertyBase CollectProperties => _property;
 | 
				
			||||||
 | 
					//    private TestCollectProperty? _property = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 在插件初始化时调用,只会执行一次,参数为插件默认的链路通道类,如未实现可忽略l
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        //做一些初始化操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        return Task.CompletedTask;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 变量打包操作,会在默认的AfterVariablesChangedAsync方法里执行,参数为设备变量列表,返回源读取变量列表
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        //实现将设备变量打包成源读取变量
 | 
				
			||||||
 | 
					//        //比如如果需要实现MC中的字多读功能,需将多个变量地址打包成一个源读取地址和读取长度,根据一系列规则,添加解析标识,然后在返回的整个字节数组中解析出原来的变量地址代表的数据字节
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        //一般可操作 VariableRuntime 类中的 index, thingsgatewaybitconvter 等属性
 | 
				
			||||||
 | 
					//        //一般可操作 VariableSourceRead 类中的 address, length 等属性
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        return Task.FromResult(new List<VariableSourceRead>());
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 实现<see cref="IDevice"/>
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override IDevice? FoundationDevice => base.FoundationDevice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 特殊方法,添加<see cref="DynamicMethodAttribute"/> 特性 ,返回IOperResult
 | 
				
			||||||
 | 
					//    /// 支持<see cref="CancellationToken"/> 参数,需放到最后
 | 
				
			||||||
 | 
					//    /// 默认解析方式为英文分号
 | 
				
			||||||
 | 
					//    /// 比如rpc参数为 test1;test2,解析query1="test1",query2="test2"
 | 
				
			||||||
 | 
					//    /// 也可以在变量地址中填入test1,rpc参数传入test2,解析query1="test1",query2="test2"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    [DynamicMethod("测试特殊方法")]
 | 
				
			||||||
 | 
					//    public IOperResult<string> TestMethod(string query1, string query2, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return new OperResult<string>() { Content = "测试特殊方法" };
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///// <summary>
 | 
				
			||||||
 | 
					///// 插件类配置
 | 
				
			||||||
 | 
					///// </summary>
 | 
				
			||||||
 | 
					//public class TestCollectProperty : CollectFoundationPackPropertyBase
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 添加<see cref="DynamicPropertyAttribute"/> 特性,如需多语言配置,可添加json资源,参考其他插件
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    [DynamicProperty(Description = null, Remark = null)]
 | 
				
			||||||
 | 
					//    public string TestString { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///// <summary>
 | 
				
			||||||
 | 
					///// 插件类,完全自定义
 | 
				
			||||||
 | 
					///// </summary>
 | 
				
			||||||
 | 
					//public class TestCollectPlugin1 : CollectBase
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 调试UI Type,如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverDebugUIType => base.DriverDebugUIType;
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件属性UI Type,继承<see cref="IPropertyUIBase"/>如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverPropertyUIType => base.DriverPropertyUIType;
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件UI Type,继承<see cref="IDriverUIBase"/>如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverUIType => base.DriverUIType;
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件变量寄存器UI Type,继承<see cref="IAddressUIBase"/>如果不存在无需重写
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override Type DriverVariableAddressUIType => base.DriverVariableAddressUIType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 插件配置项,继承<see cref="CollectPropertyBase"/> 返回类实例
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public override CollectPropertyBase CollectProperties => _property;
 | 
				
			||||||
 | 
					//    private TestCollectProperty1? _property = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 在插件初始化时调用,只会执行一次,参数为插件默认的链路通道类,如未实现可忽略l
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        //做一些初始化操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        return Task.CompletedTask;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 变量打包操作,会在默认的AfterVariablesChangedAsync方法里执行,参数为设备变量列表,返回源读取变量列表
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        //实现将设备变量打包成源读取变量
 | 
				
			||||||
 | 
					//        //比如如果需要实现MC中的字多读功能,需将多个变量地址打包成一个源读取地址和读取长度,根据一系列规则,添加解析标识,然后在返回的整个字节数组中解析出原来的变量地址代表的数据字节
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        //一般可操作 VariableRuntime 类中的 index, thingsgatewaybitconvter 等属性
 | 
				
			||||||
 | 
					//        //一般可操作 VariableSourceRead 类中的 address, length 等属性
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        return Task.FromResult(new List<VariableSourceRead>());
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 如果不实现ReadSourceAsync方法,可以返回flase
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override bool VariableSourceReadsEnable => base.VariableSourceReadsEnable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 获取任务列表,默认会实现 TestOnline任务,SetDeviceStatus任务以及 VariableSourceRead等任务,VariableSourceRead任务启用条件为<see cref="VariableSourceReadsEnable"/> 为true。任务即是timer实现,可通过<see cref="ScheduledTaskHelper.GetTask(string, Func{object?, CancellationToken, Task}, object?, TouchSocket.Core.ILog, CancellationToken)"/> 方法实现定时任务
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    /// <param name="cancellationToken"></param>
 | 
				
			||||||
 | 
					//    /// <returns></returns>
 | 
				
			||||||
 | 
					//    protected override List<IScheduledTask> ProtectedGetTasks(CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.ProtectedGetTasks(cancellationToken);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 实现离线重连任务
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    /// <param name="state"></param>
 | 
				
			||||||
 | 
					//    /// <param name="cancellationToken"></param>
 | 
				
			||||||
 | 
					//    /// <returns></returns>
 | 
				
			||||||
 | 
					//    protected override Task TestOnline(object? state, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.TestOnline(state, cancellationToken);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 返回是否成功连接设备
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    /// <returns></returns>
 | 
				
			||||||
 | 
					//    public override bool IsConnected()
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return true;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 在变量发生组态变化后执行,默认会执行<see cref="ProtectedLoadSourceReadAsync"/> 方法,重新获取源读取变量列表,并且重新启动VariableSourceRead等任务
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    /// <param name="cancellationToken"></param>
 | 
				
			||||||
 | 
					//    /// <returns></returns>
 | 
				
			||||||
 | 
					//    public override Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.AfterVariablesChangedAsync(cancellationToken);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 变量寄存器的字符串描述
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    /// <returns></returns>
 | 
				
			||||||
 | 
					//    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.GetAddressDescription();
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 设备暂停时执行,默认会暂停所有任务
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    /// <param name="pause"></param>
 | 
				
			||||||
 | 
					//    public override void PauseThread(bool pause)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        base.PauseThread(pause);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 开始前执行
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override Task ProtectedStartAsync(CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        //一般实现PLC长连接
 | 
				
			||||||
 | 
					//        return base.ProtectedStartAsync(cancellationToken);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 写入变量,实现设备写入操作,注意执行写锁,        using var writeLock =await ReadWriteLock.WriterLockAsync(cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override ValueTask<Dictionary<string, OperResult>> WriteValuesAsync(Dictionary<VariableRuntime, JToken> writeInfoLists, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.WriteValuesAsync(writeInfoLists, cancellationToken);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 读取源变量,在<see cref="VariableSourceReadsEnable"/> 为true时,添加源读取任务,任务启动时会执行
 | 
				
			||||||
 | 
					//    /// 一般需要更新设备变量值,调用<see cref="VariableRuntime.SetValue(object?, DateTime, bool)"/>
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    protected override ValueTask<OperResult<ReadOnlyMemory<byte>>> ReadSourceAsync(VariableSourceRead variableSourceRead, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.ReadSourceAsync(variableSourceRead, cancellationToken);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    protected override Task DisposeAsync(bool disposing)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return base.DisposeAsync(disposing);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 特殊方法,添加<see cref="DynamicMethodAttribute"/> 特性 ,返回IOperResult
 | 
				
			||||||
 | 
					//    /// 支持<see cref="CancellationToken"/> 参数,需放到最后
 | 
				
			||||||
 | 
					//    /// 默认解析方式为英文分号
 | 
				
			||||||
 | 
					//    /// 比如rpc参数为 test1;test2,解析query1="test1",query2="test2"
 | 
				
			||||||
 | 
					//    /// 也可以在变量地址中填入test1,rpc参数传入test2,解析query1="test1",query2="test2"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    [DynamicMethod("测试特殊方法")]
 | 
				
			||||||
 | 
					//    public IOperResult<string> TestMethod(string query1, string query2, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        return new OperResult<string>() { Content = "测试特殊方法" };
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///// <summary>
 | 
				
			||||||
 | 
					///// 插件类配置
 | 
				
			||||||
 | 
					///// </summary>
 | 
				
			||||||
 | 
					//public class TestCollectProperty1 : CollectPropertyBase
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 添加<see cref="DynamicPropertyAttribute"/> 特性,如需多语言配置,可添加json资源,参考其他插件
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    [DynamicProperty(Description = null, Remark = null)]
 | 
				
			||||||
 | 
					//    public string TestString { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
							
								
								
									
										56
									
								
								src/ThingsGateway.ScriptDebug/Test/TestDynamicModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/ThingsGateway.ScriptDebug/Test/TestDynamicModel.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					//////------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					////// 此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					////// 源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					////// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					////// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					////// 使用文档:https://thingsgateway.cn/
 | 
				
			||||||
 | 
					////// QQ群:605534569
 | 
				
			||||||
 | 
					////// ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using System.Dynamic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					//using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					//public class TestDynamicModel : IDynamicModel
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        if (datas == null) return null;
 | 
				
			||||||
 | 
					//        List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
 | 
				
			||||||
 | 
					//        //按设备名称分组
 | 
				
			||||||
 | 
					//        var groups = datas.Where(a => !string.IsNullOrEmpty(((AlarmVariable)a).DeviceName)).GroupBy(a => ((AlarmVariable)a).DeviceName, a => ((AlarmVariable)a));
 | 
				
			||||||
 | 
					//        foreach (var group in groups)
 | 
				
			||||||
 | 
					//        {
 | 
				
			||||||
 | 
					//            //按采集时间分组
 | 
				
			||||||
 | 
					//            var data = group.GroupBy(a => a.AlarmTime.DateTimeToUnixTimestamp());
 | 
				
			||||||
 | 
					//            var deviceObj = new ExpandoObject();
 | 
				
			||||||
 | 
					//            List<ExpandoObject> expandos = new List<ExpandoObject>();
 | 
				
			||||||
 | 
					//            foreach (var item in data)
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                var expando = new ExpandoObject();
 | 
				
			||||||
 | 
					//                expando.TryAdd("ts", item.Key);
 | 
				
			||||||
 | 
					//                var variableObj = new ExpandoObject();
 | 
				
			||||||
 | 
					//                foreach (var tag in item)
 | 
				
			||||||
 | 
					//                {
 | 
				
			||||||
 | 
					//                    var alarmObj = new ExpandoObject();
 | 
				
			||||||
 | 
					//                    alarmObj.TryAdd(nameof(tag.AlarmCode), tag.AlarmCode);
 | 
				
			||||||
 | 
					//                    alarmObj.TryAdd(nameof(tag.AlarmText), tag.AlarmText);
 | 
				
			||||||
 | 
					//                    alarmObj.TryAdd(nameof(tag.AlarmType), tag.AlarmType);
 | 
				
			||||||
 | 
					//                    alarmObj.TryAdd(nameof(tag.AlarmLimit), tag.AlarmLimit);
 | 
				
			||||||
 | 
					//                    alarmObj.TryAdd(nameof(tag.EventTime), tag.EventTime);
 | 
				
			||||||
 | 
					//                    alarmObj.TryAdd(nameof(tag.EventType), tag.EventType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//                    variableObj.TryAdd(tag.Name, alarmObj);
 | 
				
			||||||
 | 
					//                }
 | 
				
			||||||
 | 
					//                expando.TryAdd("alarms", variableObj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//                expandos.Add(expando);
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					//            deviceObj.TryAdd(group.Key, expandos);
 | 
				
			||||||
 | 
					//            deviceObjs.Add(deviceObj);
 | 
				
			||||||
 | 
					//        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        return deviceObjs;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//public class TestExexcuteExpressions : IExexcuteExpressions
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    public TouchSocket.Core.ILog Logger { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    public async System.Threading.Tasks.Task<NodeOutput> ExecuteAsync(NodeInput input, System.Threading.CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        //想上传mqtt,可以自己写mqtt上传代码,或者通过mqtt插件的公开方法上传
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        //直接获取mqttclient插件类型的第一个设备
 | 
				
			||||||
 | 
					//        var mqttClient = GlobalData.ReadOnlyChannels.FirstOrDefault(a => a.Value.PluginName == "ThingsGateway.Plugin.Mqtt.MqttClient").Value?.ReadDeviceRuntimes?.FirstOrDefault().Value?.Driver as ThingsGateway.Plugin.Mqtt.MqttClient;
 | 
				
			||||||
 | 
					//        if (mqttClient == null)
 | 
				
			||||||
 | 
					//            throw new("mqttClient NOT FOUND");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        TopicArray topicArray = new()
 | 
				
			||||||
 | 
					//        {
 | 
				
			||||||
 | 
					//            Topic = "test",
 | 
				
			||||||
 | 
					//            Payload = Encoding.UTF8.GetBytes("test")
 | 
				
			||||||
 | 
					//        };
 | 
				
			||||||
 | 
					//        var result = await mqttClient.MqttUpAsync(topicArray, default).ConfigureAwait(false);// 主题 和 负载
 | 
				
			||||||
 | 
					//        if (!result.IsSuccess)
 | 
				
			||||||
 | 
					//            throw new(result.ErrorMessage);
 | 
				
			||||||
 | 
					//        return new NodeOutput() { Value = result };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        //通过设备名称找出mqttClient插件
 | 
				
			||||||
 | 
					//        //var mqttClient = GlobalData.ReadOnlyDevices.FirstOrDefault(a => a.Value.Name == "mqttDevice1").Value?.Driver as ThingsGateway.Plugin.Mqtt.MqttClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        //if (mqttClient == null)
 | 
				
			||||||
 | 
					//        //    throw new("mqttClient NOT FOUND");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        //TopicArray topicArray = new()
 | 
				
			||||||
 | 
					//        //{
 | 
				
			||||||
 | 
					//        //    Topic = "test",
 | 
				
			||||||
 | 
					//        //    Payload = Encoding.UTF8.GetBytes("test")
 | 
				
			||||||
 | 
					//        //};
 | 
				
			||||||
 | 
					//        //var result = await mqttClient.MqttUpAsync(topicArray, default).ConfigureAwait(false);// 主题 和 负载
 | 
				
			||||||
 | 
					//        //if (!result.IsSuccess)
 | 
				
			||||||
 | 
					//        //    throw new(result.ErrorMessage);
 | 
				
			||||||
 | 
					//        //return new NodeOutput() { Value = result };
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
							
								
								
									
										223
									
								
								src/ThingsGateway.ScriptDebug/Test/TestKafkaDynamicModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/ThingsGateway.ScriptDebug/Test/TestKafkaDynamicModel.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,223 @@
 | 
				
			|||||||
 | 
					//////------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					////// 此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					////// 源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					////// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					////// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					////// 使用文档:https://thingsgateway.cn/
 | 
				
			||||||
 | 
					////// QQ群:605534569
 | 
				
			||||||
 | 
					////// ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					//using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					//using ThingsGateway.NewLife.Extension;
 | 
				
			||||||
 | 
					//public class TestKafkaDynamicModel : DynamicModelBase
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    private Dictionary<string, VariableRuntime> variableRuntimes = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    private long id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    public TestKafkaDynamicModel()
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        var name = "kafka1";
 | 
				
			||||||
 | 
					//        if (GlobalData.ReadOnlyDevices.TryGetValue(name, out var kafka1))
 | 
				
			||||||
 | 
					//        {
 | 
				
			||||||
 | 
					//            id = kafka1.Id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//            foreach (var item in kafka1.Driver?.IdVariableRuntimes)
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                //变量备注1作为Key(AE报警SourceId)
 | 
				
			||||||
 | 
					//                var data1 = item.Value.GetPropertyValue(id, nameof(BusinessVariableProperty.Data1));
 | 
				
			||||||
 | 
					//                if (!data1.IsNullOrEmpty())
 | 
				
			||||||
 | 
					//                {
 | 
				
			||||||
 | 
					//                    variableRuntimes.Add(data1, item.Value);
 | 
				
			||||||
 | 
					//                }
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        }
 | 
				
			||||||
 | 
					//        else
 | 
				
			||||||
 | 
					//        {
 | 
				
			||||||
 | 
					//            throw new Exception($"找不到设备 {name}");
 | 
				
			||||||
 | 
					//        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//    public override IEnumerable<dynamic> GetList(IEnumerable<object> datas)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        if (datas == null) return null;
 | 
				
			||||||
 | 
					//        var pluginEventDatas = datas.Cast<PluginEventData>();
 | 
				
			||||||
 | 
					//        var opcDatas = pluginEventDatas.Select(
 | 
				
			||||||
 | 
					//            a =>
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                if (a.ObjectValue == null)
 | 
				
			||||||
 | 
					//                {
 | 
				
			||||||
 | 
					//                    a.ObjectValue = a.Value.ToObject(Type.GetType(a.ValueType));
 | 
				
			||||||
 | 
					//                }
 | 
				
			||||||
 | 
					//                return a.ObjectValue is ThingsGateway.Plugin.OpcAe.OpcAeEventData opcData ? opcData : null;
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					//            ).Where(a => a != null).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        List<KafkaAlarmEntity> alarmEntities = new List<KafkaAlarmEntity>();
 | 
				
			||||||
 | 
					//        if (opcDatas.Count == 0)
 | 
				
			||||||
 | 
					//        {
 | 
				
			||||||
 | 
					//            Logger?.LogInformation("没有OPCAE数据");
 | 
				
			||||||
 | 
					//            return alarmEntities;
 | 
				
			||||||
 | 
					//        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        foreach (var opcAeEventData in opcDatas)
 | 
				
			||||||
 | 
					//        {
 | 
				
			||||||
 | 
					//            //一般只需要条件报警
 | 
				
			||||||
 | 
					//            //if (opcAeEventData.EventType != Opc.Ae.EventType.Condition)
 | 
				
			||||||
 | 
					//            //    continue;
 | 
				
			||||||
 | 
					//            //重连时触发的事件,可以跳过不处理
 | 
				
			||||||
 | 
					//            //if(opcAeEventData.Refresh)
 | 
				
			||||||
 | 
					//            //    continue;
 | 
				
			||||||
 | 
					//            var sourceName = opcAeEventData.SourceID;
 | 
				
			||||||
 | 
					//            if (variableRuntimes.TryGetValue(sourceName, out var variableRuntime))
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                var ack = opcAeEventData.EventType != Opc.Ae.EventType.Condition ? false : ((Opc.Ae.ConditionState)opcAeEventData.NewState).HasFlag(Opc.Ae.ConditionState.Acknowledged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//                bool isRecover = opcAeEventData.EventType != Opc.Ae.EventType.Condition ? false : !((Opc.Ae.ConditionState)opcAeEventData.NewState).HasFlag(Opc.Ae.ConditionState.Active);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//                //构建告警实体
 | 
				
			||||||
 | 
					//                KafkaAlarmEntity alarmEntity = new KafkaAlarmEntity
 | 
				
			||||||
 | 
					//                {
 | 
				
			||||||
 | 
					//                    AlarmCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data2)), //唯一编码
 | 
				
			||||||
 | 
					//                    ResourceCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data3)), //资源编码
 | 
				
			||||||
 | 
					//                    ResourceName = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data4)), //资源名称  
 | 
				
			||||||
 | 
					//                    MetricCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data5)), //指标编码
 | 
				
			||||||
 | 
					//                    MetricName = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data6)), //指标名称
 | 
				
			||||||
 | 
					//                    Content = $"{variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data4))},{opcAeEventData.Message}", //告警内容,设备名称+告警内容(包含阈值信息),可能opcae里没有带阈值信息,那么就需要录入固定值,可选Data10
 | 
				
			||||||
 | 
					//                    AlarmType = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data7)), // opcAeEventData.Severity 告警类型,子系统产生告警的类型,可能需要固定备注值
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//                    ConfirmedTime = ack ? opcAeEventData.Time.DateTimeToUnixTimestamp() : null, //告警确认时间
 | 
				
			||||||
 | 
					//                    FixTime = isRecover ? opcAeEventData.Time.DateTimeToUnixTimestamp() : null, //解除告警时间
 | 
				
			||||||
 | 
					//                    LastTime = opcAeEventData.AlarmTime.DateTimeToUnixTimestamp(), //产生告警时间
 | 
				
			||||||
 | 
					//                    Status = isRecover ? "FIXED" : "UNFIXED", //告警状态
 | 
				
			||||||
 | 
					//                    AlarmLevel = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data8)), //opcAeEventData.Severity.ToString(), //告警等级,可能需要固定备注值
 | 
				
			||||||
 | 
					//                    SubSystemCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data9)), //子系统编码
 | 
				
			||||||
 | 
					//                    Type = "SUB_SYSTEM_ALARM", //默认填写字段
 | 
				
			||||||
 | 
					//                    ConfirmAccount = opcAeEventData.ActorID, //告警确认人
 | 
				
			||||||
 | 
					//                    ClearAccount = opcAeEventData.ActorID, //告警清除人
 | 
				
			||||||
 | 
					//                    ProcessInstruction = null //告警处理说明,OPCAE不带有
 | 
				
			||||||
 | 
					//                };
 | 
				
			||||||
 | 
					//                alarmEntities.Add(alarmEntity);
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					//            else
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                Logger?.LogInformation($"找不到相关变量{sourceName}");
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					//        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        return alarmEntities;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///// <summary>
 | 
				
			||||||
 | 
					///// 告警实体
 | 
				
			||||||
 | 
					///// </summary>
 | 
				
			||||||
 | 
					//public class KafkaAlarmEntity
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警编码唯一 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"8e8a118ac452fd04da8c26fa588a7cab"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string AlarmCode { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 资源编码,唯一编码,需要按照映射表上传 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"RS_A6K9MUSG19V"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string ResourceCode { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 资源名称,需要按照映射表上传 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"MB-A7"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string ResourceName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 指标编码唯一,需要按照映射表上传 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"ActivePowerPa"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string MetricCode { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 指标名称,需要按照映射表上传 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"有功功率Pa"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string MetricName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警内容:设备名称+告警内容(包含阈值信息) (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"MB-A7,有功功率Pa > 30"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string Content { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警类型,子系统产生告警的类型 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"0101" 表示高限报警
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string AlarmType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警确认时间 (可空,时间戳)
 | 
				
			||||||
 | 
					//    /// 示例:1586152800000
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public long? ConfirmedTime { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 解除告警时间 (可空,时间戳)
 | 
				
			||||||
 | 
					//    /// 示例:1586152800000
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public long? FixTime { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 产生告警时间 (非空,时间戳)
 | 
				
			||||||
 | 
					//    /// 示例:1586152800000
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public long LastTime { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警状态 (非空)
 | 
				
			||||||
 | 
					//    /// 可选值:UNFIXED(新增告警)、FIXED(解除告警)
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string Status { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警等级,需要按照映射表上传 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"1"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string AlarmLevel { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 子系统编码 (非空)
 | 
				
			||||||
 | 
					//    /// 示例:"MS_NEW_PD_DCIM_001"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string SubSystemCode { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 默认填写字段 (非空)
 | 
				
			||||||
 | 
					//    /// 固定值:"SUB_SYSTEM_ALARM"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string Type { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警确认人 (可空)
 | 
				
			||||||
 | 
					//    /// 示例:"admin3"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string ConfirmAccount { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警清除人 (可空)
 | 
				
			||||||
 | 
					//    /// 示例:"admin"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string ClearAccount { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    /// <summary>
 | 
				
			||||||
 | 
					//    /// 告警处理说明 (可空)
 | 
				
			||||||
 | 
					//    /// 示例:"admin"
 | 
				
			||||||
 | 
					//    /// </summary>
 | 
				
			||||||
 | 
					//    public string ProcessInstruction { get; set; }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
							
								
								
									
										46
									
								
								src/ThingsGateway.ScriptDebug/Test/TestSQL.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/ThingsGateway.ScriptDebug/Test/TestSQL.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					////------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//// 此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//// 源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//// 使用文档:https://thingsgateway.cn/
 | 
				
			||||||
 | 
					//// QQ群:605534569
 | 
				
			||||||
 | 
					//// ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					//using ThingsGateway.NewLife.Json.Extension;
 | 
				
			||||||
 | 
					//using ThingsGateway.Plugin.DB;
 | 
				
			||||||
 | 
					//using ThingsGateway.SqlSugar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//using TouchSocket.Core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//public class TestSQL : DynamicSQLBase
 | 
				
			||||||
 | 
					//{
 | 
				
			||||||
 | 
					//    public override Task DBInit(ISqlSugarClient db, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        db.DbMaintenance.CreateDatabase();
 | 
				
			||||||
 | 
					//        db.CodeFirst.InitTables<ThingsGateway.Plugin.OpcAe.OpcAeEventData>();
 | 
				
			||||||
 | 
					//        return Task.CompletedTask;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    public override async Task DBInsertable(ISqlSugarClient db, IEnumerable<object> datas, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					//    {
 | 
				
			||||||
 | 
					//        var pluginEventDatas = datas.Cast<PluginEventData>();
 | 
				
			||||||
 | 
					//        var opcDatas = pluginEventDatas.Select(
 | 
				
			||||||
 | 
					//            a =>
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                if (a.ObjectValue == null)
 | 
				
			||||||
 | 
					//                {
 | 
				
			||||||
 | 
					//                    a.ObjectValue = a.Value.ToObject(Type.GetType(a.ValueType));
 | 
				
			||||||
 | 
					//                }
 | 
				
			||||||
 | 
					//                return a.ObjectValue is ThingsGateway.Plugin.OpcAe.OpcAeEventData opcData ? opcData : null;
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					//            ).Where(a => a != null).ToList();
 | 
				
			||||||
 | 
					//        if (opcDatas.Count == 0)
 | 
				
			||||||
 | 
					//            return;
 | 
				
			||||||
 | 
					//        Logger?.Info(opcDatas.ToSystemTextJsonString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//        await db.Insertable(opcDatas).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk.Web">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Import Project="..\Version.props" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease'">
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--发布版-->
 | 
				
			||||||
 | 
						<Import Project="targets\Gateway.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
 | 
				
			||||||
 | 
						<Import Project="targets\Admin.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Import Project="targets\PluginContext.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND  '$(Configuration)' != 'Debug' " />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--nuget包解压复制文件,上下文动态加载-->
 | 
				
			||||||
 | 
						<Import Project="targets\PluginContext.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND  '$(Configuration)' != 'Debug' " />
 | 
				
			||||||
 | 
						<!--直接引用-->
 | 
				
			||||||
 | 
						<Import Project="targets\PluginDebug.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug' " />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--nuget包解压复制文件,插件域隔离动态加载-->
 | 
				
			||||||
 | 
						<!--<Import Project="targets\Plugin.targets" />-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--nuget包解压复制文件,上下文动态加载,Pro插件-->
 | 
				
			||||||
 | 
						<Import Project="targets\Pro2.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR  '$(Configuration)' != 'Debug'" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--直接引用Pro-->
 | 
				
			||||||
 | 
						<Import Project="targets\PluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Import Project="targets\ProPluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--<Import Project="targets\Pro3.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' " />
 | 
				
			||||||
 | 
						<Import Project="targets\Pro5.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' " />-->
 | 
				
			||||||
 | 
						<!--<Import Project="targets\Pro6.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug'" />-->
 | 
				
			||||||
 | 
						<!--nuget包解压复制文件,上下文动态加载,Pro插件-->
 | 
				
			||||||
 | 
						<Import Project="targets\Pro7.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR  '$(Configuration)' != 'Debug'" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--打包复制-->
 | 
				
			||||||
 | 
						<Import Project="targets\PluginPublish.targets" />
 | 
				
			||||||
 | 
						<PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<GenerateDocumentationFile>false</GenerateDocumentationFile>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
 | 
				
			||||||
 | 
							<CustomTargetFramework>$(TargetFramework)</CustomTargetFramework>
 | 
				
			||||||
 | 
							<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
 | 
				
			||||||
 | 
							<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
 | 
				
			||||||
 | 
							<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
 | 
				
			||||||
 | 
							<ApplicationIcon>favicon.ico</ApplicationIcon>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--动态适用GC-->
 | 
				
			||||||
 | 
							<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<CETCompat>false</CETCompat>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--<TieredCompilation>false</TieredCompilation>-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--使用自托管线程池-->
 | 
				
			||||||
 | 
							<!--<UseWindowsThreadPool>false</UseWindowsThreadPool> -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--使用工作站GC-->
 | 
				
			||||||
 | 
							<!--<ServerGarbageCollection>true</ServerGarbageCollection>-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--<PlatformTarget>x86</PlatformTarget>-->
 | 
				
			||||||
 | 
							<!--editbin /LARGEADDRESSAWARE:NO ThingsGateway.Server.exe-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<Content Include="favicon.ico">
 | 
				
			||||||
 | 
								<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
				
			||||||
 | 
							</Content>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "ConfigurationScanDirectories": [ "Configuration", "" ], // 扫描配置文件json文件夹(自动合并该文件夹里面所有json文件)
 | 
				
			||||||
 | 
					  "IgnoreConfigurationFiles": [ "" ],
 | 
				
			||||||
 | 
					  "ExternalAssemblies": [ "" ],
 | 
				
			||||||
 | 
					  "DetailedErrors": true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/ThingsGateway.ScriptDebug/appsettings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/ThingsGateway.ScriptDebug/appsettings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "urls": "http://*:5000",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "ConfigurationScanDirectories": [ "Configuration", "" ], // 扫描配置文件json文件夹(自动合并该文件夹里面所有json文件)
 | 
				
			||||||
 | 
					  "IgnoreConfigurationFiles": [ "" ],
 | 
				
			||||||
 | 
					  "ExternalAssemblies": [ "" ],
 | 
				
			||||||
 | 
					  "DetailedErrors": true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								src/ThingsGateway.ScriptDebug/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/ThingsGateway.ScriptDebug/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										43
									
								
								src/ThingsGateway.ScriptDebug/targets/Admin.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/ThingsGateway.ScriptDebug/targets/Admin.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!--Admin-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="ThingsGateway.Admin.Razor" Version="$(Version)" />
 | 
				
			||||||
 | 
					    <PackageReference Include="ThingsGateway.Admin.Application" Version="$(Version)" GeneratePathProperty="true"/>
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  <Target Name="_ResolveCopyAdminLocalNuGetPkgXmls" AfterTargets="ResolveReferences">
 | 
				
			||||||
 | 
					    <ItemGroup>
 | 
				
			||||||
 | 
					      <ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).xml')" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)'=='ThingsGateway.Admin.Application' and Exists('%(RootDir)%(Directory)%(Filename).xml')" />
 | 
				
			||||||
 | 
					    </ItemGroup>
 | 
				
			||||||
 | 
					  </Target>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  <Target Name="CopyAdminNugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
					    <ItemGroup>
 | 
				
			||||||
 | 
					      <!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
					      <AdminApplicationPackageFiles Include="$(PkgThingsGateway_Admin_Application)\Content\SeedData\Admin\*.*" />
 | 
				
			||||||
 | 
					    </ItemGroup>
 | 
				
			||||||
 | 
					    <PropertyGroup>
 | 
				
			||||||
 | 
					      <AdminApplicationFolder>$(TargetDir)SeedData\Admin\</AdminApplicationFolder>
 | 
				
			||||||
 | 
					    </PropertyGroup>
 | 
				
			||||||
 | 
					    <RemoveDir Directories="$(AdminApplicationFolder)" />
 | 
				
			||||||
 | 
					    <Copy SourceFiles="@(AdminApplicationPackageFiles)" DestinationFolder="$(AdminApplicationFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </Target>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  <Target Name="AdminPostPublish" AfterTargets="Publish">
 | 
				
			||||||
 | 
					    <ItemGroup>
 | 
				
			||||||
 | 
					      <!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
					      <AdminFiles Include="bin\$(Configuration)\$(TargetFramework)\SeedData\**" />
 | 
				
			||||||
 | 
					    </ItemGroup>
 | 
				
			||||||
 | 
					    <PropertyGroup>
 | 
				
			||||||
 | 
					    </PropertyGroup>
 | 
				
			||||||
 | 
					    <Copy SourceFiles="@(AdminFiles)" DestinationFolder="$(PublishDir)SeedData\%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <!--Admin-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										55
									
								
								src/ThingsGateway.ScriptDebug/targets/Gateway.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/ThingsGateway.ScriptDebug/targets/Gateway.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--Gateway-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Gateway.Razor" Version="$(Version)" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Gateway.Application" Version="$(Version)" GeneratePathProperty="true"/>
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="_ResolveCopyGatewayLocalNuGetPkgXmls" AfterTargets="ResolveReferences">
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).xml')" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)'=='ThingsGateway.Gateway.Application' and Exists('%(RootDir)%(Directory)%(Filename).xml')" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyGatewayNugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<RulesEngineApplicationPackageFiles Include="$(PkgThingsGateway_Gateway_Application)\Content\SeedData\RulesEngine\*.*" />
 | 
				
			||||||
 | 
								<ManagementApplicationPackageFiles Include="$(PkgThingsGateway_Gateway_Application)\Content\SeedData\Management\*.*" />
 | 
				
			||||||
 | 
								<GatewayApplicationPackageFiles Include="$(PkgThingsGateway_Gateway_Application)\Content\SeedData\Gateway\*.*" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<RulesEngineApplicationFolder>$(TargetDir)SeedData\RulesEngine\</RulesEngineApplicationFolder>
 | 
				
			||||||
 | 
								<ManagementApplicationFolder>$(TargetDir)SeedData\Management\</ManagementApplicationFolder>
 | 
				
			||||||
 | 
								<GatewayApplicationFolder>$(TargetDir)SeedData\Gateway\</GatewayApplicationFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(RulesEngineApplicationFolder)" />
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(ManagementApplicationFolder)" />
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(GatewayApplicationFolder)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(RulesEngineApplicationPackageFiles)" DestinationFolder="$(RulesEngineApplicationFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(ManagementApplicationPackageFiles)" DestinationFolder="$(ManagementApplicationFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(GatewayApplicationPackageFiles)" DestinationFolder="$(GatewayApplicationFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="GatewayPostPublish" AfterTargets="Publish">
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<GatewayFiles Include="bin\$(Configuration)\$(TargetFramework)\SeedData\**" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(GatewayFiles)" DestinationFolder="$(PublishDir)SeedData\%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--Gateway-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										110
									
								
								src/ThingsGateway.ScriptDebug/targets/Plugin.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/ThingsGateway.ScriptDebug/targets/Plugin.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
						<!--插件隔离-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<!--Modbus 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Modbus" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--SiemensS7 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.SiemensS7" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--Dlt645 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Dlt645" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--OpcDa 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.OpcDa" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--OpcUa 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.OpcUa" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--DB 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.DB" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--Kafka 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Kafka" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--Mqtt 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Mqtt" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--RabbitMQ 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.RabbitMQ" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--webhook 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Http" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyPluginNugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)Plugins\</PluginFolder>
 | 
				
			||||||
 | 
								<GatewayPluginFolder>$(TargetDir)GatewayPlugins\</GatewayPluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(PluginFolder)" />
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(GatewayPluginFolder)" />
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_ModbusPackageFiles Include="$(PkgThingsGateway_Plugin_Modbus)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_SiemensS7PackageFiles Include="$(PkgThingsGateway_Plugin_SiemensS7)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_Dlt645PackageFiles Include="$(PkgThingsGateway_Plugin_Dlt645)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_DBPackageFiles Include="$(PkgThingsGateway_Plugin_DB)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_KafkaPackageFiles Include="$(PkgThingsGateway_Plugin_Kafka)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_MqttPackageFiles Include="$(PkgThingsGateway_Plugin_Mqtt)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_OpcDaPackageFiles Include="$(PkgThingsGateway_Plugin_OpcDa)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_OpcUaPackageFiles Include="$(PkgThingsGateway_Plugin_OpcUa)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_RabbitMQPackageFiles Include="$(PkgThingsGateway_Plugin_RabbitMQ)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_HttpPackageFiles Include="$(PkgThingsGateway_Plugin_Http)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Message Text="将开源插件复制到插件目录 $(GatewayPluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_ModbusPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.Modbus%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_SiemensS7PackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.SiemensS7%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_Dlt645PackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.Dlt645%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_DBPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.DB%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_KafkaPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.Kafka%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_MqttPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.Mqtt%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_OpcDaPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.OpcDa%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_OpcUaPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.OpcUa%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_RabbitMQPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.RabbitMQ%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_HttpPackageFiles)" DestinationFolder="$(GatewayPluginFolder)ThingsGateway.Plugin.Http%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										114
									
								
								src/ThingsGateway.ScriptDebug/targets/PluginContext.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/ThingsGateway.ScriptDebug/targets/PluginContext.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--插件直接加载到程序上下文,不隔离-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<!--Modbus 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Modbus" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--SiemensS7 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.SiemensS7" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--Dlt645 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Dlt645" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--OpcDa 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.OpcDa" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--OpcUa 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.OpcUa" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--DB 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.DB" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--Kafka 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Kafka" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--Mqtt 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Mqtt" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--RabbitMQ 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.RabbitMQ" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<!--webhook 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Http" Version="$(PluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyPluginNugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)Plugins\</PluginFolder>
 | 
				
			||||||
 | 
								<GatewayPluginFolder>$(TargetDir)GatewayPlugins\</GatewayPluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(PluginFolder)" />
 | 
				
			||||||
 | 
							<RemoveDir Directories="$(GatewayPluginFolder)" />
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_ModbusPackageFiles Include="$(PkgThingsGateway_Plugin_Modbus)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_SiemensS7PackageFiles Include="$(PkgThingsGateway_Plugin_SiemensS7)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_Dlt645PackageFiles Include="$(PkgThingsGateway_Plugin_Dlt645)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_DBPackageFiles Include="$(PkgThingsGateway_Plugin_DB)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_KafkaPackageFiles Include="$(PkgThingsGateway_Plugin_Kafka)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_MqttPackageFiles Include="$(PkgThingsGateway_Plugin_Mqtt)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_OpcDaPackageFiles Include="$(PkgThingsGateway_Plugin_OpcDa)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_OpcUaPackageFiles Include="$(PkgThingsGateway_Plugin_OpcUa)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_RabbitMQPackageFiles Include="$(PkgThingsGateway_Plugin_RabbitMQ)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_HttpPackageFiles Include="$(PkgThingsGateway_Plugin_Http)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Message Text="将开源插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_ModbusPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_SiemensS7PackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_Dlt645PackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_DBPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_KafkaPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_MqttPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_OpcDaPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_OpcUaPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_RabbitMQPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_HttpPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/ThingsGateway.ScriptDebug/targets/PluginDebug.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/ThingsGateway.ScriptDebug/targets/PluginDebug.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.Modbus\ThingsGateway.Plugin.Modbus.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.Dlt645\ThingsGateway.Plugin.Dlt645.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.SiemensS7\ThingsGateway.Plugin.SiemensS7.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.DB\ThingsGateway.Plugin.DB.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.Mqtt\ThingsGateway.Plugin.Mqtt.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.OpcDa\ThingsGateway.Plugin.OpcDa.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.OpcUa\ThingsGateway.Plugin.OpcUa.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.RabbitMQ\ThingsGateway.Plugin.RabbitMQ.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\Plugin\ThingsGateway.Plugin.Http\ThingsGateway.Plugin.Http.csproj" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/ThingsGateway.ScriptDebug/targets/PluginPublish.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/ThingsGateway.ScriptDebug/targets/PluginPublish.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="PostPublish" AfterTargets="Publish">
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PluginsFiles Include="bin\$(Configuration)\$(TargetFramework)\Plugins\**" />
 | 
				
			||||||
 | 
								<GatewayPluginsFiles Include="bin\$(Configuration)\$(TargetFramework)\GatewayPlugins\**" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PluginsFiles)" DestinationFolder="$(PublishDir)Plugins\%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(GatewayPluginsFiles)" DestinationFolder="$(PublishDir)GatewayPlugins\%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="RemoveXmlDocs1" AfterTargets="Build" Condition=" '$(Configuration)' != 'Debug' ">
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<XmlFilesToDelete Include="$(TargetDir)*.xml" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<Delete Files="@(XmlFilesToDelete)" />
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="RemoveXmlDocs2" AfterTargets="Publish" Condition=" '$(Configuration)' != 'Debug' ">
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<XmlFilesToDelete Include="$(PublishDir)*.xml" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<Delete Files="@(XmlFilesToDelete)" />
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										97
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro2.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro2.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.SyncBridge" Version="$(ProPluginVersion)" GeneratePathProperty="true">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<IncludeAssets> native;</IncludeAssets>
 | 
				
			||||||
 | 
							</PackageReference>
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Inovance" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.TIANXIN" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.HJ212" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.BACnet" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--AllenBradleyCip 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.AllenBradleyCip" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--DCON 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.DCON" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--EDPF_NT 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.EDPF_NT" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--KELID2008 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.KELID2008" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--LKSIS 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.LKSIS" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--Melsec 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Melsec" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--Omron 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Omron" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<!--DKQ_A16D 插件-->
 | 
				
			||||||
 | 
							<!--<PackageReference Include="ThingsGateway.Plugin.DKQ_A16D" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />-->
 | 
				
			||||||
 | 
							<!--IDR210 插件-->
 | 
				
			||||||
 | 
							<!--<PackageReference Include="ThingsGateway.Plugin.IDR210" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />-->
 | 
				
			||||||
 | 
							<!--URF_R330 插件-->
 | 
				
			||||||
 | 
							<!--<PackageReference Include="ThingsGateway.Plugin.URF_R330" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />-->
 | 
				
			||||||
 | 
							<!--USBScaner 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.USBScaner" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.SECS" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.TS550" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.Vigor" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets=" native;" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyCustomPluginNugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_InovancePackageFiles Include="$(PkgThingsGateway_Plugin_Inovance)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_TIANXINPackageFiles Include="$(PkgThingsGateway_Plugin_TIANXIN)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_HJ212PackageFiles Include="$(PkgThingsGateway_Plugin_HJ212)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_BACnetPackageFiles Include="$(PkgThingsGateway_Plugin_BACnet)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_AllenBradleyCipPackageFiles Include="$(PkgThingsGateway_Plugin_AllenBradleyCip)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_DCONPackageFiles Include="$(PkgThingsGateway_Plugin_DCON)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_EDPF_NTPackageFiles Include="$(PkgThingsGateway_Plugin_EDPF_NT)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_KELID2008PackageFiles Include="$(PkgThingsGateway_Plugin_KELID2008)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_LKSISPackageFiles Include="$(PkgThingsGateway_Plugin_LKSIS)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_MelsecPackageFiles Include="$(PkgThingsGateway_Plugin_Melsec)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_OmronPackageFiles Include="$(PkgThingsGateway_Plugin_Omron)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_DKQ_A16DPackageFiles Include="$(PkgThingsGateway_Plugin_DKQ_A16D)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_IDR210PackageFiles Include="$(PkgThingsGateway_Plugin_IDR210)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_URF_R330PackageFiles Include="$(PkgThingsGateway_Plugin_URF_R330)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_USBScanerPackageFiles Include="$(PkgThingsGateway_Plugin_USBScaner)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_SECSPackageFiles Include="$(PkgThingsGateway_Plugin_SECS)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_TS550PackageFiles Include="$(PkgThingsGateway_Plugin_TS550)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_VigorPackageFiles Include="$(PkgThingsGateway_Plugin_Vigor)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_SyncBridgePackageFiles Include="$(PkgThingsGateway_Plugin_SyncBridge)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)GatewayPlugins\</PluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Message Text="将PRO插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_InovancePackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Inovance%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_TIANXINPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.TIANXIN%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_HJ212PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.HJ212%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_BACnetPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.BACnet%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_AllenBradleyCipPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.AllenBradleyCip%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_DCONPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.DCON%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_EDPF_NTPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.EDPF_NT%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_KELID2008PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.KELID2008%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_LKSISPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.LKSIS%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_MelsecPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Melsec%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_OmronPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Omron%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_DKQ_A16DPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.DKQ_A16D%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_IDR210PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.IDR210%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_URF_R330PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.URF_R330%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_USBScanerPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.USBScaner%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_SECSPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.SECS%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_TS550PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.TS550%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_VigorPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Vigor%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_SyncBridgePackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.SyncBridge%(RecursiveDir)" />
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro3.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro3.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<!--HUANANSFSK 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.HUANANSFSK" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
							<!--YPSFSK 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.YPSFSK" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyOtherPlugin3NugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_HUANANSFSKPackageFiles Include="$(PkgThingsGateway_Plugin_HUANANSFSK)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_YPSFSKPackageFiles Include="$(PkgThingsGateway_Plugin_YPSFSK)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)Plugins\</PluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Message Text="将SFSK插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_HUANANSFSKPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_YPSFSKPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro4.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro4.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.ModbusC1" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.ModbusGY" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyOtherPlugin1NugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_ModbusC1PackageFiles Include="$(PkgThingsGateway_Plugin_ModbusC1)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_ModbusGYPackageFiles Include="$(PkgThingsGateway_Plugin_ModbusGY)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)Plugins\</PluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Message Text="将Modbus定制插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_ModbusC1PackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_ModbusGYPackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro5.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro5.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<!--MqttYINGKE 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.MqttYINGKE" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyOtherPlugin5NugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_MqttYINGKEPackageFiles Include="$(PkgThingsGateway_Plugin_MqttYINGKE)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)GatewayPlugins\</PluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Message Text="将MQTTYINGKE插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_MqttYINGKEPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.MqttYINGKE%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro6.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro6.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<!--MqttYINGKE 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.IXCom29s" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyOtherPlugin6NugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_IXCom29sPackageFiles Include="$(PkgThingsGateway_Plugin_IXCom29s)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)GatewayPlugins\</PluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Message Text="将IXCom29s插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_IXCom29sPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.IXCom29s%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro7.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/ThingsGateway.ScriptDebug/targets/Pro7.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<!--MqttYINGKE 插件-->
 | 
				
			||||||
 | 
							<PackageReference Include="ThingsGateway.Plugin.OpcAe" Version="$(ProPluginVersion)" GeneratePathProperty="true" Private="false"  IncludeAssets="native;" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<Target Name="CopyOtherPlugin7NugetPackages" AfterTargets="Build">
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginTargetFramework>net8.0</PluginTargetFramework>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<ItemGroup>
 | 
				
			||||||
 | 
								<!-- setting up the variable for convenience -->
 | 
				
			||||||
 | 
								<PkgThingsGateway_Plugin_OpcAePackageFiles Include="$(PkgThingsGateway_Plugin_OpcAe)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							</ItemGroup>
 | 
				
			||||||
 | 
							<PropertyGroup>
 | 
				
			||||||
 | 
								<PluginFolder>$(TargetDir)Plugins\</PluginFolder>
 | 
				
			||||||
 | 
							</PropertyGroup>
 | 
				
			||||||
 | 
							<Message Text="将OpcAe插件复制到插件目录 $(PluginFolder)" Importance="high" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Copy SourceFiles="@(PkgThingsGateway_Plugin_OpcAePackageFiles)" DestinationFolder="$(PluginFolder)%(RecursiveDir)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/ThingsGateway.ScriptDebug/targets/ProPluginDebug.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/ThingsGateway.ScriptDebug/targets/ProPluginDebug.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.SyncBridge\ThingsGateway.Plugin.SyncBridge.csproj" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\ThingsGateway.Plugin.AllenBradleyCip.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.BACnet\ThingsGateway.Plugin.BACnet.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.DCON\ThingsGateway.Plugin.DCON.csproj" />
 | 
				
			||||||
 | 
							<!--<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.DKQ_A16D\ThingsGateway.Plugin.DKQ_A16D.csproj" />-->
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.EDPF_NT\ThingsGateway.Plugin.EDPF_NT.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.HJ212\ThingsGateway.Plugin.HJ212.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.HUANANSFSK\ThingsGateway.Plugin.HUANANSFSK.csproj" />
 | 
				
			||||||
 | 
							<!--<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.IDR210\ThingsGateway.Plugin.IDR210.csproj" />-->
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.KELID2008\ThingsGateway.Plugin.KELID2008.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.LEIDIAN\ThingsGateway.Plugin.LEIDIANAPI.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.LKSIS\ThingsGateway.Plugin.LKSIS.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.Melsec\ThingsGateway.Plugin.Melsec.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.ModbusC1\ThingsGateway.Plugin.ModbusC1.csproj" />
 | 
				
			||||||
 | 
							<!--<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.MqttSZJYZ\ThingsGateway.Plugin.MqttSZJYZ.csproj" />
 | 
				
			||||||
 | 
								<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.MqttYINGKE\ThingsGateway.Plugin.MqttYINGKE.csproj" />-->
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.Omron\ThingsGateway.Plugin.Omron.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.SECS\ThingsGateway.Plugin.SECS.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.TS550\ThingsGateway.Plugin.TS550.csproj" />
 | 
				
			||||||
 | 
							<!--<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.URF_R330\ThingsGateway.Plugin.URF_R330.csproj" />-->
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.USBScaner\ThingsGateway.Plugin.USBScaner.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.Vigor\ThingsGateway.Plugin.Vigor.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.YPSFSK\ThingsGateway.Plugin.YPSFSK.csproj" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.TIANXIN\ThingsGateway.Plugin.TIANXIN.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.Inovance\ThingsGateway.Plugin.Inovance.csproj" />
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.ModbusGY\ThingsGateway.Plugin.ModbusGY.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.IXCom29s\ThingsGateway.Plugin.IXCom29s.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.OpcAe\ThingsGateway.Plugin.OpcAe.csproj" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\PluginPro\ThingsGateway.Foundation.OpcAe\ThingsGateway.Foundation.OpcAe.csproj" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -1,7 +1,4 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "Debug": "true",
 | 
					 | 
				
			||||||
  "LogPath": "Logs/XLog",
 | 
					 | 
				
			||||||
  "LogFileMaxBytes": "5", //5mb最大日志文件
 | 
					  "LogFileMaxBytes": "5", //5mb最大日志文件
 | 
				
			||||||
  "LogFileBackups": "50", //50个日志文件
 | 
					  "LogFileBackups": "50" //50个日志文件
 | 
				
			||||||
  "LogFileFormat": "{0:yyyy_MM_dd}.log"
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -126,7 +126,7 @@ public partial class MainLayout : IDisposable
 | 
				
			|||||||
        if (context is TabItem tabItem)
 | 
					        if (context is TabItem tabItem)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await WinboxRender(tabItem.ChildContent, tabItem.Text);
 | 
					            await WinboxRender(tabItem.ChildContent, tabItem.Text);
 | 
				
			||||||
            await _tab.RemoveTab(tabItem);
 | 
					            //await _tab.RemoveTab(tabItem);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    [Inject]
 | 
					    [Inject]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ public class Program
 | 
				
			|||||||
        ClaimConst.Scheme = $"{typeof(Program).Assembly.GetName().Name}{SchemeHelper.GetOrCreate()}";
 | 
					        ClaimConst.Scheme = $"{typeof(Program).Assembly.GetName().Name}{SchemeHelper.GetOrCreate()}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Runtime.CreateConfigOnMissing = true;
 | 
					        Runtime.CreateConfigOnMissing = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region 控制台输出Logo
 | 
					        #region 控制台输出Logo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Console.Write(Environment.NewLine);
 | 
					        Console.Write(Environment.NewLine);
 | 
				
			||||||
@@ -72,8 +73,17 @@ public class Program
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (Runtime.IsLegacyWindows)
 | 
					                if (Runtime.IsLegacyWindows)
 | 
				
			||||||
                    builder.Logging.ClearProviders(); //去除默认的事件日志提供者,某些情况下会日志输出异常,导致程序崩溃
 | 
					                    builder.Logging.ClearProviders(); //去除默认的事件日志提供者,某些情况下会日志输出异常,导致程序崩溃
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }).ConfigureBuilder(builder =>
 | 
					            }).ConfigureBuilder(builder =>
 | 
				
			||||||
               {
 | 
					               {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                   if (Runtime.IsSystemd)
 | 
				
			||||||
 | 
					                   {
 | 
				
			||||||
 | 
					                       builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Warning);
 | 
				
			||||||
 | 
					                   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                   if (!builder.Environment.IsDevelopment())
 | 
					                   if (!builder.Environment.IsDevelopment())
 | 
				
			||||||
                   {
 | 
					                   {
 | 
				
			||||||
                       builder.Services.AddResponseCompression(
 | 
					                       builder.Services.AddResponseCompression(
 | 
				
			||||||
@@ -108,6 +118,8 @@ public class Program
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    ReflectionInoHelper.RemoveAllCache();
 | 
					                    ReflectionInoHelper.RemoveAllCache();
 | 
				
			||||||
                    InstanceFactory.RemoveCache();
 | 
					                    InstanceFactory.RemoveCache();
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
@@ -136,6 +148,12 @@ public class Program
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            }).ConfigureBuilder(builder =>
 | 
					            }).ConfigureBuilder(builder =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (Runtime.IsSystemd)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    builder.ConfigureLogging(a => a.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Warning));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // 设置接口超时时间和上传大小-Kestrel
 | 
					                // 设置接口超时时间和上传大小-Kestrel
 | 
				
			||||||
                builder.ConfigureKestrel(u =>
 | 
					                builder.ConfigureKestrel(u =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -144,11 +162,7 @@ public class Program
 | 
				
			|||||||
                    u.Limits.MaxRequestBodySize = null;
 | 
					                    u.Limits.MaxRequestBodySize = null;
 | 
				
			||||||
                }).UseKestrel().Configure(app =>
 | 
					                }).UseKestrel().Configure(app =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // ✅ 最小中间件
 | 
					                    app.Run(context => context.Response.WriteAsync("web is disable"));
 | 
				
			||||||
                    app.Run(context =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        return context.Response.WriteAsync("web is disable");
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
                .Configure(app =>
 | 
					                .Configure(app =>
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user