Compare commits
9 Commits
10.11.15.0
...
10.11.23.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
179ca0aa0e | ||
|
|
fc09a52da1 | ||
|
|
5436b91c89 | ||
|
|
d1c46f51a6 | ||
|
|
4539d8d198 | ||
|
|
9ea9529a5f | ||
|
|
4e6be23aac | ||
|
|
2fabbd236b | ||
|
|
163a66530e |
@@ -27,6 +27,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" Private="false" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" Private="false" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
</div>
|
||||
</Side>
|
||||
<Main>
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowContextMenuFullScreen="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
|
||||
{
|
||||
return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
|
||||
|
||||
@@ -15,6 +15,7 @@ using System.Text;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.DB;
|
||||
using ThingsGateway.NewLife;
|
||||
using ThingsGateway.NewLife.Log;
|
||||
|
||||
namespace ThingsGateway.AdminServer;
|
||||
@@ -64,7 +65,7 @@ public class Program
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
builder.Host.UseSystemd();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
if (Runtime.IsLegacyWindows)
|
||||
builder.Logging.ClearProviders(); //去除默认的事件日志提供者,某些情况下会日志输出异常,导致程序崩溃
|
||||
}).ConfigureBuilder(builder =>
|
||||
{
|
||||
|
||||
@@ -30,9 +30,27 @@ public class ImportPreviewOutputBase
|
||||
/// <summary>
|
||||
/// 返回状态
|
||||
/// </summary>
|
||||
public ConcurrentList<(int Row, bool Success, string? ErrorMessage)> Results { get; set; } = new();
|
||||
public ConcurrentList<ImportPreviewResult> Results { get; set; } = new();
|
||||
}
|
||||
public class ImportPreviewResult
|
||||
{
|
||||
public ImportPreviewResult()
|
||||
{
|
||||
|
||||
}
|
||||
public ImportPreviewResult(int row, bool success, string error)
|
||||
{
|
||||
this.Row = row;
|
||||
this.Success = success;
|
||||
this.ErrorMessage = error;
|
||||
}
|
||||
|
||||
public int Row { get; set; }
|
||||
|
||||
public bool Success { get; set; }
|
||||
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 导入预览
|
||||
/// </summary>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
|
||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="9.9.3" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="9.10.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ThingsGateway.DB;
|
||||
|
||||
@@ -41,4 +42,31 @@ public static class FileExtensions
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
/// <summary>
|
||||
/// 存储本地文件
|
||||
/// </summary>
|
||||
/// <param name="pPath">存储的第一层目录</param>
|
||||
/// <param name="file"></param>
|
||||
/// <returns>文件全路径</returns>
|
||||
public static async Task<string> StorageLocal(this IFormFile file, string pPath = "imports")
|
||||
{
|
||||
string uploadFileFolder = App.WebHostEnvironment?.WebRootPath ?? "wwwroot"!;//赋值路径
|
||||
var now = CommonUtils.GetSingleId();
|
||||
var filePath = Path.Combine(uploadFileFolder, pPath);
|
||||
if (!Directory.Exists(filePath))//如果不存在就创建文件夹
|
||||
Directory.CreateDirectory(filePath);
|
||||
//var fileSuffix = Path.GetExtension(file.Name).ToLower();// 文件后缀
|
||||
var fileObjectName = $"{now}{file.Name}";//存储后的文件名
|
||||
var fileName = Path.Combine(filePath, fileObjectName);//获取文件全路径
|
||||
fileName = fileName.Replace("\\", "/");//格式化一系
|
||||
//存储文件
|
||||
using (var stream = File.Create(Path.Combine(filePath, fileObjectName)))
|
||||
{
|
||||
await file.CopyToAsync(stream).ConfigureAwait(false);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ public static class SpecificationDocumentBuilder
|
||||
// 本地函数
|
||||
static string DefaultSchemaIdSelector(Type modelType)
|
||||
{
|
||||
var modelName = modelType.Name;
|
||||
var modelName = modelType.FullName;
|
||||
|
||||
// 处理泛型类型问题
|
||||
if (modelType.IsConstructedGenericType)
|
||||
|
||||
@@ -60,6 +60,9 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
|
||||
Name = str;
|
||||
else
|
||||
Name = $"Pool<{typeof(T).Name}>";
|
||||
|
||||
// 启动定期清理的定时器
|
||||
StartTimer();
|
||||
}
|
||||
|
||||
/// <summary>销毁</summary>
|
||||
@@ -227,8 +230,7 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
|
||||
|
||||
Interlocked.Increment(ref _FreeCount);
|
||||
|
||||
// 启动定期清理的定时器
|
||||
StartTimer();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public class ExpiringDictionary<TKey, TValue> : IDisposable
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _dict = new();
|
||||
private readonly TimerX _cleanupTimer;
|
||||
|
||||
public ExpiringDictionary(int cleanupInterval = 60000)
|
||||
public ExpiringDictionary(int cleanupInterval = 600000)
|
||||
{
|
||||
_cleanupTimer = new TimerX(Clear, null, cleanupInterval, cleanupInterval) { Async = true };
|
||||
}
|
||||
|
||||
@@ -76,6 +76,65 @@ public static class PathHelper
|
||||
#endregion
|
||||
|
||||
#region 路径操作辅助
|
||||
|
||||
public static string GetRelativePath(string relativeTo, string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(relativeTo))
|
||||
throw new ArgumentNullException(nameof(relativeTo));
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
|
||||
// 转为绝对路径
|
||||
relativeTo = Path.GetFullPath(relativeTo);
|
||||
path = Path.GetFullPath(path);
|
||||
|
||||
// 末尾确保有分隔符,便于处理目录
|
||||
if (!relativeTo.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
relativeTo += Path.DirectorySeparatorChar;
|
||||
|
||||
// 相同路径
|
||||
if (string.Equals(relativeTo, path, StringComparison.OrdinalIgnoreCase))
|
||||
return ".";
|
||||
|
||||
// 检查 UNC 或不同盘符
|
||||
bool isUnc = relativeTo.StartsWith(@"\\") && path.StartsWith(@"\\");
|
||||
if (!isUnc)
|
||||
{
|
||||
// 不同盘符直接返回绝对路径
|
||||
if (!string.Equals(Path.GetPathRoot(relativeTo), Path.GetPathRoot(path), StringComparison.OrdinalIgnoreCase))
|
||||
return path;
|
||||
}
|
||||
|
||||
// 找到共同前缀长度
|
||||
int length = Math.Min(relativeTo.Length, path.Length);
|
||||
int lastSeparatorIndex = -1;
|
||||
int i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (char.ToLowerInvariant(relativeTo[i]) != char.ToLowerInvariant(path[i]))
|
||||
break;
|
||||
if (relativeTo[i] == Path.DirectorySeparatorChar)
|
||||
lastSeparatorIndex = i;
|
||||
}
|
||||
|
||||
// 计算上退的 ".."
|
||||
string up = "";
|
||||
for (int j = lastSeparatorIndex + 1; j < relativeTo.Length; j++)
|
||||
{
|
||||
if (relativeTo[j] == Path.DirectorySeparatorChar)
|
||||
up += ".." + Path.DirectorySeparatorChar;
|
||||
}
|
||||
|
||||
// 获取剩余下行部分
|
||||
string down = path.Substring(lastSeparatorIndex + 1);
|
||||
|
||||
// 拼接结果
|
||||
string result = up + down;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static String GetPath(String path, Int32 mode)
|
||||
{
|
||||
// 处理路径分隔符,兼容Windows和Linux
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ThingsGateway.NewLife.Reflection;
|
||||
|
||||
@@ -553,7 +554,10 @@ public static class Reflect
|
||||
//}
|
||||
|
||||
|
||||
private static readonly ExpiringDictionary<(MethodInfo, Type, object?), Delegate> _delegateCache = new();
|
||||
private static class DelegateCache<TFunc>
|
||||
{
|
||||
public static readonly ExpiringDictionary<DelegateCacheKey, TFunc> Cache = new();
|
||||
}
|
||||
|
||||
/// <summary>把一个方法转为泛型委托,便于快速反射调用</summary>
|
||||
/// <typeparam name="TFunc"></typeparam>
|
||||
@@ -564,17 +568,50 @@ public static class Reflect
|
||||
{
|
||||
if (method == null) return default;
|
||||
|
||||
var key = (method, typeof(TFunc), target);
|
||||
var key = new DelegateCacheKey(method, typeof(TFunc), target);
|
||||
|
||||
if (_delegateCache.TryGetValue(key, out var del))
|
||||
return (TFunc)(object)del;
|
||||
var func = DelegateCache<TFunc>.Cache.GetOrAdd(
|
||||
key,
|
||||
_ => (TFunc)(object)(
|
||||
target == null
|
||||
? Delegate.CreateDelegate(typeof(TFunc), method, true)
|
||||
: Delegate.CreateDelegate(typeof(TFunc), target, method, true)));
|
||||
|
||||
del = target == null
|
||||
? Delegate.CreateDelegate(typeof(TFunc), method, true)
|
||||
: Delegate.CreateDelegate(typeof(TFunc), target, method, true);
|
||||
|
||||
return (TFunc)(object)_delegateCache.GetOrAdd(key, del);
|
||||
return func;
|
||||
}
|
||||
|
||||
private readonly struct DelegateCacheKey : IEquatable<DelegateCacheKey>
|
||||
{
|
||||
public readonly MethodInfo Method;
|
||||
public readonly Type FuncType;
|
||||
public readonly object? Target;
|
||||
|
||||
public DelegateCacheKey(MethodInfo method, Type funcType, object? target)
|
||||
{
|
||||
Method = method;
|
||||
FuncType = funcType;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public bool Equals(DelegateCacheKey other) =>
|
||||
Method.Equals(other.Method)
|
||||
&& FuncType.Equals(other.FuncType)
|
||||
&& ReferenceEquals(Target, other.Target);
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
obj is DelegateCacheKey other && Equals(other);
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = Method.GetHashCode();
|
||||
hash = (hash * 397) ^ FuncType.GetHashCode();
|
||||
if (Target != null)
|
||||
hash = (hash * 397) ^ RuntimeHelpers.GetHashCode(Target); // 不受对象重写 GetHashCode 影响
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.0" />
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.11.15</PluginVersion>
|
||||
<ProPluginVersion>10.11.15</ProPluginVersion>
|
||||
<DefaultVersion>10.11.15</DefaultVersion>
|
||||
<AuthenticationVersion>10.11.2</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.11.2</SourceGeneratorVersion>
|
||||
<PluginVersion>10.11.23</PluginVersion>
|
||||
<ProPluginVersion>10.11.23</ProPluginVersion>
|
||||
<DefaultVersion>10.11.23</DefaultVersion>
|
||||
<AuthenticationVersion>10.11.3</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.11.3</SourceGeneratorVersion>
|
||||
<NET8Version>8.0.19</NET8Version>
|
||||
<NET9Version>9.0.8</NET9Version>
|
||||
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
|
||||
<IsTrimmable>false</IsTrimmable>
|
||||
<ManagementProPluginVersion>10.11.22</ManagementProPluginVersion>
|
||||
<ManagementPluginVersion>10.11.22</ManagementPluginVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -82,13 +82,14 @@ public static class CSharpScriptEngineExtension
|
||||
{
|
||||
if (source.IsNullOrEmpty()) return null;
|
||||
var field = $"{CacheKey}-{source}";
|
||||
var exfield = $"{CacheKey}-Exception-{source}";
|
||||
var runScript = Instance.Get<T>(field);
|
||||
if (runScript == null)
|
||||
{
|
||||
lock (m_waiterLock)
|
||||
{
|
||||
runScript = Instance.Get<T>(field);
|
||||
if (runScript == null)
|
||||
var hasValue = Instance.TryGetValue<T>(field, out runScript);
|
||||
if (hasValue == false)
|
||||
{
|
||||
var src = source.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
var _using = new StringBuilder();
|
||||
@@ -111,8 +112,6 @@ public static class CSharpScriptEngineExtension
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// 动态加载并执行代码
|
||||
runScript = evaluator.With(eval => eval.IsAssemblyUnloadingEnabled = true).LoadCode<T>(
|
||||
$@"
|
||||
@@ -140,11 +139,22 @@ public static class CSharpScriptEngineExtension
|
||||
string exString = string.Format(CSScriptResource.CSScriptResource.Error1, typeof(T).FullName);
|
||||
throw new(exString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//如果编译失败,应该不重复编译,避免oom
|
||||
Instance.Set<T>(field, null, TimeSpan.FromHours(1));
|
||||
Instance.Set(exfield, ex, TimeSpan.FromHours(1));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Instance.SetExpire(field, TimeSpan.FromHours(1));
|
||||
|
||||
Instance.SetExpire(exfield, TimeSpan.FromHours(1));
|
||||
if (runScript == null)
|
||||
{
|
||||
throw (Instance.Get<Exception>(exfield) ?? new Exception("compilation error"));
|
||||
}
|
||||
return runScript;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,30 +93,38 @@ public static class ExpressionEvaluatorExtension
|
||||
public static ReadWriteExpressions GetOrAddScript(string source)
|
||||
{
|
||||
var field = $"{CacheKey}-{source}";
|
||||
var exfield = $"{CacheKey}-Exception-{source}";
|
||||
var runScript = Instance.Get<ReadWriteExpressions>(field);
|
||||
if (runScript == null)
|
||||
{
|
||||
if (!source.Contains("return"))
|
||||
var hasValue = Instance.TryGetValue<ReadWriteExpressions>(field, out runScript);
|
||||
if (!hasValue)
|
||||
{
|
||||
source = $"return {source}";//只判断简单脚本中可省略return字符串
|
||||
}
|
||||
var src = source.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
var _using = new StringBuilder();
|
||||
var _body = new StringBuilder();
|
||||
src.ToList().ForEach(l =>
|
||||
{
|
||||
if (l.StartsWith("using "))
|
||||
|
||||
|
||||
if (!source.Contains("return"))
|
||||
{
|
||||
_using.AppendLine(l);
|
||||
source = $"return {source}";//只判断简单脚本中可省略return字符串
|
||||
}
|
||||
else
|
||||
var src = source.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
var _using = new StringBuilder();
|
||||
var _body = new StringBuilder();
|
||||
src.ToList().ForEach(l =>
|
||||
{
|
||||
_body.AppendLine(l);
|
||||
}
|
||||
});
|
||||
// 动态加载并执行代码
|
||||
runScript = CSScript.Evaluator.With(eval => eval.IsAssemblyUnloadingEnabled = true).LoadCode<ReadWriteExpressions>(
|
||||
$@"
|
||||
if (l.StartsWith("using "))
|
||||
{
|
||||
_using.AppendLine(l);
|
||||
}
|
||||
else
|
||||
{
|
||||
_body.AppendLine(l);
|
||||
}
|
||||
});
|
||||
// 动态加载并执行代码
|
||||
try
|
||||
{
|
||||
runScript = CSScript.Evaluator.With(eval => eval.IsAssemblyUnloadingEnabled = true).LoadCode<ReadWriteExpressions>(
|
||||
$@"
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
@@ -137,9 +145,26 @@ public static class ExpressionEvaluatorExtension
|
||||
}}
|
||||
}}
|
||||
");
|
||||
Instance.Set(field, runScript);
|
||||
Instance.Set(field, runScript);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//如果编译失败,应该不重复编译,避免oom
|
||||
Instance.Set<ReadWriteExpressions>(field, null, TimeSpan.FromHours(1));
|
||||
Instance.Set(exfield, ex, TimeSpan.FromHours(1));
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Instance.SetExpire(field, TimeSpan.FromHours(1));
|
||||
Instance.SetExpire(exfield, TimeSpan.FromHours(1));
|
||||
if (runScript == null)
|
||||
{
|
||||
throw (Instance.Get<Exception>(exfield) ?? new Exception("compilation error"));
|
||||
}
|
||||
return runScript;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Reliability", "CA2007:考虑对等待的任务调用 ConfigureAwait", Justification = "<挂起>", Scope = "member", Target = "~M:ThingsGateway.Foundation.Demo.Program.Main(System.String[])~System.Threading.Tasks.Task")]
|
||||
[assembly: SuppressMessage("Reliability", "CA2007:考虑对等待的任务调用 ConfigureAwait", Justification = "<挂起>", Scope = "member", Target = "~M:ThingsGateway.Foundation.Demo.ModbusMasterDemo.TestRead~System.Threading.Tasks.Task")]
|
||||
11
src/Foundation/ThingsGateway.Foundation.Demo/GlobalUsings.cs
Normal file
11
src/Foundation/ThingsGateway.Foundation.Demo/GlobalUsings.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
global using TouchSocket.Core;
|
||||
221
src/Foundation/ThingsGateway.Foundation.Demo/ModbusMasterDemo.cs
Normal file
221
src/Foundation/ThingsGateway.Foundation.Demo/ModbusMasterDemo.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.Modbus;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
|
||||
#pragma warning disable CA1861 // 不要将常量数组作为参数
|
||||
|
||||
/// <summary>
|
||||
/// ModbusMaster
|
||||
/// </summary>
|
||||
public class ModbusMasterDemo
|
||||
{
|
||||
/// <summary>
|
||||
/// 新建链路
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IChannel GetChannel(ChannelOptions channelOptions)
|
||||
{
|
||||
TouchSocketConfig touchSocketConfig = new TouchSocketConfig();
|
||||
return touchSocketConfig.GetChannel(channelOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新建协议对象
|
||||
/// </summary>
|
||||
/// <param name="channel"></param>
|
||||
/// <returns></returns>
|
||||
public ModbusMaster GetDevice(IChannel channel)
|
||||
{
|
||||
var client = new ModbusMaster();
|
||||
client.InitChannel(channel);
|
||||
return client;
|
||||
}
|
||||
public async Task TestReadWrite()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:502",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
//读取具体类型数据
|
||||
var data = await device.ReadDoubleAsync("400001"); //通过字符串转化地址,读取保持寄存器地址0
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
|
||||
//读取原始字节数组
|
||||
|
||||
var bytes = await device.ReadAsync("400001", 10); //通过字符串转化地址,读取保持寄存器地址0,10个寄存器
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
bytes = await device.ModbusReadAsync(new ModbusAddress()
|
||||
{
|
||||
StartAddress = 0,
|
||||
FunctionCode = 3,
|
||||
Length = 10,
|
||||
}); //配置地址对象,读取保持寄存器地址0,10个寄存器
|
||||
|
||||
if (bytes.IsSuccess)
|
||||
{
|
||||
//解析bytes字节数组
|
||||
var byteData = bytes.Content.Span;
|
||||
var data1 = device.ThingsGatewayBitConverter.ToDouble(byteData, 0);
|
||||
var data2 = device.ThingsGatewayBitConverter.ToDouble(byteData, 8);
|
||||
var data3 = device.ThingsGatewayBitConverter.ToUInt16(byteData, 16);
|
||||
device.Logger?.Info($"读取到的数据:{data1},{data2},{data3}");
|
||||
}
|
||||
|
||||
|
||||
//写入数据
|
||||
var write = await device.WriteAsync("400001", (double)123.456); //通过字符串转化地址,写入保持寄存器地址0
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
write = await device.WriteAsync("400001", new double[] { 123.456, 123.456 }); //通过字符串转化地址,写入保持寄存器地址2,2个double寄存器
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
|
||||
write = await device.ModbusRequestAsync(new ModbusAddress()
|
||||
{
|
||||
StartAddress = 0,
|
||||
FunctionCode = 3,
|
||||
MasterWriteDatas = device.ThingsGatewayBitConverter.GetBytes(new double[] { 123.456, 123.456 })
|
||||
}, false); //通过字符串转化地址,写入保持寄存器地址2,2个double寄存器
|
||||
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
|
||||
}
|
||||
public async Task TestMulRead()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:502",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//批量打包
|
||||
var variableRuntimes = new List<VariableClass>()
|
||||
{
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="40001",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.UInt16,
|
||||
RegisterAddress="40009",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="40005",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
var deviceVariableSourceReads = device.LoadSourceRead<VariableSourceClass>(variableRuntimes, 125, "1000");
|
||||
foreach (var item in deviceVariableSourceReads)
|
||||
{
|
||||
var result = await device.ReadAsync(item.AddressObject);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result1 = item.VariableRuntimes.PraseStructContent(device, result.Content.Span, exWhenAny: true);
|
||||
if (!result1.IsSuccess)
|
||||
{
|
||||
item.LastErrorMessage = result1.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result1.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
device.Logger?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.LastErrorMessage = result.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
device.Logger?.Info($"批量读取到的数据:{variableRuntimes.Select(a => new { a.RegisterAddress, a.Value }).ToJsonNetString()}");
|
||||
|
||||
}
|
||||
|
||||
public async Task TestVariableObject()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:502",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//使用变量对象读取
|
||||
var testModbusObject = new TestModbusObject(device, 125);
|
||||
await testModbusObject.MultiReadAsync();
|
||||
device.Logger?.Info($"批量读取到的数据:{testModbusObject.ToJsonNetString()}");
|
||||
|
||||
//源生成的写入方法
|
||||
var write = await testModbusObject.WriteDouble1Async(123.456);
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
}
|
||||
}
|
||||
[GeneratorVariable]
|
||||
public partial class TestModbusObject : VariableObject
|
||||
{
|
||||
public TestModbusObject(IDevice device, int maxPack) : base(device, maxPack)
|
||||
{
|
||||
}
|
||||
|
||||
[VariableRuntime(RegisterAddress = "400001")]
|
||||
public double Double1 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "400005")]
|
||||
public double Double2 { get; set; }
|
||||
|
||||
[VariableRuntime(RegisterAddress = "400009")]
|
||||
public ushort UShort3 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "4000010")]
|
||||
public ushort UShort4 { get; set; }
|
||||
}
|
||||
34
src/Foundation/ThingsGateway.Foundation.Demo/Program.cs
Normal file
34
src/Foundation/ThingsGateway.Foundation.Demo/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
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
|
||||
|
||||
public class Program
|
||||
{
|
||||
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
ModbusMasterDemo modbusMasterDemo = new();
|
||||
await modbusMasterDemo.TestReadWrite();
|
||||
await modbusMasterDemo.TestMulRead();
|
||||
await modbusMasterDemo.TestVariableObject();
|
||||
|
||||
Console.ReadKey();
|
||||
|
||||
SiemensS7MasterDemo siemensS7MasterDemo = new();
|
||||
await siemensS7MasterDemo.TestReadWrite();
|
||||
await siemensS7MasterDemo.TestMulRead();
|
||||
await siemensS7MasterDemo.TestVariableObject();
|
||||
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.SiemensS7;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
|
||||
#pragma warning disable CA1861 // 不要将常量数组作为参数
|
||||
|
||||
/// <summary>
|
||||
/// SiemensS7Master
|
||||
/// </summary>
|
||||
public class SiemensS7MasterDemo
|
||||
{
|
||||
/// <summary>
|
||||
/// 新建链路
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IChannel GetChannel(ChannelOptions channelOptions)
|
||||
{
|
||||
TouchSocketConfig touchSocketConfig = new TouchSocketConfig();
|
||||
return touchSocketConfig.GetChannel(channelOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新建协议对象
|
||||
/// </summary>
|
||||
/// <param name="channel"></param>
|
||||
/// <returns></returns>
|
||||
public SiemensS7Master GetDevice(IChannel channel)
|
||||
{
|
||||
var client = new SiemensS7Master();
|
||||
client.InitChannel(channel);
|
||||
return client;
|
||||
}
|
||||
public async Task TestReadWrite()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:102",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
//读取具体类型数据
|
||||
var data = await device.ReadDoubleAsync("V1"); //通过字符串转化地址,读取v1
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
|
||||
//读取原始字节数组
|
||||
|
||||
var bytes = await device.ReadAsync("V1", 20); //通过字符串转化地址,读取v1,10个寄存器
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
|
||||
if (bytes.IsSuccess)
|
||||
{
|
||||
//解析bytes字节数组
|
||||
var byteData = bytes.Content.Span;
|
||||
var data1 = device.ThingsGatewayBitConverter.ToDouble(byteData, 0);
|
||||
var data2 = device.ThingsGatewayBitConverter.ToDouble(byteData, 8);
|
||||
var data3 = device.ThingsGatewayBitConverter.ToUInt16(byteData, 16);
|
||||
device.Logger?.Info($"读取到的数据:{data1},{data2},{data3}");
|
||||
}
|
||||
|
||||
|
||||
//写入数据
|
||||
var write = await device.WriteAsync("v1", (double)123.456); //通过字符串转化地址,写入保持寄存器地址0
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
write = await device.WriteAsync("v1", new double[] { 123.456, 123.456 }); //通过字符串转化地址,写入保持寄存器地址2,2个double寄存器
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
|
||||
}
|
||||
public async Task TestMulRead()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:102",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//批量打包
|
||||
var variableRuntimes = new List<VariableClass>()
|
||||
{
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="v1",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.UInt16,
|
||||
RegisterAddress="v9",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="v11",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
var deviceVariableSourceReads = device.LoadSourceRead<VariableSourceClass>(variableRuntimes, 125, "1000");
|
||||
foreach (var item in deviceVariableSourceReads)
|
||||
{
|
||||
var result = await device.ReadAsync(item.AddressObject);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result1 = item.VariableRuntimes.PraseStructContent(device, result.Content.Span, exWhenAny: true);
|
||||
if (!result1.IsSuccess)
|
||||
{
|
||||
item.LastErrorMessage = result1.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result1.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
device.Logger?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.LastErrorMessage = result.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
device.Logger?.Info($"批量读取到的数据:{variableRuntimes.Select(a => new { a.RegisterAddress, a.Value }).ToJsonNetString()}");
|
||||
|
||||
}
|
||||
|
||||
public async Task TestVariableObject()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:102",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//使用变量对象读取
|
||||
var testS7Object = new TestS7Object(device, 125);
|
||||
await testS7Object.MultiReadAsync();
|
||||
device.Logger?.Info($"批量读取到的数据:{testS7Object.ToJsonNetString()}");
|
||||
|
||||
//源生成的写入方法
|
||||
var write = await testS7Object.WriteDouble1Async(123.456);
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 实体类操作PLC数据
|
||||
/// </summary>
|
||||
[GeneratorVariable]
|
||||
public partial class TestS7Object : VariableObject
|
||||
{
|
||||
[VariableRuntime(RegisterAddress = "v1")]
|
||||
public double Double1 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "v9")]
|
||||
public double Double2 { get; set; }
|
||||
|
||||
[VariableRuntime(RegisterAddress = "v17")]
|
||||
public ushort UShort3 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "v19")]
|
||||
public ushort UShort4 { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public TestS7Object(IDevice device, int maxPack) : base(device, maxPack)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop;
|
||||
@using ThingsGateway.Foundation
|
||||
@using ThingsGateway.NewLife.Threading
|
||||
@using ThingsGateway.Extension;
|
||||
@using BootstrapBlazor.Components
|
||||
@namespace ThingsGateway.Debug
|
||||
|
||||
<div class="w-100" style=@($"height:{HeightString}")>
|
||||
|
||||
<Card HeaderText=@HeaderText class=@("w-100 h-100")>
|
||||
<HeaderTemplate>
|
||||
<div class="flex-fill">
|
||||
</div>
|
||||
|
||||
@if (LogLevelChanged.HasDelegate)
|
||||
{
|
||||
<Select Value="@LogLevel" ValueChanged="LogLevelChanged" IsPopover></Select>
|
||||
}
|
||||
<Tooltip class=" col-auto" Title="@RazorLocalizer[Pause?"Play":"Pause"]" Placement="Placement.Bottom">
|
||||
|
||||
<Button Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@(Pause?"fa fa-play":"fa fa-pause") OnClick="OnPause" />
|
||||
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip class=" col-auto" Title="@RazorLocalizer["Export"]" Placement="Placement.Bottom">
|
||||
|
||||
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("fa fa-sign-out") OnClick="HandleOnExportClick" />
|
||||
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip class=" col-auto" Title="@RazorLocalizer["Delete"]" Placement="Placement.Bottom">
|
||||
|
||||
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("far fa-trash-alt") OnClick="Delete" />
|
||||
|
||||
</Tooltip>
|
||||
|
||||
|
||||
</HeaderTemplate>
|
||||
<BodyTemplate>
|
||||
<div style=@($"height:calc(100% - 50px);overflow-y:scroll;flex-fill;")>
|
||||
<Virtualize Items="CurrentMessages??new List<LogMessage>()" Context="itemMessage" ItemSize="60" OverscanCount=2>
|
||||
<ItemContent>
|
||||
@* <Tooltip Placement="Placement.Bottom" Title=@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 500))> *@
|
||||
<div class=@(itemMessage.Level<(byte)Microsoft.Extensions.Logging.LogLevel.Information?"":
|
||||
itemMessage.Level>=(byte)Microsoft.Extensions.Logging.LogLevel.Warning? " red--text text-truncate":"green--text text-truncate")
|
||||
title=@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 500))>
|
||||
|
||||
@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 150))
|
||||
|
||||
</div>
|
||||
@* </Tooltip> *@
|
||||
</ItemContent>
|
||||
</Virtualize>
|
||||
</div>
|
||||
|
||||
</BodyTemplate>
|
||||
</Card>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,203 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using ThingsGateway.Extension;
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.NewLife;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Debug;
|
||||
|
||||
public partial class LocalLogConsole : IDisposable
|
||||
{
|
||||
private bool Pause;
|
||||
|
||||
public bool Disposed { get; set; }
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public LogLevel LogLevel { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<LogLevel> LogLevelChanged { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string HeaderText { get; set; } = "Log";
|
||||
|
||||
[Parameter]
|
||||
public string HeightString { get; set; } = "calc(100% - 300px)";
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public string LogPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志
|
||||
/// </summary>
|
||||
public ICollection<LogMessage> Messages { get; set; } = new List<LogMessage>();
|
||||
|
||||
private ICollection<LogMessage> CurrentMessages => Pause ? PauseMessagesText : Messages;
|
||||
|
||||
[Inject]
|
||||
private DownloadService DownloadService { get; set; }
|
||||
[Inject]
|
||||
private IStringLocalizer<ThingsGateway.Razor._Imports> RazorLocalizer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 暂停缓存
|
||||
/// </summary>
|
||||
private ICollection<LogMessage> PauseMessagesText { get; set; } = new List<LogMessage>();
|
||||
|
||||
[Inject]
|
||||
private IPlatformService PlatformService { get; set; }
|
||||
|
||||
private string logPath;
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (LogPath != logPath)
|
||||
{
|
||||
logPath = LogPath;
|
||||
Messages = new List<LogMessage>();
|
||||
await ExecuteAsync();
|
||||
}
|
||||
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
[Inject]
|
||||
private ToastService ToastService { get; set; }
|
||||
[Inject]
|
||||
TextFileReadService TextFileReadService { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
Disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
private WaitLock WaitLock = new(nameof(LogConsole));
|
||||
protected async Task ExecuteAsync()
|
||||
{
|
||||
if (WaitLock.Waited) return;
|
||||
try
|
||||
{
|
||||
await WaitLock.WaitAsync();
|
||||
await Task.Delay(1000);
|
||||
|
||||
if (LogPath != null)
|
||||
{
|
||||
var files = await TextFileReadService.GetLogFilesAsync(LogPath);
|
||||
if (!files.IsSuccess)
|
||||
{
|
||||
Messages = new List<LogMessage>();
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
var result = await TextFileReadService.LastLogDataAsync(files.Content.FirstOrDefault());
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
Messages = result.Content.Where(a => a.LogLevel >= LogLevel).Select(a => new LogMessage((int)a.LogLevel, $"{a.LogTime} - {a.Message}{(a.ExceptionString.IsNullOrWhiteSpace() ? null : $"{Environment.NewLine}{a.ExceptionString}")}")).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Messages = new List<LogMessage>();
|
||||
}
|
||||
sw.Stop();
|
||||
if (sw.ElapsedMilliseconds > 500)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NewLife.Log.XTrace.WriteException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
WaitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_ = RunTimerAsync();
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private async Task Delete()
|
||||
{
|
||||
await TextFileReadService.DeleteLogDataAsync(LogPath);
|
||||
}
|
||||
|
||||
private async Task HandleOnExportClick(MouseEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Pause)
|
||||
{
|
||||
using var memoryStream = new MemoryStream();
|
||||
using StreamWriter writer = new(memoryStream);
|
||||
foreach (var item in PauseMessagesText)
|
||||
{
|
||||
await writer.WriteLineAsync(item.Message);
|
||||
}
|
||||
await writer.FlushAsync();
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// 定义文件名称规则的正则表达式模式
|
||||
string pattern = @"[\\/:*?""<>|]";
|
||||
// 使用正则表达式将不符合规则的部分替换为下划线
|
||||
string sanitizedFileName = Regex.Replace(HeaderText, pattern, "_");
|
||||
await DownloadService.DownloadFromStreamAsync($"{sanitizedFileName}{DateTime.Now.ToFileDateTimeFormat()}.txt", memoryStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlatformService != null)
|
||||
await PlatformService.OnLogExport(LogPath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ToastService.Warn(ex);
|
||||
}
|
||||
}
|
||||
private Task OnPause()
|
||||
{
|
||||
Pause = !Pause;
|
||||
if (Pause)
|
||||
PauseMessagesText = Messages.ToList();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task RunTimerAsync()
|
||||
{
|
||||
while (!Disposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ExecuteAsync();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NewLife.Log.XTrace.WriteException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,33 +142,7 @@ public partial class LogConsole : IDisposable
|
||||
|
||||
private async Task Delete()
|
||||
{
|
||||
if (LogPath != null)
|
||||
{
|
||||
var files = await TextFileReadService.GetLogFilesAsync(LogPath);
|
||||
if (files.IsSuccess)
|
||||
{
|
||||
foreach (var item in files.Content)
|
||||
{
|
||||
if (File.Exists(item))
|
||||
{
|
||||
int error = 0;
|
||||
while (error < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtil.DeleteFile(item);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Task.Delay(3000);
|
||||
error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await TextFileReadService.DeleteLogDataAsync(LogPath);
|
||||
}
|
||||
|
||||
private async Task HandleOnExportClick(MouseEventArgs args)
|
||||
|
||||
@@ -26,7 +26,7 @@ public class PlatformService : IPlatformService
|
||||
|
||||
public async Task OnLogExport(string logPath)
|
||||
{
|
||||
var files = TextFileReader.GetLogFilesAsync(logPath);
|
||||
var files = TextFileReader.GetLogFiles(logPath);
|
||||
if (!files.IsSuccess)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -34,5 +34,6 @@ public class Startup : AppStartup
|
||||
|
||||
services.AddScoped<IPlatformService, PlatformService>();
|
||||
services.AddSingleton<ITextFileReadService, TextFileReadService>();
|
||||
services.AddSingleton<TextFileReadService, TextFileReadService>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -154,7 +154,7 @@ public class DDPTcpSessionClientChannel : TcpSessionClientChannel
|
||||
var id = $"ID={message.Id}";
|
||||
if (message.Type == 0x09)
|
||||
{
|
||||
var reader = new ByteBlockReader(message.Content);
|
||||
var reader = new ClassBytesReader(message.Content);
|
||||
|
||||
if (this.DataHandlingAdapter == null)
|
||||
{
|
||||
|
||||
@@ -219,7 +219,7 @@ public static class ChannelOptionsExtensions
|
||||
#if NETSTANDARD || NET6_0_OR_GREATER
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
config.UseUdpConnReset();
|
||||
config.SetUdpConnReset(true);
|
||||
}
|
||||
#endif
|
||||
return ddpUdp;
|
||||
@@ -231,7 +231,7 @@ public static class ChannelOptionsExtensions
|
||||
#if NETSTANDARD || NET6_0_OR_GREATER
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
config.UseUdpConnReset();
|
||||
config.SetUdpConnReset(true);
|
||||
}
|
||||
#endif
|
||||
return udpSessionChannel;
|
||||
|
||||
@@ -101,7 +101,7 @@ public class DtuPlugin : PluginBase, ITcpReceivingPlugin
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
if (HeartbeatByte.Span.SequenceEqual(e.Reader.TotalSequence.Slice(0, len).First.Span))
|
||||
if (HeartbeatByte.Span.SequenceEqual(e.Reader.TotalSequence.Slice(0, (int)Math.Min(len, e.Reader.BytesRemaining + e.Reader.BytesRead)).First.Span))
|
||||
{
|
||||
if (DateTimeOffset.Now - socket.LastSentTime < TimeSpan.FromMilliseconds(200))
|
||||
{
|
||||
|
||||
@@ -181,7 +181,7 @@ internal sealed class HeartbeatAndReceivePlugin : PluginBase, ITcpConnectedPlugi
|
||||
var len = HeartbeatByte.Length;
|
||||
if (len > 0)
|
||||
{
|
||||
if (HeartbeatByte.Span.SequenceEqual(e.Reader.TotalSequence.Slice(0, len).First.Span))
|
||||
if (HeartbeatByte.Span.SequenceEqual(e.Reader.TotalSequence.Slice(0, (int)Math.Min(len, e.Reader.BytesRemaining + e.Reader.BytesRead)).First.Span))
|
||||
{
|
||||
e.Reader.Advance((int)Math.Min(len, e.Reader.BytesRemaining));
|
||||
e.Handled = true;
|
||||
|
||||
@@ -124,12 +124,12 @@ public class DeviceUdpDataHandleAdapter<TRequest> : UdpDataHandlingAdapter, IDev
|
||||
}
|
||||
request1 = request;
|
||||
|
||||
var byteBlock = new ByteBlockReader(memory);
|
||||
var byteBlock = new ClassBytesReader(memory);
|
||||
byteBlock.BytesRead = 0;
|
||||
|
||||
var pos = byteBlock.BytesRead;
|
||||
|
||||
if (request.HeaderLength > byteBlock.CanReadLength)
|
||||
if (request.HeaderLength > byteBlock.BytesRead + byteBlock.BytesRemaining)
|
||||
{
|
||||
return false;//当头部都无法解析时,直接缓存
|
||||
}
|
||||
@@ -147,7 +147,7 @@ public class DeviceUdpDataHandleAdapter<TRequest> : UdpDataHandlingAdapter, IDev
|
||||
Logger?.LogWarning($"{ToString()} {request.ErrorMessage}");
|
||||
return false;
|
||||
}
|
||||
if (request.BodyLength + request.HeaderLength > byteBlock.CanReadLength)
|
||||
if (request.BodyLength + request.HeaderLength > byteBlock.BytesRead + byteBlock.BytesRemaining)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,6 @@ public static class ByteExtensions
|
||||
|
||||
// 如果是奇数,自动补齐 0
|
||||
int evenLen = (len % 2 == 0) ? len : len + 1;
|
||||
if (evenLen == len) return inBytes;
|
||||
|
||||
Span<byte> result = new byte[evenLen];
|
||||
inBytes.CopyTo(result);
|
||||
@@ -177,7 +176,6 @@ public static class ByteExtensions
|
||||
|
||||
// 如果是奇数,自动补齐 0
|
||||
int evenLen = (len % 2 == 0) ? len : len + 1;
|
||||
if (evenLen == len) return inBytes;
|
||||
|
||||
byte[] result = new byte[evenLen];
|
||||
inBytes.CopyTo(result);
|
||||
|
||||
@@ -51,6 +51,7 @@ public class LogDataCache
|
||||
/// <summary>高性能日志文件读取器(支持倒序读取)</summary>
|
||||
public static class TextFileReader
|
||||
{
|
||||
|
||||
private static readonly MemoryCache _cache = new() { Expire = 30 };
|
||||
private static readonly MemoryCache _fileLocks = new();
|
||||
private static readonly ArrayPool<byte> _bytePool = ArrayPool<byte>.Shared;
|
||||
@@ -59,7 +60,7 @@ public static class TextFileReader
|
||||
/// </summary>
|
||||
/// <param name="directoryPath">目录路径</param>
|
||||
/// <returns>包含文件信息的列表</returns>
|
||||
public static OperResult<List<string>> GetLogFilesAsync(string directoryPath)
|
||||
public static OperResult<List<string>> GetLogFiles(string directoryPath)
|
||||
{
|
||||
OperResult<List<string>> result = new(); // 初始化结果对象
|
||||
// 检查目录是否存在
|
||||
@@ -81,17 +82,25 @@ public static class TextFileReader
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// 获取文件信息并按照最后写入时间降序排序
|
||||
var fileInfos = files.Select(filePath => new FileInfo(filePath))
|
||||
.OrderByDescending(x => x.LastWriteTime)
|
||||
.Select(x => x.FullName)
|
||||
.Select(x =>
|
||||
{
|
||||
#if !NET6_0_OR_GREATER
|
||||
return PathHelper.GetRelativePath(AppContext.BaseDirectory, x.FullName);
|
||||
#else
|
||||
return Path.GetRelativePath(AppContext.BaseDirectory, x.FullName);
|
||||
#endif
|
||||
})
|
||||
.ToList();
|
||||
result.OperCode = 0;
|
||||
result.Content = fileInfos;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static OperResult<List<LogData>> LastLogDataAsync(string file, int lineCount = 200)
|
||||
public static OperResult<List<LogData>> LastLogData(string file, int lineCount = 200)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return new OperResult<List<LogData>>("The file path is invalid");
|
||||
@@ -104,7 +113,7 @@ public static class TextFileReader
|
||||
{
|
||||
var fileInfo = new FileInfo(file);
|
||||
var length = fileInfo.Length;
|
||||
var cacheKey = $"{nameof(TextFileReader)}_{nameof(LastLogDataAsync)}_{file})";
|
||||
var cacheKey = $"{nameof(TextFileReader)}_{nameof(LastLogData)}_{file})";
|
||||
if (_cache.TryGetValue<LogDataCache>(cacheKey, out var cachedData))
|
||||
{
|
||||
if (cachedData != null && cachedData.Length == length)
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace ThingsGateway.Foundation;
|
||||
|
||||
public interface ITextFileReadService
|
||||
{
|
||||
Task DeleteLogDataAsync(string path);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定目录下所有文件信息
|
||||
/// </summary>
|
||||
|
||||
@@ -10,11 +10,46 @@
|
||||
|
||||
|
||||
|
||||
using ThingsGateway.NewLife;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
public class TextFileReadService : ITextFileReadService
|
||||
{
|
||||
public Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath) => Task.FromResult(TextFileReader.GetLogFilesAsync(directoryPath));
|
||||
public Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath) => Task.FromResult(TextFileReader.GetLogFiles(directoryPath));
|
||||
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200) => Task.FromResult(TextFileReader.LastLogDataAsync(file, lineCount));
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200) => Task.FromResult(TextFileReader.LastLogData(file, lineCount));
|
||||
|
||||
|
||||
public async Task DeleteLogDataAsync(string path)
|
||||
{
|
||||
if (path != null)
|
||||
{
|
||||
var files = TextFileReader.GetLogFiles(path);
|
||||
if (files.IsSuccess)
|
||||
{
|
||||
foreach (var item in files.Content)
|
||||
{
|
||||
if (File.Exists(item))
|
||||
{
|
||||
int error = 0;
|
||||
while (error < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtil.DeleteFile(item);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Task.Delay(3000).ConfigureAwait(false);
|
||||
error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="$(NET9Version)" />
|
||||
<PackageReference Include="TouchSocket" Version="4.0.0-beta.3" />
|
||||
<PackageReference Include="TouchSocket.SerialPorts" Version="4.0.0-beta.3" />
|
||||
<PackageReference Include="TouchSocket" Version="4.0.0-beta.6" />
|
||||
<PackageReference Include="TouchSocket.SerialPorts" Version="4.0.0-beta.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
/// <summary>
|
||||
@@ -60,6 +61,8 @@ public class VariableClass : IVariable
|
||||
/// <summary>
|
||||
/// IVariableSource
|
||||
/// </summary>
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public IVariableSource? VariableSource { get; set; }
|
||||
public object? RawValue { get; private set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace ThingsGateway.Gateway.Application
|
||||
{
|
||||
public interface IScheduledTask
|
||||
public interface IScheduledTask : IDisposable
|
||||
{
|
||||
bool Change(int dueTime, int period);
|
||||
void SetNext(int interval);
|
||||
|
||||
@@ -0,0 +1,716 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using ThingsGateway.Authentication;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Rpc;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
[ApiDescriptionSettings("ThingsGateway.OpenApi", Order = 200)]
|
||||
[Route("openApi/management/[action]")]
|
||||
[RolePermission]
|
||||
[RequestAudit]
|
||||
[ApiController]
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[TouchSocket.WebApi.Router("/miniapi/management/[action]")]
|
||||
[TouchSocket.WebApi.EnableCors("cors")]
|
||||
public partial class ManagementController : ControllerBase, IRpcServer
|
||||
{
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<BackendLog>> BackendLogPageAsync(QueryPageOptions option) => App.GetService<IBackendLogService>().BackendLogPageAsync(option);
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<List<BackendLogDayStatisticsOutput>> BackendLogStatisticsByDayAsync(int day) => App.GetService<IBackendLogService>().BackendLogStatisticsByDayAsync(day);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchEditChannelAsync([FromBody] BatchEditChannelRequest request) =>
|
||||
App.GetService<IChannelPageService>()
|
||||
.BatchEditChannelAsync(request.Models, request.OldModel, request.Model, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchEditDeviceAsync([FromBody] BatchEditDeviceRequest request) =>
|
||||
App.GetService<IDevicePageService>()
|
||||
.BatchEditDeviceAsync(request.Models, request.OldModel, request.Model, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchEditVariableAsync([FromBody] BatchEditVariableRequest request) =>
|
||||
App.GetService<IVariablePageService>()
|
||||
.BatchEditVariableAsync(request.Models, request.OldModel, request.Model, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchSaveVariableAsync([FromBody] BatchSaveVariableRequest request) =>
|
||||
App.GetService<IVariablePageService>()
|
||||
.BatchSaveVariableAsync(request.Input, request.Type, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<LogLevel> ChannelLogLevelAsync(long id) =>
|
||||
App.GetService<IChannelPageService>().ChannelLogLevelAsync(id);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> ClearChannelAsync(bool restart) =>
|
||||
App.GetService<IChannelPageService>().ClearChannelAsync(restart);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> ClearDeviceAsync(bool restart) =>
|
||||
App.GetService<IDevicePageService>().ClearDeviceAsync(restart);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task ClearRulesAsync() => App.GetService<IRulesService>().ClearRulesAsync();
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> ClearVariableAsync(bool restart) =>
|
||||
App.GetService<IVariablePageService>().ClearVariableAsync(restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task CopyChannelAsync([FromBody] CopyChannelRequest request) =>
|
||||
App.GetService<IChannelPageService>()
|
||||
.CopyChannelAsync(request.CopyCount,
|
||||
request.CopyChannelNamePrefix,
|
||||
request.CopyChannelNameSuffixNumber,
|
||||
request.CopyDeviceNamePrefix,
|
||||
request.CopyDeviceNameSuffixNumber,
|
||||
request.ChannelId,
|
||||
request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task CopyDeviceAsync([FromBody] CopyDeviceRequest request) =>
|
||||
App.GetService<IDevicePageService>()
|
||||
.CopyDeviceAsync(request.CopyCount,
|
||||
request.CopyDeviceNamePrefix,
|
||||
request.CopyDeviceNameSuffixNumber,
|
||||
request.DeviceId,
|
||||
request.AutoRestartThread);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task CopyVariableAsync([FromBody] CopyVariableRequest request) =>
|
||||
App.GetService<IVariablePageService>()
|
||||
.CopyVariableAsync(request.Model,
|
||||
request.CopyCount,
|
||||
request.CopyVariableNamePrefix,
|
||||
request.CopyVariableNameSuffixNumber,
|
||||
request.Restart);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task DeleteBackendLogAsync() => App.GetService<IBackendLogService>().DeleteBackendLogAsync();
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> DeleteChannelAsync([FromBody] DeleteRequest request) =>
|
||||
App.GetService<IChannelPageService>().DeleteChannelAsync(request.Ids, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> DeleteDeviceAsync([FromBody] DeleteRequest request) =>
|
||||
App.GetService<IDevicePageService>().DeleteDeviceAsync(request.Ids, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> DeleteVariableAsync([FromBody] DeleteRequest request) =>
|
||||
App.GetService<IVariablePageService>().DeleteVariableAsync(request.Ids, request.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task DeleteRpcLogAsync() => App.GetService<IRpcLogService>().DeleteRpcLogAsync();
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task DeleteRuleRuntimesAsync(List<long> ids) => App.GetService<IRulesEngineHostedService>().DeleteRuleRuntimesAsync(ids);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> DeleteRulesAsync(List<long> ids) => App.GetService<IRulesService>().DeleteRulesAsync(ids);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<LogLevel> DeviceLogLevelAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().DeviceLogLevelAsync(id);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task DeviceRedundantThreadAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().DeviceRedundantThreadAsync(id);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task EditRedundancyOptionAsync(RedundancyOptions input) => App.GetService<IRedundancyService>().EditRedundancyOptionAsync(input);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task EditRuleRuntimesAsync(Rules rules) => App.GetService<IRulesEngineHostedService>().EditRuleRuntimesAsync(rules);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<USheetDatas> ExportChannelAsync(List<Channel> channels) =>
|
||||
App.GetService<IChannelPageService>().ExportChannelAsync(channels);
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<string> ExportChannelFileAsync(GatewayExportFilter exportFilter) =>
|
||||
App.GetService<IChannelPageService>().ExportChannelFileAsync(exportFilter);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<USheetDatas> ExportDeviceAsync(List<Device> devices) =>
|
||||
App.GetService<IDevicePageService>().ExportDeviceAsync(devices);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<string> ExportDeviceFileAsync(GatewayExportFilter exportFilter) =>
|
||||
App.GetService<IDevicePageService>().ExportDeviceFileAsync(exportFilter);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<USheetDatas> ExportVariableAsync(List<Variable> models, string? sortName, SortOrder sortOrder) =>
|
||||
App.GetService<IVariablePageService>().ExportVariableAsync(models, sortName, sortOrder);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<string> ExportVariableFileAsync(GatewayExportFilter exportFilter) => App.GetService<IVariablePageService>().ExportVariableFileAsync(exportFilter);
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<List<Channel>> GetChannelListAsync([FromBody] GetListRequest<QueryPageOptions> request) =>
|
||||
App.GetService<IChannelPageService>().GetChannelListAsync(request.Options, request.Max);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<List<Device>> GetDeviceListAsync([FromBody] GetListRequest<QueryPageOptions> request) =>
|
||||
App.GetService<IDevicePageService>().GetDeviceListAsync(request.Options, request.Max);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<List<Variable>> GetVariableListAsync([FromBody] GetListRequest<QueryPageOptions> request) =>
|
||||
App.GetService<IVariablePageService>().GetVariableListAsync(request.Options, request.Max);
|
||||
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<List<Rules>> GetAllRulesAsync() => App.GetService<IRulesService>().GetAllRulesAsync();
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<string> GetChannelNameAsync(long id) =>
|
||||
App.GetService<IChannelPageService>().GetChannelNameAsync(id);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<IEnumerable<SelectedItem>> GetCurrentUserDeviceSelectedItemsAsync(string searchText, int startIndex, int count) => App.GetService<IGlobalDataService>().GetCurrentUserDeviceSelectedItemsAsync(searchText, startIndex, count);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<QueryData<SelectedItem>> GetCurrentUserDeviceVariableSelectedItemsAsync(string deviceText, string searchText, int startIndex, int count) => App.GetService<IGlobalDataService>().GetCurrentUserDeviceVariableSelectedItemsAsync(deviceText, searchText, startIndex, count);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<IEnumerable<AlarmVariable>> GetCurrentUserRealAlarmVariablesAsync() => App.GetService<IRealAlarmService>().GetCurrentUserRealAlarmVariablesAsync();
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<Dictionary<long, Tuple<string, string>>> GetDeviceIdNamesAsync() => App.GetService<IDevicePageService>().GetDeviceIdNamesAsync();
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<string> GetDeviceNameAsync(long redundantDeviceId) =>
|
||||
App.GetService<IDevicePageService>().GetDeviceNameAsync(redundantDeviceId);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<string> GetDevicePluginNameAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().GetDevicePluginNameAsync(id);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath) => App.GetService<ITextFileReadService>().GetLogFilesAsync(directoryPath);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<List<BackendLog>> GetNewBackendLogAsync() => App.GetService<IBackendLogService>().GetNewBackendLogAsync();
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<List<RpcLog>> GetNewRpcLogAsync() => App.GetService<IRpcLogService>().GetNewRpcLogAsync();
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<string> GetPluginNameAsync(long channelId) => App.GetService<IChannelPageService>().GetPluginNameAsync(channelId);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<List<PluginInfo>> GetPluginsAsync(PluginTypeEnum? pluginType = null) => App.GetService<IPluginPageService>().GetPluginsAsync(pluginType);
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<RedundancyOptions> GetRedundancyAsync() => App.GetService<IRedundancyService>().GetRedundancyAsync();
|
||||
[HttpGet]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Get)]
|
||||
public Task<Rules> GetRuleRuntimesAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().GetRuleRuntimesAsync(rulesId);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task ImportChannelDataAsync([FromBody] ImportChannelInput input) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelAsync(input.UpData, input.InsertData, input.Restart);
|
||||
|
||||
[HttpPost]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelAsync([FromForm] ImportRequest request)
|
||||
{
|
||||
return (await App.GetService<IChannelRuntimeService>().ImportChannelAsync(request.File, request.Restart).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
|
||||
}
|
||||
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
[TouchSocket.WebApi.Router("/miniapi/management/ImportChannel")]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> TSImportChannelAsync(TouchSocket.WebApi.IWebApiCallContext callContext)
|
||||
{
|
||||
var path = await callContext.HttpContext.Request.StorageLocalExcel().ConfigureAwait(false);
|
||||
|
||||
return (await GlobalData.ChannelRuntimeService.ImportChannelFileAsync(path, true).ConfigureAwait(false)).AdaptImportPreviewOutputBases(); ;
|
||||
|
||||
}
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
[TouchSocket.WebApi.Router("/miniapi/management/ImportDevice")]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> TSImportDeviceAsync(TouchSocket.WebApi.IWebApiCallContext callContext)
|
||||
{
|
||||
var path = await callContext.HttpContext.Request.StorageLocalExcel().ConfigureAwait(false);
|
||||
|
||||
return (await GlobalData.DeviceRuntimeService.ImportDeviceFileAsync(path, true).ConfigureAwait(false)).AdaptImportPreviewOutputBases(); ;
|
||||
|
||||
}
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
[TouchSocket.WebApi.Router("/miniapi/management/ImportVariable")]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> TSImportVariableAsync(TouchSocket.WebApi.IWebApiCallContext callContext)
|
||||
{
|
||||
var path = await callContext.HttpContext.Request.StorageLocalExcel().ConfigureAwait(false);
|
||||
|
||||
return (await GlobalData.VariableRuntimeService.ImportVariableFileAsync(path, true).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelUSheetDatasAsync([FromBody] ImportUSheetInput input)
|
||||
{
|
||||
return (await App.GetService<IChannelPageService>().ImportChannelUSheetDatasAsync(input.Input, input.Restart).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceAsync([FromForm] ImportRequest request)
|
||||
{
|
||||
|
||||
return (await App.GetService<IDeviceRuntimeService>().ImportDeviceAsync(request.File, request.Restart).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceUSheetDatasAsync([FromBody] ImportUSheetInput input)
|
||||
{
|
||||
|
||||
return (await App.GetService<IDevicePageService>().ImportDeviceUSheetDatasAsync(input.Input, input.Restart).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableAsync([FromForm] ImportRequest request)
|
||||
{
|
||||
return (await App.GetService<IVariableRuntimeService>().ImportVariableAsync(request.File, request.Restart).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableUSheetDatasAsync([FromBody] ImportUSheetInput input)
|
||||
{
|
||||
return (await App.GetService<IVariablePageService>().ImportVariableUSheetDatasAsync(input.Input, input.Restart).ConfigureAwait(false)).AdaptImportPreviewOutputBases();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task InsertTestDataAsync([FromBody] InsertTestDataInput input) =>
|
||||
App.GetService<IVariablePageService>().InsertTestDataAsync(input.TestVariableCount, input.TestDeviceCount, input.SlaveUrl, input.BusinessEnable, input.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> IsRedundantDeviceAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().IsRedundantDeviceAsync(id);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync([FromBody] LastLogDataInput input) =>
|
||||
App.GetService<ITextFileReadService>().LastLogDataAsync(input.File, input.LineCount);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<ChannelRuntime>> OnChannelQueryAsync([FromBody] QueryPageOptions options) =>
|
||||
App.GetService<IChannelPageService>().OnChannelQueryAsync(options);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<SelectedItem>> OnChannelSelectedItemQueryAsync([FromBody] VirtualizeQueryOption option) =>
|
||||
App.GetService<IChannelPageService>().OnChannelSelectedItemQueryAsync(option);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<DeviceRuntime>> OnDeviceQueryAsync([FromBody] QueryPageOptions options) =>
|
||||
App.GetService<IDevicePageService>().OnDeviceQueryAsync(options);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<SelectedItem>> OnDeviceSelectedItemQueryAsync([FromBody] OnDeviceSelectedItemQueryInput input) =>
|
||||
App.GetService<IDevicePageService>().OnDeviceSelectedItemQueryAsync(input.Option, input.IsCollect);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<SelectedItem>> OnRedundantDevicesQueryAsync([FromBody] OnRedundantDevicesQueryInput input) =>
|
||||
App.GetService<IDevicePageService>().OnRedundantDevicesQueryAsync(input.Option, input.DeviceId, input.ChannelId);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<VariableRuntime>> OnVariableQueryAsync([FromBody] QueryPageOptions options) =>
|
||||
App.GetService<IVariablePageService>().OnVariableQueryAsync(options);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<OperResult<object>> OnWriteVariableAsync(long id, string writeData) =>
|
||||
App.GetService<IVariablePageService>().OnWriteVariableAsync(id, writeData);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task PauseThreadAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().PauseThreadAsync(id);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<PluginInfo>> PluginPageAsync([FromBody] PluginQueryPageOptions options) =>
|
||||
App.GetService<IPluginPageService>().PluginPageAsync(options.Options, options.PluginType);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task RedundancyForcedSync() => App.GetService<IRedundancyHostedService>().RedundancyForcedSync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<LogLevel> RedundancyLogLevelAsync() => App.GetService<IRedundancyHostedService>().RedundancyLogLevelAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<string> RedundancyLogPathAsync() => App.GetService<IRedundancyHostedService>().RedundancyLogPathAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task ReloadPluginAsync() => App.GetService<IPluginPageService>().ReloadPluginAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task RestartChannelAsync(long channelId) =>
|
||||
App.GetService<IChannelPageService>().RestartChannelAsync(channelId);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task RestartChannelsAsync() =>
|
||||
App.GetService<IChannelPageService>().RestartChannelsAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task RestartDeviceAsync(long id, bool deleteCache) =>
|
||||
App.GetService<IDevicePageService>().RestartDeviceAsync(id, deleteCache);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task RestartServerAsync() => App.GetService<IRestartService>().RestartServerAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<RpcLog>> RpcLogPageAsync([FromBody] QueryPageOptions option) =>
|
||||
App.GetService<IRpcLogService>().RpcLogPageAsync(option);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<List<RpcLogDayStatisticsOutput>> RpcLogStatisticsByDayAsync(int day) =>
|
||||
App.GetService<IRpcLogService>().RpcLogStatisticsByDayAsync(day);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<TouchSocket.Core.LogLevel> RulesLogLevelAsync(long rulesId) =>
|
||||
App.GetService<IRulesEngineHostedService>().RulesLogLevelAsync(rulesId);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<string> RulesLogPathAsync(long rulesId) =>
|
||||
App.GetService<IRulesEngineHostedService>().RulesLogPathAsync(rulesId);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<QueryData<Rules>> RulesPageAsync([FromBody] KVQueryPageOptions option) =>
|
||||
App.GetService<IRulesService>().RulesPageAsync(option.Options, option.FilterKeyValueAction);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> SaveChannelAsync([FromBody] SaveChannelInput input) =>
|
||||
App.GetService<IChannelPageService>().SaveChannelAsync(input.Input, input.Type, input.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> SaveDeviceAsync([FromBody] SaveDeviceInput input) =>
|
||||
App.GetService<IDevicePageService>().SaveDeviceAsync(input.Input, input.Type, input.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task SavePluginByPathAsync([FromBody] PluginAddPathInput plugin) =>
|
||||
App.GetService<IPluginPageService>().SavePluginByPathAsync(plugin);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> SaveRulesAsync([FromBody] Rules input, ItemChangedType type) =>
|
||||
App.GetService<IRulesService>().SaveRulesAsync(input, type);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> SaveVariableAsync([FromBody] SaveVariableInput input) =>
|
||||
App.GetService<IVariablePageService>().SaveVariableAsync(input.Input, input.Type, input.Restart);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task SetChannelLogLevelAsync([FromBody] SetChannelLogLevelInput input) =>
|
||||
App.GetService<IChannelPageService>().SetChannelLogLevelAsync(input.Id, input.LogLevel);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task SetDeviceLogLevelAsync([FromBody] SetDeviceLogLevelInput input) =>
|
||||
App.GetService<IDevicePageService>().SetDeviceLogLevelAsync(input.Id, input.LogLevel);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task SetRedundancyLogLevelAsync(LogLevel logLevel) =>
|
||||
App.GetService<IRedundancyHostedService>().SetRedundancyLogLevelAsync(logLevel);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task SetRulesLogLevelAsync([FromBody] SetRulesLogLevelInput input) =>
|
||||
App.GetService<IRulesEngineHostedService>().SetRulesLogLevelAsync(input.RulesId, input.LogLevel);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> StartBusinessChannelEnableAsync() => App.GetService<IChannelEnableService>().StartBusinessChannelEnableAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> StartCollectChannelEnableAsync() => App.GetService<IChannelEnableService>().StartCollectChannelEnableAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task StartRedundancyTaskAsync() => App.GetService<IRedundancyHostedService>().StartRedundancyTaskAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task StopRedundancyTaskAsync() => App.GetService<IRedundancyHostedService>().StopRedundancyTaskAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<AuthorizeInfo> TryAuthorizeAsync(string password) => App.GetService<IAuthenticationService>().TryAuthorizeAsync(password);
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<AuthorizeInfo> TryGetAuthorizeInfoAsync() => App.GetService<IAuthenticationService>().TryGetAuthorizeInfoAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task UnAuthorizeAsync() => App.GetService<IAuthenticationService>().UnAuthorizeAsync();
|
||||
|
||||
[HttpPost]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<string> UUIDAsync() => App.GetService<IAuthenticationService>().UUIDAsync();
|
||||
}
|
||||
// 定义请求 DTO
|
||||
public class BatchEditChannelRequest
|
||||
{
|
||||
public List<Channel> Models { get; set; }
|
||||
public Channel OldModel { get; set; }
|
||||
public Channel Model { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class BatchEditDeviceRequest
|
||||
{
|
||||
public List<Device> Models { get; set; }
|
||||
public Device OldModel { get; set; }
|
||||
public Device Model { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class BatchEditVariableRequest
|
||||
{
|
||||
public List<Variable> Models { get; set; }
|
||||
public Variable OldModel { get; set; }
|
||||
public Variable Model { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class BatchSaveVariableRequest
|
||||
{
|
||||
public List<Variable> Input { get; set; }
|
||||
public ItemChangedType Type { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
public class CopyChannelRequest
|
||||
{
|
||||
public int CopyCount { get; set; }
|
||||
public string CopyChannelNamePrefix { get; set; }
|
||||
public int CopyChannelNameSuffixNumber { get; set; }
|
||||
public string CopyDeviceNamePrefix { get; set; }
|
||||
public int CopyDeviceNameSuffixNumber { get; set; }
|
||||
public long ChannelId { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class CopyDeviceRequest
|
||||
{
|
||||
public int CopyCount { get; set; }
|
||||
public string CopyDeviceNamePrefix { get; set; }
|
||||
public int CopyDeviceNameSuffixNumber { get; set; }
|
||||
public long DeviceId { get; set; }
|
||||
public bool AutoRestartThread { get; set; }
|
||||
}
|
||||
|
||||
public class CopyVariableRequest
|
||||
{
|
||||
public List<Variable> Model { get; set; }
|
||||
public int CopyCount { get; set; }
|
||||
public string CopyVariableNamePrefix { get; set; }
|
||||
public int CopyVariableNameSuffixNumber { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
public class DeleteRequest
|
||||
{
|
||||
public List<long> Ids { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
public class GetListRequest<TOptions>
|
||||
{
|
||||
public TOptions Options { get; set; }
|
||||
public int Max { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class ImportChannelInput
|
||||
{
|
||||
public List<Channel> UpData { get; set; }
|
||||
public List<Channel> InsertData { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class ImportFileInput
|
||||
{
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class ImportUSheetInput
|
||||
{
|
||||
public USheetDatas Input { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class InsertTestDataInput
|
||||
{
|
||||
public int TestVariableCount { get; set; }
|
||||
public int TestDeviceCount { get; set; }
|
||||
public string SlaveUrl { get; set; }
|
||||
public bool BusinessEnable { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class LastLogDataInput
|
||||
{
|
||||
public string File { get; set; }
|
||||
public int LineCount { get; set; } = 200;
|
||||
}
|
||||
|
||||
public class OnDeviceSelectedItemQueryInput
|
||||
{
|
||||
public VirtualizeQueryOption Option { get; set; }
|
||||
public bool IsCollect { get; set; }
|
||||
}
|
||||
|
||||
public class OnRedundantDevicesQueryInput
|
||||
{
|
||||
public VirtualizeQueryOption Option { get; set; }
|
||||
public long DeviceId { get; set; }
|
||||
public long ChannelId { get; set; }
|
||||
}
|
||||
|
||||
public class SaveChannelInput
|
||||
{
|
||||
public Channel Input { get; set; }
|
||||
public ItemChangedType Type { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class SaveDeviceInput
|
||||
{
|
||||
public Device Input { get; set; }
|
||||
public ItemChangedType Type { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class SaveVariableInput
|
||||
{
|
||||
public Variable Input { get; set; }
|
||||
public ItemChangedType Type { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public class SetChannelLogLevelInput
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
}
|
||||
|
||||
public class SetDeviceLogLevelInput
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
}
|
||||
|
||||
public class SetRulesLogLevelInput
|
||||
{
|
||||
public long RulesId { get; set; }
|
||||
public TouchSocket.Core.LogLevel LogLevel { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class ImportRequest
|
||||
{
|
||||
public IFormFile File { get; set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class PluginQueryPageOptions
|
||||
{
|
||||
public QueryPageOptions Options { get; set; }
|
||||
public PluginTypeEnum PluginType { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class KVQueryPageOptions
|
||||
{
|
||||
public QueryPageOptions Options { get; set; }
|
||||
public FilterKeyValueAction FilterKeyValueAction { get; set; }
|
||||
}
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
/// <summary>
|
||||
@@ -35,7 +33,7 @@ public class BackendLog : PrimaryIdEntity
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "日志级别", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public LogLevel LogLevel { get; set; }
|
||||
public Microsoft.Extensions.Logging.LogLevel LogLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志来源
|
||||
|
||||
@@ -61,7 +61,7 @@ public class LogJob : IJob
|
||||
|
||||
//网关通道日志以通道id命名
|
||||
var rulesService = App.RootServices.GetService<IRulesService>();
|
||||
var ruleNames = (await rulesService.GetAllAsync().ConfigureAwait(false)).Select(a => a.Name.ToString()).ToHashSet();
|
||||
var ruleNames = (await rulesService.GetAllRulesAsync().ConfigureAwait(false)).Select(a => a.Name.ToString()).ToHashSet();
|
||||
var ruleBaseDir = RulesEngineHostedService.LogDir;
|
||||
Directory.CreateDirectory(ruleBaseDir);
|
||||
|
||||
|
||||
@@ -67,4 +67,9 @@ public static partial class GatewayMapper
|
||||
public static partial Device AdaptDevice(this Device src);
|
||||
public static partial Variable AdaptVariable(this Variable src);
|
||||
public static partial List<PluginInfo> AdaptListPluginInfo(this List<PluginInfo> src);
|
||||
|
||||
|
||||
public static partial Dictionary<string, ImportPreviewOutputBase> AdaptImportPreviewOutputBases(this Dictionary<string, ImportPreviewOutputBase> src);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
@@ -401,6 +402,33 @@ public class ChannelRuntimeService : IChannelRuntimeService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelAsync(IFormFile file, bool restart)
|
||||
{
|
||||
try
|
||||
{
|
||||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
var data = await GlobalData.ChannelService.PreviewAsync(file).ConfigureAwait(false);
|
||||
|
||||
if (data.Any(a => a.Value.HasError)) return data;
|
||||
var result = await GlobalData.ChannelService.ImportChannelAsync(data).ConfigureAwait(false);
|
||||
|
||||
var newChannelRuntimes = await RuntimeServiceHelper.GetNewChannelRuntimesAsync(result).ConfigureAwait(false);
|
||||
|
||||
RuntimeServiceHelper.Init(newChannelRuntimes);
|
||||
|
||||
//根据条件重启通道线程
|
||||
if (restart)
|
||||
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
WaitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using MiniExcelLibs;
|
||||
|
||||
@@ -409,8 +410,6 @@ internal sealed class ChannelService : BaseService<Channel>, IChannelService
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile)
|
||||
{
|
||||
@@ -418,6 +417,13 @@ internal sealed class ChannelService : BaseService<Channel>, IChannelService
|
||||
return await PreviewAsync(path).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IFormFile browserFile)
|
||||
{
|
||||
var path = await browserFile.StorageLocal().ConfigureAwait(false);
|
||||
return await PreviewAsync(path).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(string path)
|
||||
{
|
||||
@@ -468,7 +474,7 @@ internal sealed class ChannelService : BaseService<Channel>, IChannelService
|
||||
if (channel == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, unportNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, unportNull));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -491,7 +497,7 @@ internal sealed class ChannelService : BaseService<Channel>, IChannelService
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -512,19 +518,19 @@ internal sealed class ChannelService : BaseService<Channel>, IChannelService
|
||||
|
||||
if (channel.IsUp && ((dataScope != null && dataScope?.Count > 0 && !dataScope.Contains(channel.CreateOrgId)) || dataScope?.Count == 0 && channel.CreateUserId != UserManager.UserId))
|
||||
{
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, "Operation not permitted"));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, "Operation not permitted"));
|
||||
}
|
||||
else
|
||||
{
|
||||
channels.Add(channel);
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), true, null));
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
@@ -38,7 +39,5 @@ public interface IChannelRuntimeService : IChannelPageService
|
||||
Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, bool restart);
|
||||
Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart);
|
||||
Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart);
|
||||
|
||||
|
||||
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelAsync(IFormFile file, bool restart);
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using System.Linq.Expressions;
|
||||
|
||||
@@ -105,4 +106,5 @@ internal interface IChannelService
|
||||
Task<HashSet<long>> ImportChannelAsync(List<Channel> upData, List<Channel> insertData);
|
||||
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(string path);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IFormFile browserFile);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
@@ -356,6 +357,42 @@ public class DeviceRuntimeService : IDeviceRuntimeService
|
||||
WaitLock.Release();
|
||||
}
|
||||
}
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceAsync(IFormFile file, bool restart)
|
||||
{
|
||||
try
|
||||
{
|
||||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
var data = await GlobalData.DeviceService.PreviewAsync(file).ConfigureAwait(false);
|
||||
|
||||
if (data.Any(a => a.Value.HasError)) return data;
|
||||
|
||||
var deviceids = await GlobalData.DeviceService.ImportDeviceAsync(data).ConfigureAwait(false);
|
||||
|
||||
var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(deviceids).ConfigureAwait(false);
|
||||
|
||||
if (restart)
|
||||
{
|
||||
var newDeciceIds = newDeviceRuntimes.Select(a => a.Id).ToHashSet();
|
||||
await RuntimeServiceHelper.RemoveDeviceAsync(newDeciceIds).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//批量修改之后,需要重新加载通道
|
||||
RuntimeServiceHelper.Init(newDeviceRuntimes);
|
||||
|
||||
//根据条件重启通道线程
|
||||
if (restart)
|
||||
{
|
||||
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
finally
|
||||
{
|
||||
WaitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceUSheetDatasAsync(USheetDatas input, bool restart)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using MiniExcelLibs;
|
||||
|
||||
@@ -403,14 +404,20 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
return upData.Select(a => a.Id).Concat(insertData.Select(a => a.Id)).ToHashSet();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile)
|
||||
{
|
||||
var path = await browserFile.StorageLocal().ConfigureAwait(false); // 上传文件并获取文件路径
|
||||
|
||||
return await PreviewAsync(path).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IFormFile browserFile)
|
||||
{
|
||||
var path = await browserFile.StorageLocal().ConfigureAwait(false); // 上传文件并获取文件路径
|
||||
|
||||
return await PreviewAsync(path).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(string path)
|
||||
{
|
||||
@@ -495,7 +502,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (device == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ImportNullError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ImportNullError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -512,7 +519,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
{
|
||||
// 如果找不到对应的冗余设备,则添加错误信息到导入预览结果并返回
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, RedundantDeviceError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, RedundantDeviceError));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -522,7 +529,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (device.RedundantEnable)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, RedundantDeviceError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, RedundantDeviceError));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -536,7 +543,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
{
|
||||
// 如果找不到对应的通道信息,则添加错误信息到导入预览结果并返回
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ChannelError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ChannelError));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -544,7 +551,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
{
|
||||
// 如果未提供通道信息,则添加错误信息到导入预览结果并返回
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ChannelError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ChannelError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -567,7 +574,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -590,12 +597,12 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
// 将设备添加到设备列表中,并添加成功信息到导入预览结果
|
||||
if (device.IsUp && ((dataScope != null && dataScope?.Count > 0 && !dataScope.Contains(device.CreateOrgId)) || dataScope?.Count == 0 && device.CreateUserId != UserManager.UserId))
|
||||
{
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, "Operation not permitted"));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, "Operation not permitted"));
|
||||
}
|
||||
else
|
||||
{
|
||||
devices.Add(device);
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), true, null));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -603,7 +610,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -636,7 +643,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (driverPluginType == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["NotNull", sheetName]));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, Localizer["NotNull", sheetName]));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -677,7 +684,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (propertys.Item1 == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, PluginNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, PluginNotNull));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -685,7 +692,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (!item.TryGetValue(GatewayExportString.DeviceName, out var deviceName))
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, DeviceNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, DeviceNotNull));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -697,7 +704,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (!hasDevice)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["NotNull", value]));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, Localizer["NotNull", value]));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -708,7 +715,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (pluginProp == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ImportNullError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ImportNullError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -731,7 +738,7 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -747,14 +754,14 @@ internal sealed class DeviceService : BaseService<Device>, IDeviceService
|
||||
|
||||
// 更新设备导入预览数据中对应设备的属性信息,并添加成功信息到导入预览结果
|
||||
deviceImportPreview.Data[value].DevicePropertys = devices;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), true, null));
|
||||
continue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果并返回
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application
|
||||
{
|
||||
@@ -24,5 +25,6 @@ namespace ThingsGateway.Gateway.Application
|
||||
Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart);
|
||||
Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type, bool restart);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceAsync(IFormFile file, bool restart);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq.Expressions;
|
||||
@@ -121,4 +122,5 @@ internal interface IDeviceService
|
||||
Task UpdateLogAsync(long deviceId, TouchSocket.Core.LogLevel logLevel);
|
||||
Task<HashSet<long>> ImportDeviceAsync(List<Device> upData, List<Device> insertData);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(string path);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IFormFile browserFile);
|
||||
}
|
||||
|
||||
@@ -64,9 +64,15 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
|
||||
CancellationToken.Register(() => GlobalData.DeviceStatusChangeEvent -= GlobalData_DeviceStatusChangeEvent);
|
||||
|
||||
_ = Task.Run(() => CheckThreadAsync(CancellationToken));
|
||||
_ = Task.Run(() => CheckRedundantAsync(CancellationToken));
|
||||
CheckThreadAsyncTimer = ScheduledTaskHelper.GetTask(ManageHelper.ChannelThreadOptions.CheckInterval.ToString(), CheckThreadAsync, null, LogMessage, CancellationToken);
|
||||
CheckRedundantAsyncTimer = ScheduledTaskHelper.GetTask("5000", CheckRedundantAsync, null, LogMessage, CancellationToken);
|
||||
CheckThreadAsyncTimer.Start();
|
||||
CheckRedundantAsyncTimer.Start();
|
||||
}
|
||||
|
||||
private IScheduledTask CheckThreadAsyncTimer;
|
||||
private IScheduledTask CheckRedundantAsyncTimer;
|
||||
|
||||
private CancellationTokenSource CancellationTokenSource = new();
|
||||
|
||||
private CancellationToken CancellationToken;
|
||||
@@ -674,52 +680,47 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
private async Task CheckRedundantAsync(CancellationToken cancellationToken)
|
||||
private async Task CheckRedundantAsync(object? state, CancellationToken cancellationToken)
|
||||
{
|
||||
while (!Disposed)
|
||||
try
|
||||
{
|
||||
try
|
||||
foreach (var kv in Drivers)
|
||||
{
|
||||
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
||||
foreach (var kv in Drivers)
|
||||
if (Disposed) return;
|
||||
var deviceRuntime = kv.Value.CurrentDevice;
|
||||
if (deviceRuntime != null && GlobalData.IsRedundant(deviceRuntime.Id) && deviceRuntime.Driver != null && deviceRuntime.RedundantSwitchType == RedundantSwitchTypeEnum.Script)
|
||||
{
|
||||
if (Disposed) return;
|
||||
var deviceRuntime = kv.Value.CurrentDevice;
|
||||
if (deviceRuntime != null && GlobalData.IsRedundant(deviceRuntime.Id) && deviceRuntime.Driver != null && deviceRuntime.RedundantSwitchType == RedundantSwitchTypeEnum.Script)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
if (deviceRuntime.Driver != null)
|
||||
{
|
||||
if (deviceRuntime.Driver != null)
|
||||
if (deviceRuntime.RedundantScript.GetExpressionsResult(deviceRuntime).ToBoolean(true) && (deviceRuntime.Driver?.IsInitSuccess == false || deviceRuntime.Driver?.IsStarted == true) && deviceRuntime.Driver?.DisposedValue != true)
|
||||
{
|
||||
if (deviceRuntime.RedundantScript.GetExpressionsResult(deviceRuntime).ToBoolean(true) && (deviceRuntime.Driver?.IsInitSuccess == false || deviceRuntime.Driver?.IsStarted == true) && deviceRuntime.Driver?.DisposedValue != true)
|
||||
await Task.Delay(deviceRuntime.RedundantScanIntervalTime, cancellationToken).ConfigureAwait(false);//10s后再次检测
|
||||
if (Disposed) return;
|
||||
if ((deviceRuntime.RedundantScript.GetExpressionsResult(deviceRuntime).ToBoolean(true) && deviceRuntime.Driver?.IsInitSuccess == false || deviceRuntime.Driver?.IsStarted == true) && deviceRuntime.Driver?.DisposedValue != true && deviceRuntime.RedundantType != RedundantTypeEnum.Standby)
|
||||
{
|
||||
await Task.Delay(deviceRuntime.RedundantScanIntervalTime, cancellationToken).ConfigureAwait(false);//10s后再次检测
|
||||
if (Disposed) return;
|
||||
if ((deviceRuntime.RedundantScript.GetExpressionsResult(deviceRuntime).ToBoolean(true) && deviceRuntime.Driver?.IsInitSuccess == false || deviceRuntime.Driver?.IsStarted == true) && deviceRuntime.Driver?.DisposedValue != true && deviceRuntime.RedundantType != RedundantTypeEnum.Standby)
|
||||
//冗余切换
|
||||
if (GlobalData.IsRedundant(deviceRuntime.Id))
|
||||
{
|
||||
//冗余切换
|
||||
if (GlobalData.IsRedundant(deviceRuntime.Id))
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
await DeviceRedundantThreadAsync(deviceRuntime.Id, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
await DeviceRedundantThreadAsync(deviceRuntime.Id, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, nameof(CheckRedundantAsync));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, nameof(CheckRedundantAsync));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,60 +729,57 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
#region 假死检测
|
||||
|
||||
/// <inheritdoc/>
|
||||
private async Task CheckThreadAsync(CancellationToken cancellationToken)
|
||||
private async Task CheckThreadAsync(object? state, CancellationToken cancellationToken)
|
||||
{
|
||||
while (!Disposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
//检测设备线程假死
|
||||
await Task.Delay(ManageHelper.ChannelThreadOptions.CheckInterval, cancellationToken).ConfigureAwait(false);
|
||||
if (Disposed) return;
|
||||
|
||||
var num = Drivers.Count;
|
||||
foreach (var driver in Drivers.Select(a => a.Value).Where(a => a != null).ToList())
|
||||
try
|
||||
{
|
||||
if (Disposed) return;
|
||||
|
||||
var num = Drivers.Count;
|
||||
foreach (var driver in Drivers.Select(a => a.Value).Where(a => a != null).ToList())
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
if (Disposed) return;
|
||||
if (driver.CurrentDevice != null)
|
||||
{
|
||||
if (Disposed) return;
|
||||
if (driver.CurrentDevice != null)
|
||||
//线程卡死/初始化失败检测
|
||||
if (((driver.IsStarted && driver.CurrentDevice.ActiveTime != DateTime.UnixEpoch.ToLocalTime() && driver.CurrentDevice.ActiveTime.AddMilliseconds(ManageHelper.ChannelThreadOptions.CheckInterval) <= DateTime.Now)
|
||||
|| (driver.IsInitSuccess == false)) && !driver.DisposedValue)
|
||||
{
|
||||
//线程卡死/初始化失败检测
|
||||
if (((driver.IsStarted && driver.CurrentDevice.ActiveTime != DateTime.UnixEpoch.ToLocalTime() && driver.CurrentDevice.ActiveTime.AddMilliseconds(ManageHelper.ChannelThreadOptions.CheckInterval) <= DateTime.Now)
|
||||
|| (driver.IsInitSuccess == false)) && !driver.DisposedValue)
|
||||
{
|
||||
//如果线程处于暂停状态,跳过
|
||||
if (driver.CurrentDevice.DeviceStatus == DeviceStatusEnum.Pause)
|
||||
continue;
|
||||
//如果初始化失败
|
||||
if (!driver.IsInitSuccess)
|
||||
LogMessage?.LogWarning($"Device {driver.CurrentDevice.Name} initialization failed, restarting thread");
|
||||
else
|
||||
LogMessage?.LogWarning($"Device {driver.CurrentDevice.Name} thread died, restarting thread");
|
||||
//重启线程
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
await RestartDeviceAsync(driver.CurrentDevice, false).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
//如果线程处于暂停状态,跳过
|
||||
if (driver.CurrentDevice.DeviceStatus == DeviceStatusEnum.Pause)
|
||||
continue;
|
||||
//如果初始化失败
|
||||
if (!driver.IsInitSuccess)
|
||||
LogMessage?.LogWarning($"Device {driver.CurrentDevice.Name} initialization failed, restarting thread");
|
||||
else
|
||||
LogMessage?.LogWarning($"Device {driver.CurrentDevice.Name} thread died, restarting thread");
|
||||
//重启线程
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
await RestartDeviceAsync(driver.CurrentDevice, false).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, nameof(CheckThreadAsync));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, nameof(CheckThreadAsync));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, nameof(CheckThreadAsync));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, nameof(CheckThreadAsync));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -803,6 +801,9 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
Disposed = true;
|
||||
try
|
||||
{
|
||||
CheckThreadAsyncTimer.SafeDispose();
|
||||
CheckRedundantAsyncTimer.SafeDispose();
|
||||
|
||||
await CancellationTokenSource.SafeCancelAsync().ConfigureAwait(false);
|
||||
CancellationTokenSource.SafeDispose();
|
||||
GlobalData.DeviceStatusChangeEvent -= GlobalData_DeviceStatusChangeEvent;
|
||||
|
||||
@@ -14,34 +14,69 @@ using ThingsGateway.Authentication;
|
||||
|
||||
using TouchSocket.Dmtp.Rpc;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.WebApi;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
#if Management
|
||||
[GeneratorRpcProxy(GeneratorFlag = GeneratorFlag.ExtensionAsync)]
|
||||
#endif
|
||||
[TouchSocket.WebApi.Router("/miniapi/managementrpc/[action]")]
|
||||
public interface IManagementRpcServer : IRpcServer
|
||||
{
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, Dictionary<string, OperResult<object>>>> RpcAsync(ICallContext callContext, Dictionary<string, Dictionary<string, string>> deviceDatas);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task DeleteBackendLogAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<List<BackendLog>> GetNewBackendLogAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<BackendLog>> BackendLogPageAsync(QueryPageOptions option);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<List<BackendLogDayStatisticsOutput>> BackendLogStatisticsByDayAsync(int day);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> BatchEditChannelAsync(List<Channel> models, Channel oldModel, Channel model, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> BatchEditDeviceAsync(List<Device> models, Device oldModel, Device model, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> BatchEditVariableAsync(List<Variable> models, Variable oldModel, Variable model, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> BatchSaveVariableAsync(List<Variable> input, ItemChangedType type, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<TouchSocket.Core.LogLevel> ChannelLogLevelAsync(long id);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> ClearChannelAsync(bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> ClearDeviceAsync(bool restart);
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有规则
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
Task ClearRulesAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> ClearVariableAsync(bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task CopyChannelAsync(int CopyCount, string CopyChannelNamePrefix, int CopyChannelNameSuffixNumber, string CopyDeviceNamePrefix, int CopyDeviceNameSuffixNumber, long channelId, bool AutoRestartThread);
|
||||
|
||||
[DmtpRpc]
|
||||
Task CopyDeviceAsync(int CopyCount, string CopyDeviceNamePrefix, int CopyDeviceNameSuffixNumber, long deviceId, bool AutoRestartThread);
|
||||
|
||||
[DmtpRpc]
|
||||
Task CopyVariableAsync(List<Variable> Model, int CopyCount, string CopyVariableNamePrefix, int CopyVariableNameSuffixNumber, bool AutoRestartThread);
|
||||
|
||||
[DmtpRpc]
|
||||
Task DeleteBackendLogAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> DeleteChannelAsync(List<long> ids, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> DeleteDeviceAsync(List<long> ids, bool restart);
|
||||
[DmtpRpc]
|
||||
Task DeleteLogDataAsync(string path);
|
||||
|
||||
/// <summary>
|
||||
/// 删除 RpcLog 表中的所有记录
|
||||
@@ -50,24 +85,220 @@ public interface IManagementRpcServer : IRpcServer
|
||||
/// 调用此方法会删除 RpcLog 表中的所有记录。
|
||||
/// </remarks>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task DeleteRpcLogAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task DeleteRuleRuntimesAsync(List<long> ids);
|
||||
|
||||
/// <summary>
|
||||
/// 删除规则
|
||||
/// </summary>
|
||||
/// <param name="ids">待删除规则的ID列表</param>
|
||||
[DmtpRpc]
|
||||
Task<bool> DeleteRulesAsync(List<long> ids);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> DeleteVariableAsync(List<long> ids, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<TouchSocket.Core.LogLevel> DeviceLogLevelAsync(long id);
|
||||
|
||||
[DmtpRpc]
|
||||
Task DeviceRedundantThreadAsync(long id);
|
||||
|
||||
/// <summary>
|
||||
/// 修改冗余设置
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
[DmtpRpc]
|
||||
Task EditRedundancyOptionAsync(RedundancyOptions input);
|
||||
|
||||
[DmtpRpc]
|
||||
Task EditRuleRuntimesAsync(Rules rules);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<USheetDatas> ExportChannelAsync(List<Channel> channels);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> ExportChannelFileAsync(GatewayExportFilter exportFilter);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<USheetDatas> ExportDeviceAsync(List<Device> devices);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> ExportDeviceFileAsync(GatewayExportFilter exportFilter);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<USheetDatas> ExportVariableAsync(List<Variable> models, string? sortName, SortOrder sortOrder);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> ExportVariableFileAsync(GatewayExportFilter exportFilter);
|
||||
|
||||
/// <summary>
|
||||
/// 从缓存/数据库获取全部信息
|
||||
/// </summary>
|
||||
/// <returns>规则列表</returns>
|
||||
[DmtpRpc]
|
||||
Task<List<Rules>> GetAllRulesAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<List<Channel>> GetChannelListAsync(QueryPageOptions options, int max = 0);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> GetChannelNameAsync(long channelId);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<IEnumerable<SelectedItem>> GetCurrentUserDeviceSelectedItemsAsync(string searchText, int startIndex, int count);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<SelectedItem>> GetCurrentUserDeviceVariableSelectedItemsAsync(string deviceText, string searchText, int startIndex, int count);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<IEnumerable<AlarmVariable>> GetCurrentUserRealAlarmVariablesAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<long, Tuple<string, string>>> GetDeviceIdNamesAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<List<Device>> GetDeviceListAsync(QueryPageOptions option, int v);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> GetDeviceNameAsync(long redundantDeviceId);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> GetDevicePluginNameAsync(long id);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<List<BackendLog>> GetNewBackendLogAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新的十条 RpcLog 记录
|
||||
/// </summary>
|
||||
/// <returns>最新的十条记录</returns>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<List<RpcLog>> GetNewRpcLogAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> GetPluginNameAsync(long channelId);
|
||||
|
||||
/// <summary>
|
||||
/// 根据插件类型获取信息
|
||||
/// </summary>
|
||||
/// <param name="pluginType"></param>
|
||||
/// <returns></returns>
|
||||
[DmtpRpc]
|
||||
Task<List<PluginInfo>> GetPluginsAsync(PluginTypeEnum? pluginType = null);
|
||||
|
||||
/// <summary>
|
||||
/// 获取冗余设置
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
Task<RedundancyOptions> GetRedundancyAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Rules> GetRuleRuntimesAsync(long rulesId);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<List<Variable>> GetVariableListAsync(QueryPageOptions option, int v);
|
||||
|
||||
[DmtpRpc]
|
||||
Task ImportChannelAsync(List<Channel> upData, List<Channel> insertData, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelFileAsync(string filePath, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelUSheetDatasAsync(USheetDatas input, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceFileAsync(string filePath, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceUSheetDatasAsync(USheetDatas input, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableFileAsync(string filePath, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableUSheetDatasAsync(USheetDatas data, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task InsertTestDataAsync(int testVariableCount, int testDeviceCount, string slaveUrl, bool businessEnable, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> IsRedundantDeviceAsync(long id);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<ChannelRuntime>> OnChannelQueryAsync(QueryPageOptions options);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<SelectedItem>> OnChannelSelectedItemQueryAsync(VirtualizeQueryOption option);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<DeviceRuntime>> OnDeviceQueryAsync(QueryPageOptions options);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<SelectedItem>> OnDeviceSelectedItemQueryAsync(VirtualizeQueryOption option, bool isCollect);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<SelectedItem>> OnRedundantDevicesQueryAsync(VirtualizeQueryOption option, long deviceId, long channelId);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<QueryData<VariableRuntime>> OnVariableQueryAsync(QueryPageOptions options);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<OperResult<object>> OnWriteVariableAsync(long id, string writeData);
|
||||
|
||||
[DmtpRpc]
|
||||
Task PauseThreadAsync(long id);
|
||||
|
||||
/// <summary>
|
||||
/// 分页显示插件
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
Task<QueryData<PluginInfo>> PluginPageAsync(QueryPageOptions options, PluginTypeEnum? pluginTypeEnum = null);
|
||||
|
||||
[DmtpRpc]
|
||||
Task RedundancyForcedSync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<TouchSocket.Core.LogLevel> RedundancyLogLevelAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> RedundancyLogPathAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 重载插件
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
Task ReloadPluginAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task RestartChannelAsync(long channelId);
|
||||
|
||||
[DmtpRpc]
|
||||
Task RestartChannelsAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task RestartDeviceAsync(long id, bool deleteCache);
|
||||
|
||||
[DmtpRpc]
|
||||
Task RestartServerAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<Dictionary<string, Dictionary<string, OperResult<object>>>> RpcAsync(ICallContext callContext, Dictionary<string, Dictionary<string, string>> deviceDatas);
|
||||
/// <summary>
|
||||
/// 分页查询 RpcLog 数据
|
||||
/// </summary>
|
||||
/// <param name="option">查询选项</param>
|
||||
/// <returns>查询到的数据</returns>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<RpcLog>> RpcLogPageAsync(QueryPageOptions option);
|
||||
|
||||
/// <summary>
|
||||
@@ -76,170 +307,12 @@ public interface IManagementRpcServer : IRpcServer
|
||||
/// <param name="day">统计的天数</param>
|
||||
/// <returns>按天统计的结果列表</returns>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<List<RpcLogDayStatisticsOutput>> RpcLogStatisticsByDayAsync(int day);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task RestartServerAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> UUIDAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<AuthorizeInfo> TryAuthorizeAsync(string password);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<AuthorizeInfo> TryGetAuthorizeInfoAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task UnAuthorizeAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> StartBusinessChannelEnableAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> StartCollectChannelEnableAsync();
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task StartRedundancyTaskAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task StopRedundancyTaskAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task RedundancyForcedSync();
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<TouchSocket.Core.LogLevel> RedundancyLogLevelAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task SetRedundancyLogLevelAsync(TouchSocket.Core.LogLevel logLevel);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> RedundancyLogPathAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 修改冗余设置
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task EditRedundancyOptionAsync(RedundancyOptions input);
|
||||
/// <summary>
|
||||
/// 获取冗余设置
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<RedundancyOptions> GetRedundancyAsync();
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据插件类型获取信息
|
||||
/// </summary>
|
||||
/// <param name="pluginType"></param>
|
||||
/// <returns></returns>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<List<PluginInfo>> GetPluginsAsync(PluginTypeEnum? pluginType = null);
|
||||
|
||||
/// <summary>
|
||||
/// 分页显示插件
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<PluginInfo>> PluginPageAsync(QueryPageOptions options, PluginTypeEnum? pluginTypeEnum = null);
|
||||
|
||||
/// <summary>
|
||||
/// 重载插件
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task ReloadPluginAsync();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加插件
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task SavePluginByPathAsync(PluginAddPathInput plugin);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<IEnumerable<AlarmVariable>> GetCurrentUserRealAlarmVariablesAsync();
|
||||
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<IEnumerable<SelectedItem>> GetCurrentUserDeviceSelectedItemsAsync(string searchText, int startIndex, int count);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<QueryData<SelectedItem>> GetCurrentUserDeviceVariableSelectedItemsAsync(string deviceText, string searchText, int startIndex, int count);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<TouchSocket.Core.LogLevel> RulesLogLevelAsync(long rulesId);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task SetRulesLogLevelAsync(long rulesId, TouchSocket.Core.LogLevel logLevel);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> RulesLogPathAsync(long rulesId);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<Rules> GetRuleRuntimesAsync(long rulesId);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task DeleteRuleRuntimesAsync(List<long> ids);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task EditRuleRuntimesAsync(Rules rules);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有规则
|
||||
/// </summary>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task ClearRulesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 删除规则
|
||||
/// </summary>
|
||||
/// <param name="ids">待删除规则的ID列表</param>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> DeleteRulesAsync(List<long> ids);
|
||||
|
||||
/// <summary>
|
||||
/// 从缓存/数据库获取全部信息
|
||||
/// </summary>
|
||||
/// <returns>规则列表</returns>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<List<Rules>> GetAllAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 报表查询
|
||||
@@ -247,226 +320,66 @@ public interface IManagementRpcServer : IRpcServer
|
||||
/// <param name="option">查询条件</param>
|
||||
/// <param name="filterKeyValueAction">查询条件</param>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<Rules>> RulesPageAsync(QueryPageOptions option, FilterKeyValueAction filterKeyValueAction = null);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart);
|
||||
|
||||
/// <summary>
|
||||
/// 添加插件
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
[DmtpRpc]
|
||||
Task SavePluginByPathAsync(PluginAddPathInput plugin);
|
||||
|
||||
/// <summary>
|
||||
/// 保存规则
|
||||
/// </summary>
|
||||
/// <param name="input">规则对象</param>
|
||||
/// <param name="type">保存类型</param>
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> SaveRulesAsync(Rules input, ItemChangedType type);
|
||||
|
||||
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> GetPluginNameAsync(long channelId);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task RestartChannelAsync(long channelId);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task RestartChannelsAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<TouchSocket.Core.LogLevel> ChannelLogLevelAsync(long id);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task SetChannelLogLevelAsync(long id, TouchSocket.Core.LogLevel logLevel);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task CopyChannelAsync(int CopyCount, string CopyChannelNamePrefix, int CopyChannelNameSuffixNumber, string CopyDeviceNamePrefix, int CopyDeviceNameSuffixNumber, long channelId, bool AutoRestartThread);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<ChannelRuntime>> OnChannelQueryAsync(QueryPageOptions options);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<List<Channel>> GetChannelListAsync(QueryPageOptions options, int max = 0);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> BatchEditChannelAsync(List<Channel> models, Channel oldModel, Channel model, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> DeleteChannelAsync(List<long> ids, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> ClearChannelAsync(bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task ImportChannelAsync(List<Channel> upData, List<Channel> insertData, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelUSheetDatasAsync(USheetDatas input, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelFileAsync(string filePath, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<USheetDatas> ExportChannelAsync(List<Channel> channels);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<string> ExportChannelFileAsync(GatewayExportFilter exportFilter);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<SelectedItem>> OnChannelSelectedItemQueryAsync(VirtualizeQueryOption option);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> GetChannelNameAsync(long channelId);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task SetDeviceLogLevelAsync(long id, TouchSocket.Core.LogLevel logLevel);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task CopyDeviceAsync(int CopyCount, string CopyDeviceNamePrefix, int CopyDeviceNameSuffixNumber, long deviceId, bool AutoRestartThread);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<TouchSocket.Core.LogLevel> DeviceLogLevelAsync(long id);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> BatchEditDeviceAsync(List<Device> models, Device oldModel, Device model, bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> DeleteDeviceAsync(List<long> ids, bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceUSheetDatasAsync(USheetDatas input, bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<USheetDatas> ExportDeviceAsync(List<Device> devices);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<string> ExportDeviceFileAsync(GatewayExportFilter exportFilter);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<SelectedItem>> OnRedundantDevicesQueryAsync(VirtualizeQueryOption option, long deviceId, long channelId);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceFileAsync(string filePath, bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task DeviceRedundantThreadAsync(long id);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task RestartDeviceAsync(long id, bool deleteCache);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task PauseThreadAsync(long id);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<DeviceRuntime>> OnDeviceQueryAsync(QueryPageOptions options);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<List<Device>> GetDeviceListAsync(QueryPageOptions option, int v);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> ClearDeviceAsync(bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<bool> IsRedundantDeviceAsync(long id);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> GetDeviceNameAsync(long redundantDeviceId);
|
||||
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<SelectedItem>> OnDeviceSelectedItemQueryAsync(VirtualizeQueryOption option, bool isCollect);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<string> GetDevicePluginNameAsync(long id);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> BatchEditVariableAsync(List<Variable> models, Variable oldModel, Variable model, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> DeleteVariableAsync(List<long> ids, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> ClearVariableAsync(bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task InsertTestDataAsync(int testVariableCount, int testDeviceCount, string slaveUrl, bool businessEnable, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> BatchSaveVariableAsync(List<Variable> input, ItemChangedType type, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<bool> SaveVariableAsync(Variable input, ItemChangedType type, bool restart);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task CopyVariableAsync(List<Variable> Model, int CopyCount, string CopyVariableNamePrefix, int CopyVariableNameSuffixNumber, bool AutoRestartThread);
|
||||
Task SetChannelLogLevelAsync(long id, TouchSocket.Core.LogLevel logLevel);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<QueryData<VariableRuntime>> OnVariableQueryAsync(QueryPageOptions options);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<string> ExportVariableFileAsync(GatewayExportFilter exportFilter);
|
||||
Task SetDeviceLogLevelAsync(long id, TouchSocket.Core.LogLevel logLevel);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<List<Variable>> GetVariableListAsync(QueryPageOptions option, int v);
|
||||
Task SetRedundancyLogLevelAsync(TouchSocket.Core.LogLevel logLevel);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<USheetDatas> ExportVariableAsync(List<Variable> models, string? sortName, SortOrder sortOrder);
|
||||
Task SetRulesLogLevelAsync(long rulesId, TouchSocket.Core.LogLevel logLevel);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableUSheetDatasAsync(USheetDatas data, bool restart);
|
||||
Task<bool> StartBusinessChannelEnableAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<OperResult<object>> OnWriteVariableAsync(long id, string writeData);
|
||||
|
||||
Task<bool> StartCollectChannelEnableAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableFileAsync(string filePath, bool restart);
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<Dictionary<long, Tuple<string, string>>> GetDeviceIdNamesAsync();
|
||||
Task StartRedundancyTaskAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task StopRedundancyTaskAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<AuthorizeInfo> TryAuthorizeAsync(string password);
|
||||
|
||||
[DmtpRpc]
|
||||
Task<AuthorizeInfo> TryGetAuthorizeInfoAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task UnAuthorizeAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
Task<string> UUIDAsync();
|
||||
}
|
||||
@@ -30,8 +30,8 @@ internal sealed class ManagementHostedService : BackgroundService
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await Task.Yield();
|
||||
_ = RemoteClientManagementTask.StartAsync(stoppingToken);
|
||||
_ = RemoteServerManagementTask.StartAsync(stoppingToken);
|
||||
await RemoteClientManagementTask.StartAsync(stoppingToken).ConfigureAwait(false);
|
||||
await RemoteServerManagementTask.StartAsync(stoppingToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -15,7 +15,6 @@ using Microsoft.AspNetCore.Components.Forms;
|
||||
using ThingsGateway.Authentication;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Dmtp.Rpc;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
@@ -24,189 +23,78 @@ namespace ThingsGateway.Gateway.Application;
|
||||
public partial class ManagementRpcServer : IRpcServer, IManagementRpcServer, IBackendLogService, IRpcLogService, IRestartService, IAuthenticationService, IChannelEnableService, IRedundancyHostedService, IRedundancyService, ITextFileReadService, IPluginPageService, IRealAlarmService, IChannelPageService, IDevicePageService, IVariablePageService
|
||||
{
|
||||
|
||||
[DmtpRpc]
|
||||
public Task DeleteBackendLogAsync() => App.GetService<IBackendLogService>().DeleteBackendLogAsync();
|
||||
[DmtpRpc]
|
||||
public Task<List<BackendLogDayStatisticsOutput>> BackendLogStatisticsByDayAsync(int day) => App.GetService<IBackendLogService>().BackendLogStatisticsByDayAsync(day);
|
||||
|
||||
[DmtpRpc]
|
||||
public Task<List<BackendLog>> GetNewBackendLogAsync() => App.GetService<IBackendLogService>().GetNewBackendLogAsync();
|
||||
|
||||
[DmtpRpc]
|
||||
public Task<QueryData<BackendLog>> BackendLogPageAsync(QueryPageOptions option) => App.GetService<IBackendLogService>().BackendLogPageAsync(option);
|
||||
|
||||
public Task<List<BackendLogDayStatisticsOutput>> BackendLogStatisticsByDayAsync(int day) => App.GetService<IBackendLogService>().BackendLogStatisticsByDayAsync(day);
|
||||
|
||||
[DmtpRpc]
|
||||
public async Task<Dictionary<string, Dictionary<string, OperResult<object>>>> RpcAsync(ICallContext callContext, Dictionary<string, Dictionary<string, string>> deviceDatas)
|
||||
{
|
||||
var data = await GlobalData.RpcService.InvokeDeviceMethodAsync($"Management[{(callContext.Caller is ITcpSession tcpSession ? tcpSession.GetIPPort() : string.Empty)}]", deviceDatas, callContext.Token).ConfigureAwait(false);
|
||||
public Task<bool> BatchEditChannelAsync(List<Channel> models, Channel oldModel, Channel model, bool restart) =>
|
||||
App.GetService<IChannelPageService>().BatchEditChannelAsync(models, oldModel, model, restart);
|
||||
|
||||
return data.ToDictionary(a => a.Key, a => a.Value.ToDictionary(b => b.Key, b => b.Value.GetOperResult()));
|
||||
}
|
||||
public Task<bool> BatchEditDeviceAsync(List<Device> models, Device oldModel, Device model, bool restart) =>
|
||||
App.GetService<IDevicePageService>().BatchEditDeviceAsync(models, oldModel, model, restart);
|
||||
|
||||
public Task DeleteRpcLogAsync() => App.GetService<IRpcLogService>().DeleteRpcLogAsync();
|
||||
public Task<bool> BatchEditVariableAsync(List<Variable> models, Variable oldModel, Variable model, bool restart) =>
|
||||
App.GetService<IVariablePageService>().BatchEditVariableAsync(models, oldModel, model, restart);
|
||||
|
||||
public Task<List<RpcLog>> GetNewRpcLogAsync() => App.GetService<IRpcLogService>().GetNewRpcLogAsync();
|
||||
public Task<bool> BatchSaveVariableAsync(List<Variable> input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IVariablePageService>().BatchSaveVariableAsync(input, type, restart);
|
||||
|
||||
public Task<QueryData<RpcLog>> RpcLogPageAsync(QueryPageOptions option) => App.GetService<IRpcLogService>().RpcLogPageAsync(option);
|
||||
|
||||
public Task<List<RpcLogDayStatisticsOutput>> RpcLogStatisticsByDayAsync(int day) => App.GetService<IRpcLogService>().RpcLogStatisticsByDayAsync(day);
|
||||
|
||||
public Task RestartServerAsync() => App.GetService<IRestartService>().RestartServerAsync();
|
||||
|
||||
public Task<string> UUIDAsync() => App.GetService<IAuthenticationService>().UUIDAsync();
|
||||
|
||||
public Task<AuthorizeInfo> TryAuthorizeAsync(string password) => App.GetService<IAuthenticationService>().TryAuthorizeAsync(password);
|
||||
|
||||
public Task<AuthorizeInfo> TryGetAuthorizeInfoAsync() => App.GetService<IAuthenticationService>().TryGetAuthorizeInfoAsync();
|
||||
|
||||
public Task UnAuthorizeAsync() => App.GetService<IAuthenticationService>().UnAuthorizeAsync();
|
||||
|
||||
public Task<bool> StartBusinessChannelEnableAsync() => App.GetService<IChannelEnableService>().StartBusinessChannelEnableAsync();
|
||||
|
||||
|
||||
public Task<bool> StartCollectChannelEnableAsync() => App.GetService<IChannelEnableService>().StartCollectChannelEnableAsync();
|
||||
|
||||
public Task StartRedundancyTaskAsync() => App.GetService<IRedundancyHostedService>().StartRedundancyTaskAsync();
|
||||
|
||||
public Task StopRedundancyTaskAsync() => App.GetService<IRedundancyHostedService>().StopRedundancyTaskAsync();
|
||||
|
||||
public Task RedundancyForcedSync() => App.GetService<IRedundancyHostedService>().RedundancyForcedSync();
|
||||
|
||||
|
||||
public Task EditRedundancyOptionAsync(RedundancyOptions input) => App.GetService<IRedundancyService>().EditRedundancyOptionAsync(input);
|
||||
|
||||
public Task<RedundancyOptions> GetRedundancyAsync() => App.GetService<IRedundancyService>().GetRedundancyAsync();
|
||||
|
||||
public Task<LogLevel> RedundancyLogLevelAsync() => App.GetService<IRedundancyHostedService>().RedundancyLogLevelAsync();
|
||||
|
||||
|
||||
public Task SetRedundancyLogLevelAsync(LogLevel logLevel) => App.GetService<IRedundancyHostedService>().SetRedundancyLogLevelAsync(logLevel);
|
||||
|
||||
public Task<string> RedundancyLogPathAsync() => App.GetService<IRedundancyHostedService>().RedundancyLogPathAsync();
|
||||
|
||||
public Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath) => App.GetService<ITextFileReadService>().GetLogFilesAsync(directoryPath);
|
||||
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200) => App.GetService<ITextFileReadService>().LastLogDataAsync(file, lineCount);
|
||||
|
||||
public Task<List<PluginInfo>> GetPluginsAsync(PluginTypeEnum? pluginType = null) => App.GetService<IPluginPageService>().GetPluginsAsync(pluginType);
|
||||
|
||||
public Task<QueryData<PluginInfo>> PluginPageAsync(QueryPageOptions options, PluginTypeEnum? pluginTypeEnum = null) => App.GetService<IPluginPageService>().PluginPageAsync(options, pluginTypeEnum);
|
||||
|
||||
public Task ReloadPluginAsync() => App.GetService<IPluginPageService>().ReloadPluginAsync();
|
||||
|
||||
|
||||
|
||||
public Task SavePluginByPathAsync(PluginAddPathInput plugin) => App.GetService<IPluginPageService>().SavePluginByPathAsync(plugin);
|
||||
|
||||
public Task<IEnumerable<AlarmVariable>> GetCurrentUserRealAlarmVariablesAsync() => App.GetService<IRealAlarmService>().GetCurrentUserRealAlarmVariablesAsync();
|
||||
|
||||
public Task<IEnumerable<SelectedItem>> GetCurrentUserDeviceSelectedItemsAsync(string searchText, int startIndex, int count) => App.GetService<IGlobalDataService>().GetCurrentUserDeviceSelectedItemsAsync(searchText, startIndex, count);
|
||||
|
||||
public Task<QueryData<SelectedItem>> GetCurrentUserDeviceVariableSelectedItemsAsync(string deviceText, string searchText, int startIndex, int count) => App.GetService<IGlobalDataService>().GetCurrentUserDeviceVariableSelectedItemsAsync(deviceText, searchText, startIndex, count);
|
||||
|
||||
public Task<TouchSocket.Core.LogLevel> RulesLogLevelAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().RulesLogLevelAsync(rulesId);
|
||||
public Task SetRulesLogLevelAsync(long rulesId, TouchSocket.Core.LogLevel logLevel) => App.GetService<IRulesEngineHostedService>().SetRulesLogLevelAsync(rulesId, logLevel);
|
||||
public Task<string> RulesLogPathAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().RulesLogPathAsync(rulesId);
|
||||
public Task<Rules> GetRuleRuntimesAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().GetRuleRuntimesAsync(rulesId);
|
||||
|
||||
|
||||
public Task DeleteRuleRuntimesAsync(List<long> ids) => App.GetService<IRulesEngineHostedService>().DeleteRuleRuntimesAsync(ids);
|
||||
|
||||
public Task EditRuleRuntimesAsync(Rules rules) => App.GetService<IRulesEngineHostedService>().EditRuleRuntimesAsync(rules);
|
||||
|
||||
public Task ClearRulesAsync() => App.GetService<IRulesService>().ClearRulesAsync();
|
||||
|
||||
|
||||
public Task<bool> DeleteRulesAsync(List<long> ids) => App.GetService<IRulesService>().DeleteRulesAsync(ids);
|
||||
|
||||
public Task<List<Rules>> GetAllAsync() => App.GetService<IRulesService>().GetAllAsync();
|
||||
|
||||
|
||||
public Task<QueryData<Rules>> RulesPageAsync(QueryPageOptions option, FilterKeyValueAction filterKeyValueAction = null) => App.GetService<IRulesService>().RulesPageAsync(option, filterKeyValueAction);
|
||||
|
||||
|
||||
public Task<bool> SaveRulesAsync(Rules input, ItemChangedType type) => App.GetService<IRulesService>().SaveRulesAsync(input, type);
|
||||
|
||||
public Task<string> GetPluginNameAsync(long channelId) => App.GetService<IChannelPageService>().GetPluginNameAsync(channelId);
|
||||
|
||||
public Task RestartChannelAsync(long channelId) =>
|
||||
App.GetService<IChannelPageService>().RestartChannelAsync(channelId);
|
||||
public Task RestartChannelsAsync() =>
|
||||
App.GetService<IChannelPageService>().RestartChannelsAsync();
|
||||
public Task<LogLevel> ChannelLogLevelAsync(long id) =>
|
||||
App.GetService<IChannelPageService>().ChannelLogLevelAsync(id);
|
||||
|
||||
public Task SetChannelLogLevelAsync(long id, LogLevel logLevel) =>
|
||||
App.GetService<IChannelPageService>().SetChannelLogLevelAsync(id, logLevel);
|
||||
public Task<bool> ClearChannelAsync(bool restart) =>
|
||||
App.GetService<IChannelPageService>().ClearChannelAsync(restart);
|
||||
|
||||
public Task<bool> ClearDeviceAsync(bool restart) =>
|
||||
App.GetService<IDevicePageService>().ClearDeviceAsync(restart);
|
||||
|
||||
public Task ClearRulesAsync() => App.GetService<IRulesService>().ClearRulesAsync();
|
||||
|
||||
public Task<bool> ClearVariableAsync(bool restart) =>
|
||||
App.GetService<IVariablePageService>().ClearVariableAsync(restart);
|
||||
|
||||
public Task CopyChannelAsync(int copyCount, string copyChannelNamePrefix, int copyChannelNameSuffixNumber,
|
||||
string copyDeviceNamePrefix, int copyDeviceNameSuffixNumber, long channelId, bool restart) =>
|
||||
App.GetService<IChannelPageService>().CopyChannelAsync(copyCount, copyChannelNamePrefix, copyChannelNameSuffixNumber,
|
||||
copyDeviceNamePrefix, copyDeviceNameSuffixNumber, channelId, restart);
|
||||
|
||||
public Task<QueryData<ChannelRuntime>> OnChannelQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IChannelPageService>().OnChannelQueryAsync(options);
|
||||
|
||||
public Task<List<Channel>> GetChannelListAsync(QueryPageOptions options, int max = 0) =>
|
||||
App.GetService<IChannelPageService>().GetChannelListAsync(options, max);
|
||||
|
||||
public Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IChannelPageService>().SaveChannelAsync(input, type, restart);
|
||||
|
||||
public Task<bool> BatchEditChannelAsync(List<Channel> models, Channel oldModel, Channel model, bool restart) =>
|
||||
App.GetService<IChannelPageService>().BatchEditChannelAsync(models, oldModel, model, restart);
|
||||
|
||||
public Task<bool> DeleteChannelAsync(List<long> ids, bool restart) =>
|
||||
App.GetService<IChannelPageService>().DeleteChannelAsync(ids, restart);
|
||||
|
||||
public Task<bool> ClearChannelAsync(bool restart) =>
|
||||
App.GetService<IChannelPageService>().ClearChannelAsync(restart);
|
||||
|
||||
public Task ImportChannelAsync(List<Channel> upData, List<Channel> insertData, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelAsync(upData, insertData, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelUSheetDatasAsync(USheetDatas input, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelUSheetDatasAsync(input, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelFileAsync(string filePath, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelFileAsync(filePath, restart);
|
||||
|
||||
public Task<USheetDatas> ExportChannelAsync(List<Channel> channels) =>
|
||||
App.GetService<IChannelPageService>().ExportChannelAsync(channels);
|
||||
|
||||
public Task<QueryData<SelectedItem>> OnChannelSelectedItemQueryAsync(VirtualizeQueryOption option) =>
|
||||
App.GetService<IChannelPageService>().OnChannelSelectedItemQueryAsync(option);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelAsync(IBrowserFile file, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelAsync(file, restart);
|
||||
|
||||
public Task<string> ExportChannelFileAsync(GatewayExportFilter exportFilter) =>
|
||||
App.GetService<IChannelPageService>().ExportChannelFileAsync(exportFilter);
|
||||
|
||||
public Task<string> GetChannelNameAsync(long id) =>
|
||||
App.GetService<IChannelPageService>().GetChannelNameAsync(id);
|
||||
|
||||
public Task SetDeviceLogLevelAsync(long id, LogLevel logLevel) =>
|
||||
App.GetService<IDevicePageService>().SetDeviceLogLevelAsync(id, logLevel);
|
||||
|
||||
public Task CopyDeviceAsync(int CopyCount, string CopyDeviceNamePrefix, int CopyDeviceNameSuffixNumber, long deviceId, bool AutoRestartThread) =>
|
||||
App.GetService<IDevicePageService>().CopyDeviceAsync(CopyCount, CopyDeviceNamePrefix, CopyDeviceNameSuffixNumber, deviceId, AutoRestartThread);
|
||||
|
||||
public Task<LogLevel> DeviceLogLevelAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().DeviceLogLevelAsync(id);
|
||||
public Task CopyVariableAsync(List<Variable> model, int copyCount, string copyVariableNamePrefix, int copyVariableNameSuffixNumber, bool restart) =>
|
||||
App.GetService<IVariablePageService>().CopyVariableAsync(model, copyCount, copyVariableNamePrefix, copyVariableNameSuffixNumber, restart);
|
||||
|
||||
public Task<bool> BatchEditDeviceAsync(List<Device> models, Device oldModel, Device model, bool restart) =>
|
||||
App.GetService<IDevicePageService>().BatchEditDeviceAsync(models, oldModel, model, restart);
|
||||
|
||||
public Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IDevicePageService>().SaveDeviceAsync(input, type, restart);
|
||||
public Task DeleteBackendLogAsync() => App.GetService<IBackendLogService>().DeleteBackendLogAsync();
|
||||
public Task<bool> DeleteChannelAsync(List<long> ids, bool restart) =>
|
||||
App.GetService<IChannelPageService>().DeleteChannelAsync(ids, restart);
|
||||
|
||||
public Task<bool> DeleteDeviceAsync(List<long> ids, bool restart) =>
|
||||
App.GetService<IDevicePageService>().DeleteDeviceAsync(ids, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceUSheetDatasAsync(USheetDatas input, bool restart) =>
|
||||
App.GetService<IDevicePageService>().ImportDeviceUSheetDatasAsync(input, restart);
|
||||
public Task DeleteRpcLogAsync() => App.GetService<IRpcLogService>().DeleteRpcLogAsync();
|
||||
|
||||
public Task DeleteRuleRuntimesAsync(List<long> ids) => App.GetService<IRulesEngineHostedService>().DeleteRuleRuntimesAsync(ids);
|
||||
|
||||
public Task<bool> DeleteRulesAsync(List<long> ids) => App.GetService<IRulesService>().DeleteRulesAsync(ids);
|
||||
|
||||
public Task<bool> DeleteVariableAsync(List<long> ids, bool restart) =>
|
||||
App.GetService<IVariablePageService>().DeleteVariableAsync(ids, restart);
|
||||
|
||||
public Task<LogLevel> DeviceLogLevelAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().DeviceLogLevelAsync(id);
|
||||
|
||||
public Task DeviceRedundantThreadAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().DeviceRedundantThreadAsync(id);
|
||||
|
||||
public Task EditRedundancyOptionAsync(RedundancyOptions input) => App.GetService<IRedundancyService>().EditRedundancyOptionAsync(input);
|
||||
|
||||
public Task EditRuleRuntimesAsync(Rules rules) => App.GetService<IRulesEngineHostedService>().EditRuleRuntimesAsync(rules);
|
||||
|
||||
public Task<USheetDatas> ExportChannelAsync(List<Channel> channels) =>
|
||||
App.GetService<IChannelPageService>().ExportChannelAsync(channels);
|
||||
|
||||
public Task<string> ExportChannelFileAsync(GatewayExportFilter exportFilter) =>
|
||||
App.GetService<IChannelPageService>().ExportChannelFileAsync(exportFilter);
|
||||
|
||||
public Task<USheetDatas> ExportDeviceAsync(List<Device> devices) =>
|
||||
App.GetService<IDevicePageService>().ExportDeviceAsync(devices);
|
||||
@@ -214,80 +102,72 @@ public partial class ManagementRpcServer : IRpcServer, IManagementRpcServer, IBa
|
||||
public Task<string> ExportDeviceFileAsync(GatewayExportFilter exportFilter) =>
|
||||
App.GetService<IDevicePageService>().ExportDeviceFileAsync(exportFilter);
|
||||
|
||||
public Task<QueryData<SelectedItem>> OnRedundantDevicesQueryAsync(VirtualizeQueryOption option, long deviceId, long channelId) =>
|
||||
App.GetService<IDevicePageService>().OnRedundantDevicesQueryAsync(option, deviceId, channelId);
|
||||
public Task<USheetDatas> ExportVariableAsync(List<Variable> models, string? sortName, SortOrder sortOrder) =>
|
||||
App.GetService<IVariablePageService>().ExportVariableAsync(models, sortName, sortOrder);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceFileAsync(string filePath, bool restart) =>
|
||||
App.GetService<IDevicePageService>().ImportDeviceFileAsync(filePath, restart);
|
||||
public Task<string> ExportVariableFileAsync(GatewayExportFilter exportFilter) => App.GetService<IVariablePageService>().ExportVariableFileAsync(exportFilter);
|
||||
|
||||
public Task DeviceRedundantThreadAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().DeviceRedundantThreadAsync(id);
|
||||
public Task<List<Rules>> GetAllRulesAsync() => App.GetService<IRulesService>().GetAllRulesAsync();
|
||||
|
||||
public Task RestartDeviceAsync(long id, bool deleteCache) =>
|
||||
App.GetService<IDevicePageService>().RestartDeviceAsync(id, deleteCache);
|
||||
public Task<List<Channel>> GetChannelListAsync(QueryPageOptions options, int max = 0) =>
|
||||
App.GetService<IChannelPageService>().GetChannelListAsync(options, max);
|
||||
|
||||
public Task PauseThreadAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().PauseThreadAsync(id);
|
||||
public Task<string> GetChannelNameAsync(long id) =>
|
||||
App.GetService<IChannelPageService>().GetChannelNameAsync(id);
|
||||
|
||||
public Task<QueryData<DeviceRuntime>> OnDeviceQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IDevicePageService>().OnDeviceQueryAsync(options);
|
||||
public Task<IEnumerable<SelectedItem>> GetCurrentUserDeviceSelectedItemsAsync(string searchText, int startIndex, int count) => App.GetService<IGlobalDataService>().GetCurrentUserDeviceSelectedItemsAsync(searchText, startIndex, count);
|
||||
|
||||
public Task<QueryData<SelectedItem>> GetCurrentUserDeviceVariableSelectedItemsAsync(string deviceText, string searchText, int startIndex, int count) => App.GetService<IGlobalDataService>().GetCurrentUserDeviceVariableSelectedItemsAsync(deviceText, searchText, startIndex, count);
|
||||
|
||||
public Task<IEnumerable<AlarmVariable>> GetCurrentUserRealAlarmVariablesAsync() => App.GetService<IRealAlarmService>().GetCurrentUserRealAlarmVariablesAsync();
|
||||
|
||||
public Task<Dictionary<long, Tuple<string, string>>> GetDeviceIdNamesAsync() => App.GetService<IDevicePageService>().GetDeviceIdNamesAsync();
|
||||
|
||||
public Task<List<Device>> GetDeviceListAsync(QueryPageOptions option, int v) =>
|
||||
App.GetService<IDevicePageService>().GetDeviceListAsync(option, v);
|
||||
|
||||
public Task<bool> ClearDeviceAsync(bool restart) =>
|
||||
App.GetService<IDevicePageService>().ClearDeviceAsync(restart);
|
||||
|
||||
public Task<bool> IsRedundantDeviceAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().IsRedundantDeviceAsync(id);
|
||||
|
||||
public Task<string> GetDeviceNameAsync(long redundantDeviceId) =>
|
||||
App.GetService<IDevicePageService>().GetDeviceNameAsync(redundantDeviceId);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceAsync(IBrowserFile file, bool restart) =>
|
||||
App.GetService<IDevicePageService>().ImportDeviceAsync(file, restart);
|
||||
|
||||
public Task<QueryData<SelectedItem>> OnDeviceSelectedItemQueryAsync(VirtualizeQueryOption option, bool isCollect) =>
|
||||
App.GetService<IDevicePageService>().OnDeviceSelectedItemQueryAsync(option, isCollect);
|
||||
|
||||
public Task<string> GetDevicePluginNameAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().GetDevicePluginNameAsync(id);
|
||||
|
||||
public Task<bool> BatchEditVariableAsync(List<Variable> models, Variable oldModel, Variable model, bool restart) =>
|
||||
App.GetService<IVariablePageService>().BatchEditVariableAsync(models, oldModel, model, restart);
|
||||
public Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath) => App.GetService<ITextFileReadService>().GetLogFilesAsync(directoryPath);
|
||||
|
||||
public Task<bool> DeleteVariableAsync(List<long> ids, bool restart) =>
|
||||
App.GetService<IVariablePageService>().DeleteVariableAsync(ids, restart);
|
||||
public Task<List<BackendLog>> GetNewBackendLogAsync() => App.GetService<IBackendLogService>().GetNewBackendLogAsync();
|
||||
public Task<List<RpcLog>> GetNewRpcLogAsync() => App.GetService<IRpcLogService>().GetNewRpcLogAsync();
|
||||
|
||||
public Task<bool> ClearVariableAsync(bool restart) =>
|
||||
App.GetService<IVariablePageService>().ClearVariableAsync(restart);
|
||||
public Task<string> GetPluginNameAsync(long channelId) => App.GetService<IChannelPageService>().GetPluginNameAsync(channelId);
|
||||
|
||||
public Task InsertTestDataAsync(int testVariableCount, int testDeviceCount, string slaveUrl, bool businessEnable, bool restart) =>
|
||||
App.GetService<IVariablePageService>().InsertTestDataAsync(testVariableCount, testDeviceCount, slaveUrl, businessEnable, restart);
|
||||
public Task<List<PluginInfo>> GetPluginsAsync(PluginTypeEnum? pluginType = null) => App.GetService<IPluginPageService>().GetPluginsAsync(pluginType);
|
||||
|
||||
public Task<bool> BatchSaveVariableAsync(List<Variable> input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IVariablePageService>().BatchSaveVariableAsync(input, type, restart);
|
||||
public Task<RedundancyOptions> GetRedundancyAsync() => App.GetService<IRedundancyService>().GetRedundancyAsync();
|
||||
|
||||
public Task<bool> SaveVariableAsync(Variable input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IVariablePageService>().SaveVariableAsync(input, type, restart);
|
||||
|
||||
public Task CopyVariableAsync(List<Variable> model, int copyCount, string copyVariableNamePrefix, int copyVariableNameSuffixNumber, bool restart) =>
|
||||
App.GetService<IVariablePageService>().CopyVariableAsync(model, copyCount, copyVariableNamePrefix, copyVariableNameSuffixNumber, restart);
|
||||
|
||||
public Task<QueryData<VariableRuntime>> OnVariableQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IVariablePageService>().OnVariableQueryAsync(options);
|
||||
public Task<Rules> GetRuleRuntimesAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().GetRuleRuntimesAsync(rulesId);
|
||||
|
||||
public Task<List<Variable>> GetVariableListAsync(QueryPageOptions option, int v) =>
|
||||
App.GetService<IVariablePageService>().GetVariableListAsync(option, v);
|
||||
|
||||
public Task<USheetDatas> ExportVariableAsync(List<Variable> models, string? sortName, SortOrder sortOrder) =>
|
||||
App.GetService<IVariablePageService>().ExportVariableAsync(models, sortName, sortOrder);
|
||||
public Task ImportChannelAsync(List<Channel> upData, List<Channel> insertData, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelAsync(upData, insertData, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableUSheetDatasAsync(USheetDatas data, bool restart) =>
|
||||
App.GetService<IVariablePageService>().ImportVariableUSheetDatasAsync(data, restart);
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelAsync(IBrowserFile file, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelAsync(file, restart);
|
||||
|
||||
public Task<OperResult<object>> OnWriteVariableAsync(long id, string writeData) =>
|
||||
App.GetService<IVariablePageService>().OnWriteVariableAsync(id, writeData);
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelFileAsync(string filePath, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelFileAsync(filePath, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportChannelUSheetDatasAsync(USheetDatas input, bool restart) =>
|
||||
App.GetService<IChannelPageService>().ImportChannelUSheetDatasAsync(input, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceAsync(IBrowserFile file, bool restart) =>
|
||||
App.GetService<IDevicePageService>().ImportDeviceAsync(file, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceFileAsync(string filePath, bool restart) =>
|
||||
App.GetService<IDevicePageService>().ImportDeviceFileAsync(filePath, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceUSheetDatasAsync(USheetDatas input, bool restart) =>
|
||||
App.GetService<IDevicePageService>().ImportDeviceUSheetDatasAsync(input, restart);
|
||||
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableAsync(IBrowserFile a, bool restart) =>
|
||||
App.GetService<IVariablePageService>().ImportVariableAsync(a, restart);
|
||||
@@ -295,7 +175,113 @@ public partial class ManagementRpcServer : IRpcServer, IManagementRpcServer, IBa
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableFileAsync(string filePath, bool restart) =>
|
||||
App.GetService<IVariablePageService>().ImportVariableFileAsync(filePath, restart);
|
||||
|
||||
public Task<string> ExportVariableFileAsync(GatewayExportFilter exportFilter) => App.GetService<IVariablePageService>().ExportVariableFileAsync(exportFilter);
|
||||
public Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableUSheetDatasAsync(USheetDatas data, bool restart) =>
|
||||
App.GetService<IVariablePageService>().ImportVariableUSheetDatasAsync(data, restart);
|
||||
|
||||
public Task<Dictionary<long, Tuple<string, string>>> GetDeviceIdNamesAsync() => App.GetService<IDevicePageService>().GetDeviceIdNamesAsync();
|
||||
public Task InsertTestDataAsync(int testVariableCount, int testDeviceCount, string slaveUrl, bool businessEnable, bool restart) =>
|
||||
App.GetService<IVariablePageService>().InsertTestDataAsync(testVariableCount, testDeviceCount, slaveUrl, businessEnable, restart);
|
||||
|
||||
public Task<bool> IsRedundantDeviceAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().IsRedundantDeviceAsync(id);
|
||||
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200) => App.GetService<ITextFileReadService>().LastLogDataAsync(file, lineCount);
|
||||
public Task DeleteLogDataAsync(string path) => App.GetService<ITextFileReadService>().DeleteLogDataAsync(path);
|
||||
public Task<QueryData<ChannelRuntime>> OnChannelQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IChannelPageService>().OnChannelQueryAsync(options);
|
||||
|
||||
public Task<QueryData<SelectedItem>> OnChannelSelectedItemQueryAsync(VirtualizeQueryOption option) =>
|
||||
App.GetService<IChannelPageService>().OnChannelSelectedItemQueryAsync(option);
|
||||
|
||||
public Task<QueryData<DeviceRuntime>> OnDeviceQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IDevicePageService>().OnDeviceQueryAsync(options);
|
||||
|
||||
public Task<QueryData<SelectedItem>> OnDeviceSelectedItemQueryAsync(VirtualizeQueryOption option, bool isCollect) =>
|
||||
App.GetService<IDevicePageService>().OnDeviceSelectedItemQueryAsync(option, isCollect);
|
||||
|
||||
public Task<QueryData<SelectedItem>> OnRedundantDevicesQueryAsync(VirtualizeQueryOption option, long deviceId, long channelId) =>
|
||||
App.GetService<IDevicePageService>().OnRedundantDevicesQueryAsync(option, deviceId, channelId);
|
||||
|
||||
public Task<QueryData<VariableRuntime>> OnVariableQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IVariablePageService>().OnVariableQueryAsync(options);
|
||||
|
||||
public Task<OperResult<object>> OnWriteVariableAsync(long id, string writeData) =>
|
||||
App.GetService<IVariablePageService>().OnWriteVariableAsync(id, writeData);
|
||||
|
||||
public Task PauseThreadAsync(long id) =>
|
||||
App.GetService<IDevicePageService>().PauseThreadAsync(id);
|
||||
|
||||
public Task<QueryData<PluginInfo>> PluginPageAsync(QueryPageOptions options, PluginTypeEnum? pluginTypeEnum = null) => App.GetService<IPluginPageService>().PluginPageAsync(options, pluginTypeEnum);
|
||||
|
||||
public Task RedundancyForcedSync() => App.GetService<IRedundancyHostedService>().RedundancyForcedSync();
|
||||
|
||||
public Task<LogLevel> RedundancyLogLevelAsync() => App.GetService<IRedundancyHostedService>().RedundancyLogLevelAsync();
|
||||
|
||||
public Task<string> RedundancyLogPathAsync() => App.GetService<IRedundancyHostedService>().RedundancyLogPathAsync();
|
||||
|
||||
public Task ReloadPluginAsync() => App.GetService<IPluginPageService>().ReloadPluginAsync();
|
||||
|
||||
public Task RestartChannelAsync(long channelId) =>
|
||||
App.GetService<IChannelPageService>().RestartChannelAsync(channelId);
|
||||
|
||||
public Task RestartChannelsAsync() =>
|
||||
App.GetService<IChannelPageService>().RestartChannelsAsync();
|
||||
|
||||
public Task RestartDeviceAsync(long id, bool deleteCache) =>
|
||||
App.GetService<IDevicePageService>().RestartDeviceAsync(id, deleteCache);
|
||||
|
||||
public Task RestartServerAsync() => App.GetService<IRestartService>().RestartServerAsync();
|
||||
|
||||
public async Task<Dictionary<string, Dictionary<string, OperResult<object>>>> RpcAsync(ICallContext callContext, Dictionary<string, Dictionary<string, string>> deviceDatas)
|
||||
{
|
||||
var data = await GlobalData.RpcService.InvokeDeviceMethodAsync($"Management[{(callContext.Caller is ITcpSession tcpSession ? tcpSession.GetIPPort() : string.Empty)}]", deviceDatas, callContext.Token).ConfigureAwait(false);
|
||||
|
||||
return data.ToDictionary(a => a.Key, a => a.Value.ToDictionary(b => b.Key, b => b.Value.GetOperResult()));
|
||||
}
|
||||
public Task<QueryData<RpcLog>> RpcLogPageAsync(QueryPageOptions option) => App.GetService<IRpcLogService>().RpcLogPageAsync(option);
|
||||
|
||||
public Task<List<RpcLogDayStatisticsOutput>> RpcLogStatisticsByDayAsync(int day) => App.GetService<IRpcLogService>().RpcLogStatisticsByDayAsync(day);
|
||||
public Task<TouchSocket.Core.LogLevel> RulesLogLevelAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().RulesLogLevelAsync(rulesId);
|
||||
|
||||
public Task<string> RulesLogPathAsync(long rulesId) => App.GetService<IRulesEngineHostedService>().RulesLogPathAsync(rulesId);
|
||||
|
||||
public Task<QueryData<Rules>> RulesPageAsync(QueryPageOptions option, FilterKeyValueAction filterKeyValueAction = null) => App.GetService<IRulesService>().RulesPageAsync(option, filterKeyValueAction);
|
||||
|
||||
public Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IChannelPageService>().SaveChannelAsync(input, type, restart);
|
||||
|
||||
public Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IDevicePageService>().SaveDeviceAsync(input, type, restart);
|
||||
|
||||
public Task SavePluginByPathAsync(PluginAddPathInput plugin) => App.GetService<IPluginPageService>().SavePluginByPathAsync(plugin);
|
||||
|
||||
public Task<bool> SaveRulesAsync(Rules input, ItemChangedType type) => App.GetService<IRulesService>().SaveRulesAsync(input, type);
|
||||
|
||||
public Task<bool> SaveVariableAsync(Variable input, ItemChangedType type, bool restart) =>
|
||||
App.GetService<IVariablePageService>().SaveVariableAsync(input, type, restart);
|
||||
|
||||
public Task SetChannelLogLevelAsync(long id, LogLevel logLevel) =>
|
||||
App.GetService<IChannelPageService>().SetChannelLogLevelAsync(id, logLevel);
|
||||
|
||||
public Task SetDeviceLogLevelAsync(long id, LogLevel logLevel) =>
|
||||
App.GetService<IDevicePageService>().SetDeviceLogLevelAsync(id, logLevel);
|
||||
|
||||
public Task SetRedundancyLogLevelAsync(LogLevel logLevel) => App.GetService<IRedundancyHostedService>().SetRedundancyLogLevelAsync(logLevel);
|
||||
|
||||
public Task SetRulesLogLevelAsync(long rulesId, TouchSocket.Core.LogLevel logLevel) => App.GetService<IRulesEngineHostedService>().SetRulesLogLevelAsync(rulesId, logLevel);
|
||||
|
||||
public Task<bool> StartBusinessChannelEnableAsync() => App.GetService<IChannelEnableService>().StartBusinessChannelEnableAsync();
|
||||
|
||||
public Task<bool> StartCollectChannelEnableAsync() => App.GetService<IChannelEnableService>().StartCollectChannelEnableAsync();
|
||||
|
||||
public Task StartRedundancyTaskAsync() => App.GetService<IRedundancyHostedService>().StartRedundancyTaskAsync();
|
||||
|
||||
public Task StopRedundancyTaskAsync() => App.GetService<IRedundancyHostedService>().StopRedundancyTaskAsync();
|
||||
|
||||
public Task<AuthorizeInfo> TryAuthorizeAsync(string password) => App.GetService<IAuthenticationService>().TryAuthorizeAsync(password);
|
||||
|
||||
public Task<AuthorizeInfo> TryGetAuthorizeInfoAsync() => App.GetService<IAuthenticationService>().TryGetAuthorizeInfoAsync();
|
||||
|
||||
public Task UnAuthorizeAsync() => App.GetService<IAuthenticationService>().UnAuthorizeAsync();
|
||||
|
||||
public Task<string> UUIDAsync() => App.GetService<IAuthenticationService>().UUIDAsync();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ public partial class ManagementTask : AsyncDisposableObject
|
||||
_logger?.Log_Out(logLevel, source, message, exception);
|
||||
}
|
||||
private bool success = true;
|
||||
|
||||
private IScheduledTask _scheduledTask;
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_managementOptions.Enable) return;
|
||||
@@ -60,25 +62,23 @@ public partial class ManagementTask : AsyncDisposableObject
|
||||
{
|
||||
_tcpDmtpClient ??= await GetTcpDmtpClient().ConfigureAwait(false);
|
||||
}
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
_scheduledTask = ScheduledTaskHelper.GetTask("10000", OpenTask, null, LogMessage, cancellationToken);
|
||||
_scheduledTask.Start();
|
||||
}
|
||||
|
||||
private async Task OpenTask(object? state, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureChannelOpenAsync(cancellationToken).ConfigureAwait(false);
|
||||
success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (success)
|
||||
LogMessage?.LogWarning(ex, "Start");
|
||||
|
||||
success = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await Task.Delay(10000, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
await EnsureChannelOpenAsync(cancellationToken).ConfigureAwait(false);
|
||||
success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (success)
|
||||
LogMessage?.LogWarning(ex, "Start");
|
||||
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@ public partial class ManagementTask : AsyncDisposableObject
|
||||
|
||||
protected override async Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_scheduledTask?.SafeDispose();
|
||||
if (_tcpDmtpClient != null)
|
||||
{
|
||||
await _tcpDmtpClient.CloseAsync().ConfigureAwait(false);
|
||||
|
||||
@@ -30,12 +30,13 @@ public static class FileServerHelpers
|
||||
|
||||
var metadata = new Metadata();//传递到服务器的元数据
|
||||
metadata.Add(FileConst.FilePathKey, path);
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(300));
|
||||
var fileOperator = new FileOperator//实例化本次传输的控制器,用于获取传输进度、速度、状态等。
|
||||
{
|
||||
SavePath = savePath,//客户端本地保存路径
|
||||
ResourcePath = path,//请求文件的资源路径
|
||||
Metadata = metadata,//传递到服务器的元数据
|
||||
Timeout = TimeSpan.FromSeconds(60),//传输超时时长
|
||||
Token = cts.Token,
|
||||
TryCount = 10,//当遇到失败时,尝试次数
|
||||
FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值
|
||||
};
|
||||
@@ -75,12 +76,13 @@ public static class FileServerHelpers
|
||||
var metadata = new Metadata();//传递到服务器的元数据
|
||||
metadata.Add(FileConst.FilePathKey, serverPath);
|
||||
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(300));
|
||||
var fileOperator = new FileOperator//实例化本次传输的控制器,用于获取传输进度、速度、状态等。
|
||||
{
|
||||
SavePath = serverPath,//服务器本地保存路径
|
||||
ResourcePath = resourcePath,//客户端本地即将上传文件的资源路径
|
||||
Metadata = metadata,//传递到服务器的元数据
|
||||
Timeout = TimeSpan.FromSeconds(60),//传输超时时长
|
||||
Token = cts.Token,
|
||||
TryCount = 10,//当遇到失败时,尝试次数
|
||||
FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值
|
||||
};
|
||||
|
||||
@@ -11,22 +11,18 @@
|
||||
|
||||
using TouchSocket.Dmtp.Rpc;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.WebApi;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
#if Management
|
||||
[GeneratorRpcProxy(GeneratorFlag = GeneratorFlag.ExtensionAsync)]
|
||||
#endif
|
||||
[TouchSocket.WebApi.Router("/miniapi/upgrade/[action]")]
|
||||
public interface IUpgradeRpcServer : IRpcServer
|
||||
{
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Post)]
|
||||
Task UpgradeAsync(ICallContext callContext, UpdateZipFile updateZipFile);
|
||||
|
||||
[DmtpRpc]
|
||||
[WebApi(Method = HttpMethodType.Get)]
|
||||
Task<UpdateZipFileInput> GetUpdateZipFileInputAsync(ICallContext callContext);
|
||||
Task<UpdateZipFileInput> GetUpdateZipFileInputAsync();
|
||||
|
||||
}
|
||||
@@ -14,7 +14,6 @@ using System.Runtime.InteropServices;
|
||||
using ThingsGateway.NewLife;
|
||||
|
||||
using TouchSocket.Dmtp;
|
||||
using TouchSocket.Dmtp.Rpc;
|
||||
using TouchSocket.Rpc;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
@@ -22,14 +21,12 @@ namespace ThingsGateway.Gateway.Application;
|
||||
public partial class UpgradeRpcServer : IRpcServer, IUpgradeRpcServer
|
||||
{
|
||||
|
||||
[DmtpRpc]
|
||||
public async Task UpgradeAsync(ICallContext callContext, UpdateZipFile updateZipFile)
|
||||
{
|
||||
if (callContext.Caller is IDmtpActorObject dmtpActorObject)
|
||||
await Update(dmtpActorObject.DmtpActor, updateZipFile).ConfigureAwait(false);
|
||||
}
|
||||
[DmtpRpc]
|
||||
public Task<UpdateZipFileInput> GetUpdateZipFileInputAsync(ICallContext callContext)
|
||||
public Task<UpdateZipFileInput> GetUpdateZipFileInputAsync()
|
||||
{
|
||||
return Task.FromResult(new UpdateZipFileInput()
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ using TouchSocket.Core;
|
||||
using TouchSocket.Http;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
using TouchSocket.WebApi.Swagger;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
@@ -89,8 +88,8 @@ public partial class WebApiTask : AsyncDisposableObject
|
||||
store.RegisterServer<RuntimeInfoController>();
|
||||
store.RegisterServer<TestController>();
|
||||
|
||||
store.RegisterServer<IManagementRpcServer>(new ManagementRpcServer());
|
||||
store.RegisterServer<IUpgradeRpcServer>(new UpgradeRpcServer());
|
||||
store.RegisterServer<ManagementController>();
|
||||
|
||||
|
||||
foreach (var type in App.EffectiveTypes.Where(p => typeof(IPluginRpcServer).IsAssignableFrom(p) && !p.IsAbstract && p.IsClass))
|
||||
{
|
||||
@@ -115,16 +114,17 @@ public partial class WebApiTask : AsyncDisposableObject
|
||||
{
|
||||
a.UseTcpSessionCheckClear();
|
||||
|
||||
a.Add(new AuthenticationPlugin(_webApiOptions));
|
||||
a.Add<AuthenticationPlugin>().SetCredentials(_webApiOptions.UserName, _webApiOptions.Password).SetRealm(nameof(ThingsGateway));
|
||||
|
||||
a.UseWebApi();
|
||||
|
||||
#if DEBUG
|
||||
a.UseSwagger().SetPrefix("api");
|
||||
#else
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
a.UseSwagger().SetPrefix("api");
|
||||
#endif
|
||||
//#if DEBUG
|
||||
// a.UseSwagger().SetPrefix("api");
|
||||
//#else
|
||||
// if (App.WebHostEnvironment.IsDevelopment())
|
||||
// a.UseSwagger().SetPrefix("api");
|
||||
//#endif
|
||||
|
||||
a.UseDefaultHttpServicePlugin();
|
||||
});
|
||||
|
||||
@@ -158,60 +158,69 @@ public partial class WebApiTask : AsyncDisposableObject
|
||||
TextLogger?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 鉴权插件
|
||||
/// Basic auth 认证插件
|
||||
/// </summary>
|
||||
class AuthenticationPlugin : PluginBase, IHttpPlugin
|
||||
public sealed class AuthenticationPlugin : PluginBase, IHttpPlugin
|
||||
{
|
||||
WebApiOptions _webApiOptions;
|
||||
public AuthenticationPlugin(WebApiOptions webApiOptions)
|
||||
public string UserName { get; set; } = "admin";
|
||||
public string Password { get; set; } = "111111";
|
||||
public string Realm { get; set; } = "Server";
|
||||
|
||||
public AuthenticationPlugin SetCredentials(string userName, string password)
|
||||
{
|
||||
_webApiOptions = webApiOptions;
|
||||
this.UserName = userName;
|
||||
this.Password = password;
|
||||
return this;
|
||||
}
|
||||
public AuthenticationPlugin SetRealm(string realm = "Server")
|
||||
{
|
||||
this.Realm = realm;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Task Challenge(HttpContextEventArgs e, string message)
|
||||
{
|
||||
e.Context.Response.Headers.Add("WWW-Authenticate", $"Basic realm=\"{Realm}\"");
|
||||
return e.Context.Response
|
||||
.SetStatus(401, message)
|
||||
.AnswerAsync();
|
||||
}
|
||||
|
||||
public Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e)
|
||||
{
|
||||
string authorizationHeader = e.Context.Request.Headers["Authorization"];
|
||||
if (string.IsNullOrEmpty(authorizationHeader))
|
||||
{
|
||||
|
||||
e.Context.Response.Headers.Add("WWW-Authenticate", "Basic realm=\"ThingsGateway\"");
|
||||
return e.Context.Response
|
||||
.SetStatus(401, "Empty Authorization Header")
|
||||
.AnswerAsync();
|
||||
}
|
||||
if (string.IsNullOrEmpty(authorizationHeader))
|
||||
return Challenge(e, "Empty Authorization Header");
|
||||
|
||||
if (!authorizationHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
|
||||
return Challenge(e, "Invalid Authorization Header");
|
||||
|
||||
string authBase64 = authorizationHeader.Substring("Basic ".Length).Trim();
|
||||
|
||||
string authString;
|
||||
try
|
||||
{
|
||||
e.Context.Response.Headers.Add("WWW-Authenticate", "Basic realm=\"ThingsGateway\"");
|
||||
return e.Context.Response
|
||||
.SetStatus(401, "Invalid Authorization Header")
|
||||
.AnswerAsync();
|
||||
authString = Encoding.UTF8.GetString(Convert.FromBase64String(authBase64));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Challenge(e, "Invalid Base64 Authorization Header");
|
||||
}
|
||||
|
||||
var authBase64 = authorizationHeader.Substring("Basic ".Length).Trim();
|
||||
var authBytes = Convert.FromBase64String(authBase64);
|
||||
var authString = Encoding.UTF8.GetString(authBytes);
|
||||
var credentials = authString.Split(':', 2);
|
||||
|
||||
var credentials = authString.Split(':');
|
||||
if (credentials.Length != 2)
|
||||
{
|
||||
e.Context.Response.Headers.Add("WWW-Authenticate", "Basic realm=\"ThingsGateway\"");
|
||||
return e.Context.Response
|
||||
.SetStatus(401, "Invalid Authorization Header")
|
||||
.AnswerAsync();
|
||||
}
|
||||
return Challenge(e, "Invalid Authorization Header");
|
||||
|
||||
var username = credentials[0];
|
||||
var password = credentials[1];
|
||||
|
||||
if (username != _webApiOptions.UserName || password != _webApiOptions.Password)
|
||||
{
|
||||
e.Context.Response.Headers.Add("WWW-Authenticate", "Basic realm=\"ThingsGateway\"");
|
||||
return e.Context.Response
|
||||
.SetStatus(401, "Invalid Username or Password")
|
||||
.AnswerAsync();
|
||||
}
|
||||
if (username != UserName || password != Password)
|
||||
return Challenge(e, "Invalid Username or Password");
|
||||
|
||||
// 验证通过,继续下一个中间件或处理器
|
||||
return e.InvokeNext();
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class TimeIntervalTriggerNode : TextNode, ITriggerNode, IDisposable
|
||||
Text = "500";
|
||||
}
|
||||
_task = ScheduledTaskHelper.GetTask(Text, Timer, null, Logger, cancellationToken);
|
||||
_task.Start();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public interface IRulesService
|
||||
/// 从缓存/数据库获取全部信息
|
||||
/// </summary>
|
||||
/// <returns>规则列表</returns>
|
||||
Task<List<Rules>> GetAllAsync();
|
||||
Task<List<Rules>> GetAllRulesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 报表查询
|
||||
|
||||
@@ -240,7 +240,7 @@ internal sealed class RulesEngineHostedService : BackgroundService, IRulesEngine
|
||||
TokenSource ??= new CancellationTokenSource();
|
||||
Clear();
|
||||
|
||||
Rules = await App.GetService<IRulesService>().GetAllAsync().ConfigureAwait(false);
|
||||
Rules = await App.GetService<IRulesService>().GetAllRulesAsync().ConfigureAwait(false);
|
||||
Diagrams = new();
|
||||
foreach (var rules in Rules.Where(a => a.Status))
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ internal sealed class RulesService : BaseService<Rules>, IRulesService
|
||||
|
||||
using var db = GetDB();
|
||||
|
||||
var data = (await GetAllAsync().ConfigureAwait(false))
|
||||
var data = (await GetAllRulesAsync().ConfigureAwait(false))
|
||||
.WhereIf(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询
|
||||
.WhereIf(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId)
|
||||
.Select(a => a.Id).ToList();
|
||||
@@ -75,7 +75,7 @@ internal sealed class RulesService : BaseService<Rules>, IRulesService
|
||||
/// 从缓存/数据库获取全部信息
|
||||
/// </summary>
|
||||
/// <returns>列表</returns>
|
||||
public async Task<List<Rules>> GetAllAsync()
|
||||
public async Task<List<Rules>> GetAllRulesAsync()
|
||||
{
|
||||
var channels = App.CacheService.Get<List<Rules>>(cacheKey);
|
||||
if (channels == null)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application
|
||||
{
|
||||
@@ -21,5 +22,6 @@ namespace ThingsGateway.Gateway.Application
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile);
|
||||
|
||||
Task<MemoryStream> ExportMemoryStream(List<Variable> data, string devName);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableAsync(IFormFile file, bool restart);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
@@ -110,4 +111,5 @@ internal interface IVariableService
|
||||
List<VariableRuntime> GetAllVariableRuntime();
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(string filePath);
|
||||
Task<HashSet<long>> ImportVariableAsync(List<Variable> upData, List<Variable> insertData);
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IFormFile browserFile);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
@@ -311,6 +312,42 @@ public class VariableRuntimeService : IVariableRuntimeService
|
||||
//WaitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableAsync(IFormFile file, bool restart)
|
||||
{
|
||||
try
|
||||
{
|
||||
// await WaitLock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
var data = await GlobalData.VariableService.PreviewAsync(file).ConfigureAwait(false);
|
||||
|
||||
if (data.Any(a => a.Value.HasError)) return data;
|
||||
|
||||
var result = await GlobalData.VariableService.ImportVariableAsync(data).ConfigureAwait(false);
|
||||
|
||||
using var db = DbContext.GetDB<Variable>();
|
||||
var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => result.Contains(a.Id)).ToListAsync().ConfigureAwait(false)).AdaptListVariableRuntime();
|
||||
|
||||
var variableIds = newVariableRuntimes.Select(a => a.Id).ToHashSet();
|
||||
|
||||
ConcurrentHashSet<IDriver> changedDriver = new();
|
||||
RuntimeServiceHelper.VariableRuntimesDispose(variableIds);
|
||||
RuntimeServiceHelper.AddCollectChangedDriver(newVariableRuntimes, changedDriver);
|
||||
RuntimeServiceHelper.AddBusinessChangedDriver(variableIds, changedDriver);
|
||||
|
||||
if (restart)
|
||||
{
|
||||
//根据条件重启通道线程
|
||||
await RuntimeServiceHelper.ChangedDriverAsync(changedDriver, _logger).ConfigureAwait(false);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
finally
|
||||
{
|
||||
//WaitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportVariableFileAsync(string filePath, bool restart)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using MiniExcelLibs;
|
||||
|
||||
@@ -588,7 +589,12 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
|
||||
return await PreviewAsync(path).ConfigureAwait(false);
|
||||
}
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IFormFile browserFile)
|
||||
{
|
||||
var path = await browserFile.StorageLocal().ConfigureAwait(false); // 上传文件并获取文件路径
|
||||
|
||||
return await PreviewAsync(path).ConfigureAwait(false);
|
||||
}
|
||||
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(string path)
|
||||
{
|
||||
// 上传文件并获取文件路径
|
||||
@@ -675,7 +681,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (deviceId == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["NotNull", deviceName]));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, Localizer["NotNull", deviceName]));
|
||||
return;
|
||||
}
|
||||
// 手动补录变量ID和设备ID
|
||||
@@ -698,7 +704,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -717,19 +723,19 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
}
|
||||
if (device.IsUp && ((dataScope != null && dataScope?.Count > 0 && !dataScope.Contains(variable.CreateOrgId)) || dataScope?.Count == 0 && variable.CreateUserId != UserManager.UserId))
|
||||
{
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, "Operation not permitted"));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, "Operation not permitted"));
|
||||
}
|
||||
else
|
||||
{
|
||||
variables.Add(variable);
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), true, null));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -764,7 +770,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (alarm == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ImportNullError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ImportNullError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -776,13 +782,13 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (collectDevName == null || collectDevice == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, DeviceNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, DeviceNotNull));
|
||||
return;
|
||||
}
|
||||
if (variableNameObj == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, VariableNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, VariableNotNull));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -805,7 +811,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -815,12 +821,12 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (deviceImportPreview.Data.TryGetValue(collectDevice.Id.ToString(), out var deviceVariables) && deviceVariables.TryGetValue(variableName, out var deviceVariable))
|
||||
{
|
||||
deviceVariable.AlarmPropertys = alarm;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), true, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, VariableNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, VariableNotNull));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -828,7 +834,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -848,7 +854,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (driverPluginType == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["NotNull", sheetName]));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, Localizer["NotNull", sheetName]));
|
||||
return deviceImportPreview;
|
||||
}
|
||||
|
||||
@@ -885,7 +891,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (propertys.Item3?.Count == null || propertys.Item1 == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ImportNullError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ImportNullError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -896,7 +902,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (pluginProp == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ImportNullError));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ImportNullError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -911,13 +917,13 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (businessDevName == null || businessDevice == null || collectDevName == null || collectDevice == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, DeviceNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, DeviceNotNull));
|
||||
return;
|
||||
}
|
||||
if (variableNameObj == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, VariableNotNull));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, VariableNotNull));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -940,7 +946,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -961,12 +967,12 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
{
|
||||
deviceVariable.VariablePropertys ??= new();
|
||||
deviceVariable.VariablePropertys?.AddOrUpdate(businessDevice.Id, dependencyProperties);
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), true, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["VariableNotNull"]));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, Localizer["VariableNotNull"]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -974,7 +980,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -982,7 +988,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
importPreviewOutput.Results.Add(new(Interlocked.Increment(ref row), false, ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
|
||||
<PackageReference Include="Rougamo.Fody" Version="5.0.1" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
|
||||
<PackageReference Include="TouchSocket.Dmtp" Version="4.0.0-beta.3" />
|
||||
<PackageReference Include="TouchSocket.WebApi.Swagger" Version="4.0.0-beta.3" />
|
||||
<PackageReference Include="TouchSocket.Dmtp" Version="4.0.0-beta.6" />
|
||||
<!--<PackageReference Include="TouchSocket.WebApi.Swagger" Version="4.0.0-beta.6" />-->
|
||||
<PackageReference Include="TouchSocket.WebApi" Version="4.0.0-beta.6" />
|
||||
<PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" />
|
||||
<!--<ProjectReference Include="..\..\PluginPro\ThingsGateway.Authentication\ThingsGateway.Authentication.csproj" />-->
|
||||
|
||||
|
||||
@@ -15,6 +15,32 @@ namespace ThingsGateway.Gateway.Application;
|
||||
[ThingsGateway.DependencyInjection.SuppressSniffer]
|
||||
public static class GatewayResourceUtil
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 存储本地文件
|
||||
/// </summary>
|
||||
/// <param name="pPath">存储的第一层目录</param>
|
||||
/// <param name="file"></param>
|
||||
/// <returns>文件全路径</returns>
|
||||
public static async Task<string> StorageLocalExcel(this TouchSocket.Http.HttpRequest file, string pPath = "imports")
|
||||
{
|
||||
string uploadFileFolder = App.WebHostEnvironment?.WebRootPath ?? "wwwroot"!;//赋值路径
|
||||
var now = CommonUtils.GetSingleId();
|
||||
var filePath = Path.Combine(uploadFileFolder, pPath);
|
||||
if (!Directory.Exists(filePath))//如果不存在就创建文件夹
|
||||
Directory.CreateDirectory(filePath);
|
||||
//var fileSuffix = Path.GetExtension(file.Name).ToLower();// 文件后缀
|
||||
var fileObjectName = $"{now}.xlsx";//存储后的文件名
|
||||
var fileName = Path.Combine(filePath, fileObjectName);//获取文件全路径
|
||||
fileName = fileName.Replace("\\", "/");//格式化一系
|
||||
//存储文件
|
||||
using (var stream = File.Create(Path.Combine(filePath, fileObjectName)))
|
||||
{
|
||||
await file.ReadCopyToAsync(stream).ConfigureAwait(false);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造选择项,ID/Name
|
||||
/// </summary>
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
<TableColumn Field="@context.DeviceName" FieldExpression=@(() => context.DeviceName) ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.Name" ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.Description" ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.BusinessGroup" ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.CollectGroup" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.BusinessGroup" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.BusinessGroupUpdateTrigger" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.RpcWriteCheck" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
|
||||
@@ -51,7 +52,7 @@
|
||||
|
||||
<TableColumn @bind-Field="@context.SaveValue" Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.DataType" Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn Field="@context.RuntimeType" ShowTips=true FieldExpression=@(() => context.RuntimeType) Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn Field="@context.RuntimeType" ShowTips=true FieldExpression=@(() => context.RuntimeType) Filterable=true Sortable=true Visible=false />
|
||||
|
||||
<TableColumn @bind-Field="@context.RegisterAddress" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.ArrayLength" Filterable=true Sortable=true Visible=false />
|
||||
@@ -60,7 +61,7 @@
|
||||
<TableColumn @bind-Field="@context.IntervalTime" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.OtherMethod" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.RpcWriteEnable" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.ReadExpressions" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.ReadExpressions" Filterable=true Sortable=true Visible="true" />
|
||||
<TableColumn @bind-Field="@context.WriteExpressions" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.Unit" Filterable=true Sortable=true Visible="false" />
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@
|
||||
</Side>
|
||||
<Main>
|
||||
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowContextMenuFullScreen="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
|
||||
{
|
||||
return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
|
||||
|
||||
@@ -189,7 +189,7 @@ public class Dlt645_2007Send : ISendMessage
|
||||
lenSpan.WriteValue<byte>((byte)(length - 1));//数据域长度
|
||||
|
||||
int num = 0;
|
||||
for (int index = 0; index < byteBlock.WrittenCount; ++index)
|
||||
for (int index = 0; index < byteBlock.WrittenCount - SendHeadCodeIndex; ++index)
|
||||
num += span[index];
|
||||
WriterExtension.WriteValue(ref byteBlock, (byte)num);//校验码,总加和
|
||||
WriterExtension.WriteValue(ref byteBlock, (byte)0x16);//结束符
|
||||
|
||||
@@ -37,7 +37,7 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheAlarm
|
||||
get
|
||||
{
|
||||
#if !Management
|
||||
if (_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
|
||||
if (_driverPropertys.VariableAlarmEnable && _driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
|
||||
return typeof(HistoryAlarmPage);
|
||||
else
|
||||
return null;
|
||||
|
||||
@@ -102,7 +102,7 @@ internal sealed class Program
|
||||
hybridApp.MainWindow.SetUseOsDefaultLocation(false);
|
||||
hybridApp.MainWindow.SetUseOsDefaultSize(false);
|
||||
hybridApp.MainWindow.SetSize(new System.Drawing.Size(1920, 1080));
|
||||
hybridApp.MainWindow.SetTitle("ThingsGateway.Photino");
|
||||
hybridApp.MainWindow.SetTitle("ThingsGateway边缘网关");
|
||||
hybridApp.MainWindow.SetIconFile("favicon.ico");
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
|
||||
|
||||
@@ -2,45 +2,51 @@
|
||||
|
||||
<Import Project="..\Version.props" />
|
||||
|
||||
<ItemGroup Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' ">
|
||||
<PackageReference Include="ThingsGateway.Photino.Blazor" Version="$(Version)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease'">
|
||||
<ProjectReference Include="..\Admin\ThingsGateway.Photino.Blazor\ThingsGateway.Photino.Blazor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease' ">
|
||||
|
||||
<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease'">
|
||||
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" />
|
||||
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj" />
|
||||
<ProjectReference Include="..\Admin\ThingsGateway.Photino.Blazor\ThingsGateway.Photino.Blazor.csproj" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<!--发布版-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\Gateway.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
|
||||
<Import Project="..\ThingsGateway.Server\targets\Admin.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
|
||||
|
||||
<ItemGroup Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' ">
|
||||
<PackageReference Include="ThingsGateway.Photino.Blazor" Version="$(Version)" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginContext.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
|
||||
|
||||
<!--nuget包解压复制文件,上下文动态加载-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginContext.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
|
||||
<!--直接引用-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug' " />
|
||||
|
||||
<!--直接引用Pro-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginContext.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
|
||||
|
||||
<!--nuget包解压复制文件,插件域隔离动态加载-->
|
||||
<!--<Import Project="targets\Plugin.targets" />-->
|
||||
<!--<Import Project="..\ThingsGateway.Server\targets\Plugin.targets" />-->
|
||||
|
||||
<!--nuget包解压复制文件,上下文动态加载,Pro插件-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\Pro2.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR '$(Configuration)' != 'Debug'" />
|
||||
|
||||
<!--直接引用Pro-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
|
||||
|
||||
|
||||
<Import Project="..\ThingsGateway.Server\targets\ProPluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
|
||||
|
||||
<!--<Import Project="..\ThingsGateway.Server\targets\Pro3.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' " />
|
||||
<Import Project="..\ThingsGateway.Server\targets\Pro5.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' " />-->
|
||||
<!--<Import Project="..\ThingsGateway.Server\targets\Pro6.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug'" />-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\Pro7.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug'" />
|
||||
|
||||
<!--打包复制-->
|
||||
<Import Project="..\ThingsGateway.Server\targets\PluginPublish.targets" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||
<CustomTargetFramework>$(TargetFramework)</CustomTargetFramework>
|
||||
@@ -54,7 +60,7 @@
|
||||
|
||||
<!--动态适用GC-->
|
||||
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
|
||||
|
||||
|
||||
<!--使用工作站GC-->
|
||||
<!--<ServerGarbageCollection>true</ServerGarbageCollection>-->
|
||||
<!--<PlatformTarget>x86</PlatformTarget>-->
|
||||
@@ -86,7 +92,7 @@
|
||||
|
||||
|
||||
<Content Include="..\ThingsGateway.Server\ThingsGateway.pfx" Link="ThingsGateway.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
||||
|
||||
@@ -122,7 +128,7 @@
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="launchSettings.json" />
|
||||
<Content Remove="launchSettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -132,10 +138,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Properties\launchSettings.json">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</None>
|
||||
<None Include="Properties\launchSettings.json">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@
|
||||
</div>
|
||||
</Side>
|
||||
<Main>
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowContextMenuFullScreen="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
|
||||
{
|
||||
return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
|
||||
|
||||
@@ -70,7 +70,7 @@ public class Program
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
builder.Host.UseSystemd();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
if (Runtime.IsLegacyWindows)
|
||||
builder.Logging.ClearProviders(); //去除默认的事件日志提供者,某些情况下会日志输出异常,导致程序崩溃
|
||||
}).ConfigureBuilder(builder =>
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<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' " />
|
||||
<!--直接引用-->
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
|
||||
<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'" />-->
|
||||
@@ -42,7 +42,7 @@
|
||||
<PropertyGroup>
|
||||
|
||||
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
||||
|
||||
|
||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||
<CustomTargetFramework>$(TargetFramework)</CustomTargetFramework>
|
||||
<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
|
||||
@@ -57,10 +57,10 @@
|
||||
<CETCompat>false</CETCompat>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--<TieredCompilation>false</TieredCompilation>-->
|
||||
|
||||
|
||||
<!--使用自托管线程池-->
|
||||
<!--<UseWindowsThreadPool>false</UseWindowsThreadPool> -->
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<None Include="Layout\BlazorAppNet8.razor" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<!--安装服务守护-->
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Update="ThingsGateway.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="WindowsService">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
@@ -136,7 +136,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="WindowsWebDisable.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="WindowsServiceCreate.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
||||
@@ -111,6 +111,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation",
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "debug", "debug", "{053AB5FA-9742-96EC-76A1-2AEC739860C6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThingsGateway.Foundation.Demo", "Foundation\ThingsGateway.Foundation.Demo\ThingsGateway.Foundation.Demo.csproj", "{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -281,6 +283,10 @@ Global
|
||||
{EAEE6A03-D2E7-7283-0F7A-F15B6261EE96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EAEE6A03-D2E7-7283-0F7A-F15B6261EE96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EAEE6A03-D2E7-7283-0F7A-F15B6261EE96}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -327,10 +333,11 @@ Global
|
||||
{1D9CD7A3-9700-A851-0ABD-183347D9CC33} = {36510D70-161F-4241-B8D0-781E21032816}
|
||||
{E6EF2033-F02A-CDAD-5A72-EE397A89742E} = {36510D70-161F-4241-B8D0-781E21032816}
|
||||
{053AB5FA-9742-96EC-76A1-2AEC739860C6} = {36510D70-161F-4241-B8D0-781E21032816}
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA} = {2AC600BB-4325-4E0A-93A7-B1F53C8E2CA7}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {199B1B96-4F56-4828-9531-813BA02DB282}
|
||||
RESX_NeutralResourcesLanguage = zh-Hans
|
||||
RESX_Rules = {"EnabledRules":[]}
|
||||
RESX_NeutralResourcesLanguage = zh-Hans
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Reference in New Issue
Block a user