Files
squad-rain-ops-mini/Services/OnlineUserService.cs

178 lines
6.9 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using RainOpsMini.Helpers;
using RainOpsMini.Helpers.RCON;
using RainOpsMini.Models;
namespace RainOpsMini.Services
{
public class OnlineUserService
{
// Panel Users: Username -> ConnectionCount
private ConcurrentDictionary<string, int> _panelUsers = new ConcurrentDictionary<string, int>();
private readonly RconDataCache _rconCache;
public OnlineUserService(RconDataCache rconCache)
{
_rconCache = rconCache;
}
public void UserConnected(string username)
{
if (string.IsNullOrEmpty(username)) return;
_panelUsers.AddOrUpdate(username, 1, (k, v) => v + 1);
}
public void UserDisconnected(string username)
{
if (string.IsNullOrEmpty(username)) return;
_panelUsers.AddOrUpdate(username, 0, (k, v) => v > 1 ? v - 1 : 0);
// Clean up zeros
if (_panelUsers.TryGetValue(username, out int count) && count <= 0)
{
_panelUsers.TryRemove(username, out _);
}
}
public List<string> GetOnlinePanelUsers()
{
return _panelUsers.Where(kvp => kvp.Value > 0).Select(kvp => kvp.Key).ToList();
}
public List<CameramanInfo> GetOnlineCameramen()
{
// Priority 1: Check Current Directory (likely Project Root in Dev, or App Root in Prod)
var configPath = Path.Combine(Directory.GetCurrentDirectory(), "SquadGame", "ServerConfig", "Admins.cfg");
// Priority 2: Check Base Directory (Bin folder)
if (!File.Exists(configPath))
{
configPath = Path.Combine(Environment.CurrentDirectory, "SquadGame", "ServerConfig", "Admins.cfg");
}
if (!File.Exists(configPath)) return new List<CameramanInfo>();
// RainOpsMini.Helpers.RainOpsLog.Log($"Loading Admins.cfg from: {configPath}");
var groupsWithCameraman = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var onlineCameramen = new List<CameramanInfo>();
try
{
var lines = File.ReadAllLines(configPath);
// 1. Identify Groups with 'cameraman' permission
foreach (var line in lines)
{
var trimLine = line.Trim();
if (string.IsNullOrWhiteSpace(trimLine) || trimLine.StartsWith("//") || trimLine.StartsWith("#")) continue;
if (trimLine.StartsWith("Group=", StringComparison.OrdinalIgnoreCase))
{
// Format: Group=GroupName:perm1,perm2...
var parts = trimLine.Substring(6).Split(':');
if (parts.Length >= 2)
{
var groupName = parts[0].Trim();
var perms = parts[1].Split(',').Select(p => p.Trim().ToLower()).ToHashSet();
if (perms.Contains("cameraman"))
{
groupsWithCameraman.Add(groupName);
}
}
}
}
// 2. Identify Admins in those groups
var definedCameramen = new List<CameramanInfo>();
foreach (var line in lines)
{
var trimLine = line.Trim();
if (string.IsNullOrWhiteSpace(trimLine) || trimLine.StartsWith("//") || trimLine.StartsWith("#")) continue;
if (trimLine.StartsWith("Admin=", StringComparison.OrdinalIgnoreCase))
{
// Format: Admin=SteamID:GroupName//Comment
var content = trimLine.Substring(6);
var parts = content.Split(':');
if (parts.Length >= 2)
{
var steamId = parts[0].Trim();
var rest = parts[1];
// Split GroupName and Comment
string groupName;
string comment = "";
int commentIdx = rest.IndexOf("//");
if (commentIdx >= 0)
{
groupName = rest.Substring(0, commentIdx).Trim();
comment = rest.Substring(commentIdx + 2).Trim();
}
else
{
groupName = rest.Trim();
}
if (groupsWithCameraman.Contains(groupName))
{
definedCameramen.Add(new CameramanInfo
{
SteamId = steamId,
Name = comment, // Use comment as name
GroupName = groupName
});
}
}
}
}
// 3. Check online status
// We use cached player list
var currentPlayers = _rconCache.Players ?? new List<PlayerInfo>();
// Safe dictionary creation to avoid duplicate keys exception
var onlineSteamIds = new Dictionary<string, string>();
foreach (var p in currentPlayers)
{
if (!string.IsNullOrEmpty(p.SteamId) && !onlineSteamIds.ContainsKey(p.SteamId))
{
onlineSteamIds[p.SteamId] = p.Name;
}
}
foreach (var cam in definedCameramen)
{
if (onlineSteamIds.ContainsKey(cam.SteamId))
{
cam.IsOnline = true;
// Optionally update name from actual player name if available
// cam.Name = $"{cam.Name} ({onlineSteamIds[cam.SteamId]})";
onlineCameramen.Add(cam);
}
}
}
catch (Exception ex)
{
RainOpsLog.Log($"Error parsing Admins.cfg: {ex.Message}");
}
return onlineCameramen;
}
}
public class CameramanInfo
{
public string SteamId { get; set; } = "";
public string Name { get; set; } = "";
public string GroupName { get; set; } = "";
public bool IsOnline { get; set; }
}
}