fix: 尝试去修复后端无法停止扫描数码管的问题
This commit is contained in:
parent
9bd3fb29e3
commit
c974de593a
|
@ -8,6 +8,8 @@ using DotNext;
|
|||
using Peripherals.SevenDigitalTubesClient;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
#pragma warning disable 1998
|
||||
|
||||
namespace server.Hubs;
|
||||
|
||||
[Hub]
|
||||
|
@ -16,7 +18,7 @@ public interface IDigitalTubesHub
|
|||
Task<bool> StartScan();
|
||||
Task<bool> StopScan();
|
||||
Task<bool> SetFrequency(int frequency);
|
||||
Task<DigitalTubeTaskStatus> GetStatus();
|
||||
Task<DigitalTubeTaskStatus?> GetStatus();
|
||||
}
|
||||
|
||||
[Receiver]
|
||||
|
@ -31,23 +33,27 @@ public class DigitalTubeTaskStatus
|
|||
public int Frequency { get; set; } = 100;
|
||||
public bool IsRunning { get; set; } = false;
|
||||
|
||||
public DigitalTubeTaskStatus(DigitalTubeInfo info)
|
||||
public DigitalTubeTaskStatus(ScanTaskInfo info)
|
||||
{
|
||||
Frequency = info.Frequency;
|
||||
IsRunning = info.IsRunning;
|
||||
}
|
||||
}
|
||||
|
||||
public class DigitalTubeInfo
|
||||
public class ScanTaskInfo
|
||||
{
|
||||
public string BoardID { get; set; }
|
||||
public string ClientID { get; set; }
|
||||
public Task? ScanTask { 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 bool IsRunning { get; set; } = false;
|
||||
|
||||
public DigitalTubeInfo(string clientID, SevenDigitalTubesCtrl client)
|
||||
public ScanTaskInfo(
|
||||
string boardID, string clientID, SevenDigitalTubesCtrl client)
|
||||
{
|
||||
BoardID = boardID;
|
||||
ClientID = clientID;
|
||||
TubeClient = client;
|
||||
}
|
||||
|
@ -58,11 +64,10 @@ public class DigitalTubeInfo
|
|||
public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly IHubContext<DigitalTubesHub, IDigitalTubesReceiver> _hubContext;
|
||||
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)
|
||||
{
|
||||
|
@ -95,17 +100,18 @@ public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
|||
return boardRet.Value.Value;
|
||||
}
|
||||
|
||||
private Task ScanAllTubes(DigitalTubeInfo info)
|
||||
private Task ScanAllTubes(ScanTaskInfo scanInfo)
|
||||
{
|
||||
var token = scanInfo.CTS.Token;
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var cntError = 0;
|
||||
while (!info.CTS.IsCancellationRequested)
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
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)
|
||||
{
|
||||
logger.Error($"Failed to scan tubes: {dataRet.Error}");
|
||||
|
@ -113,126 +119,138 @@ public class DigitalTubesHub : Hub<IDigitalTubesReceiver>, IDigitalTubesHub
|
|||
if (cntError > 3)
|
||||
{
|
||||
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;
|
||||
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
|
||||
{
|
||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||
if (_infoDict.GetOrAdd(
|
||||
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);
|
||||
}
|
||||
}
|
||||
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||
|
||||
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)
|
||||
{
|
||||
logger.Error(ex, "Failed to start scan");
|
||||
return Task.FromResult(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> StopScan()
|
||||
public async Task<bool> StopScan()
|
||||
{
|
||||
try
|
||||
{
|
||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||
if (_infoDict.GetOrAdd(
|
||||
board.ID.ToString(),
|
||||
(_) => new DigitalTubeInfo(
|
||||
Context.ConnectionId,
|
||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
||||
) is DigitalTubeInfo info)
|
||||
{
|
||||
info.IsRunning = false;
|
||||
info.CTS.Cancel();
|
||||
}
|
||||
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (frequency < 1 || frequency > 1000) return Task.FromException<bool>(
|
||||
new ArgumentException("Frequency must be between 1 and 1000"));
|
||||
if (frequency < 1 || frequency > 1000)
|
||||
return false;
|
||||
|
||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||
if (_infoDict.GetOrAdd(
|
||||
board.ID.ToString(),
|
||||
(_) => new DigitalTubeInfo(
|
||||
Context.ConnectionId,
|
||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
||||
) is DigitalTubeInfo info)
|
||||
{
|
||||
info.Frequency = frequency;
|
||||
}
|
||||
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||
|
||||
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)
|
||||
{
|
||||
logger.Error(ex, "Failed to set frequency");
|
||||
return Task.FromResult(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<DigitalTubeTaskStatus> GetStatus()
|
||||
public async Task<DigitalTubeTaskStatus?> GetStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
var board = TryGetBoard().OrThrow(() => new Exception("Board not found"));
|
||||
if (_infoDict.GetOrAdd(
|
||||
board.ID.ToString(),
|
||||
(_) => new DigitalTubeInfo(
|
||||
Context.ConnectionId,
|
||||
new SevenDigitalTubesCtrl(board.IpAddr, board.Port, 2))
|
||||
) is DigitalTubeInfo info)
|
||||
{
|
||||
return Task.FromResult(new DigitalTubeTaskStatus(info));
|
||||
}
|
||||
var key = (board.ID.ToString(), Context.ConnectionId);
|
||||
|
||||
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)
|
||||
{
|
||||
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>;
|
||||
/**
|
||||
* @returns Transpiled from System.Threading.Tasks.Task<server.Hubs.DigitalTubeTaskStatus>
|
||||
* @returns Transpiled from System.Threading.Tasks.Task<server.Hubs.DigitalTubeTaskStatus?>
|
||||
*/
|
||||
getStatus(): Promise<DigitalTubeTaskStatus>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue