feat: 完成数码管websocket通信

This commit is contained in:
2025-08-14 20:25:32 +08:00
parent 7bfc362b1f
commit 56eeb5dce3
12 changed files with 444 additions and 243 deletions

View File

@@ -4,22 +4,40 @@ using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Cors;
using TypedSignalR.Client;
using Tapper;
using server.Services;
using DotNext;
using Peripherals.SevenDigitalTubesClient;
using System.Collections.Concurrent;
namespace server.Hubs;
[Hub]
public interface IDigitalTubesHub
{
Task<bool> Join(string taskId);
Task<bool> StartScan();
Task<bool> StopScan();
Task<bool> SetFrequency(int frequency);
}
[Receiver]
public interface IDigitalTubesReceiver
{
Task OnReceive();
Task OnReceive(byte[] data);
}
class DigitalTubeInfo
{
public string ClientID { get; set; }
public SevenDigitalTubesCtrl TubeClient { get; set; }
public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
public int Frequency { get; set; } = 100;
public bool IsRunning { get; set; } = false;
public DigitalTubeInfo(string clientID, SevenDigitalTubesCtrl client)
{
ClientID = clientID;
TubeClient = client;
}
}
[Authorize]
[EnableCors("SignalR")]
@@ -28,14 +46,152 @@ 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;
public DigitalTubesHub(IHubContext<DigitalTubesHub, IDigitalTubesReceiver> hubContext)
private ConcurrentDictionary<string, DigitalTubeInfo> _infoDict = new();
public DigitalTubesHub(
IHubContext<DigitalTubesHub, IDigitalTubesReceiver> hubContext,
Database.UserManager userManager)
{
_hubContext = hubContext;
_userManager = userManager;
}
public async Task<bool> Join(string taskId)
private Optional<Database.Board> TryGetBoard()
{
return true;
var userName = Context.User?.FindFirstValue(ClaimTypes.Name);
if (string.IsNullOrEmpty(userName))
{
logger.Error("User name is null or empty");
return null;
}
var userRet = _userManager.GetUserByName(userName);
if (!userRet.IsSuccessful || !userRet.Value.HasValue)
{
logger.Error($"User '{userName}' not found");
return null;
}
var user = userRet.Value.Value;
var boardRet = _userManager.GetBoardByID(user.BoardID);
if (!boardRet.IsSuccessful || !boardRet.Value.HasValue)
{
logger.Error($"Board not found");
return null;
}
return boardRet.Value.Value;
}
private Task ScanAllTubes(DigitalTubeInfo info)
{
return Task.Run(async () =>
{
var cntError = 0;
while (info.IsRunning && !info.CTS.IsCancellationRequested)
{
var beginTime = DateTime.Now;
var waitTime = TimeSpan.FromMilliseconds(1000 / info.Frequency);
var dataRet = await info.TubeClient.ScanAllTubes();
if (!dataRet.IsSuccessful)
{
logger.Error($"Failed to scan tubes: {dataRet.Error}");
cntError++;
if (cntError > 3)
{
logger.Error($"Too many errors, stopping scan");
info.IsRunning = false;
}
}
await _hubContext.Clients.Client(info.ClientID).OnReceive(dataRet.Value);
var processTime = DateTime.Now - beginTime;
if (processTime < waitTime)
{
await Task.Delay(waitTime - processTime);
}
}
}, info.CTS.Token);
}
public 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;
_ = ScanAllTubes(info);
}
}
return Task.FromResult(true);
}
catch (Exception ex)
{
logger.Error(ex, "Failed to start scan");
return Task.FromResult(false);
}
}
public 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)
{
if (info.IsRunning) info.IsRunning = false;
}
return Task.FromResult(true);
}
catch (Exception ex)
{
logger.Error(ex, "Failed to stop scan");
return Task.FromResult(false);
}
}
public Task<bool> SetFrequency(int frequency)
{
try
{
if (frequency < 1 || frequency > 1000)
throw new ArgumentException("Frequency must be between 1 and 1000");
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;
}
return Task.FromResult(true);
}
catch (Exception ex)
{
logger.Error(ex, "Failed to set frequency");
return Task.FromResult(false);
}
}
}