mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-31 23:53:58 +08:00 
			
		
		
		
	| @@ -1,11 +1,11 @@ | ||||
| <Project> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<PluginVersion>10.9.42</PluginVersion> | ||||
| 		<ProPluginVersion>10.9.42</ProPluginVersion> | ||||
| 		<DefaultVersion>10.9.42</DefaultVersion> | ||||
| 		<AuthenticationVersion>2.9.19</AuthenticationVersion> | ||||
| 		<SourceGeneratorVersion>10.9.19</SourceGeneratorVersion> | ||||
| 		<PluginVersion>10.9.41</PluginVersion> | ||||
| 		<ProPluginVersion>10.9.41</ProPluginVersion> | ||||
| 		<DefaultVersion>10.9.41</DefaultVersion> | ||||
| 		<AuthenticationVersion>2.9.18</AuthenticationVersion> | ||||
| 		<SourceGeneratorVersion>10.9.18</SourceGeneratorVersion> | ||||
| 		<NET8Version>8.0.18</NET8Version> | ||||
| 		<NET9Version>9.0.7</NET9Version> | ||||
| 		<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages> | ||||
|   | ||||
| @@ -350,9 +350,6 @@ public abstract class DeviceBase : DisposableObject, IDevice | ||||
|             if (SendDelayTime != 0) | ||||
|                 await Task.Delay(SendDelayTime, token).ConfigureAwait(false); | ||||
|  | ||||
|             if (token.IsCancellationRequested) | ||||
|                 return new OperResult(new OperationCanceledException()); | ||||
|  | ||||
|             if (channel is IDtuUdpSessionChannel udpSession) | ||||
|             { | ||||
|                 await udpSession.SendAsync(endPoint, sendMessage).ConfigureAwait(false); | ||||
| @@ -560,9 +557,6 @@ public abstract class DeviceBase : DisposableObject, IDevice | ||||
|             if (clientChannel.ReadOnlyDataHandlingAdapter != null) | ||||
|                 clientChannel.ReadOnlyDataHandlingAdapter.Logger = Logger; | ||||
|  | ||||
|             if (cancellationToken.IsCancellationRequested) | ||||
|                 return new MessageBase(new OperationCanceledException()); | ||||
|  | ||||
|             waitData.SetCancellationToken(cancellationToken); | ||||
|  | ||||
|             Channel.ChannelReceivedWaitDict.TryAdd(sign, ChannelReceived); | ||||
| @@ -572,14 +566,6 @@ public abstract class DeviceBase : DisposableObject, IDevice | ||||
|  | ||||
|             await waitData.WaitAsync(timeout).ConfigureAwait(false); | ||||
|  | ||||
|             if (cancellationToken.IsCancellationRequested) | ||||
|             { | ||||
|                 if (!this.DisposedValue) | ||||
|                 { | ||||
|                     await Task.Delay(timeout, CancellationToken.None).ConfigureAwait(false); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var result = waitData.Check(); | ||||
|             if (result.IsSuccess) | ||||
|             { | ||||
|   | ||||
| @@ -16,18 +16,17 @@ public class AsyncReadWriteLock | ||||
| { | ||||
|     private AsyncAutoResetEvent _readerLock = new AsyncAutoResetEvent(false); // 控制读计数 | ||||
|     private long _writerCount = 0; // 当前活跃的写线程数 | ||||
|     private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取读锁,支持多个线程并发读取,但写入时会阻止所有读取。 | ||||
|     /// </summary> | ||||
|     public async Task<CancellationToken> ReaderLockAsync(CancellationToken cancellationToken) | ||||
|     public async Task ReaderLockAsync(CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (Interlocked.Read(ref _writerCount) > 0) | ||||
|         { | ||||
|             // 第一个读者需要获取写入锁,防止写操作 | ||||
|             await _readerLock.WaitOneAsync(cancellationToken).ConfigureAwait(false); | ||||
|         } | ||||
|         return _cancellationTokenSource.Token; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -35,14 +34,7 @@ public class AsyncReadWriteLock | ||||
|     /// </summary> | ||||
|     public IDisposable WriterLock() | ||||
|     { | ||||
|         if (Interlocked.Increment(ref _writerCount) == 1) | ||||
|         { | ||||
|             var cancellationTokenSource = _cancellationTokenSource; | ||||
|             _cancellationTokenSource = new(); | ||||
|             cancellationTokenSource.Cancel();//取消读取 | ||||
|             cancellationTokenSource.SafeDispose(); | ||||
|         } | ||||
|  | ||||
|         Interlocked.Increment(ref _writerCount); | ||||
|         return new Writer(this); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -148,9 +148,9 @@ public class ControlController : ControllerBase | ||||
|     /// </summary> | ||||
|     [HttpPost("batchSaveChannel")] | ||||
|     [DisplayName("保存通道")] | ||||
|     public Task<bool> BatchSaveChannelAsync([FromBody] List<ChannelInput> channels, ItemChangedType type) | ||||
|     public Task<bool> BatchSaveChannelAsync([FromBody] List<ChannelInput> channels, ItemChangedType type, bool restart) | ||||
|     { | ||||
|         return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.AdaptListChannel(), type); | ||||
|         return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.AdaptListChannel(), type, restart); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -158,9 +158,9 @@ public class ControlController : ControllerBase | ||||
|     /// </summary> | ||||
|     [HttpPost("batchSaveDevice")] | ||||
|     [DisplayName("保存设备")] | ||||
|     public Task<bool> BatchSaveDeviceAsync([FromBody] List<DeviceInput> devices, ItemChangedType type) | ||||
|     public Task<bool> BatchSaveDeviceAsync([FromBody] List<DeviceInput> devices, ItemChangedType type, bool restart) | ||||
|     { | ||||
|         return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.AdaptListDevice(), type); | ||||
|         return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.AdaptListDevice(), type, restart); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -178,10 +178,10 @@ public class ControlController : ControllerBase | ||||
|     /// </summary> | ||||
|     [HttpPost("deleteChannel")] | ||||
|     [DisplayName("删除通道")] | ||||
|     public Task<bool> DeleteChannelAsync([FromBody] List<long> ids) | ||||
|     public Task<bool> DeleteChannelAsync([FromBody] List<long> ids, bool restart) | ||||
|     { | ||||
|         if (ids == null || ids.Count == 0) ids = GlobalData.IdChannels.Keys.ToList(); | ||||
|         return GlobalData.ChannelRuntimeService.DeleteChannelAsync(ids, default); | ||||
|         return GlobalData.ChannelRuntimeService.DeleteChannelAsync(ids, restart, default); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @@ -190,10 +190,10 @@ public class ControlController : ControllerBase | ||||
|     /// </summary> | ||||
|     [HttpPost("deleteDevice")] | ||||
|     [DisplayName("删除设备")] | ||||
|     public Task<bool> DeleteDeviceAsync([FromBody] List<long> ids) | ||||
|     public Task<bool> DeleteDeviceAsync([FromBody] List<long> ids, bool restart) | ||||
|     { | ||||
|         if (ids == null || ids.Count == 0) ids = GlobalData.IdDevices.Keys.ToList(); | ||||
|         return GlobalData.DeviceRuntimeService.DeleteDeviceAsync(ids, default); | ||||
|         return GlobalData.DeviceRuntimeService.DeleteDeviceAsync(ids, restart, default); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -344,25 +344,18 @@ public abstract class CollectBase : DriverBase, IRpcDriver | ||||
|     { | ||||
|         if (state is not VariableSourceRead variableSourceRead) return; | ||||
|  | ||||
|         if (Pause) return; | ||||
|         if (cancellationToken.IsCancellationRequested) return; | ||||
|         if (Pause) | ||||
|             return; | ||||
|         if (cancellationToken.IsCancellationRequested) | ||||
|             return; | ||||
|  | ||||
|         var readErrorCount = 0; | ||||
|  | ||||
|         var readToken = await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|         if (readToken.IsCancellationRequested) | ||||
|         { | ||||
|             await ReadVariableSource(state, cancellationToken).ConfigureAwait(false); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         using var allTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, readToken); | ||||
|         var allToken = allTokenSource.Token; | ||||
|         await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|         //if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace) | ||||
|         //    LogMessage?.Trace(string.Format("{0} - Collecting [{1} - {2}]", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length)); | ||||
|         var readResult = await ReadSourceAsync(variableSourceRead, allToken).ConfigureAwait(false); | ||||
|         var readResult = await ReadSourceAsync(variableSourceRead, cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|         // 读取失败时重试一定次数 | ||||
|         while (!readResult.IsSuccess && readErrorCount < CollectProperties.RetryCount) | ||||
| @@ -372,12 +365,6 @@ public abstract class CollectBase : DriverBase, IRpcDriver | ||||
|             if (cancellationToken.IsCancellationRequested) | ||||
|                 return; | ||||
|  | ||||
|             if (readToken.IsCancellationRequested) | ||||
|             { | ||||
|                 await ReadVariableSource(state, cancellationToken).ConfigureAwait(false); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             readErrorCount++; | ||||
|             if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace) | ||||
|                 LogMessage?.Trace(string.Format("{0} - Collection [{1} - {2}] failed - {3}", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.ErrorMessage)); | ||||
| @@ -400,12 +387,6 @@ public abstract class CollectBase : DriverBase, IRpcDriver | ||||
|             if (cancellationToken.IsCancellationRequested) | ||||
|                 return; | ||||
|  | ||||
|             if (readToken.IsCancellationRequested) | ||||
|             { | ||||
|                 await ReadVariableSource(state, cancellationToken).ConfigureAwait(false); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // 读取失败时记录日志并增加失败计数器,更新错误信息并清除变量状态 | ||||
|             if (variableSourceRead.LastErrorMessage != readResult.ErrorMessage) | ||||
|             { | ||||
|   | ||||
| @@ -25,12 +25,7 @@ public class RpcLog : PrimaryIdEntity | ||||
|     [SugarColumn(ColumnDescription = "日志时间", IsNullable = false)] | ||||
|     [AutoGenerateColumn(Visible = true, DefaultSort = true, Sortable = true, DefaultSortOrder = SortOrder.Desc)] | ||||
|     public DateTime LogTime { get; set; } | ||||
|     /// <summary> | ||||
|     /// 执行时间 | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnDescription = "执行时间", IsNullable = true)] | ||||
|     [AutoGenerateColumn(Visible = true, DefaultSort = true, Sortable = true, DefaultSortOrder = SortOrder.Desc)] | ||||
|     public int ExecutionTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 操作源 | ||||
|     ///</summary> | ||||
|   | ||||
| @@ -404,7 +404,6 @@ | ||||
|     "OperateMethod": "RPCMethod", | ||||
|     "OperateObject": "OperationObject", | ||||
|     "OperateSource": "OperationSource", | ||||
|     "ExecutionTime": "ExecutionTime", | ||||
|     "ParamJson": "RequestParameters", | ||||
|     "ResultJson": "ReturnResults" | ||||
|   }, | ||||
|   | ||||
| @@ -405,7 +405,6 @@ | ||||
|     "OperateMethod": "RPC方法", | ||||
|     "OperateObject": "操作对象", | ||||
|     "OperateSource": "操作源", | ||||
|     "ExecutionTime": "执行时间", | ||||
|     "ParamJson": "请求参数", | ||||
|     "ResultJson": "返回结果" | ||||
|   }, | ||||
|   | ||||
| @@ -26,7 +26,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|     } | ||||
|     private WaitLock WaitLock { get; set; } = new WaitLock(); | ||||
|  | ||||
|     public async Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken) | ||||
|     public async Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -43,7 +43,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|  | ||||
| @@ -59,7 +59,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken) | ||||
|     public async Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -76,7 +76,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|  | ||||
| @@ -92,7 +92,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken) | ||||
|     public async Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -109,7 +109,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|  | ||||
| @@ -125,7 +125,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model) | ||||
|     public async Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model, bool restart = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -138,7 +138,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             RuntimeServiceHelper.Init(newChannelRuntimes); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|             } | ||||
| @@ -151,7 +151,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> DeleteChannelAsync(IEnumerable<long> ids, CancellationToken cancellationToken) | ||||
|     public async Task<bool> DeleteChannelAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -163,7 +163,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             var changedDriver = RuntimeServiceHelper.DeleteChannelRuntime(array); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await GlobalData.ChannelThreadManage.RemoveChannelAsync(array).ConfigureAwait(false); | ||||
|  | ||||
| @@ -186,7 +186,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|     public Task<MemoryStream> ExportMemoryStream(IEnumerable<Channel> data) => | ||||
|       GlobalData.ChannelService.ExportMemoryStream(data); | ||||
|  | ||||
|     public async Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input) | ||||
|     public async Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -199,8 +199,8 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             RuntimeServiceHelper.Init(newChannelRuntimes); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|             if (restart) | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|  | ||||
|         } | ||||
|  | ||||
| @@ -209,7 +209,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             WaitLock.Release(); | ||||
|         } | ||||
|     } | ||||
|     public async Task<bool> SaveChannelAsync(Channel input, ItemChangedType type) | ||||
|     public async Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -222,8 +222,8 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             RuntimeServiceHelper.Init(newChannelRuntimes); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|             if (restart) | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
| @@ -234,7 +234,7 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public async Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type) | ||||
|     public async Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type, bool restart) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -247,8 +247,8 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             RuntimeServiceHelper.Init(newChannelRuntimes); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|             if (restart) | ||||
|                 await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false); | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|   | ||||
| @@ -21,14 +21,16 @@ public interface IChannelRuntimeService | ||||
|     /// </summary> | ||||
|     /// <param name="input">通道对象</param> | ||||
|     /// <param name="type">保存类型</param> | ||||
|     Task<bool> SaveChannelAsync(Channel input, ItemChangedType type); | ||||
|     /// <param name="restart">重启</param> | ||||
|     Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 保存通道 | ||||
|     /// </summary> | ||||
|     /// <param name="input">通道对象</param> | ||||
|     /// <param name="type">保存类型</param> | ||||
|     Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type); | ||||
|     /// <param name="restart">重启</param> | ||||
|     Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type, bool restart); | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -37,23 +39,24 @@ public interface IChannelRuntimeService | ||||
|     /// <param name="models">列表</param> | ||||
|     /// <param name="oldModel">旧数据</param> | ||||
|     /// <param name="model">新数据</param> | ||||
|     /// <param name="restart">重启</param> | ||||
|     /// <returns></returns> | ||||
|     Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model); | ||||
|     Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model, bool restart); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 删除通道 | ||||
|     /// </summary> | ||||
|     Task<bool> DeleteChannelAsync(IEnumerable<long> ids, CancellationToken cancellationToken); | ||||
|     Task<bool> DeleteChannelAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 导入通道数据 | ||||
|     /// </summary> | ||||
|     Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input); | ||||
|     Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart); | ||||
|     Task<Dictionary<string, object>> ExportChannelAsync(ExportFilter exportFilter); | ||||
|     Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile); | ||||
|     Task<MemoryStream> ExportMemoryStream(IEnumerable<Channel> data); | ||||
|     Task RestartChannelAsync(IEnumerable<ChannelRuntime> oldChannelRuntimes); | ||||
|     Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken); | ||||
|     Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken); | ||||
|     Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken); | ||||
|     Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken); | ||||
|     Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken); | ||||
|     Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken); | ||||
| } | ||||
| @@ -30,7 +30,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|     private WaitLock WaitLock { get; set; } = new WaitLock(); | ||||
|  | ||||
|  | ||||
|     public async Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken) | ||||
|     public async Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -45,7 +45,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false); | ||||
|                 await RuntimeServiceHelper.ChangedDriverAsync(_logger, cancellationToken).ConfigureAwait(false); | ||||
| @@ -60,7 +60,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model) | ||||
|     public async Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model, bool restart = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -71,7 +71,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|             var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(deviceids).ConfigureAwait(false); | ||||
|  | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 var newDeciceIds = newDeviceRuntimes.Select(a => a.Id).ToHashSet(); | ||||
|  | ||||
| @@ -82,7 +82,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|  | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false); | ||||
|             } | ||||
| @@ -95,7 +95,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, CancellationToken cancellationToken) | ||||
|     public async Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -111,7 +111,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|             ConcurrentHashSet<IDriver> changedDriver = RuntimeServiceHelper.DeleteDeviceRuntime(deviceRuntimes); | ||||
|  | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 await RuntimeServiceHelper.RemoveDeviceAsync(deviceRuntimes).ConfigureAwait(false); | ||||
|  | ||||
| @@ -136,7 +136,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|           GlobalData.DeviceService.ExportMemoryStream(data, channelName, plugin); | ||||
|  | ||||
|  | ||||
|     public async Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input) | ||||
|     public async Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -146,7 +146,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|             var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(deviceids).ConfigureAwait(false); | ||||
|  | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|  | ||||
|                 var newDeciceIds = newDeviceRuntimes.Select(a => a.Id).ToHashSet(); | ||||
| @@ -158,7 +158,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|             RuntimeServiceHelper.Init(newDeviceRuntimes); | ||||
|  | ||||
|             //根据条件重启通道线程 | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|  | ||||
|                 await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false); | ||||
| @@ -174,7 +174,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public async Task<bool> SaveDeviceAsync(Device input, ItemChangedType type) | ||||
|     public async Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -190,7 +190,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|             RuntimeServiceHelper.Init(newDeviceRuntimes); | ||||
|  | ||||
|  | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 //根据条件重启通道线程 | ||||
|                 await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false); | ||||
| @@ -205,7 +205,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public async Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type) | ||||
|     public async Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type, bool restart) | ||||
|     { | ||||
|  | ||||
|         try | ||||
| @@ -219,7 +219,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService | ||||
|  | ||||
|             RuntimeServiceHelper.Init(newDeviceRuntimes); | ||||
|  | ||||
|             //if (restart) | ||||
|             if (restart) | ||||
|             { | ||||
|                 //根据条件重启通道线程 | ||||
|                 await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false); | ||||
|   | ||||
| @@ -16,14 +16,14 @@ namespace ThingsGateway.Gateway.Application | ||||
| { | ||||
|     public interface IDeviceRuntimeService | ||||
|     { | ||||
|         Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model); | ||||
|         Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken); | ||||
|         Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, CancellationToken cancellationToken); | ||||
|         Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model, bool restart); | ||||
|         Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken); | ||||
|         Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken); | ||||
|         Task<Dictionary<string, object>> ExportDeviceAsync(ExportFilter exportFilter); | ||||
|         Task<MemoryStream> ExportMemoryStream(List<Device> data, string channelName, string plugin); | ||||
|         Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input); | ||||
|         Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart); | ||||
|         Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile); | ||||
|         Task<bool> SaveDeviceAsync(Device input, ItemChangedType type); | ||||
|         Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type); | ||||
|         Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart); | ||||
|         Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type, bool restart); | ||||
|     } | ||||
| } | ||||
| @@ -428,22 +428,22 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage | ||||
|  | ||||
|  | ||||
|                 if (DriverTasks.TryRemove(deviceId, out var task)) | ||||
|                 { | ||||
|                     task.Stop(); | ||||
|                 } | ||||
|                { | ||||
|                    task.Stop(); | ||||
|                } | ||||
|  | ||||
|                 // 取消驱动程序的操作 | ||||
|                 if (CancellationTokenSources.TryRemove(deviceId, out var token)) | ||||
|                 { | ||||
|                     if (token != null) | ||||
|                     { | ||||
|                         token.Cancel(); | ||||
|                         token.Dispose(); | ||||
|                     } | ||||
|                 } | ||||
|                // 取消驱动程序的操作 | ||||
|                if (CancellationTokenSources.TryRemove(deviceId, out var token)) | ||||
|                { | ||||
|                    if (token != null) | ||||
|                    { | ||||
|                        token.Cancel(); | ||||
|                        token.Dispose(); | ||||
|                    } | ||||
|                } | ||||
|  | ||||
|  | ||||
|             }); | ||||
|            }); | ||||
|  | ||||
|  | ||||
|             await Task.Delay(100).ConfigureAwait(false); | ||||
|   | ||||
| @@ -146,8 +146,8 @@ internal sealed partial class ReverseCallbackServer : SingletonRpcServer | ||||
|         } | ||||
|  | ||||
|  | ||||
|         await GlobalData.ChannelRuntimeService.InsertAsync(addChannels, addDevices, addVariables, default).ConfigureAwait(false); | ||||
|         await GlobalData.ChannelRuntimeService.UpdateAsync(upChannels, upDevices, upVariables, default).ConfigureAwait(false); | ||||
|         await GlobalData.ChannelRuntimeService.InsertAsync(addChannels, addDevices, addVariables, true, default).ConfigureAwait(false); | ||||
|         await GlobalData.ChannelRuntimeService.UpdateAsync(upChannels, upDevices, upVariables, true, default).ConfigureAwait(false); | ||||
|  | ||||
|         RedundancyTask.LogMessage?.LogTrace($"Sync data success"); | ||||
|  | ||||
|   | ||||
| @@ -130,10 +130,9 @@ internal sealed class RpcService : IRpcService | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 var start = DateTime.Now; | ||||
|                 // 调用设备的写入方法 | ||||
|                 var result = await driverData.Key.InVokeWriteAsync(driverData.Value, cancellationToken).ConfigureAwait(false); | ||||
|                 var end = DateTime.Now; | ||||
|  | ||||
|                 // 写入日志 | ||||
|                 foreach (var resultItem in result) | ||||
|                 { | ||||
| @@ -150,8 +149,7 @@ internal sealed class RpcService : IRpcService | ||||
|                             _logQueues.Enqueue( | ||||
|                                 new RpcLog() | ||||
|                                 { | ||||
|                                     LogTime = start, | ||||
|                                     ExecutionTime = (int)(end - start).TotalMilliseconds, | ||||
|                                     LogTime = DateTime.Now, | ||||
|                                     OperateMessage = variableResult.Value.IsSuccess ? null : variableResult.Value.ToString(), | ||||
|                                     IsSuccess = variableResult.Value.IsSuccess, | ||||
|                                     OperateMethod = AppResource.WriteVariable, | ||||
| @@ -192,12 +190,10 @@ internal sealed class RpcService : IRpcService | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 var start = DateTime.Now; | ||||
|                 // 调用设备的写入方法 | ||||
|                 var result = await driverData.Key.InvokeMethodAsync(driverData.Value, cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|                 Dictionary<string, string> operateMethods = driverData.Value.Select(a => a.Key).ToDictionary(a => a.Name, a => a.OtherMethod!); | ||||
|                 var end = DateTime.Now; | ||||
|  | ||||
|                 // 写入日志 | ||||
|                 foreach (var resultItem in result) | ||||
| @@ -214,8 +210,7 @@ internal sealed class RpcService : IRpcService | ||||
|                             _logQueues.Enqueue( | ||||
|                                 new RpcLog() | ||||
|                                 { | ||||
|                                     LogTime = start, | ||||
|                                     ExecutionTime = (int)(end - start).TotalMilliseconds, | ||||
|                                     LogTime = DateTime.Now, | ||||
|                                     OperateMessage = variableResult.Value.IsSuccess ? null : variableResult.Value.ToString(), | ||||
|                                     IsSuccess = variableResult.Value.IsSuccess, | ||||
|                                     OperateMethod = operateMethods[variableResult.Key], | ||||
|   | ||||
| @@ -184,7 +184,7 @@ | ||||
|     "Reload": "重载" | ||||
|   }, | ||||
|   "ThingsGateway.Gateway.Razor.QuickActions": { | ||||
|     "AutoRestartThread": "变量修改立即生效", | ||||
|     "AutoRestartThread": "自动重启线程", | ||||
|     "HeaderText": "快捷操作", | ||||
|     "ReloadPluginConfirmText": "确定重载插件?", | ||||
|     "ReloadServiceConfirmText": "确定重启运行时?", | ||||
|   | ||||
| @@ -133,7 +133,7 @@ public partial class ChannelTable : IDisposable | ||||
|              {nameof(ChannelCopyComponent.OnSave), async (List<Channel> channels,Dictionary<Device,List<Variable>> devices) => | ||||
|             { | ||||
|  | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices, default)); | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices,AutoRestartThread, default)); | ||||
|                     await InvokeAsync(table.QueryAsync); | ||||
|  | ||||
|             }}, | ||||
| @@ -174,7 +174,7 @@ public partial class ChannelTable : IDisposable | ||||
|         { | ||||
|              {nameof(ChannelEditComponent.OnValidSubmit), async () => | ||||
|             { | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel)); | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel,AutoRestartThread)); | ||||
|  | ||||
|                    await InvokeAsync(table.QueryAsync); | ||||
|  | ||||
| @@ -197,7 +197,7 @@ public partial class ChannelTable : IDisposable | ||||
|         { | ||||
|             return await Task.Run(async () => | ||||
|             { | ||||
|                 return await GlobalData.ChannelRuntimeService.DeleteChannelAsync(channels.Select(a => a.Id), default); | ||||
|                 return await GlobalData.ChannelRuntimeService.DeleteChannelAsync(channels.Select(a => a.Id), AutoRestartThread, default); | ||||
|             }); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -215,7 +215,7 @@ public partial class ChannelTable : IDisposable | ||||
|         try | ||||
|         { | ||||
|             channel = channel.AdaptChannel(); | ||||
|             return await Task.Run(() => GlobalData.ChannelRuntimeService.SaveChannelAsync(channel, itemChangedType)); | ||||
|             return await Task.Run(() => GlobalData.ChannelRuntimeService.SaveChannelAsync(channel, itemChangedType, AutoRestartThread)); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
| @@ -304,7 +304,7 @@ public partial class ChannelTable : IDisposable | ||||
|                 await Task.Run(async ()=> | ||||
|                 { | ||||
|               var importData=await  ChannelServiceHelpers.ImportAsync(data); | ||||
|                 await    GlobalData.ChannelRuntimeService.ImportChannelAsync(importData); | ||||
|                 await    GlobalData.ChannelRuntimeService.ImportChannelAsync(importData,AutoRestartThread); | ||||
|                 }) | ||||
|                     ; | ||||
|     } | ||||
| @@ -346,7 +346,7 @@ finally | ||||
|         }; | ||||
|  | ||||
|         Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> preview = (a => GlobalData.ChannelRuntimeService.PreviewAsync(a)); | ||||
|         Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.ChannelRuntimeService.ImportChannelAsync(value)); | ||||
|         Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.ChannelRuntimeService.ImportChannelAsync(value, AutoRestartThread)); | ||||
|         op.Component = BootstrapDynamicComponent.CreateComponent<ImportExcel>(new Dictionary<string, object?> | ||||
|         { | ||||
|              {nameof(ImportExcel.Import),import }, | ||||
| @@ -367,7 +367,7 @@ finally | ||||
|             await Task.Run(async () => | ||||
|             { | ||||
|  | ||||
|                 await GlobalData.ChannelRuntimeService.DeleteChannelAsync(Items.Select(a => a.Id), default); | ||||
|                 await GlobalData.ChannelRuntimeService.DeleteChannelAsync(Items.Select(a => a.Id), AutoRestartThread, default); | ||||
|                 await InvokeAsync(async () => | ||||
|                 { | ||||
|                     await ToastService.Default(); | ||||
| @@ -386,7 +386,8 @@ finally | ||||
|     } | ||||
|     #endregion | ||||
|  | ||||
|  | ||||
|     [Parameter] | ||||
|     public bool AutoRestartThread { get; set; } | ||||
|     [Parameter] | ||||
|     public ChannelDeviceTreeItem SelectModel { get; set; } | ||||
|     [Inject] | ||||
|   | ||||
| @@ -83,7 +83,7 @@ namespace ThingsGateway.Gateway.Razor | ||||
|  | ||||
|  | ||||
|  | ||||
|         internal static async Task ShowCopy(Channel oneModel, Dictionary<Device, List<Variable>> deviceDict, string text, Func<Task> onsave, DialogService dialogService) | ||||
|         internal static async Task ShowCopy(Channel oneModel, Dictionary<Device, List<Variable>> deviceDict, string text, bool autoRestart, Func<Task> onsave, DialogService dialogService) | ||||
|         { | ||||
|             var op = new DialogOption() | ||||
|             { | ||||
| @@ -100,7 +100,7 @@ namespace ThingsGateway.Gateway.Razor | ||||
|              {nameof(ChannelCopyComponent.OnSave), async (List<Channel> channels,Dictionary<Device,List<Variable>> devices) => | ||||
|             { | ||||
|  | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices, default)); | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices,autoRestart, default)); | ||||
|                 if(onsave!=null) | ||||
|                     await onsave(); | ||||
|  | ||||
|   | ||||
| @@ -55,6 +55,9 @@ public partial class ChannelDeviceTree | ||||
|         await OnShowTypeChanged(showType); | ||||
|     } | ||||
|  | ||||
|     [Parameter] | ||||
|     public bool AutoRestartThread { get; set; } | ||||
|  | ||||
|     private static string GetClass(ChannelDeviceTreeItem item) | ||||
|     { | ||||
|         if (item.TryGetChannelRuntime(out var channelRuntime)) | ||||
| @@ -120,7 +123,7 @@ public partial class ChannelDeviceTree | ||||
|         { | ||||
|              {nameof(ChannelEditComponent.OnValidSubmit), async () => | ||||
|             { | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,itemChangedType)); | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,itemChangedType,AutoRestartThread)); | ||||
|                ////await Notify(); | ||||
|             }}, | ||||
|             {nameof(ChannelEditComponent.Model),oneModel }, | ||||
| @@ -172,7 +175,7 @@ public partial class ChannelDeviceTree | ||||
|              {nameof(ChannelCopyComponent.OnSave), async (List<Channel> channels,Dictionary<Device,List<Variable>> devices) => | ||||
|             { | ||||
|  | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices, default)); | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices,AutoRestartThread, default)); | ||||
|                     //await Notify(); | ||||
|  | ||||
|             }}, | ||||
| @@ -247,7 +250,7 @@ public partial class ChannelDeviceTree | ||||
|              {nameof(ChannelEditComponent.OnValidSubmit), async () => | ||||
|             { | ||||
|                 Spinner.SetRun(true); | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel)); | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel,AutoRestartThread)); | ||||
|  | ||||
|               //await Notify(); | ||||
|                 await InvokeAsync(() => | ||||
| @@ -298,7 +301,7 @@ public partial class ChannelDeviceTree | ||||
|                 await Task.Run(async ()=> | ||||
|                 { | ||||
|               var importData=await  ChannelServiceHelpers.ImportAsync(data); | ||||
|                 await    GlobalData.ChannelRuntimeService.ImportChannelAsync(importData); | ||||
|                 await    GlobalData.ChannelRuntimeService.ImportChannelAsync(importData,AutoRestartThread); | ||||
|                 }) | ||||
|                     ; | ||||
|     } | ||||
| @@ -424,7 +427,7 @@ finally | ||||
|  | ||||
|                 Spinner.SetRun(true); | ||||
|  | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(modelIds.Select(a => a.Id), default)); | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(modelIds.Select(a => a.Id), AutoRestartThread, default)); | ||||
|                 //await Notify(); | ||||
|                 await InvokeAsync(() => | ||||
|                 { | ||||
| @@ -468,7 +471,7 @@ finally | ||||
|                 Spinner.SetRun(true); | ||||
|  | ||||
|                 var key = await GlobalData.GetCurrentUserChannels().ConfigureAwait(false); | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(key.Select(a => a.Id), default)); | ||||
|                 await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(key.Select(a => a.Id), AutoRestartThread, default)); | ||||
|                 //await Notify(); | ||||
|                 await InvokeAsync(() => | ||||
|                 { | ||||
| @@ -601,7 +604,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|                 Spinner.SetRun(true); | ||||
|  | ||||
|             }); | ||||
|             await Task.Run(() => GlobalData.ChannelRuntimeService.ImportChannelAsync(value)); | ||||
|             await Task.Run(() => GlobalData.ChannelRuntimeService.ImportChannelAsync(value, AutoRestartThread)); | ||||
|             //await Notify(); | ||||
|             await InvokeAsync(() => | ||||
|             { | ||||
| @@ -656,7 +659,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|              {nameof(DeviceCopyComponent.OnSave), async (Dictionary<Device,List<Variable>> devices) => | ||||
|             { | ||||
|  | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices, default)); | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices,AutoRestartThread, default)); | ||||
|                //await Notify(); | ||||
|  | ||||
|             }}, | ||||
| @@ -709,10 +712,11 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|         { | ||||
|              {nameof(DeviceEditComponent.OnValidSubmit), async () => | ||||
|              { | ||||
|                  await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,itemChangedType)); | ||||
|                  await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,itemChangedType, AutoRestartThread)); | ||||
|                //await Notify(); | ||||
|             }}, | ||||
|             {nameof(DeviceEditComponent.Model),oneModel }, | ||||
|             {nameof(DeviceEditComponent.AutoRestartThread),AutoRestartThread }, | ||||
|             {nameof(DeviceEditComponent.ValidateEnable),true }, | ||||
|             {nameof(DeviceEditComponent.BatchEditEnable),false }, | ||||
|         }); | ||||
| @@ -794,7 +798,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|                 Spinner.SetRun(true); | ||||
|  | ||||
|                 }); | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels,oldModel,oneModel)); | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels,oldModel,oneModel,AutoRestartThread)); | ||||
|                 //await Notify(); | ||||
|                          await InvokeAsync(() => | ||||
|             { | ||||
| @@ -802,6 +806,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|                 }); | ||||
|             }}, | ||||
|             {nameof(DeviceEditComponent.Model),oneModel }, | ||||
|             {nameof(DeviceEditComponent.AutoRestartThread),AutoRestartThread }, | ||||
|             {nameof(DeviceEditComponent.ValidateEnable),true }, | ||||
|             {nameof(DeviceEditComponent.BatchEditEnable),true }, | ||||
|         }); | ||||
| @@ -837,7 +842,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|                 await Task.Run(async ()=> | ||||
|                 { | ||||
|               var importData=await  DeviceServiceHelpers.ImportAsync(data); | ||||
|                 await    GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData); | ||||
|                 await    GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData,AutoRestartThread); | ||||
|                 }) | ||||
|                     ; | ||||
|     } | ||||
| @@ -969,7 +974,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|  | ||||
|                 Spinner.SetRun(true); | ||||
|  | ||||
|                 await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(modelIds.Select(a => a.Id), default)); | ||||
|                 await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(modelIds.Select(a => a.Id), AutoRestartThread, default)); | ||||
|                 //await Notify(); | ||||
|                 await InvokeAsync(() => | ||||
|                 { | ||||
| @@ -1016,7 +1021,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|  | ||||
|                 var data = await GlobalData.GetCurrentUserDevices().ConfigureAwait(false); | ||||
|  | ||||
|                 await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(data.Select(a => a.Id), default)); | ||||
|                 await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(data.Select(a => a.Id), AutoRestartThread, default)); | ||||
|                 //await Notify(); | ||||
|                 await InvokeAsync(() => | ||||
|                 { | ||||
| @@ -1150,7 +1155,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|  | ||||
|             }); | ||||
|  | ||||
|             await Task.Run(() => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value)); | ||||
|             await Task.Run(() => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value, AutoRestartThread)); | ||||
|             //await Notify(); | ||||
|             await InvokeAsync(() => | ||||
|             { | ||||
|   | ||||
| @@ -28,6 +28,8 @@ public partial class DeviceEditComponent | ||||
|     [EditorRequired] | ||||
|     public Device Model { get; set; } | ||||
|  | ||||
|     [Parameter] | ||||
|     public bool AutoRestartThread { get; set; } | ||||
|  | ||||
|     [Parameter] | ||||
|     public Func<Task> OnValidSubmit { get; set; } | ||||
| @@ -86,7 +88,7 @@ public partial class DeviceEditComponent | ||||
|         { | ||||
|              {nameof(ChannelEditComponent.OnValidSubmit), async () => | ||||
|              { | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,ItemChangedType.Add)); | ||||
|                 await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,ItemChangedType.Add,AutoRestartThread)); | ||||
|                  OnParametersSet(); | ||||
|             }}, | ||||
|             {nameof(ChannelEditComponent.Model),oneModel }, | ||||
|   | ||||
| @@ -66,7 +66,7 @@ | ||||
|     </TableColumns> | ||||
|  | ||||
|     <EditTemplate Context="context"> | ||||
|         <DeviceEditComponent Model=@(context) ValidateEnable=false BatchEditEnable=false></DeviceEditComponent> | ||||
|         <DeviceEditComponent Model=@(context) ValidateEnable=false BatchEditEnable=false AutoRestartThread=AutoRestartThread></DeviceEditComponent> | ||||
|     </EditTemplate> | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -133,7 +133,7 @@ public partial class DeviceTable : IDisposable | ||||
|              {nameof(DeviceCopyComponent.OnSave), async (Dictionary<Device,List<Variable>> devices) => | ||||
|             { | ||||
|  | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices, default)); | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices,AutoRestartThread, default)); | ||||
|                     await InvokeAsync(table.QueryAsync); | ||||
|  | ||||
|             }}, | ||||
| @@ -173,7 +173,7 @@ public partial class DeviceTable : IDisposable | ||||
|         { | ||||
|              {nameof(DeviceEditComponent.OnValidSubmit), async () => | ||||
|             { | ||||
|                 await Task.Run(() => GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel)); | ||||
|                 await Task.Run(() => GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel,AutoRestartThread)); | ||||
|  | ||||
|                    await InvokeAsync(table.QueryAsync); | ||||
|  | ||||
| @@ -196,7 +196,7 @@ public partial class DeviceTable : IDisposable | ||||
|         { | ||||
|             return await Task.Run(async () => | ||||
|             { | ||||
|                 return await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(devices.Select(a => a.Id), default); | ||||
|                 return await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(devices.Select(a => a.Id), AutoRestartThread, default); | ||||
|             }); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -215,7 +215,7 @@ public partial class DeviceTable : IDisposable | ||||
|         { | ||||
|             device.DevicePropertys = PluginServiceUtil.SetDict(device.ModelValueValidateForm.Value); | ||||
|             device = device.AdaptDevice(); | ||||
|             return await Task.Run(() => GlobalData.DeviceRuntimeService.SaveDeviceAsync(device, itemChangedType)); | ||||
|             return await Task.Run(() => GlobalData.DeviceRuntimeService.SaveDeviceAsync(device, itemChangedType, AutoRestartThread)); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
| @@ -305,7 +305,7 @@ public partial class DeviceTable : IDisposable | ||||
|                 await Task.Run(async ()=> | ||||
|                 { | ||||
|               var importData=await  DeviceServiceHelpers.ImportAsync(data); | ||||
|                 await    GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData); | ||||
|                 await    GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData,AutoRestartThread); | ||||
|                 }) | ||||
|                     ; | ||||
|     } | ||||
| @@ -347,7 +347,7 @@ finally | ||||
|         }; | ||||
|  | ||||
|         Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> preview = (a => GlobalData.DeviceRuntimeService.PreviewAsync(a)); | ||||
|         Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value)); | ||||
|         Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value, AutoRestartThread)); | ||||
|         op.Component = BootstrapDynamicComponent.CreateComponent<ImportExcel>(new Dictionary<string, object?> | ||||
|         { | ||||
|              {nameof(ImportExcel.Import),import }, | ||||
| @@ -368,7 +368,7 @@ finally | ||||
|             await Task.Run(async () => | ||||
|             { | ||||
|  | ||||
|                 await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(Items.Select(a => a.Id), default); | ||||
|                 await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(Items.Select(a => a.Id), AutoRestartThread, default); | ||||
|                 await InvokeAsync(async () => | ||||
|                 { | ||||
|                     await ToastService.Default(); | ||||
| @@ -387,7 +387,8 @@ finally | ||||
|     } | ||||
|     #endregion | ||||
|  | ||||
|  | ||||
|     [Parameter] | ||||
|     public bool AutoRestartThread { get; set; } | ||||
|     [Parameter] | ||||
|     public ChannelDeviceTreeItem SelectModel { get; set; } | ||||
|     [Inject] | ||||
|   | ||||
| @@ -22,10 +22,10 @@ else if (ShowType == ShowTypeEnum.LogInfo) | ||||
| } | ||||
| else if (ShowType == ShowTypeEnum.ChannelTable) | ||||
| { | ||||
|     <ChannelTable SelectModel="SelectModel" Items="ChannelRuntimes"/> | ||||
|     <ChannelTable SelectModel="SelectModel" Items="ChannelRuntimes" AutoRestartThread=AutoRestartThread /> | ||||
| } | ||||
|  | ||||
| else if (ShowType == ShowTypeEnum.DeviceTable) | ||||
| { | ||||
|     <DeviceTable SelectModel="SelectModel" Items="DeviceRuntimes"/> | ||||
|     <DeviceTable SelectModel="SelectModel" Items="DeviceRuntimes" AutoRestartThread=AutoRestartThread /> | ||||
| } | ||||
| @@ -15,7 +15,7 @@ | ||||
|  | ||||
|             <Card IsShadow=true class="h-100 me-1" Color="Color.Primary"> | ||||
|                 <BodyTemplate> | ||||
|                     <ChannelDeviceTree @bind-ShowType=ShowType  | ||||
|                     <ChannelDeviceTree @bind-ShowType=ShowType AutoRestartThread="AutoRestartThread" | ||||
|                                        ChannelDeviceChanged="TreeChangedAsync" Value="SelectModel"></ChannelDeviceTree> | ||||
|                 </BodyTemplate> | ||||
|             </Card> | ||||
|   | ||||
| @@ -214,10 +214,11 @@ public partial class VariableEditComponent | ||||
|         { | ||||
|              {nameof(DeviceEditComponent.OnValidSubmit), async () => | ||||
|              { | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,ItemChangedType.Add)); | ||||
|                 await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,ItemChangedType.Add,AutoRestartThread)); | ||||
|                  OnParametersSet(); | ||||
|             }}, | ||||
|             {nameof(DeviceEditComponent.Model),oneModel }, | ||||
|             {nameof(DeviceEditComponent.AutoRestartThread),AutoRestartThread }, | ||||
|             {nameof(DeviceEditComponent.ValidateEnable),true }, | ||||
|             {nameof(DeviceEditComponent.BatchEditEnable),false }, | ||||
|         }); | ||||
|   | ||||
| @@ -148,16 +148,17 @@ public class OpcDaMaster : CollectBase | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ValueTask<OperResult<byte[]>> ReadSourceAsync(VariableSourceRead deviceVariableSourceRead, CancellationToken cancellationToken) | ||||
|     protected override async ValueTask<OperResult<byte[]>> ReadSourceAsync(VariableSourceRead deviceVariableSourceRead, CancellationToken cancellationToken) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false); | ||||
|             _plc.ReadItemsWithGroup(deviceVariableSourceRead.RegisterAddress); | ||||
|             return ValueTask.FromResult(OperResult.CreateSuccessResult(Array.Empty<byte>())); | ||||
|             return OperResult.CreateSuccessResult(Array.Empty<byte>()); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return ValueTask.FromResult(new OperResult<byte[]>($"ReadSourceAsync Error:{Environment.NewLine}{ex}")); | ||||
|             return new OperResult<byte[]>($"ReadSourceAsync Error:{Environment.NewLine}{ex}"); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|   | ||||
| @@ -234,8 +234,8 @@ public partial class OpcDaImportVariable | ||||
|                 await ToastService.Warning(OpcDaPropertyLocalizer["NoVariablesAvailable"], OpcDaPropertyLocalizer["NoVariablesAvailable"]); | ||||
|                 return; | ||||
|             } | ||||
|             await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add); | ||||
|             await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add); | ||||
|             await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add, true); | ||||
|             await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add, true); | ||||
|             await App.RootServices.GetRequiredService<IVariableRuntimeService>().BatchSaveVariableAsync(data.Item3, ItemChangedType.Add, true, default); | ||||
|             await ToastService.Default(); | ||||
|         } | ||||
|   | ||||
| @@ -247,6 +247,7 @@ public class OpcUaMaster : CollectBase | ||||
|         var addresss = deviceVariableSourceRead.VariableRuntimes.Where(a => !a.RegisterAddress.IsNullOrEmpty()).Select(a => a.RegisterAddress!).ToArray(); | ||||
|         try | ||||
|         { | ||||
|             await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|             var result = await _plc.ReadJTokenValueAsync(addresss, cancellationToken).ConfigureAwait(false); | ||||
|             foreach (var data in result) | ||||
|   | ||||
| @@ -263,8 +263,8 @@ public partial class OpcUaImportVariable | ||||
|                 await ToastService.Warning(OpcUaPropertyLocalizer["NoVariablesAvailable"], OpcUaPropertyLocalizer["NoVariablesAvailable"]); | ||||
|                 return; | ||||
|             } | ||||
|             await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add); | ||||
|             await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add); | ||||
|             await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add, true); | ||||
|             await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add, true); | ||||
|             await App.RootServices.GetRequiredService<IVariableRuntimeService>().BatchSaveVariableAsync(data.Item3.ToList(), ItemChangedType.Add, true, default); | ||||
|             await ToastService.Default(); | ||||
|         } | ||||
|   | ||||
| @@ -23,7 +23,7 @@ | ||||
|     <title>ThingsGateway</title> | ||||
|  | ||||
|     @{ | ||||
|     #if !NET8_0 | ||||
|         #if !NET8_0 | ||||
|     } | ||||
|  | ||||
|     <link rel="stylesheet" href=@(Assets[$"_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css"]) /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Diego
					Diego