重构控制台指令系统;添加 CORS 配置;添加启动项读取 (#57)

* 重构控制台指令系统;添加 CORS 配置;添加启动项读取

* 修改BUG
This commit is contained in:
milimoe 2026-04-08 01:20:38 +08:00 committed by GitHub
parent 4498a6fbf8
commit 3c81cf7217
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 316 additions and 168 deletions

View File

@ -30,8 +30,8 @@ else
Console.Title = Config.ServerName + " - FunGame Server Port: " + Config.ServerPort;
}
// 初始化命令菜单
ServerHelper.InitOrderList();
// 读取启动项
FunGameSystem.GetStartupArguments(args);
// 初始化SQLHelper
FunGameSystem.InitSQLHelper();
@ -86,41 +86,44 @@ FunGameSystem.CloseListener += async () =>
}
};
// 初始化命令菜单
if (SocketListener != null)
{
ConsoleModel.InitOrders(SocketListener);
}
else
{
ConsoleModel.InitOrders(WebSocketListener);
}
while (Running)
{
string order = Console.ReadLine() ?? "";
string input = Console.ReadLine()?.Trim() ?? "";
ServerHelper.Type();
if (order != "" && Running)
if (input != "" && Running)
{
order = order.ToLower();
if (FunGameSystem.OrderList.TryGetValue(order, out Action<string>? action) && action != null)
string[] strings = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (strings.Length > 0)
{
action(order);
}
switch (order)
{
case OrderDictionary.Quit:
case OrderDictionary.Exit:
case OrderDictionary.Close:
CloseServer();
break;
case OrderDictionary.Restart:
if (SocketListener is null || WebSocketListener is null)
{
StartServerListening();
}
else ServerHelper.WriteLine("服务器正在运行,请手动结束服务器进程再启动!");
break;
default:
if (SocketListener != null)
{
await ConsoleModel.Order(SocketListener, order);
}
else
{
await ConsoleModel.Order(WebSocketListener, order);
}
break;
string order = strings[0].ToLower();
string[] inputArgs = [.. strings.Skip(1)];
switch (order)
{
case OrderDictionary.Quit:
case OrderDictionary.Exit:
case OrderDictionary.Close:
CloseServer();
break;
case OrderDictionary.Restart:
if (SocketListener is null || WebSocketListener is null)
{
StartServerListening();
}
else ServerHelper.WriteLine("服务器正在运行,请手动结束服务器进程再启动!");
break;
default:
await ConsoleModel.Order(order, inputArgs);
break;
}
}
}
}

View File

@ -13,85 +13,188 @@ namespace Milimoe.FunGame.Server.Model
{
public class ConsoleModel
{
public static async Task Order<T>(ISocketListener<T>? server, string order) where T : ISocketMessageProcessor
public static void InitOrders<T>(ISocketListener<T>? server) where T : ISocketMessageProcessor
{
FunGameSystem.OrderList[OrderDictionary.Kick] = async (args) =>
{
if (args.Length == 0 || args[0] is not string client)
{
ServerHelper.Write("输入需要踢出的客户端名称:");
client = await Console.In.ReadLineAsync() ?? "";
}
if (client != "" && server != null && server.ClientList.ContainsKey(client))
{
await Kick(server.ClientList[client]);
}
else
{
ServerHelper.WriteLine("未找到指定的客户端。");
}
};
FunGameSystem.OrderList[OrderDictionary.Logout] = async (args) =>
{
if (args.Length == 0 || args[0] is not string user)
{
ServerHelper.Write("输入需要强制下线的玩家ID");
user = await Console.In.ReadLineAsync() ?? "";
}
if (user != "" && server != null && server.UserList.ContainsKey(user))
{
await ForceLogOut(server.UserList[user]);
}
else
{
ServerHelper.WriteLine("未找到指定的玩家。");
}
};
FunGameSystem.OrderList[OrderDictionary.Show] = async (args) =>
{
if (args.Length > 0 && args[0] is string type)
{
switch (type)
{
case "clients":
case "-c":
ShowClients(server);
break;
case "users":
case "-u":
ShowUsers(server);
break;
default:
ServerHelper.WriteLine($"指令 '{OrderDictionary.Show}' 的参数 '{type}' 无效。", InvokeMessageType.Warning);
ShowClients(server);
ShowUsers(server);
break;
}
}
else
{
ShowClients(server);
ShowUsers(server);
}
};
FunGameSystem.OrderList[OrderDictionary.ShowClients] = async (args) =>
{
ShowClients(server);
};
FunGameSystem.OrderList[OrderDictionary.ShowUsers] = async (args) =>
{
ShowUsers(server);
};
FunGameSystem.OrderList[OrderDictionary.Reload] = async (args) =>
{
if (args.Length > 0 && args[0] is string type)
{
switch (type)
{
case "addons":
case "-a":
FunGameSystem.HotReloadServerPlugins();
FunGameSystem.HotReloadWebAPIPlugins();
FunGameSystem.HotReloadGameModuleList();
break;
case "modules":
case "-m":
FunGameSystem.HotReloadGameModuleList();
break;
case "plugins":
case "-p":
FunGameSystem.HotReloadServerPlugins();
FunGameSystem.HotReloadWebAPIPlugins();
break;
case "serverplugins":
case "-sp":
FunGameSystem.HotReloadServerPlugins();
break;
case "webapiplugins":
case "-wp":
FunGameSystem.HotReloadWebAPIPlugins();
break;
default:
ServerHelper.WriteLine($"指令 '{OrderDictionary.Reload}' 的参数 '{type}' 无效。", InvokeMessageType.Error);
break;
}
}
};
FunGameSystem.OrderList[OrderDictionary.Help] = async (args) =>
{
ServerHelper.WriteLine($"可用指令:{string.Join("", FunGameSystem.OrderList.Keys.Select(c => $"{c}{GetOrderAliases(c)}"))}");
};
FunGameSystem.OrderList[OrderDictionary.Ban] = async (args) =>
{
if (args.Length > 0 && args[0] is string type)
{
if (args.Length == 1 || args[1] is not string banned)
{
ServerHelper.WriteLine($"没有提供指令 '{OrderDictionary.Ban}' 所需的第二个参数 'banned ip' 值。", InvokeMessageType.Error);
return;
}
if (!NetworkUtility.IsIP(banned))
{
ServerHelper.WriteLine($"指令 '{OrderDictionary.Ban}' 的参数 '{banned}' 不是一个 IP 地址。", InvokeMessageType.Error);
return;
}
switch (type)
{
case "add":
case "-a":
Config.ServerBannedList.Add(banned);
ServerHelper.WriteLine($"将 {banned} 添加入黑名单成功。");
break;
case "remove":
case "-r":
Config.ServerBannedList.Remove(banned);
ServerHelper.WriteLine($"将 {banned} 移出黑名单成功。");
break;
default:
ServerHelper.WriteLine($"指令 '{OrderDictionary.Ban}' 的参数 '{type}' 无效。", InvokeMessageType.Error);
break;
}
}
else
{
ServerHelper.WriteLine($"没有提供指令 '{OrderDictionary.Ban}' 所需的参数。", InvokeMessageType.Error);
}
};
}
public static void AddOrderAlias(string order, params string[] aliases)
{
foreach (string alias in aliases)
{
FunGameSystem.OrderAliasList[alias] = order;
}
}
public static async Task Order(string order, string[] args)
{
try
{
switch (order)
if (FunGameSystem.OrderList.TryGetValue(order, out Func<string[], Task>? func) && func != null)
{
case OrderDictionary.Kick:
{
ServerHelper.Write("输入需要踢出的客户端名称:");
string client = Console.ReadLine() ?? "";
if (client != "" && server != null)
{
await Kick(server.ClientList[client]);
}
break;
}
case OrderDictionary.Logout:
{
ServerHelper.Write("输入需要强制下线的玩家ID");
string user = Console.ReadLine() ?? "";
if (user != "" && server != null)
{
await ForceLogOut(server.UserList[user]);
}
break;
}
case OrderDictionary.ShowList:
ShowClients(server);
ShowUsers(server);
break;
case OrderDictionary.ShowClients1:
case OrderDictionary.ShowClients2:
ShowClients(server);
break;
case OrderDictionary.ShowUsers1:
case OrderDictionary.ShowUsers2:
ShowUsers(server);
break;
case OrderDictionary.ReloadAddons:
FunGameSystem.HotReloadServerPlugins();
FunGameSystem.HotReloadWebAPIPlugins();
FunGameSystem.HotReloadGameModuleList();
break;
case OrderDictionary.ReloadPlugins1:
FunGameSystem.HotReloadServerPlugins();
FunGameSystem.HotReloadWebAPIPlugins();
break;
case OrderDictionary.ReloadPlugins2:
FunGameSystem.HotReloadServerPlugins();
FunGameSystem.HotReloadWebAPIPlugins();
break;
case OrderDictionary.ReloadPlugins3:
FunGameSystem.HotReloadServerPlugins();
break;
case OrderDictionary.ReloadPlugins4:
FunGameSystem.HotReloadWebAPIPlugins();
break;
case OrderDictionary.ReloadModules1:
FunGameSystem.HotReloadGameModuleList();
break;
case OrderDictionary.ReloadModules2:
FunGameSystem.HotReloadGameModuleList();
break;
default:
break;
await func.Invoke(args);
}
else if (FunGameSystem.OrderAliasList.TryGetValue(order, out string? actualOrder) && actualOrder != null)
{
if (FunGameSystem.OrderList.TryGetValue(actualOrder, out Func<string[], Task>? func2) && func2 != null)
{
await func2.Invoke(args);
}
}
// 广播到插件
if (FunGameSystem.ServerPluginLoader != null)
{
foreach (ServerPlugin plugin in FunGameSystem.ServerPluginLoader.Plugins.Values)
{
plugin.ProcessInput(order);
plugin.ProcessInput(order, args);
}
}
if (FunGameSystem.WebAPIPluginLoader != null)
{
foreach (WebAPIPlugin plugin in FunGameSystem.WebAPIPluginLoader.Plugins.Values)
{
plugin.ProcessInput(order);
plugin.ProcessInput(order, args);
}
}
}
@ -101,17 +204,23 @@ namespace Milimoe.FunGame.Server.Model
}
}
public static async Task Kick(IServerModel clientModel)
public static string GetOrderAliases(string order)
{
string[] alias = [.. FunGameSystem.OrderAliasList.Where(kv => kv.Value == order).Select(kv => kv.Key)];
return alias.Length > 0 ? $"(替代:{string.Join("", alias)}" : "";
}
private static async Task Kick(IServerModel clientModel)
{
await clientModel.Kick("您已被服务器管理员踢出此服务器。");
}
public static async Task ForceLogOut(IServerModel clientModel)
private static async Task ForceLogOut(IServerModel clientModel)
{
await clientModel.ForceLogOut("您已被服务器管理员强制下线。");
}
public static void ShowClients<T>(ISocketListener<T>? server) where T : ISocketMessageProcessor
private static void ShowClients<T>(ISocketListener<T>? server) where T : ISocketMessageProcessor
{
if (server != null)
{
@ -124,7 +233,7 @@ namespace Milimoe.FunGame.Server.Model
}
}
public static void ShowUsers<T>(ISocketListener<T>? server) where T : ISocketMessageProcessor
private static void ShowUsers<T>(ISocketListener<T>? server) where T : ISocketMessageProcessor
{
if (server != null)
{

View File

@ -154,6 +154,11 @@ namespace Milimoe.FunGame.Server.Others
/// </summary>
public static SQLMode SQLMode { get; set; } = SQLMode.None;
/// <summary>
/// CORS允许所有来源
/// </summary>
public static bool AllowAnyOrigin { get; set; } = false;
/// <summary>
/// 未Loadmodules时此属性表示至少需要安装的模组
/// </summary>

View File

@ -7,23 +7,12 @@
public const string Exit = "exit";
public const string Close = "close";
public const string Restart = "restart";
public const string AddBanned1 = "ban add";
public const string AddBanned2 = "ban -a";
public const string RemoveBanned1 = "ban remove";
public const string RemoveBanned2 = "ban -r";
public const string Ban = "ban";
public const string Kick = "kick";
public const string Logout = "logout";
public const string ShowList = "showlist";
public const string ShowClients1 = "show clients";
public const string ShowClients2 = "clients";
public const string ShowUsers1 = "show users";
public const string ShowUsers2 = "users";
public const string ReloadAddons = "reload addons";
public const string ReloadPlugins1 = "reload plugins";
public const string ReloadPlugins2 = "reload -p";
public const string ReloadPlugins3 = "reload -sp";
public const string ReloadPlugins4 = "reload -wp";
public const string ReloadModules1 = "reload modules";
public const string ReloadModules2 = "reload -m";
public const string Show = "show";
public const string ShowClients = "clients";
public const string ShowUsers = "users";
public const string Reload = "reload";
}
}

View File

@ -20,7 +20,12 @@ namespace Milimoe.FunGame.Server.Services
/// <summary>
/// 服务器指令列表
/// </summary>
public static Dictionary<string, Action<string>> OrderList { get; } = [];
public static Dictionary<string, Func<string[], Task>> OrderList { get; } = [];
/// <summary>
/// 服务器指令的别名列表
/// </summary>
public static Dictionary<string, string> OrderAliasList { get; } = [];
/// <summary>
/// 在线房间列表
@ -72,6 +77,31 @@ namespace Milimoe.FunGame.Server.Services
/// </summary>
public const string APISecretFileName = ".apisecret";
/// <summary>
/// 读取启动项
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static void GetStartupArguments(string[] args)
{
foreach (string arg in args)
{
switch (arg)
{
case "--debug":
case "-d":
FunGameInfo.FunGame_DebugMode = true;
break;
case "--allowanyorigin":
case "-aao":
Config.AllowAnyOrigin = true;
break;
default:
break;
}
}
}
/// <summary>
/// 初始化数据库连接器
/// </summary>

View File

@ -245,16 +245,6 @@ namespace Milimoe.FunGame.Server.Services
Error(e);
}
}
public static void InitOrderList()
{
FunGameSystem.OrderList.Clear();
FunGameSystem.OrderList.Add(OrderDictionary.Help, s => WriteLine("Milimoe -> 帮助"));
FunGameSystem.OrderList.Add(OrderDictionary.Quit, s => WriteLine("关闭服务器"));
FunGameSystem.OrderList.Add(OrderDictionary.Exit, s => WriteLine("关闭服务器"));
FunGameSystem.OrderList.Add(OrderDictionary.Close, s => WriteLine("关闭服务器"));
FunGameSystem.OrderList.Add(OrderDictionary.Restart, s => WriteLine("重启服务器"));
}
}
public class SmtpHelper

View File

@ -52,8 +52,8 @@ try
ServerHelper.GetServerSettings();
}
// 初始化命令菜单
ServerHelper.InitOrderList();
// 读取启动项
FunGameSystem.GetStartupArguments(args);
// 初始化 SQLHelper
FunGameSystem.InitSQLHelper();
@ -132,7 +132,16 @@ try
{
options.AddPolicy("AllowSpecificOrigin", policy =>
{
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
if (Config.AllowAnyOrigin)
{
ServerHelper.WriteLine($"已允许所有来源跨域访问", InvokeMessageType.Warning);
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
}
else
{
string[] allowedOrigins = builder.Configuration.GetSection("AllowOrigins").Get<string[]>() ?? ["http://localhost:12099", "https://localhost:12099"];
policy.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
}
});
});
// 添加 JWT 认证
@ -279,30 +288,33 @@ catch (Exception e)
async Task GetConsoleOrder()
{
// 初始化命令菜单
ConsoleModel.InitOrders(listener);
while (true)
{
string order = await Console.In.ReadLineAsync() ?? "";
string input = (await Console.In.ReadLineAsync())?.Trim() ?? "";
ServerHelper.Type();
if (order != "")
if (input != "")
{
order = order.ToLower();
if (FunGameSystem.OrderList.TryGetValue(order, out Action<string>? action) && action != null)
string[] strings = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (strings.Length > 0)
{
action(order);
}
switch (order)
{
case OrderDictionary.Quit:
case OrderDictionary.Exit:
case OrderDictionary.Close:
CloseServer();
break;
case OrderDictionary.Restart:
ServerHelper.WriteLine("服务器正在运行,请手动结束服务器进程再启动!");
break;
default:
await ConsoleModel.Order(listener, order);
break;
string order = strings[0].ToLower();
string[] args = [.. strings.Skip(1)];
switch (order)
{
case OrderDictionary.Quit:
case OrderDictionary.Exit:
case OrderDictionary.Close:
CloseServer();
break;
case OrderDictionary.Restart:
ServerHelper.WriteLine("服务器正在运行,请手动结束服务器进程再启动!");
break;
default:
await ConsoleModel.Order(order, args);
break;
}
}
}
}
@ -360,8 +372,8 @@ async Task WebSocketConnectionHandler(HttpContext context)
{
Config.DecrementConnectingPlayerCount();
ConnectEventArgs eventArgs = new(clientip, Config.ServerPort, ConnectResult.CanNotConnect);
FunGameSystem.ServerPluginLoader?.OnAfterConnectEvent(context, eventArgs);
FunGameSystem.WebAPIPluginLoader?.OnAfterConnectEvent(context, eventArgs);
FunGameSystem.ServerPluginLoader?.OnAfterConnectEvent(socket, eventArgs);
FunGameSystem.WebAPIPluginLoader?.OnAfterConnectEvent(socket, eventArgs);
ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 中断连接!", InvokeMessageType.Core);
ServerHelper.Error(e);
}

View File

@ -1,33 +1,25 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:45590",
"sslPort": 44356
}
},
{
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "scalar",
"applicationUrl": "http://localhost:5117",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5117"
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"commandLineArgs": "-aao",
"launchBrowser": true,
"launchUrl": "scalar",
"applicationUrl": "https://localhost:7162;http://localhost:5117",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7162;http://localhost:5117"
},
"IIS Express": {
"commandName": "IISExpress",
@ -37,5 +29,14 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:45590",
"sslPort": 44356
}
}
}
}

View File

@ -1,8 +1,13 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Default": "Debug",
"Microsoft.AspNetCore": "Warning"
}
},
"Jwt": {
"Key": "166afec8ff6e0c3a647c7230294ea10be39d5d217f37aa5195f795017403da730ce6313790335b4975d7387c14aaa06c52d1cd90b5ef47d1831b6d7d524a12bf",
"Issuer": "FunGame",
"Audience": "FunGame Web API"
}
}

View File

@ -11,6 +11,10 @@
"Protocols": "Http1AndHttp2AndHttp3"
}
},
"AllowOrigins": [
"http://localhost:12099",
"https://localhost:12099"
],
"Jwt": {
"Key": "166afec8ff6e0c3a647c7230294ea10be39d5d217f37aa5195f795017403da730ce6313790335b4975d7387c14aaa06c52d1cd90b5ef47d1831b6d7d524a12bf",
"Issuer": "FunGame",