using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace LANCommander.Server.Services;
///
/// Periodically ends play sessions that have stopped sending keepalives (e.g. the launcher crashed
/// or lost its connection), so the active-session list stays accurate for autostop and player
/// counts. Stale sessions are ended at their last known-alive time. Each affected game is handed to
/// so on-player-activity servers still autostop.
///
public sealed class PlaySessionSweepService(
IServiceScopeFactory scopeFactory,
ServerManager serverManager,
SettingsProvider settingsProvider,
ILogger logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
var gameServers = settingsProvider.CurrentValue.Server.GameServers;
var interval = TimeSpan.FromSeconds(Math.Max(5, gameServers.KeepAliveSweepInterval));
var timeout = TimeSpan.FromSeconds(Math.Max(1, gameServers.KeepAliveTimeout));
await Task.Delay(interval, stoppingToken);
using var scope = scopeFactory.CreateScope();
var playSessionService = scope.ServiceProvider.GetRequiredService();
var affectedGameIds = await playSessionService.EndStaleSessionsAsync(timeout);
foreach (var gameId in affectedGameIds)
serverManager.ScheduleStop(gameId);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
logger.LogError(ex, "Play session sweep failed");
}
}
}
}