using Microsoft.AspNetCore.Builder;
using SqlSugar;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;
using System.Reflection;
using RainOpsMini.Models;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System;
using System.IO;
using RainOpsMini.Helpers.SquadGameLog;
using RainOpsMini.Helpers;
using RainOpsMini.Helpers.RCON;
using RainOpsMini.Services;
using RainOpsMini.Plugins;
using RainOpsMini.Hubs;
using Microsoft.AspNetCore.SignalR;
using RainOpsMini.Apis;
namespace RainOpsMini
{
using RainOpsMini.Models;
using RainOpsMini;
public class Program
{
///
/// RCON配置类,用于存储连接信息和Web服务配置
///
public class RconConfig
{
///
/// RCON服务器IP地址
///
public string Ip { get; set; } = "";
///
/// RCON端口
///
public int Port { get; set; }
///
/// RCON密码
///
public string Password { get; set; } = "";
///
/// Web管理界面端口,默认5000
///
public int WebPort { get; set; } = 5000;
///
/// Web管理界面用户名
///
public string WebUser { get; set; } = "";
///
/// Web管理界面密码
///
public string WebPassword { get; set; } = "";
}
// 全局配置实例
public static RconConfig Config = new RconConfig();
// 配置文件路径
public static string ConfigPath = "rcon_Config.json";
// RCON客户端实例
static RconClient? client;
// 公开访问的RCON客户端属性
public static RconClient? Client => client;
// SignalR Hub上下文,用于发送实时消息
public static IHubContext? ChatHubContext { get; set; }
// 静态缓存实例,在静态上下文和DI容器之间共享
public static RconDataCache RconCache = new RconDataCache();
// 插件监听原始RCON消息的事件
public static event Action? OnRconMessageReceived;
// 系统是否已配置标记
public static bool isConfigured = false;
static async Task Main(string[] args)
{
// 1. 初始化数据库
// 确保数据库表结构存在,这是程序运行的基础
try
{
Console.WriteLine("====== STARTING DATABASE INITIALIZATION ======");
DbHelper.InitDatabase();
Console.WriteLine("====== DATABASE INITIALIZATION COMPLETED ======");
}
catch (Exception ex)
{
// 数据库初始化失败,打印严重错误并退出程序
Console.WriteLine($"\n\n[FATAL ERROR] Database initialization failed. The program cannot start.");
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine("Please check 'db_init_error.log' for details.");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
return;
}
// 2. 启动 Squad 游戏日志监听(后台任务)
// 负责实时解析游戏日志文件,捕捉击杀、聊天等关键事件
Task.Run(() =>
{
try
{
SquadLogHelper squadLogHelper = new SquadLogHelper();
// 确定日志文件路径,当前默认为程序运行目录下的 SquadGame/Saved/Logs/SquadGame.log
// 建议后续改为可配置路径
string logpath = Environment.CurrentDirectory + "/SquadGame/Saved/Logs/SquadGame.log";
squadLogHelper.Run(logpath);
}
catch (Exception ex)
{
Console.WriteLine($"日志监听启动失败: {ex.Message}");
}
});
// 3. 确定 Web 服务端口
// 默认端口 23368
int webPort = 23368;
// 尝试从命令行参数获取端口,优先级最高
if (args.Length > 0 && int.TryParse(args[0], out int p) && p > 0 && p < 65536)
{
webPort = p;
}
// 加载配置文件 rcon_Config.json
LoadConfig();
// 端口优先级逻辑:命令行参数 > 配置文件 > 默认值
// 如果指定了命令行参数,则覆盖配置中的端口
if (Config.WebPort == 0) Config.WebPort = webPort;
else if (args.Length > 0) Config.WebPort = webPort;
// 自动检测端口占用,如果被占用则自动+1查找
Config.WebPort = GetAvailablePort(Config.WebPort);
// 4. 初始化 RCON 连接
// 如果系统已配置(非首次运行),则尝试连接 RCON
if (isConfigured)
{
await InitializeRcon();
}
// 启动后台任务:保持 RCON 连接活跃并自动重连
_ = KeepAliveAndReconnectTask();
// 5. 配置 Web 应用程序构建器
var builder = WebApplication.CreateBuilder(args);
// 优化控制台体验:设置日志级别为 Warning,减少常规日志干扰控制台交互
builder.Logging.SetMinimumLevel(LogLevel.Warning);
// 注册 RCON 客户端(注意:这里可能为空或占位符,后续会更新)
builder.Services.AddSingleton(client ?? new RconClient("", 0, "")); // 占位,避免 DI 报错
// 注册缓存和 RCON 轮询服务
builder.Services.AddMemoryCache();
builder.Services.AddSingleton(RconCache);
builder.Services.AddHostedService(); // RCON 状态轮询
builder.Services.AddHostedService(); // VIP 过期检查
builder.Services.AddHostedService(); // 服务器历史信息存储
builder.Services.AddHostedService(); // 数据库清理任务
builder.Services.AddSingleton(); // 在线玩家服务
builder.Services.AddSingleton(); // 封禁管理服务
builder.Services.AddSingleton(); // 封禁同步状态
builder.Services.AddHostedService(); // 封禁同步后台服务
// 注册玩家数据维护服务
builder.Services.AddHostedService();
// 注册 FRP 内网穿透管理服务
builder.Services.AddSingleton();
// 注册插件系统 (使用扩展方法自动扫描注册)
builder.Services.AddAllPlugins();
// 注册 SignalR (实时通信)
builder.Services.AddSignalR();
// 配置 Cookie 认证服务
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/login.html";
options.ExpireTimeSpan = TimeSpan.FromDays(1);
});
builder.Services.AddAuthorization();
// 配置 JSON 序列化选项 (忽略大小写)
builder.Services.Configure(options =>
{
options.SerializerOptions.PropertyNameCaseInsensitive = true;
});
// 6. 构建并配置 Web 应用管道
var app = builder.Build();
// 获取 ChatHub 上下文,供非 Hub 类使用
ChatHubContext = app.Services.GetRequiredService>();
// 开启认证中间件
app.UseAuthentication();
app.UseAuthorization();
// 7. 配置静态文件服务
// 优先使用物理目录下的 wwwroot(便于开发调试),如果不存在则使用嵌入式资源
IFileProvider fileProvider = new ManifestEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "wwwroot");
string physicalWwwroot = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
if (Directory.Exists(physicalWwwroot))
{
fileProvider = new CompositeFileProvider(
new PhysicalFileProvider(physicalWwwroot),
fileProvider
);
}
// 启用默认文件映射(如 index.html)
app.UseDefaultFiles(new DefaultFilesOptions
{
FileProvider = fileProvider
});
// 8. 自定义请求拦截中间件
// 处理系统初始化检查、页面重定向和全局权限验证
app.Use(async (context, next) =>
{
var path = context.Request.Path.Value?.ToLower();
// 场景A: 系统未初始化
// 强制重定向到安装向导 (setup.html),除非正在访问安装相关接口
if (!isConfigured)
{
if (path == "/setup.html" || path == "/api/setup" || path == "/api/setup/detect-Config")
{
await next();
return;
}
context.Response.Redirect("/setup.html");
return;
}
// 场景B: 系统已初始化
// 禁止再次访问安装向导,重定向回首页
if (path == "/setup.html" || path == "/api/setup" || path == "/api/setup/detect-Config")
{
context.Response.Redirect("/");
return;
}
// 场景C: 公开资源访问
// 放行登录页面、登录接口和验证码接口
if (path == "/login.html" || path == "/api/login" || path == "/api/captcha")
{
await next();
return;
}
// 场景D: 需要认证的资源
// 检查用户是否已登录
if (!context.User.Identity?.IsAuthenticated ?? true)
{
// 特殊处理 SignalR 连接 (chatHub)
// 允许协商请求通过,SignalR 内部会处理或依赖 Cookie
if (path?.StartsWith("/chatHub") == true || path?.StartsWith("/presenceHub") == true)
{
await next();
return;
}
// 如果是 API 请求,返回 401 未授权状态码
if (path?.StartsWith("/api/") == true)
{
context.Response.StatusCode = 401;
return;
}
// 如果是普通页面访问,重定向到登录页
context.Response.Redirect("/login.html");
return;
}
// 已认证,放行请求
await next();
});
// 启用静态文件中间件
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider
});
// API 路由
// Register Modular APIs
app.MapSystemApis();
app.MapAuthApis();
app.MapUserApis();
app.MapVipApis();
app.MapPlayerApis();
app.MapServerApis();
app.MapLogApis();
app.MapFrpApis();
app.MapBanApis();
// Ensure PluginManager is initialized and Configs are loaded
try
{
app.Services.GetRequiredService();
}
catch (Exception ex)
{
Console.WriteLine($"[Warning] PluginManager initialization failed: {ex.Message}");
}
Console.WriteLine($"Web 服务启动中: http://localhost:{Config.WebPort}");
// FRP no longer auto-starts at application startup.
// Use console command "frp start" or /api/frp/start when needed.
// 9. 启动 Web 服务
// 使用异步非阻塞方式启动,以便主线程可以继续运行控制台交互循环
var webTask = app.RunAsync($"http://*:{Config.WebPort}");
// 10. 启动控制台交互循环
// 允许用户在控制台直接输入命令进行管理
await RunConsoleLoop(app);
// 当控制台退出时,优雅停止 Web 服务
await app.StopAsync();
await webTask;
}
// 控制台交互主循环
// 允许用户在控制台直接输入命令进行管理
static async Task RunConsoleLoop(WebApplication app)
{
var version = Assembly.GetExecutingAssembly().GetName().Version;
Console.WriteLine("--------------------------------------------------");
Console.WriteLine($" RainOPS Mini 控制台已就绪 v{version}");
Console.WriteLine(" 输入 'help' 查看可用命令");
Console.WriteLine("--------------------------------------------------");
while (true)
{
string statusIndicator = (client != null && client.IsConnected) ? "Online" : "Offline";
Console.Write($"RainOPS [{statusIndicator}]> ");
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) continue;
string cmd = input.Trim();
switch (cmd.ToLower())
{
case "help":
PrintHelp();
break;
case "1":
case "Config":
ShowConfig();
break;
case "2":
case "setrcon":
await UpdateRconConfig();
break;
case "3":
case "setwebport":
UpdateWebPort();
break;
case "4":
case "showlogin":
ShowLoginInfo();
break;
case "5":
case "resetlogin":
ResetLoginInfo();
break;
case "setinterval":
Console.WriteLine("请输入刷新间隔 (10-60 秒):");
string? intStr = Console.ReadLine();
if (int.TryParse(intStr, out int interval))
{
var cache = app.Services.GetService();
if (cache != null)
{
cache.RefreshIntervalSeconds = interval;
Console.WriteLine($"刷新频率已设置为 {cache.RefreshIntervalSeconds} 秒");
}
}
else
{
Console.WriteLine("输入无效");
}
break;
case "status":
ShowStatus(app);
break;
case "frp":
Console.WriteLine("用法: frp start | frp stop | frp restart");
break;
case "frp start":
var frpStart = app.Services.GetService();
if (frpStart != null)
{
try {
frpStart.Start();
Console.WriteLine("FRP 任务已启动,日志将显示在下方。");
} catch (Exception ex) {
Console.WriteLine($"启动失败: {ex.Message}");
}
}
break;
case "frp stop":
var frpStop = app.Services.GetService();
if (frpStop != null)
{
frpStop.Stop();
Console.WriteLine("FRP 任务已停止。");
}
break;
case "frp restart":
var frpRestart = app.Services.GetService();
if (frpRestart != null)
{
try {
frpRestart.Restart();
Console.WriteLine("FRP 任务已重启。");
} catch (Exception ex) {
Console.WriteLine($"重启失败: {ex.Message}");
}
}
break;
case "connect":
await ManualConnect();
break;
case "exit":
case "quit":
Console.WriteLine("正在退出程序...");
return;
default:
// 尝试作为 RCON 命令发送到游戏服务器
if (client != null && client.IsConnected)
{
try
{
// Console.WriteLine($"[发送] {cmd}");
string response = await client.SendCommandAsync(cmd);
if (!string.IsNullOrWhiteSpace(response))
{
Console.WriteLine(response);
}
else
{
Console.WriteLine("(无返回数据)");
}
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 命令执行失败: {ex.Message}");
}
}
else
{
Console.WriteLine("未知命令,且 RCON 未连接。输入 'help' 查看帮助。");
}
break;
}
}
}
// 显示系统状态
// 打印 RCON 连接、Web 端口、FRP 状态等信息
static void ShowStatus(WebApplication app)
{
Console.WriteLine("------------- 系统状态 -------------");
Console.WriteLine($" RCON 连接状态 : {(client?.IsConnected == true ? "已连接" : "未连接")}");
if (client?.IsConnected == true)
{
Console.WriteLine($" RCON 目标 : {Config.Ip}:{Config.Port}");
}
Console.WriteLine($" Web 服务端口 : {Config.WebPort}");
var frp = app.Services.GetService();
if (frp != null)
{
Console.WriteLine($" FRP 运行状态 : {(frp.IsRunning ? "运行中" : "未运行")}");
}
Console.WriteLine("------------------------------------");
}
// 手动连接 RCON
// 尝试根据当前配置重新连接游戏服务器
static async Task ManualConnect()
{
Console.WriteLine("正在尝试连接 RCON...");
if (!isConfigured) LoadConfig();
if (string.IsNullOrEmpty(Config.Ip))
{
Console.WriteLine("错误: 未配置 RCON IP。请先使用 'Config' 或 'setrcon' 进行配置。");
return;
}
await InitializeRcon();
}
// 打印帮助信息
// 显示控制台支持的所有命令
static void PrintHelp()
{
Console.WriteLine("================ 功能菜单 ================");
Console.WriteLine(" [直接输入 RCON 命令即可发送到服务器]");
Console.WriteLine(" status - 查看连接状态");
Console.WriteLine(" connect - 手动尝试连接 RCON");
Console.WriteLine(" 1. 查看配置文件全部信息 (或输入 Config)");
Console.WriteLine(" - 显示服务器IP、端口、RCON密码、登录名、登录密码等");
Console.WriteLine(" 2. 修改 RCON 信息 (或输入 setrcon)");
Console.WriteLine(" 3. 修改 WEB 端口 (或输入 setwebport)");
Console.WriteLine(" 4. 查看登录名和密码 (或输入 showlogin)");
Console.WriteLine(" 5. 重置登录名和密码 (或输入 resetlogin)");
Console.WriteLine(" setinterval - 设置 RCON 数据刷新频率 (10-60秒)");
Console.WriteLine(" frp start - 启动 FRP 任务");
Console.WriteLine(" frp stop - 停止 FRP 任务");
Console.WriteLine(" frp restart - 重启 FRP 任务");
Console.WriteLine(" help - 显示此帮助信息");
Console.WriteLine(" exit - 退出程序");
Console.WriteLine("==========================================");
}
// 显示配置信息
// 打印当前加载的所有配置项
static void ShowConfig()
{
Console.WriteLine("------------- 当前配置信息 -------------");
Console.WriteLine($" RCON 服务器IP : {Config.Ip}");
Console.WriteLine($" RCON 端口 : {Config.Port}");
Console.WriteLine($" RCON 密码 : {Config.Password}");
Console.WriteLine($" WEB 端口 : {Config.WebPort}");
Console.WriteLine($" WEB 登录名 : {Config.WebUser}");
Console.WriteLine($" WEB 登录密码 : {Config.WebPassword}");
Console.WriteLine("----------------------------------------");
}
// 显示登录凭据
// 打印当前的 Web 登录用户名和密码
static void ShowLoginInfo()
{
Console.WriteLine("------------- 登录凭据 -------------");
Console.WriteLine($" 登录名 : {Config.WebUser}");
Console.WriteLine($" 登录密码 : {Config.WebPassword}");
Console.WriteLine("------------------------------------");
}
// 修改 RCON 配置
// 交互式修改 IP、端口和密码
static async Task UpdateRconConfig()
{
Console.WriteLine(">>> 修改 RCON 配置 (直接回车保持原值) <<<");
Console.Write($"输入新IP [{Config.Ip}]: ");
string? ip = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(ip)) Config.Ip = ip.Trim();
Console.Write($"输入新端口 [{Config.Port}]: ");
string? portStr = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(portStr) && int.TryParse(portStr, out int p)) Config.Port = p;
Console.Write($"输入新密码 [{Config.Password}]: ");
string? pass = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(pass)) Config.Password = pass.Trim();
SaveConfigToFile();
Console.WriteLine("配置已保存。正在重新初始化 RCON 连接...");
isConfigured = true;
await InitializeRcon();
}
// 修改 Web 端口
// 修改 Web 服务监听端口(需重启生效)
static void UpdateWebPort()
{
Console.WriteLine(">>> 修改 WEB 端口 <<<");
Console.Write($"输入新端口 [{Config.WebPort}]: ");
string? portStr = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(portStr) && int.TryParse(portStr, out int p) && p > 0 && p < 65536)
{
Config.WebPort = p;
SaveConfigToFile();
Console.WriteLine($"端口已修改为 {p}。");
Console.WriteLine("注意:Web 端口修改需要重启程序才能生效!");
}
else
{
Console.WriteLine("端口无效或未修改。");
}
}
// 重置 Web 登录信息
// 修改或生成新的 Web 登录凭据
static void ResetLoginInfo()
{
Console.WriteLine(">>> 重置 Web 登录信息 <<<");
Console.Write($"输入新用户名 (回车保持 '{Config.WebUser}'): ");
string? user = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(user)) Config.WebUser = user.Trim();
Console.Write("输入新密码 (回车自动生成随机密码): ");
string? pass = Console.ReadLine();
if (string.IsNullOrWhiteSpace(pass))
{
pass = GenerateRandomPassword();
Console.WriteLine($"已生成随机密码: {pass}");
}
else
{
if (!ValidatePassword(pass))
{
Console.WriteLine("密码强度不足(需至少包含字母、数字、符号中的两种,且长度>=6)。是否强制使用?(y/n)");
string? confirm = Console.ReadLine();
if (confirm?.Trim().ToLower() != "y")
{
Console.WriteLine("取消修改。");
return;
}
}
}
Config.WebPassword = pass;
SaveConfigToFile();
Console.WriteLine("登录信息已更新并保存。");
}
// 保存配置到文件
// 将内存中的 Config 对象序列化并写入 JSON 文件
public static void SaveConfigToFile()
{
try
{
string json = JsonSerializer.Serialize(Config, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(ConfigPath, json);
Console.WriteLine("[系统] 配置文件已更新。");
}
catch (Exception ex)
{
Console.WriteLine($"[错误] 保存配置文件失败: {ex.Message}");
}
}
// 加载配置文件
// 从 JSON 文件读取配置,如果不存在则提示
static void LoadConfig()
{
if (!File.Exists(ConfigPath))
{
Console.WriteLine("未检测到配置文件,请通过 Web 页面进行初始化配置,或在控制台使用命令配置。");
isConfigured = false;
}
else
{
try
{
string json = File.ReadAllText(ConfigPath);
var loadedConfig = JsonSerializer.Deserialize(json);
if (loadedConfig != null)
{
Config = loadedConfig;
isConfigured = true;
Console.WriteLine($"已加载配置: RCON IP={Config.Ip}, Port={Config.Port}");
}
else
{
Console.WriteLine("配置文件格式错误,需重新配置。");
isConfigured = false;
}
}
catch (Exception ex)
{
Console.WriteLine($"读取配置文件出错: {ex.Message}");
isConfigured = false;
}
}
}
// 初始化 RCON 连接
// 建立连接并设置事件监听器
public static async Task InitializeRcon()
{
if (!string.IsNullOrEmpty(Config.Ip) && Config.Port > 0)
{
// 如果已有连接,尝试断开并清理资源
client?.Dispose();
client = new RconClient(Config.Ip, Config.Port, Config.Password);
// 监听 RCON 服务端主动推送的消息 (如聊天、击杀日志)
client.OnMessageReceived += (msg) =>
{
// 1. 通知插件系统
try
{
OnRconMessageReceived?.Invoke(msg);
}
catch (Exception ex)
{
Console.WriteLine($"[Error] Plugin RCON message handler failed: {ex.Message}");
}
// 2. 解析聊天消息
var chatMsg = RconParser.ParseChatMessage(msg);
if (chatMsg != null)
{
// 尝试从缓存中补充玩家的队伍和分队信息
var player = RconCache.GetPlayer(chatMsg.SteamId, chatMsg.EosId);
if (player != null)
{
chatMsg.TeamId = player.TeamId;
chatMsg.SquadId = player.SquadId;
}
// 添加到内存缓存
RconCache.AddChatMessage(chatMsg);
// 3. 保存到数据库 (SQLite)
try
{
var chatLog = new ChatLog
{
Type = chatMsg.Type,
EosId = chatMsg.EosId,
SteamId = chatMsg.SteamId,
Name = chatMsg.Name,
Message = chatMsg.Message,
Timestamp = chatMsg.Timestamp,
TeamId = chatMsg.TeamId,
SquadId = chatMsg.SquadId
};
using (var db = DbHelper.GetInstance())
{
db.Insertable(chatLog).ExecuteCommand();
}
}
catch (Exception ex)
{
Console.WriteLine($"[Error] Failed to save chat to DB: {ex.Message}");
}
Console.WriteLine($"[{chatMsg.Type}] {chatMsg.Name}: {chatMsg.Message}");
// 4. 通过 SignalR 广播给前端
if (ChatHubContext != null)
{
_ = ChatHubContext.Clients.All.SendAsync("ReceiveChat", chatMsg);
}
}
else
{
// 非聊天消息,直接打印
Console.WriteLine($"[RCON Push] {msg}");
}
};
//client.OnLog += (log) => Console.WriteLine($"[RCON Log] {log}");
try
{
await client.ConnectAsync();
Console.WriteLine($"[系统] RCON 客户端已连接 ({Config.Ip}:{Config.Port})");
}
catch (Exception ex)
{
Console.WriteLine($"[警告] RCON 连接失败: {ex.Message}");
}
}
}
static int GetAvailablePort(int startPort)
{
int port = startPort;
while (IsPortInUse(port))
{
Console.WriteLine($"[系统] 端口 {port} 已被占用,尝试使用 {port + 10}...");
port += 10;
if (port > 65535)
{
throw new Exception("无法找到可用端口");
}
}
if (port != startPort)
{
Console.WriteLine($"[系统] 最终使用端口: {port}");
}
return port;
}
static bool IsPortInUse(int port)
{
bool inUse = false;
System.Net.NetworkInformation.IPGlobalProperties ipProperties = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
System.Net.IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
foreach (System.Net.IPEndPoint endPoint in ipEndPoints)
{
if (endPoint.Port == port)
{
inUse = true;
break;
}
}
return inUse;
}
static async Task KeepAliveAndReconnectTask()
{
while (true)
{
if (client != null && !client.IsConnected)
{
// Console.WriteLine("[系统] 检测到 RCON 未连接,正在尝试连接...");
try
{
await client.ConnectAsync();
// Console.WriteLine("[系统] RCON 重连成功");
}
catch
{
// 静默失败,等待下次重试
}
}
await Task.Delay(5000);
}
}
public static bool ValidatePassword(string pwd)
{
if (string.IsNullOrEmpty(pwd) || pwd.Length < 6) return false;
int types = 0;
if (pwd.Any(char.IsDigit)) types++;
if (pwd.Any(char.IsLetter)) types++;
if (pwd.Any(c => !char.IsLetterOrDigit(c))) types++;
return types >= 2;
}
public static string GenerateRandomPassword()
{
const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string digits = "0123456789";
const string symbols = "!@#$%^&*()_+-=[]{}|;:,.<>?";
var random = new Random();
var password = new char[12];
// 确保至少包含各类字符以满足要求
password[0] = chars[random.Next(chars.Length)];
password[1] = digits[random.Next(digits.Length)];
password[2] = symbols[random.Next(symbols.Length)];
string allChars = chars + digits + symbols;
for (int i = 3; i < 12; i++)
{
password[i] = allChars[random.Next(allChars.Length)];
}
// 打乱顺序
return new string(password.OrderBy(x => random.Next()).ToArray());
}
}
public class CommandRequest
{
public string Command { get; set; } = string.Empty;
}
public class LoginRequest
{
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string CaptchaId { get; set; } = string.Empty;
public string CaptchaCode { get; set; } = string.Empty;
}
public class SetupRequest
{
public string Ip { get; set; } = "";
public int Port { get; set; }
public string Password { get; set; } = "";
public string WebUser { get; set; } = "";
public string WebPassword { get; set; } = "";
}
public class ConfigSaveRequest
{
public string Filename { get; set; } = "";
public string Content { get; set; } = "";
}
public class PasswordResetRequest
{
public string NewPassword { get; set; } = string.Empty;
}
public class BanRequest
{
public string SteamId { get; set; } = "";
public string Reason { get; set; } = "";
public string Duration { get; set; } = "perm";
}
public class KickRequest
{
public string SteamId { get; set; } = "";
public string Reason { get; set; } = "";
}
public class IntervalRequest
{
public int Seconds { get; set; }
}
public class TicketRequest
{
public int TeamId { get; set; }
public int Tickets { get; set; }
}
public class GameTimeUpdateModel
{
public int Hours { get; set; }
}
}