RobotStatusPushService.cs
5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Rcs.Api.Hubs;
using Rcs.Application.DTOs;
using Rcs.Application.Services;
using Rcs.Domain.Repositories;
using Rcs.Shared.Utils;
namespace Rcs.Api.BackgroundServices
{
/// <summary>
/// 机器人状态推送后台服务 - 定时推送机器人实时状态到前端
/// @author zzy
/// </summary>
public class RobotStatusPushService : BackgroundService
{
private readonly ILogger<RobotStatusPushService> _logger;
private readonly IHubContext<RobotStatusHub> _hubContext;
private readonly IServiceScopeFactory _scopeFactory;
private readonly TimeSpan _pushInterval = TimeSpan.FromMilliseconds(200);
private readonly TimeSpan _locationPushInterval = TimeSpan.FromSeconds(2);
private DateTime _lastLocationPush = DateTime.MinValue;
public RobotStatusPushService(
ILogger<RobotStatusPushService> logger,
IHubContext<RobotStatusHub> hubContext,
IServiceScopeFactory scopeFactory)
{
_logger = logger;
_hubContext = hubContext;
_scopeFactory = scopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("[RobotStatusPush] 服务启动");
while (!stoppingToken.IsCancellationRequested)
{
try
{
await PushRobotStatusAsync(stoppingToken);
await PushStorageLocationsAsync(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "[RobotStatusPush] 推送异常");
}
await Task.Delay(_pushInterval, stoppingToken);
}
}
/// <summary>
/// 推送机器人状态到订阅的客户端(纯缓存读取,不查数据库)
/// @author zzy
/// </summary>
private async Task PushRobotStatusAsync(CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var cacheService = scope.ServiceProvider.GetRequiredService<IRobotCacheService>();
// 从缓存获取所有启用的机器人
var activeRobots = await cacheService.GetAllActiveRobotCacheAsync();
// 按地图分组
var robotsByMap = activeRobots
.Where(r => r.Location?.MapId.HasValue == true)
.GroupBy(r => r.Location!.MapId!.Value);
foreach (var mapGroup in robotsByMap)
{
var statusList = mapGroup.Select(r => new RobotRealtimeStatusDto
{
RobotId = r.Basic.RobotId,
RobotType = r.Basic.RobotType,
RobotCode = r.Basic.RobotCode,
RobotName = r.Basic.RobotName,
X = r.Location?.X,
Y = r.Location?.Y,
Theta = AngleConverter.ToDegrees(r.Location?.Theta),
Status = r.Status != null ? (int)r.Status.Status : 1,
Online = r.Status != null ? (int)r.Status.Online : 2,
BatteryLevel = r.Status?.BatteryLevel,
Driving = r.Status?.Driving ?? false,
Charging = r.Status?.Charging ?? false,
Errors = r.Status?.Errors,
Path = r.Location?.Path
}).ToList();
await _hubContext.Clients.Group($"map_{mapGroup.Key}")
.SendAsync("RobotStatusUpdate", statusList, cancellationToken);
}
}
/// <summary>
/// 推送库位状态到订阅的客户端(按地图分组,降频推送)
/// @author zzy
/// </summary>
private async Task PushStorageLocationsAsync(CancellationToken cancellationToken)
{
// 降频:每2秒推送一次库位状态
if (DateTime.Now - _lastLocationPush < _locationPushInterval)
return;
_lastLocationPush = DateTime.Now;
using var scope = _scopeFactory.CreateScope();
var locationRepo = scope.ServiceProvider.GetRequiredService<IStorageLocationRepository>();
var mapRepo = scope.ServiceProvider.GetRequiredService<IMapRepository>();
// 获取所有启用的地图
var maps = await mapRepo.GetAllAsync(cancellationToken);
foreach (var map in maps.Where(m => m.Active))
{
var locations = await locationRepo.GetByMapIdAsync(map.MapId, cancellationToken);
var locationList = locations.Select(l => new
{
locationId = l.LocationId.ToString(),
mapNodeId = l.MapNodeId?.ToString(),
locationCode = l.LocationCode,
locationName = l.LocationName,
status = (int)l.Status
}).ToList();
await _hubContext.Clients.Group($"map_{map.MapId}")
.SendAsync("StorageLocationsUpdate", locationList, cancellationToken);
}
}
}
}