Files
squad-rain-ops-mini/Helpers/RCON/RconPollingService.cs

169 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using RainOpsMini;
using RainOpsMini.Models;
using RainOpsMini.Helpers.SquadGameLog;
using RainOpsMini; // Ensure Program is visible
namespace RainOpsMini.Helpers.RCON
{
public class RconPollingService : BackgroundService
{
private readonly RconDataCache _cache;
public RconPollingService(RconDataCache cache)
{
_cache = cache;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
RainOpsMini.Helpers.RainOpsLog.Log("RCON Polling Service started.");
while (!stoppingToken.IsCancellationRequested)
{
int delaySeconds = _cache.RefreshIntervalSeconds;
try
{
if (Program.Client != null && Program.Client.IsConnected)
{
await UpdateRconDataAsync();
}
}
catch (Exception ex)
{
RainOpsMini.Helpers.RainOpsLog.Log($"[RconPollingService] Error: {ex.Message}");
}
await Task.Delay(TimeSpan.FromSeconds(delaySeconds), stoppingToken);
}
}
private async Task UpdateRconDataAsync()
{
var client = Program.Client;
if (client == null) return;
try
{
// 1. Fetch Server Info
string serverInfoRaw = await client.SendCommandAsync("ShowServerInfo");
var serverInfo = RconParser.ParseServerInfo(serverInfoRaw);
// 2. Fetch Squads
string squadsRaw = await client.SendCommandAsync("ListSquads");
var squads = RconParser.ParseSquads(squadsRaw);
// 3. Fetch Players (with retry logic similar to original API)
List<PlayerInfo> players = new List<PlayerInfo>();
int retryCount = 0;
const int maxRetries = 3;
int expectedPlayerCount = 0;
if (serverInfo != null && int.TryParse(serverInfo.PlayerCount_I, out int pc))
{
expectedPlayerCount = pc;
}
while (retryCount < maxRetries)
{
string playersRaw = await client.SendCommandAsync("ListPlayers");
var currentPlayers = RconParser.ParsePlayers(playersRaw);
if (currentPlayers.Count > players.Count)
{
players = currentPlayers;
}
if (expectedPlayerCount > 0)
{
if (players.Count >= expectedPlayerCount * 0.8)
{
break;
}
}
else
{
if (players.Count > 0) break;
}
if (retryCount < maxRetries - 1)
{
await Task.Delay(500);
}
retryCount++;
}
// 4. Enrich Data
foreach (var squad in squads)
{
if (!string.IsNullOrEmpty(squad.CreatorSteamId))
{
var creationTime = LogStorage.Instance.GetLastSquadCreationTime(squad.CreatorSteamId);
if (creationTime.HasValue)
{
squad.LastCreatedTime = creationTime.Value.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}
DateTime matchStartTime = DateTime.MinValue;
if (serverInfo != null && serverInfo.PlayTime_I > 0)
{
matchStartTime = DateTime.Now.AddSeconds(-serverInfo.PlayTime_I - 60);
}
foreach (var player in players)
{
LogStorage.Instance.RegisterPlayer(player.Name, player.SteamId);
var stats = LogStorage.Instance.GetPlayerStats(player.SteamId, matchStartTime);
player.Kills = stats.Kills;
player.Deaths = stats.Deaths;
}
// 5. Update Cache
_cache.UpdateData(serverInfo, squads, players);
// 6. Async Update Steam Playtime
_ = Task.Run(async () =>
{
try
{
var cachedTimes = _cache.GetGameTimes();
foreach (var p in players)
{
if (!string.IsNullOrEmpty(p.SteamId))
{
// If not in cache, or value is 0 (maybe failed previously), update it.
// You might also want to re-check periodically, but for now let's stick to missing/zero.
if (!cachedTimes.ContainsKey(p.SteamId) || cachedTimes[p.SteamId] <= 0)
{
int minutes = await SteamHelper.GetSquadPlaytimeAsync(p.SteamId);
if (minutes > 0)
{
_cache.UpdateGameTime(p.SteamId, minutes);
}
await Task.Delay(200); // Rate limit
}
}
}
}
catch (Exception ex)
{
RainOpsMini.Helpers.RainOpsLog.Log($"[RconPollingService] Playtime update failed: {ex.Message}");
}
});
}
catch (Exception ex)
{
RainOpsMini.Helpers.RainOpsLog.Log($"[RconPollingService] Update failed: {ex.Message}");
}
}
}
}