fix: 尝试去修复后端无法停止扫描数码管的问题

This commit is contained in:
SikongJueluo 2025-08-16 14:21:26 +08:00
parent 9bd3fb29e3
commit c974de593a
No known key found for this signature in database
2 changed files with 94 additions and 76 deletions

View File

@ -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);
}
}

View File

@ -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>;
}