fix: 尝试去修复后端无法停止扫描数码管的问题
This commit is contained in:
parent
9bd3fb29e3
commit
c974de593a
|
@ -8,6 +8,8 @@ using DotNext;
|
||||||
using Peripherals.SevenDigitalTubesClient;
|
using Peripherals.SevenDigitalTubesClient;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
#pragma warning disable 1998
|
||||||
|
|
||||||
namespace server.Hubs;
|
namespace server.Hubs;
|
||||||
|
|
||||||
[Hub]
|
[Hub]
|
||||||
|
@ -16,7 +18,7 @@ public interface IDigitalTubesHub
|
||||||
Task<bool> StartScan();
|
Task<bool> StartScan();
|
||||||
Task<bool> StopScan();
|
Task<bool> StopScan();
|
||||||
Task<bool> SetFrequency(int frequency);
|
Task<bool> SetFrequency(int frequency);
|
||||||
Task<DigitalTubeTaskStatus> GetStatus();
|
Task<DigitalTubeTaskStatus?> GetStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Receiver]
|
[Receiver]
|
||||||
|
@ -31,23 +33,27 @@ public class DigitalTubeTaskStatus
|
||||||
public int Frequency { get; set; } = 100;
|
public int Frequency { get; set; } = 100;
|
||||||
public bool IsRunning { get; set; } = false;
|
public bool IsRunning { get; set; } = false;
|
||||||
|
|
||||||
public DigitalTubeTaskStatus(DigitalTubeInfo info)
|
public DigitalTubeTaskStatus(ScanTaskInfo info)
|
||||||
{
|
{
|
||||||
Frequency = info.Frequency;
|
Frequency = info.Frequency;
|
||||||
IsRunning = info.IsRunning;
|
IsRunning = info.IsRunning;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DigitalTubeInfo
|
public class ScanTaskInfo
|
||||||
{
|
{
|
||||||
|
public string BoardID { get; set; }
|
||||||
public string ClientID { get; set; }
|
public string ClientID { get; set; }
|
||||||
|
public Task? ScanTask { get; set; }
|
||||||
public SevenDigitalTubesCtrl TubeClient { get; set; }
|
public SevenDigitalTubesCtrl TubeClient { get; set; }
|
||||||
public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
|
public CancellationTokenSource CTS { get; set; } = new();
|
||||||
public int Frequency { get; set; } = 100;
|
public int Frequency { get; set; } = 100;
|
||||||
public bool IsRunning { get; set; } = false;
|
public bool IsRunning { get; set; } = false;
|
||||||
|
|
||||||
public DigitalTubeInfo(string clientID, SevenDigitalTubesCtrl client)
|
public ScanTaskInfo(
|
||||||
|
string boardID, string clientID, SevenDigitalTubesCtrl client)
|
||||||
{
|
{
|
||||||
|
BoardID = boardID;
|
||||||
ClientID = clientID;
|
ClientID = clientID;
|
||||||
TubeClient = client;
|
TubeClient = client;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +64,10 @@ public class DigitalTubeInfo
|
||||||
public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
||||||
{
|
{
|
||||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private readonly IHubContext<DigitalTubesHub, IDigitalTubesReceiver> _hubContext;
|
private readonly IHubContext<DigitalTubesHub, IDigitalTubesReceiver> _hubContext;
|
||||||
private readonly Database.UserManager _userManager = new();
|
private readonly Database.UserManager _userManager = new();
|
||||||
|
|
||||||
private ConcurrentDictionary<string, DigitalTubeInfo> _infoDict = new();
|
private ConcurrentDictionary<(string, string), ScanTaskInfo> _scanTasks = new();
|
||||||
|
|
||||||
public DigitalTubesHub(IHubContext<DigitalTubesHub, IDigitalTubesReceiver> hubContext)
|
public DigitalTubesHub(IHubContext<DigitalTubesHub, IDigitalTubesReceiver> hubContext)
|
||||||
{
|
{
|
||||||
|
@ -95,17 +100,18 @@ public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
||||||
return boardRet.Value.Value;
|
return boardRet.Value.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task ScanAllTubes(DigitalTubeInfo info)
|
private Task ScanAllTubes(ScanTaskInfo scanInfo)
|
||||||
{
|
{
|
||||||
|
var token = scanInfo.CTS.Token;
|
||||||
return Task.Run(async () =>
|
return Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var cntError = 0;
|
var cntError = 0;
|
||||||
while (!info.CTS.IsCancellationRequested)
|
while (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var beginTime = DateTime.Now;
|
var beginTime = DateTime.Now;
|
||||||
var waitTime = TimeSpan.FromMilliseconds(1000 / info.Frequency);
|
var waitTime = TimeSpan.FromMilliseconds(1000 / scanInfo.Frequency);
|
||||||
|
|
||||||
var dataRet = await info.TubeClient.ScanAllTubes();
|
var dataRet = await scanInfo.TubeClient.ScanAllTubes();
|
||||||
if (!dataRet.IsSuccessful)
|
if (!dataRet.IsSuccessful)
|
||||||
{
|
{
|
||||||
logger.Error($"Failed to scan tubes: {dataRet.Error}");
|
logger.Error($"Failed to scan tubes: {dataRet.Error}");
|
||||||
|
@ -113,126 +119,138 @@ public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
||||||
if (cntError > 3)
|
if (cntError > 3)
|
||||||
{
|
{
|
||||||
logger.Error($"Too many errors, stopping scan");
|
logger.Error($"Too many errors, stopping scan");
|
||||||
info.IsRunning = false;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await _hubContext.Clients.Client(info.ClientID).OnReceive(dataRet.Value);
|
await _hubContext.Clients.Client(scanInfo.ClientID).OnReceive(dataRet.Value);
|
||||||
|
|
||||||
var processTime = DateTime.Now - beginTime;
|
var processTime = DateTime.Now - beginTime;
|
||||||
if (processTime < waitTime)
|
if (processTime < waitTime)
|
||||||
{
|
{
|
||||||
await Task.Delay(waitTime - processTime);
|
await Task.Delay(waitTime - processTime, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, info.CTS.Token);
|
scanInfo.IsRunning = false;
|
||||||
|
}, token)
|
||||||
|
.ContinueWith((task) =>
|
||||||
|
{
|
||||||
|
if (task.IsFaulted)
|
||||||
|
{
|
||||||
|
logger.Error(
|
||||||
|
$"Digital tubes scan operation failesj for board {task.Exception}");
|
||||||
|
}
|
||||||
|
else if (task.IsCanceled)
|
||||||
|
{
|
||||||
|
logger.Info(
|
||||||
|
$"Digital tubes scan operation cancelled for board {scanInfo.BoardID}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Info(
|
||||||
|
$"Digital tubes scan completed successfully for board {scanInfo.BoardID}");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> StartScan()
|
public async Task<bool> StartScan()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||||
if (_infoDict.GetOrAdd(
|
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||||
board.ID.ToString(),
|
|
||||||
(_) => new DigitalTubeInfo(
|
|
||||||
Context.ConnectionId,
|
|
||||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
|
||||||
) is DigitalTubeInfo info)
|
|
||||||
{
|
|
||||||
if (!info.IsRunning)
|
|
||||||
{
|
|
||||||
info.IsRunning = true;
|
|
||||||
if (info.CTS.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
info.CTS.Dispose();
|
|
||||||
info.CTS = new CancellationTokenSource();
|
|
||||||
}
|
|
||||||
_ = ScanAllTubes(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromResult(true);
|
if (_scanTasks.TryGetValue(key, out var existing) && existing.IsRunning)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
var scanTaskInfo = new ScanTaskInfo(
|
||||||
|
board.ID.ToString(), Context.ConnectionId,
|
||||||
|
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 0)
|
||||||
|
);
|
||||||
|
scanTaskInfo.ScanTask = ScanAllTubes(scanTaskInfo);
|
||||||
|
|
||||||
|
_scanTasks[key] = scanTaskInfo;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error(ex, "Failed to start scan");
|
logger.Error(ex, "Failed to start scan");
|
||||||
return Task.FromResult(false);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> StopScan()
|
public async Task<bool> StopScan()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||||
if (_infoDict.GetOrAdd(
|
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||||
board.ID.ToString(),
|
|
||||||
(_) => new DigitalTubeInfo(
|
|
||||||
Context.ConnectionId,
|
|
||||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
|
||||||
) is DigitalTubeInfo info)
|
|
||||||
{
|
|
||||||
info.IsRunning = false;
|
|
||||||
info.CTS.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromResult(true);
|
if (_scanTasks.TryRemove(key, out var scanInfo))
|
||||||
|
{
|
||||||
|
scanInfo.IsRunning = false;
|
||||||
|
scanInfo.CTS.Cancel();
|
||||||
|
if (scanInfo.ScanTask != null)
|
||||||
|
await scanInfo.ScanTask;
|
||||||
|
scanInfo.CTS.Dispose();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error(ex, "Failed to stop scan");
|
logger.Error(ex, "Failed to stop scan");
|
||||||
return Task.FromResult(false);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> SetFrequency(int frequency)
|
public async Task<bool> SetFrequency(int frequency)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (frequency < 1 || frequency > 1000) return Task.FromException<bool>(
|
if (frequency < 1 || frequency > 1000)
|
||||||
new ArgumentException("Frequency must be between 1 and 1000"));
|
return false;
|
||||||
|
|
||||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||||
if (_infoDict.GetOrAdd(
|
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||||
board.ID.ToString(),
|
|
||||||
(_) => new DigitalTubeInfo(
|
|
||||||
Context.ConnectionId,
|
|
||||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
|
||||||
) is DigitalTubeInfo info)
|
|
||||||
{
|
|
||||||
info.Frequency = frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromResult(true);
|
if (_scanTasks.TryGetValue(key, out var scanInfo) && scanInfo.IsRunning)
|
||||||
|
{
|
||||||
|
scanInfo.Frequency = frequency;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"SetFrequency called but no running scan for board {board.ID} and client {Context.ConnectionId}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error(ex, "Failed to set frequency");
|
logger.Error(ex, "Failed to set frequency");
|
||||||
return Task.FromResult(false);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<DigitalTubeTaskStatus> GetStatus()
|
public async Task<DigitalTubeTaskStatus?> GetStatus()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||||
if (_infoDict.GetOrAdd(
|
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||||
board.ID.ToString(),
|
|
||||||
(_) => new DigitalTubeInfo(
|
|
||||||
Context.ConnectionId,
|
|
||||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
|
||||||
) is DigitalTubeInfo info)
|
|
||||||
{
|
|
||||||
return Task.FromResult(new DigitalTubeTaskStatus(info));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromException<DigitalTubeTaskStatus>(new ArgumentException("Wrong argument"));
|
if (_scanTasks.TryGetValue(key, out var scanInfo))
|
||||||
|
{
|
||||||
|
return new DigitalTubeTaskStatus(scanInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error(ex, "Failed to get status");
|
logger.Error(ex, "Failed to get status");
|
||||||
return Task.FromException<DigitalTubeTaskStatus>(new Exception("Failed to get status"));
|
throw new Exception("Failed to get status", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ export type IDigitalTubesHub = {
|
||||||
*/
|
*/
|
||||||
setFrequency(frequency: number): Promise<boolean>;
|
setFrequency(frequency: number): Promise<boolean>;
|
||||||
/**
|
/**
|
||||||
* @returns Transpiled from System.Threading.Tasks.Task<server.Hubs.DigitalTubeTaskStatus>
|
* @returns Transpiled from System.Threading.Tasks.Task<server.Hubs.DigitalTubeTaskStatus?>
|
||||||
*/
|
*/
|
||||||
getStatus(): Promise<DigitalTubeTaskStatus>;
|
getStatus(): Promise<DigitalTubeTaskStatus>;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue