Files
BuYuHouDuan/ChessGameHost/Services/ChessTimeoutService.cs
T
2026-10-12 16:22:04 +08:00

139 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ChessGameService;
using ChessGameDomain;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ChessGameHost.Services
{
public class ChessTimeoutService : BackgroundService
{
private readonly ILogger<ChessTimeoutService> _logger;
private readonly IChessGameService _chessService;
private readonly IHubContext<ChessGameHub> _hubContext;
public ChessTimeoutService(
ILogger<ChessTimeoutService> logger,
IChessGameService chessService,
IHubContext<ChessGameHub> hubContext)
{
_logger = logger;
_chessService = chessService;
_hubContext = hubContext;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await CheckAllRoomsTimeout();
}
catch (Exception ex)
{
_logger.LogError(ex, "检查象棋断线/挂起超时时发生错误");
}
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
}
}
private async Task CheckAllRoomsTimeout()
{
var playingRooms = _chessService.GetAllPlayingRooms();
if (playingRooms == null || !playingRooms.Any())
return;
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
foreach (var room in playingRooms)
{
foreach (var user in room.users)
{
if (user.IsLeave && user.DisconnectTime > 0)
{
var timeout = room.TimeoutSeconds > 0 ? room.TimeoutSeconds : 60;
if ((now - user.DisconnectTime) > timeout)
{
var winUserId = room.users
.FirstOrDefault(u => u.userId != user.userId)?.userId ?? "";
var settledConnectionIds = room.users
.Where(u => !string.IsNullOrWhiteSpace(u.Cid))
.Select(u => u.Cid)
.Distinct()
.ToList();
var (success, message, endRoom) = await _chessService.EndGame(room.RoomId, winUserId);
if (!success || endRoom == null)
{
break;
}
await _hubContext.Clients.Group(room.RoomId).SendAsync("GameEnd", new
{
winUserId,
room = endRoom
});
await _hubContext.Clients.Group(ChessGameHub.LobbyGroup).SendAsync("ExitRoomNotice", endRoom);
await _hubContext.Clients.Clients(settledConnectionIds).SendAsync("ExitRoomNotice", endRoom);
foreach (var connectionId in settledConnectionIds)
{
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, room.RoomId);
await _hubContext.Groups.AddToGroupAsync(connectionId, ChessGameHub.LobbyGroup);
}
break;
}
}
}
var latestRoom = _chessService.GetRoom(room.RoomId);
if (latestRoom != null && latestRoom.state == 2)
await CheckRoomAfk(latestRoom);
}
}
private async Task CheckRoomAfk(ChessGameRoom room)
{
if (room.state != 2 || room.users == null || room.users.Count < 2)
return;
if (!room.users.Any(u => u.IsAfk))
return;
var settledConnectionIds = room.users
.Where(u => !string.IsNullOrWhiteSpace(u.Cid))
.Select(u => u.Cid)
.Distinct()
.ToList();
var (isTimeout, loserUserId) = await _chessService.CheckRoomAfkTimeout(room.RoomId);
if (!isTimeout || string.IsNullOrEmpty(loserUserId))
return;
var winUserId = room.users.FirstOrDefault(u => u.userId != loserUserId)?.userId ?? "";
var endRoom = _chessService.GetRoom(room.RoomId);
await _hubContext.Clients.Group(room.RoomId).SendAsync("GameEnd", new
{
winUserId,
room = endRoom
});
await _hubContext.Clients.Group(ChessGameHub.LobbyGroup).SendAsync("ExitRoomNotice", endRoom);
await _hubContext.Clients.Clients(settledConnectionIds).SendAsync("ExitRoomNotice", endRoom);
foreach (var connectionId in settledConnectionIds)
{
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, room.RoomId);
await _hubContext.Groups.AddToGroupAsync(connectionId, ChessGameHub.LobbyGroup);
}
}
}
}