using System.Net.WebSockets; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using YD_YiLu.Api.WebSockets; using YD_YiLu.Commons.Dto.Running; namespace YD_YiLu.Api.Controllers { /// /// 阳光跑接口。 /// [AllowAnonymous] public class RunningController : ControllerBase { private readonly ICameraDeviceSocketRegistry _registry; private readonly ILogger _logger; public RunningController(ICameraDeviceSocketRegistry registry, ILogger logger) { _registry = registry; _logger = logger; } /// /// 跑道人员变更状态。 /// [HttpPost] [Route("/running/result/stage")] public object ResultStage([FromBody] RunningStageRequestDto dto) { _logger.LogInformation( "Running stage changed. DeviceSerial: {DeviceSerial}, UserCount: {UserCount}", dto?.DeviceSerial, dto?.RunUserList?.Count ?? 0); return new { }; } /// /// 平台指定用户下发人脸通知(旧)。 /// [HttpPost] [Route("/station:user:push")] public async Task StationUserPush([FromBody] JObject body, [FromQuery] string deviceSerial = "") { return await SendSocketMessageAsync("station:user:push", body, deviceSerial); } /// /// 平台下发人脸通知。 /// [HttpPost] [Route("/station:remind")] public async Task StationRemind([FromBody] JObject body, [FromQuery] string deviceSerial = "") { return await SendSocketMessageAsync("station:remind", body, deviceSerial); } /// /// 跑步小组重启。 /// [HttpPost] [Route("/running:group:restart")] public async Task RunningGroupRestart([FromBody] JObject body, [FromQuery] string deviceSerial = "") { return await SendSocketMessageAsync("running:group:restart", body, deviceSerial); } /// /// 跑步小组推送。 /// [HttpPost] [Route("/running:group:push")] public async Task RunningGroupPush([FromBody] JObject body, [FromQuery] string deviceSerial = "") { return await SendSocketMessageAsync("running:group:push", body, deviceSerial); } /// /// 跑步小组自动分组。 /// [HttpPost] [Route("/running:group:auto")] public async Task RunningGroupAuto([FromBody] JObject body, [FromQuery] string deviceSerial = "") { return await SendSocketMessageAsync("running:group:auto", body, deviceSerial); } /// /// 设备指令。 /// [HttpPost] [Route("/device:instruct")] public async Task DeviceInstruct([FromBody] JObject body, [FromQuery] string deviceSerial = "") { return await SendSocketMessageAsync("device:instruct", body, deviceSerial); } private async Task SendSocketMessageAsync(string request, JObject body, string deviceSerial) { body ??= new JObject(); var serial = FirstNotEmpty(deviceSerial, FindString(body, "serialNumber"), FindString(body, "deviceSerial")); if (string.IsNullOrWhiteSpace(serial)) { return new { success = false, message = "deviceSerial不能为空" }; } if (!_registry.TryGet(serial, out var socket) || socket.State != WebSocketState.Open) { return new { success = false, serialNumber = serial, message = "设备不在线" }; } var message = NormalizeSocketMessage(request, body); await CameraDeviceWebSocketHandler.SendAsync( socket, message.ToString(Formatting.None), HttpContext.RequestAborted); _logger.LogInformation("Running socket message sent. Request: {Request}, SerialNumber: {SerialNumber}", request, serial); return new { success = true, serialNumber = serial }; } private static JObject NormalizeSocketMessage(string request, JObject body) { var message = (JObject)body.DeepClone(); if (string.IsNullOrWhiteSpace(message["msgId"]?.ToString())) message["msgId"] = Guid.NewGuid().ToString("N"); message["request"] = request; message["code"] ??= 0; message["msg"] ??= ""; message["data"] ??= new JObject(); return message; } private static string FirstNotEmpty(params string[] values) { return values.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x)) ?? ""; } private static string FindString(JToken token, string name) { if (token == null) return ""; if (token.Type == JTokenType.Object) { var obj = (JObject)token; foreach (var property in obj.Properties()) { if (string.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase)) { var value = property.Value?.ToString(); if (!string.IsNullOrWhiteSpace(value)) return value; } } } foreach (var child in token.Children()) { var value = FindString(child, name); if (!string.IsNullOrWhiteSpace(value)) return value; } return ""; } } }