Files
squad-rain-ops-mini/Helpers/VipStorage.cs

208 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using RainOpsMini.Models;
namespace RainOpsMini.Helpers
{
public class VipStorage
{
private static readonly string FilePath = "vip_members.json";
private static List<VipMember> _members = new List<VipMember>();
private static object _lock = new object();
static VipStorage()
{
Load();
}
private static void Load()
{
lock (_lock)
{
if (File.Exists(FilePath))
{
try
{
var json = File.ReadAllText(FilePath);
_members = JsonSerializer.Deserialize<List<VipMember>>(json) ?? new List<VipMember>();
}
catch
{
_members = new List<VipMember>();
}
}
}
}
public static void Save()
{
lock (_lock)
{
var json = JsonSerializer.Serialize(_members, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(FilePath, json);
}
}
public static List<VipMember> GetAll()
{
lock (_lock)
{
// Refresh load in case file changed externally?
// For now, assume single process ownership.
return _members.OrderByDescending(m => m.CreatedAt).ToList();
}
}
public static void Add(VipMember member)
{
lock (_lock)
{
_members.Add(member);
Save();
}
}
public static void Remove(string steamId)
{
lock (_lock)
{
_members.RemoveAll(m => m.SteamId == steamId);
Save();
}
}
public static void Update(VipMember member)
{
lock (_lock)
{
var existing = _members.FirstOrDefault(m => m.SteamId == member.SteamId);
if (existing != null)
{
existing.Name = member.Name;
existing.Group = member.Group;
existing.ExpiryDate = member.ExpiryDate;
existing.Remark = member.Remark;
Save();
}
}
}
public static VipMember? GetBySteamId(string steamId)
{
lock (_lock)
{
return _members.FirstOrDefault(m => m.SteamId == steamId);
}
}
public static void SyncToAdminConfig(string adminConfigPath)
{
lock (_lock)
{
List<string> lines = new List<string>();
if (File.Exists(adminConfigPath))
{
lines = File.ReadAllLines(adminConfigPath).ToList();
}
// 1. Remove existing definitions for our managed groups
// We do this to ensure we enforce the permissions requested by the user.
lines.RemoveAll(l => l.Trim().StartsWith("Group=VIP_RainOpsMini:"));
lines.RemoveAll(l => l.Trim().StartsWith("Group=SVIP_RainOpsMini:"));
// 2. Remove existing Admin lines for these groups
// We match strict pattern to avoid false positives in comments
// Pattern: Admin=...:VIP_RainOpsMini...
lines.RemoveAll(l =>
{
var trim = l.Trim();
if (!trim.StartsWith("Admin=")) return false;
// Check if the group part matches
// Format: Admin=SteamID:GroupId [// comment]
// We can check if it contains ":VIP_RainOpsMini" or ":SVIP_RainOpsMini" before any comment start "//"
// Simple check: split by // first
var content = trim.Split("//")[0];
return content.Contains(":VIP_RainOpsMini") || content.Contains(":SVIP_RainOpsMini");
});
// 3. Add Group Definitions
// Find a good place to insert. Usually top or after other groups.
// We'll insert at the beginning if no groups, or after the last group.
int lastGroupIndex = lines.FindLastIndex(l => l.Trim().StartsWith("Group="));
int insertIndex = lastGroupIndex != -1 ? lastGroupIndex + 1 : 0;
// Insert in reverse order so they appear in order
lines.Insert(insertIndex, "Group=SVIP_RainOpsMini:reserve,teamchange");
lines.Insert(insertIndex, "Group=VIP_RainOpsMini:reserve");
// 4. Add Valid VIPs (Refresh status first)
bool needSave = false;
// Use a copy for iteration or index to avoid modification issues if we were removing (we are not removing here, just updating)
foreach (var m in _members)
{
// If managed expiries are present, re-evaluate status
if (m.VipExpiryDate.HasValue || m.SvipExpiryDate.HasValue)
{
bool isSvipActive = m.SvipExpiryDate.HasValue && m.SvipExpiryDate.Value > DateTime.Now;
bool isVipActive = m.VipExpiryDate.HasValue && m.VipExpiryDate.Value > DateTime.Now;
string newGroup = m.Group;
DateTime newExpiry = m.ExpiryDate;
if (isSvipActive)
{
newGroup = "SVIP_RainOpsMini";
newExpiry = m.SvipExpiryDate.Value;
}
else if (isVipActive)
{
newGroup = "VIP_RainOpsMini";
newExpiry = m.VipExpiryDate.Value;
}
else
{
// Both expired, but we don't change group/expiry to "Expired" state explicitly,
// we just let ExpiryDate be the last one?
// Or we set ExpiryDate to the latest one that expired?
// For consistency, let's set it to the latest expiry date.
DateTime svipExp = m.SvipExpiryDate ?? DateTime.MinValue;
DateTime vipExp = m.VipExpiryDate ?? DateTime.MinValue;
newExpiry = svipExp > vipExp ? svipExp : vipExp;
// Keep last group or downgrade?
// If SVIP expired last, keep SVIP group but with expired date.
// If VIP expired last, keep VIP group.
newGroup = svipExp > vipExp ? "SVIP_RainOpsMini" : "VIP_RainOpsMini";
}
if (m.Group != newGroup || m.ExpiryDate != newExpiry)
{
m.Group = newGroup;
m.ExpiryDate = newExpiry;
needSave = true;
}
}
}
if (needSave)
{
Save();
}
var validMembers = _members.Where(m => m.ExpiryDate > DateTime.Now).ToList();
foreach (var m in validMembers)
{
// Admin=SteamID:Group // Name - Remark
string line = $"Admin={m.SteamId}:{m.Group} // {m.Name} - {m.Remark} (Expires: {m.ExpiryDate:yyyy-MM-dd})";
lines.Add(line);
}
File.WriteAllLines(adminConfigPath, lines);
}
}
}
}