mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-20 10:50:48 +08:00
533 lines
19 KiB
C#
533 lines
19 KiB
C#
// ------------------------------------------------------------------------------
|
||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||
// 使用文档:https://thingsgateway.cn/
|
||
// QQ群:605534569
|
||
// ------------------------------------------------------------------------------
|
||
|
||
using BootstrapBlazor.Components;
|
||
|
||
using Microsoft.AspNetCore.Components.Forms;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.Extensions.Logging;
|
||
|
||
using ThingsGateway.Extension.Generic;
|
||
using ThingsGateway.NewLife;
|
||
using ThingsGateway.NewLife.Collections;
|
||
using ThingsGateway.NewLife.DictionaryExtensions;
|
||
using ThingsGateway.NewLife.Extension;
|
||
|
||
namespace ThingsGateway.Gateway.Application;
|
||
|
||
public class DeviceRuntimeService : IDeviceRuntimeService
|
||
{
|
||
private ILogger _logger;
|
||
public DeviceRuntimeService(ILogger<DeviceRuntimeService> logger)
|
||
{
|
||
_logger = logger;
|
||
}
|
||
|
||
public Task<Dictionary<long, Tuple<string, string>>> GetDeviceIdNamesAsync()
|
||
{
|
||
|
||
return Task.FromResult(GlobalData.ReadOnlyIdDevices.ToDictionary(a => a.Key, a => Tuple.Create(a.Value.Name, a.Value.PluginName)));
|
||
}
|
||
public async Task<QueryData<SelectedItem>> OnDeviceSelectedItemQueryAsync(VirtualizeQueryOption option, bool isCollect)
|
||
{
|
||
var devices = await GlobalData.GetCurrentUserDevices().ConfigureAwait(false);
|
||
|
||
return devices.Where(a => a.IsCollect == isCollect).WhereIf(!option.SearchText.IsNullOrWhiteSpace(), a => a.Name.Contains(option.SearchText)).GetQueryData(option, GatewayResourceUtil.BuildDeviceSelectList);
|
||
|
||
}
|
||
|
||
|
||
public Task<string> GetDevicePluginNameAsync(long id)
|
||
{
|
||
return Task.FromResult(GlobalData.ReadOnlyIdDevices.TryGetValue(id, out var deviceRuntime) ? deviceRuntime.PluginName : string.Empty);
|
||
}
|
||
public Task<string> GetDeviceNameAsync(long redundantDeviceId)
|
||
{
|
||
return Task.FromResult(GlobalData.ReadOnlyIdDevices.TryGetValue(redundantDeviceId, out var deviceRuntime) ? deviceRuntime.Name : string.Empty);
|
||
}
|
||
|
||
public Task<bool> IsRedundantDeviceAsync(long id)
|
||
{
|
||
return Task.FromResult(GlobalData.IsRedundant(id));
|
||
}
|
||
|
||
public Task<QueryData<DeviceRuntime>> OnDeviceQueryAsync(QueryPageOptions options)
|
||
{
|
||
var data = GlobalData.IdDevices.Select(a => a.Value)
|
||
.WhereIf(!options.SearchText.IsNullOrWhiteSpace(), a => a.Name.Contains(options.SearchText))
|
||
.GetQueryData(options);
|
||
return Task.FromResult(data);
|
||
}
|
||
public Task<List<Device>> GetDeviceListAsync(QueryPageOptions options, int max = 0)
|
||
{
|
||
var models = GlobalData.IdDevices.Select(a => a.Value)
|
||
.WhereIf(!options.SearchText.IsNullOrWhiteSpace(), a => a.Name.Contains(options.SearchText))
|
||
.GetData(options, out var total).Cast<Device>().ToList();
|
||
|
||
if (max > 0 && models.Count > max)
|
||
{
|
||
throw new("online Excel max data count 2000");
|
||
}
|
||
return Task.FromResult(models);
|
||
}
|
||
|
||
public Task<bool> ClearDeviceAsync(bool restart)
|
||
{
|
||
return DeleteDeviceAsync(GlobalData.IdChannels.Keys.ToList(), restart);
|
||
}
|
||
|
||
|
||
|
||
public async Task DeviceRedundantThreadAsync(long id)
|
||
{
|
||
if (GlobalData.IdDevices.TryGetValue(id, out var deviceRuntime) && GlobalData.TryGetDeviceThreadManage(deviceRuntime, out var deviceThreadManage))
|
||
{
|
||
await deviceThreadManage.DeviceRedundantThreadAsync(id, default).ConfigureAwait(false);
|
||
}
|
||
}
|
||
public async Task RestartDeviceAsync(long id, bool deleteCache)
|
||
{
|
||
if (GlobalData.IdDevices.TryGetValue(id, out var deviceRuntime) && GlobalData.TryGetDeviceThreadManage(deviceRuntime, out var deviceThreadManage))
|
||
{
|
||
await deviceThreadManage.RestartDeviceAsync(deviceRuntime, deleteCache).ConfigureAwait(false);
|
||
}
|
||
}
|
||
|
||
public Task PauseThreadAsync(long id)
|
||
{
|
||
if (GlobalData.IdDevices.TryGetValue(id, out var deviceRuntime))
|
||
{
|
||
deviceRuntime.Driver?.PauseThread(!deviceRuntime.Pause);
|
||
}
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
public Task<USheetDatas> ExportDeviceAsync(List<Device> devices)
|
||
{
|
||
return Task.FromResult(DeviceServiceHelpers.ExportDevice(devices));
|
||
}
|
||
|
||
|
||
private WaitLock WaitLock { get; set; } = new WaitLock(nameof(DeviceRuntimeService));
|
||
|
||
public async Task<QueryData<SelectedItem>> OnRedundantDevicesQueryAsync(VirtualizeQueryOption option, long deviceId, long channelId)
|
||
{
|
||
|
||
var devices = await GlobalData.GetCurrentUserDevices().ConfigureAwait(false);
|
||
var pluginName = GlobalData.ReadOnlyIdChannels.TryGetValue(channelId, out var channel) ? channel.PluginName : string.Empty;
|
||
var ret = devices.WhereIf(!option.SearchText.IsNullOrWhiteSpace(), a => a.Name.Contains(option.SearchText))
|
||
.Where(a => a.PluginName == pluginName && a.Id != deviceId).GetQueryData(option, GatewayResourceUtil.BuildDeviceSelectList
|
||
);
|
||
|
||
|
||
return ret;
|
||
}
|
||
|
||
public Task<TouchSocket.Core.LogLevel> DeviceLogLevelAsync(long id)
|
||
{
|
||
GlobalData.IdDevices.TryGetValue(id, out var DeviceRuntime);
|
||
var data = DeviceRuntime?.Driver?.LogMessage?.LogLevel ?? TouchSocket.Core.LogLevel.Trace;
|
||
return Task.FromResult(data);
|
||
}
|
||
|
||
|
||
public async Task SetDeviceLogLevelAsync(long id, TouchSocket.Core.LogLevel logLevel)
|
||
{
|
||
if (GlobalData.IdDevices.TryGetValue(id, out var DeviceRuntime))
|
||
{
|
||
if (DeviceRuntime.Driver != null)
|
||
{
|
||
await DeviceRuntime.Driver.SetLogAsync(logLevel).ConfigureAwait(false);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
public async Task CopyDeviceAsync(int CopyCount, string CopyDeviceNamePrefix, int CopyDeviceNameSuffixNumber, long deviceId, bool AutoRestartThread)
|
||
{
|
||
if (!GlobalData.IdDevices.TryGetValue(deviceId, out var deviceRuntime))
|
||
{
|
||
return;
|
||
}
|
||
|
||
Device Model = deviceRuntime.AdaptDevice();
|
||
Model.Id = 0;
|
||
var Variables = deviceRuntime.ReadOnlyVariableRuntimes.Select(a => a.Value).AdaptListVariable();
|
||
|
||
|
||
Dictionary<Device, List<Variable>> devices = new();
|
||
for (int i = 0; i < CopyCount; i++)
|
||
{
|
||
Device device = Model.AdaptDevice();
|
||
device.Id = CommonUtils.GetSingleId();
|
||
device.Name = $"{CopyDeviceNamePrefix}{CopyDeviceNameSuffixNumber + i}";
|
||
List<Variable> variables = new();
|
||
|
||
foreach (var item in Variables)
|
||
{
|
||
Variable v = item.AdaptVariable();
|
||
v.Id = CommonUtils.GetSingleId();
|
||
v.DeviceId = device.Id;
|
||
variables.Add(v);
|
||
}
|
||
devices.Add(device, variables);
|
||
}
|
||
|
||
await GlobalData.DeviceRuntimeService.CopyAsync(devices, AutoRestartThread).ConfigureAwait(false);
|
||
}
|
||
|
||
|
||
|
||
|
||
public async Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var result = await GlobalData.DeviceService.CopyAsync(devices).ConfigureAwait(false);
|
||
|
||
var deviceids = devices.Select(a => a.Key.Id).ToHashSet();
|
||
var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(deviceids).ConfigureAwait(false);
|
||
|
||
await RuntimeServiceHelper.InitAsync(newDeviceRuntimes, _logger).ConfigureAwait(false);
|
||
|
||
//根据条件重启通道线程
|
||
if (restart)
|
||
{
|
||
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
|
||
await RuntimeServiceHelper.ChangedDriverAsync(GlobalData.GetAllVariableBusinessDeviceRuntime().Where(a => !newDeviceRuntimes.Contains(a)).ToArray(), _logger).ConfigureAwait(false);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
finally
|
||
{
|
||
WaitLock.Release();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public async Task<bool> BatchEditDeviceAsync(List<Device> models, Device oldModel, Device model, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var result = await GlobalData.DeviceService.BatchEditAsync(models, oldModel, model).ConfigureAwait(false);
|
||
var deviceids = models.Select(a => a.Id).ToHashSet();
|
||
|
||
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 true;
|
||
}
|
||
finally
|
||
{
|
||
WaitLock.Release();
|
||
}
|
||
}
|
||
|
||
public async Task<bool> DeleteDeviceAsync(List<long> ids, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var devids = ids.ToHashSet();
|
||
|
||
var result = await GlobalData.DeviceService.DeleteDeviceAsync(devids).ConfigureAwait(false);
|
||
|
||
//根据条件重启通道线程
|
||
var deviceRuntimes = GlobalData.IdDevices.FilterByKeys(devids).Select(a => a.Value).ToList();
|
||
|
||
ConcurrentHashSet<IDriver> changedDriver = RuntimeServiceHelper.DeleteDeviceRuntime(deviceRuntimes);
|
||
|
||
if (restart)
|
||
{
|
||
await RuntimeServiceHelper.RemoveDeviceAsync(deviceRuntimes).ConfigureAwait(false);
|
||
|
||
await RuntimeServiceHelper.ChangedDriverAsync(changedDriver, _logger).ConfigureAwait(false);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
finally
|
||
{
|
||
WaitLock.Release();
|
||
}
|
||
}
|
||
|
||
public Task<Dictionary<string, object>> ExportDeviceAsync(GatewayExportFilter exportFilter) => GlobalData.DeviceService.ExportDeviceAsync(exportFilter);
|
||
public Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile) => GlobalData.DeviceService.PreviewAsync(browserFile);
|
||
public Task<MemoryStream> ExportMemoryStream(List<Device> data, string channelName, string plugin) =>
|
||
GlobalData.DeviceService.ExportMemoryStream(data, channelName, plugin);
|
||
|
||
public async Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var deviceids = await GlobalData.DeviceService.ImportDeviceAsync(input).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);
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
WaitLock.Release();
|
||
}
|
||
}
|
||
|
||
public async Task<Dictionary<string, ImportPreviewOutputBase>> ImportDeviceAsync(IBrowserFile 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>> 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)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
|
||
var data = await DeviceServiceHelpers.ImportAsync(input).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>> ImportDeviceFileAsync(string filePath, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var data = await GlobalData.DeviceService.PreviewAsync(filePath).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<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var result = await GlobalData.DeviceService.SaveDeviceAsync(input, type).ConfigureAwait(false);
|
||
|
||
var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(new HashSet<long>() { input.Id }).ConfigureAwait(false);
|
||
|
||
RuntimeServiceHelper.Init(newDeviceRuntimes);
|
||
|
||
if (restart)
|
||
{
|
||
//根据条件重启通道线程
|
||
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
finally
|
||
{
|
||
WaitLock.Release();
|
||
}
|
||
}
|
||
|
||
public async Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type, bool restart)
|
||
{
|
||
try
|
||
{
|
||
await WaitLock.WaitAsync().ConfigureAwait(false);
|
||
|
||
var result = await GlobalData.DeviceService.BatchSaveDeviceAsync(input, type).ConfigureAwait(false);
|
||
|
||
var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(input.Select(a => a.Id).ToHashSet()).ConfigureAwait(false);
|
||
|
||
RuntimeServiceHelper.Init(newDeviceRuntimes);
|
||
|
||
if (restart)
|
||
{
|
||
//根据条件重启通道线程
|
||
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
finally
|
||
{
|
||
WaitLock.Release();
|
||
}
|
||
}
|
||
|
||
public async Task<string> ExportDeviceFileAsync(GatewayExportFilter exportFilter)
|
||
{
|
||
var sheets = await GlobalData.DeviceService.ExportDeviceAsync(exportFilter).ConfigureAwait(false);
|
||
return await App.GetService<IImportExportService>().CreateFileAsync<Device>(sheets, "Device", false).ConfigureAwait(false);
|
||
|
||
}
|
||
|
||
|
||
} |