feat: 完成数码管websocket通信
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user