mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-04-23 04:29:36 +08:00
完善 HTTPClient;添加日志级别;添加匿名服务器模组;修复不同时间多客户端连接游戏模组时可能产生的线程安全问题 (#106)
* 完善 HTTPClient;添加日志级别;添加匿名服务器模组(此模组不强制要求登录、客户端安装) * 添加参数 * 添加 null 检查 * 修复不同时间多客户端连接游戏模组时可能产生的线程安全问题
This commit is contained in:
parent
ce0c933b35
commit
d23c6597d1
@ -70,13 +70,13 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
/// 插件则使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequestForAddon(DataRequestType)"/> 创建一个新的请求<para/>
|
/// 插件则使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequestForAddon(DataRequestType)"/> 创建一个新的请求<para/>
|
||||||
/// 此数据请求只能调用异步方法 <see cref="SendRequestAsync"/> 请求数据
|
/// 此数据请求只能调用异步方法 <see cref="SendRequestAsync"/> 请求数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="WebSocket"></param>
|
/// <param name="HTTPClient"></param>
|
||||||
/// <param name="RequestType"></param>
|
/// <param name="RequestType"></param>
|
||||||
/// <param name="IsLongRunning"></param>
|
/// <param name="IsLongRunning"></param>
|
||||||
/// <param name="RuntimeType"></param>
|
/// <param name="RuntimeType"></param>
|
||||||
internal DataRequest(HTTPClient WebSocket, DataRequestType RequestType, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client)
|
internal DataRequest(HTTPClient HTTPClient, DataRequestType RequestType, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client)
|
||||||
{
|
{
|
||||||
Worker = new(WebSocket, RequestType, Guid.NewGuid(), IsLongRunning, RuntimeType);
|
Worker = new(HTTPClient, RequestType, Guid.NewGuid(), IsLongRunning, RuntimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -99,13 +99,13 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
/// 此构造方法是给 <see cref="Library.Common.Addon.GameModule"/> 提供的<para/>
|
/// 此构造方法是给 <see cref="Library.Common.Addon.GameModule"/> 提供的<para/>
|
||||||
/// 此数据请求只能调用异步方法 <see cref="SendRequestAsync"/> 请求数据
|
/// 此数据请求只能调用异步方法 <see cref="SendRequestAsync"/> 请求数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="WebSocket"></param>
|
/// <param name="Client"></param>
|
||||||
/// <param name="GamingType"></param>
|
/// <param name="GamingType"></param>
|
||||||
/// <param name="IsLongRunning"></param>
|
/// <param name="IsLongRunning"></param>
|
||||||
/// <param name="RuntimeType"></param>
|
/// <param name="RuntimeType"></param>
|
||||||
internal DataRequest(HTTPClient WebSocket, GamingType GamingType, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client)
|
internal DataRequest(HTTPClient Client, GamingType GamingType, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client)
|
||||||
{
|
{
|
||||||
GamingWorker = new(WebSocket, GamingType, Guid.NewGuid(), IsLongRunning, RuntimeType);
|
GamingWorker = new(Client, GamingType, Guid.NewGuid(), IsLongRunning, RuntimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -194,7 +194,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
public string Error => _Error;
|
public string Error => _Error;
|
||||||
|
|
||||||
private readonly Socket? Socket = null;
|
private readonly Socket? Socket = null;
|
||||||
private readonly HTTPClient? WebSocket = null;
|
private readonly HTTPClient? HTTPClient = null;
|
||||||
private readonly DataRequestType RequestType = DataRequestType.UnKnown;
|
private readonly DataRequestType RequestType = DataRequestType.UnKnown;
|
||||||
private readonly Guid RequestID = Guid.Empty;
|
private readonly Guid RequestID = Guid.Empty;
|
||||||
private readonly bool IsLongRunning = false;
|
private readonly bool IsLongRunning = false;
|
||||||
@ -212,9 +212,9 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
this.RuntimeType = RuntimeType;
|
this.RuntimeType = RuntimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketRequest(HTTPClient? WebSocket, DataRequestType RequestType, Guid RequestID, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client) : base(WebSocket)
|
public SocketRequest(HTTPClient? HTTPClient, DataRequestType RequestType, Guid RequestID, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client) : base(HTTPClient)
|
||||||
{
|
{
|
||||||
this.WebSocket = WebSocket;
|
this.HTTPClient = HTTPClient;
|
||||||
this.RequestType = RequestType;
|
this.RequestType = RequestType;
|
||||||
this.RequestID = RequestID;
|
this.RequestID = RequestID;
|
||||||
this.IsLongRunning = IsLongRunning;
|
this.IsLongRunning = IsLongRunning;
|
||||||
@ -236,7 +236,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
{
|
{
|
||||||
WaitForWorkDone();
|
WaitForWorkDone();
|
||||||
}
|
}
|
||||||
else if (WebSocket != null)
|
else if (HTTPClient != null)
|
||||||
{
|
{
|
||||||
throw new AsyncSendException();
|
throw new AsyncSendException();
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
{
|
{
|
||||||
await WaitForWorkDoneAsync();
|
await WaitForWorkDoneAsync();
|
||||||
}
|
}
|
||||||
else if (WebSocket != null && await WebSocket.Send(SocketMessageType.DataRequest, RequestType, RequestID, RequestData) == SocketResult.Success)
|
else if (HTTPClient != null && await HTTPClient.Send(SocketMessageType.DataRequest, RequestType, RequestID, RequestData) == SocketResult.Success)
|
||||||
{
|
{
|
||||||
await WaitForWorkDoneAsync();
|
await WaitForWorkDoneAsync();
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
public string Error => _Error;
|
public string Error => _Error;
|
||||||
|
|
||||||
private readonly Socket? Socket = null;
|
private readonly Socket? Socket = null;
|
||||||
private readonly HTTPClient? WebSocket = null;
|
private readonly HTTPClient? HTTPClient = null;
|
||||||
private readonly GamingType GamingType = GamingType.None;
|
private readonly GamingType GamingType = GamingType.None;
|
||||||
private readonly Guid RequestID = Guid.Empty;
|
private readonly Guid RequestID = Guid.Empty;
|
||||||
private readonly bool IsLongRunning = false;
|
private readonly bool IsLongRunning = false;
|
||||||
@ -335,9 +335,9 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
this.RuntimeType = RuntimeType;
|
this.RuntimeType = RuntimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GamingRequest(HTTPClient? WebSocket, GamingType GamingType, Guid RequestID, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client) : base(WebSocket)
|
public GamingRequest(HTTPClient? HTTPClient, GamingType GamingType, Guid RequestID, bool IsLongRunning = false, SocketRuntimeType RuntimeType = SocketRuntimeType.Client) : base(HTTPClient)
|
||||||
{
|
{
|
||||||
this.WebSocket = WebSocket;
|
this.HTTPClient = HTTPClient;
|
||||||
this.GamingType = GamingType;
|
this.GamingType = GamingType;
|
||||||
this.RequestID = RequestID;
|
this.RequestID = RequestID;
|
||||||
this.IsLongRunning = IsLongRunning;
|
this.IsLongRunning = IsLongRunning;
|
||||||
@ -359,7 +359,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
{
|
{
|
||||||
WaitForWorkDone();
|
WaitForWorkDone();
|
||||||
}
|
}
|
||||||
else if (WebSocket != null)
|
else if (HTTPClient != null)
|
||||||
{
|
{
|
||||||
throw new AsyncSendException();
|
throw new AsyncSendException();
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
|
|||||||
{
|
{
|
||||||
await WaitForWorkDoneAsync();
|
await WaitForWorkDoneAsync();
|
||||||
}
|
}
|
||||||
else if (WebSocket != null && await WebSocket.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success)
|
else if (HTTPClient != null && await HTTPClient.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success)
|
||||||
{
|
{
|
||||||
await WaitForWorkDoneAsync();
|
await WaitForWorkDoneAsync();
|
||||||
}
|
}
|
||||||
|
@ -443,7 +443,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
byte[] key_bytes = General.DefaultEncoding.GetBytes(key);
|
byte[] key_bytes = General.DefaultEncoding.GetBytes(key);
|
||||||
HMACSHA512 hmacsha512 = new(key_bytes);
|
HMACSHA512 hmacsha512 = new(key_bytes);
|
||||||
byte[] hash_bytes = hmacsha512.ComputeHash(text_bytes);
|
byte[] hash_bytes = hmacsha512.ComputeHash(text_bytes);
|
||||||
string hmac = BitConverter.ToString(hash_bytes).Replace("-", "");
|
string hmac = Convert.ToHexString(hash_bytes);
|
||||||
return hmac.ToLower();
|
return hmac.ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,12 +452,12 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="file_path">要计算哈希值的文件路径</param>
|
/// <param name="file_path">要计算哈希值的文件路径</param>
|
||||||
/// <returns>文件的 SHA-256 哈希值</returns>
|
/// <returns>文件的 SHA-256 哈希值</returns>
|
||||||
public static string FileSha512(string file_path)
|
public static string FileSha256(string file_path)
|
||||||
{
|
{
|
||||||
using SHA256 sha256 = SHA256.Create();
|
using SHA256 sha256 = SHA256.Create();
|
||||||
using FileStream stream = File.OpenRead(file_path);
|
using FileStream stream = File.OpenRead(file_path);
|
||||||
byte[] hash = sha256.ComputeHash(stream);
|
byte[] hash = sha256.ComputeHash(stream);
|
||||||
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
return Convert.ToHexStringLower(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -471,7 +471,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
byte[] plain = General.DefaultEncoding.GetBytes(plain_text);
|
byte[] plain = General.DefaultEncoding.GetBytes(plain_text);
|
||||||
using RSACryptoServiceProvider rsa = new();
|
using RSACryptoServiceProvider rsa = new();
|
||||||
rsa.FromXmlString(plublic_key);
|
rsa.FromXmlString(plublic_key);
|
||||||
byte[] encrypted = rsa.Encrypt(plain, false);
|
byte[] encrypted = rsa.Encrypt(plain, true);
|
||||||
return Convert.ToBase64String(encrypted);
|
return Convert.ToBase64String(encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,7 +486,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
byte[] secret = Convert.FromBase64String(secret_text);
|
byte[] secret = Convert.FromBase64String(secret_text);
|
||||||
using RSACryptoServiceProvider rsa = new();
|
using RSACryptoServiceProvider rsa = new();
|
||||||
rsa.FromXmlString(private_key);
|
rsa.FromXmlString(private_key);
|
||||||
byte[] decrypted = rsa.Decrypt(secret, false);
|
byte[] decrypted = rsa.Decrypt(secret, true);
|
||||||
return General.DefaultEncoding.GetString(decrypted);
|
return General.DefaultEncoding.GetString(decrypted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,12 +76,16 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
WriteINI("Account", "AutoKey", "");
|
WriteINI("Account", "AutoKey", "");
|
||||||
break;
|
break;
|
||||||
case FunGameInfo.FunGame.FunGame_Server:
|
case FunGameInfo.FunGame.FunGame_Server:
|
||||||
|
/**
|
||||||
|
* Console
|
||||||
|
*/
|
||||||
|
WriteINI("Console", "LogLevel", "INFO");
|
||||||
/**
|
/**
|
||||||
* Server
|
* Server
|
||||||
*/
|
*/
|
||||||
WriteINI("Server", "Name", "FunGame Server");
|
WriteINI("Server", "Name", "FunGame Server");
|
||||||
WriteINI("Server", "Password", "");
|
WriteINI("Server", "Password", "");
|
||||||
WriteINI("Server", "Describe", "Just Another FunGame Server.");
|
WriteINI("Server", "Description", "Just Another FunGame Server.");
|
||||||
WriteINI("Server", "Notice", "This is the FunGame Server's Notice.");
|
WriteINI("Server", "Notice", "This is the FunGame Server's Notice.");
|
||||||
WriteINI("Server", "Key", "");
|
WriteINI("Server", "Key", "");
|
||||||
WriteINI("Server", "Status", "1");
|
WriteINI("Server", "Status", "1");
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Milimoe.FunGame.Core.Interface.Addons;
|
using Milimoe.FunGame.Core.Interface.Addons;
|
||||||
using Milimoe.FunGame.Core.Library.Common.Addon;
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Controller
|
namespace Milimoe.FunGame.Core.Controller
|
||||||
{
|
{
|
||||||
@ -17,7 +18,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 输出系统消息
|
/// 输出系统消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Action<string> MaskMethod_WriteLine { get; set; }
|
protected Action<string, string, LogLevel, bool> MaskMethod_WriteLine { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 输出错误消息
|
/// 输出错误消息
|
||||||
@ -28,8 +29,10 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
/// 输出系统消息
|
/// 输出系统消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="msg"></param>
|
/// <param name="msg"></param>
|
||||||
|
/// <param name="level"></param>
|
||||||
|
/// <param name="useLevel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public void WriteLine(string msg) => MaskMethod_WriteLine(msg);
|
public void WriteLine(string msg, LogLevel level = LogLevel.Info, bool useLevel = true) => MaskMethod_WriteLine(Addon.Name, msg, level, useLevel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 输出错误消息
|
/// 输出错误消息
|
||||||
@ -46,7 +49,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
public BaseAddonController(IAddon addon, Dictionary<string, object> delegates)
|
public BaseAddonController(IAddon addon, Dictionary<string, object> delegates)
|
||||||
{
|
{
|
||||||
Addon = (T)addon;
|
Addon = (T)addon;
|
||||||
if (delegates.TryGetValue("WriteLine", out object? value)) MaskMethod_WriteLine = value != null ? (Action<string>)value : new(DefaultPrint);
|
if (delegates.TryGetValue("WriteLine", out object? value)) MaskMethod_WriteLine = value != null ? (Action<string, string, LogLevel, bool>)value : new(DefaultPrint);
|
||||||
if (delegates.TryGetValue("Error", out value)) MaskMethod_Error = value != null ? (Action<Exception>)value : new(DefaultPrint);
|
if (delegates.TryGetValue("Error", out value)) MaskMethod_Error = value != null ? (Action<Exception>)value : new(DefaultPrint);
|
||||||
MaskMethod_WriteLine ??= new(DefaultPrint);
|
MaskMethod_WriteLine ??= new(DefaultPrint);
|
||||||
MaskMethod_Error ??= new(DefaultPrint);
|
MaskMethod_Error ??= new(DefaultPrint);
|
||||||
@ -55,15 +58,22 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认的输出错误消息方法
|
/// 默认的输出错误消息方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
/// <param name="msg"></param>
|
/// <param name="msg"></param>
|
||||||
|
/// <param name="level"></param>
|
||||||
|
/// <param name="useLevel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private void DefaultPrint(string msg) => Console.Write("\r" + msg + "\n\r> ");
|
private void DefaultPrint(string name, string msg, LogLevel level = LogLevel.Info, bool useLevel = true)
|
||||||
|
{
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
Console.Write("\r" + now.AddMilliseconds(-now.Millisecond).ToString() + $" {CommonSet.GetLogLevelPrefix(level)}/[Addon] {Addon.Name}:\n\r> ");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 输出错误消息
|
/// 输出错误消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private void DefaultPrint(Exception e) => DefaultPrint(e.ToString());
|
private void DefaultPrint(Exception e) => DefaultPrint(Addon.Name, e.ToString(), LogLevel.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 与服务器的连接套接字实例(WebSocket)
|
/// 与服务器的连接套接字实例(WebSocket)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HTTPClient? WebSocket => _WebSocket;
|
public HTTPClient? HTTPClient => _HTTPClient;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 套接字是否已经连接
|
/// 套接字是否已经连接
|
||||||
@ -41,7 +41,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于类内赋值
|
/// 用于类内赋值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected HTTPClient? _WebSocket;
|
protected HTTPClient? _HTTPClient;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否正在接收服务器信息
|
/// 是否正在接收服务器信息
|
||||||
@ -204,6 +204,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
_Socket.ConnectionLost += Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,12 +232,12 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
string serverName = "";
|
string serverName = "";
|
||||||
string notice = "";
|
string notice = "";
|
||||||
|
|
||||||
_WebSocket?.Close();
|
_HTTPClient?.Close();
|
||||||
_WebSocket = await HTTPClient.Connect(address, ssl, port, subUrl, connectArgs.Cast<object>().ToArray());
|
_HTTPClient = await HTTPClient.Connect(address, ssl, port, subUrl, connectArgs.Cast<object>().ToArray());
|
||||||
if (_WebSocket.Connected)
|
if (_HTTPClient.Connected)
|
||||||
{
|
{
|
||||||
bool webSocketConnected = false;
|
bool webSocketConnected = false;
|
||||||
_WebSocket.AddSocketObjectHandler(obj =>
|
_HTTPClient.AddSocketObjectHandler(obj =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -247,7 +248,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
result = success ? ConnectResult.Success : ConnectResult.ConnectFailed;
|
result = success ? ConnectResult.Success : ConnectResult.ConnectFailed;
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
_WebSocket.Token = obj.GetParam<Guid>(2);
|
_HTTPClient.Token = obj.GetParam<Guid>(2);
|
||||||
serverName = obj.GetParam<string>(3) ?? "";
|
serverName = obj.GetParam<string>(3) ?? "";
|
||||||
notice = obj.GetParam<string>(4) ?? "";
|
notice = obj.GetParam<string>(4) ?? "";
|
||||||
}
|
}
|
||||||
@ -265,10 +266,11 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
}
|
}
|
||||||
|
_HTTPClient.ConnectionLost += Error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_WebSocket?.Close();
|
_HTTPClient?.Close();
|
||||||
result = ConnectResult.ConnectFailed;
|
result = ConnectResult.ConnectFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,10 +372,10 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_WebSocket != null)
|
if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
_WebSocket.Close();
|
_HTTPClient.Close();
|
||||||
_WebSocket = null;
|
_HTTPClient = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -388,7 +390,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
/// 输出消息
|
/// 输出消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="msg"></param>
|
/// <param name="msg"></param>
|
||||||
public abstract void WritelnSystemInfo(string msg);
|
/// <param name="level"></param>
|
||||||
|
/// <param name="useLevel"></param>
|
||||||
|
public abstract void WritelnSystemInfo(string msg, LogLevel level = LogLevel.Info, bool useLevel = true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 自定处理异常的方法
|
/// 自定处理异常的方法
|
||||||
@ -410,9 +414,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
DataRequest request = new(_Socket, RequestType);
|
DataRequest request = new(_Socket, RequestType);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
else if (_WebSocket != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
DataRequest request = new(_WebSocket, RequestType);
|
DataRequest request = new(_HTTPClient, RequestType);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
throw new ConnectFailedException();
|
throw new ConnectFailedException();
|
||||||
@ -431,9 +435,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
DataRequest request = new(_Socket, RequestType, true);
|
DataRequest request = new(_Socket, RequestType, true);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
else if (_WebSocket != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
DataRequest request = new(_WebSocket, RequestType, true);
|
DataRequest request = new(_HTTPClient, RequestType, true);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
throw new ConnectFailedException();
|
throw new ConnectFailedException();
|
||||||
@ -453,9 +457,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
DataRequest request = new(_Socket, RequestType, false, SocketRuntimeType.Addon);
|
DataRequest request = new(_Socket, RequestType, false, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
else if (_WebSocket != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
DataRequest request = new(_WebSocket, RequestType, false, SocketRuntimeType.Addon);
|
DataRequest request = new(_HTTPClient, RequestType, false, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
throw new ConnectFailedException();
|
throw new ConnectFailedException();
|
||||||
@ -475,9 +479,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
DataRequest request = new(_Socket, RequestType, true, SocketRuntimeType.Addon);
|
DataRequest request = new(_Socket, RequestType, true, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
else if (_WebSocket != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
DataRequest request = new(_WebSocket, RequestType, true, SocketRuntimeType.Addon);
|
DataRequest request = new(_HTTPClient, RequestType, true, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
throw new ConnectFailedException();
|
throw new ConnectFailedException();
|
||||||
@ -497,9 +501,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
DataRequest request = new(_Socket, GamingType, false, SocketRuntimeType.Addon);
|
DataRequest request = new(_Socket, GamingType, false, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
else if (_WebSocket != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
DataRequest request = new(_WebSocket, GamingType, false, SocketRuntimeType.Addon);
|
DataRequest request = new(_HTTPClient, GamingType, false, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
throw new ConnectFailedException();
|
throw new ConnectFailedException();
|
||||||
@ -519,9 +523,9 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
DataRequest request = new(_Socket, GamingType, true, SocketRuntimeType.Addon);
|
DataRequest request = new(_Socket, GamingType, true, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
else if (_WebSocket != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
DataRequest request = new(_WebSocket, GamingType, true, SocketRuntimeType.Addon);
|
DataRequest request = new(_HTTPClient, GamingType, true, SocketRuntimeType.Addon);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
throw new ConnectFailedException();
|
throw new ConnectFailedException();
|
||||||
@ -576,8 +580,8 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// 报错中断服务器连接
|
_Socket?.OnConnectionLost(e);
|
||||||
Error(e);
|
Close_Socket();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -642,6 +646,10 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
SocketHandler_Gaming(obj);
|
SocketHandler_Gaming(obj);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SocketMessageType.AnonymousGameServer:
|
||||||
|
SocketHandler_AnonymousGameServer(obj);
|
||||||
|
break;
|
||||||
|
|
||||||
case SocketMessageType.Unknown:
|
case SocketMessageType.Unknown:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -735,5 +743,14 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 客户端接收并处理匿名服务器的消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ServerMessage"></param>
|
||||||
|
protected virtual void SocketHandler_AnonymousGameServer(SocketObject ServerMessage)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteLine("已经创建过 SQLHelper 实例。");
|
WriteLine("已经创建过 SQLHelper 实例。", Library.Constant.LogLevel.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ namespace Milimoe.FunGame.Core.Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteLine("已经创建过 MailSender 实例。");
|
WriteLine("已经创建过 MailSender 实例。", Library.Constant.LogLevel.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,6 @@ namespace Milimoe.FunGame.Core.Interface.Addons
|
|||||||
{
|
{
|
||||||
public bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] args);
|
public bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] args);
|
||||||
|
|
||||||
public Task<Dictionary<string, object>> GamingMessageHandler(string username, GamingType type, Dictionary<string, object> data);
|
public Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
using Milimoe.FunGame.Core.Api.Transmittal;
|
using Milimoe.FunGame.Core.Api.Transmittal;
|
||||||
using Milimoe.FunGame.Core.Api.Utility;
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Entity;
|
||||||
@ -128,29 +129,31 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
|
|
||||||
public override GameModuleDepend GameModuleDepend => ExampleGameModuleConstant.GameModuleDepend;
|
public override GameModuleDepend GameModuleDepend => ExampleGameModuleConstant.GameModuleDepend;
|
||||||
|
|
||||||
protected Room Room = General.HallInstance;
|
private readonly struct ModuleServerWorker(Room room, List<User> users, IServerModel roomMaster, Dictionary<string, IServerModel> serverModels)
|
||||||
protected List<User> Users = [];
|
{
|
||||||
protected IServerModel? RoomMaster;
|
public Room Room { get; } = room;
|
||||||
protected Dictionary<string, IServerModel> All = [];
|
public List<User> Users { get; } = users;
|
||||||
|
public IServerModel RoomMaster { get; } = roomMaster;
|
||||||
|
public Dictionary<string, IServerModel> All { get; } = serverModels;
|
||||||
|
public List<User> ConnectedUser { get; } = [];
|
||||||
|
public Dictionary<string, Dictionary<string, object>> UserData { get; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConcurrentDictionary<string, ModuleServerWorker> Workers { get; } = [];
|
||||||
|
|
||||||
public override bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] Args)
|
public override bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] Args)
|
||||||
{
|
{
|
||||||
// 将参数转为本地属性
|
// 因为模组是单例的,需要为这个房间创建一个工作类接收参数,不能直接用本地变量处理
|
||||||
this.Room = Room;
|
ModuleServerWorker worker = new(Room, Users, RoomMasterServerModel, ServerModels);
|
||||||
this.Users = Users;
|
Workers[Room.Roomid] = worker;
|
||||||
RoomMaster = RoomMasterServerModel;
|
|
||||||
All = ServerModels;
|
|
||||||
// 创建一个线程执行Test()
|
// 创建一个线程执行Test()
|
||||||
TaskUtility.NewTask(Test).OnError(Controller.Error);
|
TaskUtility.NewTask(async () => await Test(worker)).OnError(Controller.Error);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<User> ConnectedUser = [];
|
private async Task Test(ModuleServerWorker worker)
|
||||||
private readonly Dictionary<string, Dictionary<string, object>> UserData = [];
|
|
||||||
|
|
||||||
private async Task Test()
|
|
||||||
{
|
{
|
||||||
Controller.WriteLine("欢迎各位玩家进入房间 " + Room.Roomid + " 。");
|
Controller.WriteLine("欢迎各位玩家进入房间 " + worker.Room.Roomid + " 。");
|
||||||
|
|
||||||
// 通常,我们可以对客户端的连接状态进行确认,此方法展示如何确认客户端的连接
|
// 通常,我们可以对客户端的连接状态进行确认,此方法展示如何确认客户端的连接
|
||||||
// 有两种确认的方式,1是服务器主动确认,2是客户端发起确认
|
// 有两种确认的方式,1是服务器主动确认,2是客户端发起确认
|
||||||
@ -165,33 +168,36 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
data.Add("connect_token", token);
|
data.Add("connect_token", token);
|
||||||
|
|
||||||
// 我们保存到字典UserData中,这样可以方便跨方法检查变量
|
// 我们保存到字典UserData中,这样可以方便跨方法检查变量
|
||||||
foreach (string username in Users.Select(u => u.Username).Distinct())
|
foreach (string username in worker.Users.Select(u => u.Username).Distinct())
|
||||||
{
|
{
|
||||||
if (UserData.TryGetValue(username, out Dictionary<string, object>? value))
|
if (worker.UserData.TryGetValue(username, out Dictionary<string, object>? value))
|
||||||
{
|
{
|
||||||
value.Add("connect_token", token);
|
value.Add("connect_token", token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UserData.Add(username, []);
|
worker.UserData.Add(username, []);
|
||||||
UserData[username].Add("connect_token", token);
|
worker.UserData[username].Add("connect_token", token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await SendGamingMessage(All.Values, GamingType.UpdateInfo, data);
|
await SendGamingMessage(worker.All.Values, GamingType.UpdateInfo, data);
|
||||||
|
|
||||||
// 新建一个线程等待所有玩家确认
|
// 新建一个线程等待所有玩家确认
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (ConnectedUser.Count == Users.Count) break;
|
if (worker.ConnectedUser.Count == worker.Users.Count) break;
|
||||||
// 每200ms确认一次,不需要太频繁
|
// 每200ms确认一次,不需要太频繁
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
}
|
}
|
||||||
Controller.WriteLine("所有玩家都已经连接。");
|
Controller.WriteLine("所有玩家都已经连接。");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Dictionary<string, object>> GamingMessageHandler(string username, GamingType type, Dictionary<string, object> data)
|
public override async Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> result = [];
|
Dictionary<string, object> result = [];
|
||||||
|
// 获取model所在的房间工作类
|
||||||
|
ModuleServerWorker worker = Workers[model.InRoom.Roomid];
|
||||||
|
string username = model.User.Username;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -200,12 +206,12 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
// 如果需要处理客户端传递的参数:获取与客户端约定好的参数key对应的值
|
// 如果需要处理客户端传递的参数:获取与客户端约定好的参数key对应的值
|
||||||
string un = NetworkUtility.JsonDeserializeFromDictionary<string>(data, "username") ?? "";
|
string un = NetworkUtility.JsonDeserializeFromDictionary<string>(data, "username") ?? "";
|
||||||
Guid token = NetworkUtility.JsonDeserializeFromDictionary<Guid>(data, "connect_token");
|
Guid token = NetworkUtility.JsonDeserializeFromDictionary<Guid>(data, "connect_token");
|
||||||
if (un == username && UserData.TryGetValue(username, out Dictionary<string, object>? value) && value != null && (value["connect_token"]?.Equals(token) ?? false))
|
if (un == username && worker.UserData.TryGetValue(username, out Dictionary<string, object>? value) && value != null && (value["connect_token"]?.Equals(token) ?? false))
|
||||||
{
|
{
|
||||||
ConnectedUser.Add(Users.Where(u => u.Username == username).First());
|
worker.ConnectedUser.Add(worker.Users.Where(u => u.Username == username).First());
|
||||||
Controller.WriteLine(username + " 已经连接。");
|
Controller.WriteLine(username + " 已经连接。");
|
||||||
}
|
}
|
||||||
else Controller.WriteLine(username + " 确认连接失败!");
|
else Controller.WriteLine(username + " 确认连接失败!", LogLevel.Warning);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
await Task.Delay(1);
|
await Task.Delay(1);
|
||||||
@ -214,6 +220,53 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected HashSet<IServerModel> _clientModels = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 匿名服务器示例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override bool StartAnonymousServer(IServerModel model, Dictionary<string, object> data)
|
||||||
|
{
|
||||||
|
// 可以做验证处理
|
||||||
|
string access_token = NetworkUtility.JsonDeserializeFromDictionary<string>(data, "access_token") ?? "";
|
||||||
|
if (access_token == "approval_access_token")
|
||||||
|
{
|
||||||
|
// 接收连接匿名服务器的客户端
|
||||||
|
_clientModels.Add(model);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CloseAnonymousServer(IServerModel model)
|
||||||
|
{
|
||||||
|
// 移除客户端
|
||||||
|
_clientModels.Remove(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 接收并处理匿名服务器消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override async Task<Dictionary<string, object>> AnonymousGameServerHandler(IServerModel model, Dictionary<string, object> data)
|
||||||
|
{
|
||||||
|
Dictionary<string, object> result = [];
|
||||||
|
|
||||||
|
// 根据服务器和客户端的数据传输约定,自行处理 data,并返回。
|
||||||
|
if (data.Count > 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
result.Add("msg", "匿名服务器已经收到消息了");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -39,6 +39,11 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract GameModuleDepend GameModuleDepend { get; }
|
public abstract GameModuleDepend GameModuleDepend { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是匿名服务器
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsAnonymous { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 包含了一些常用方法的控制器
|
/// 包含了一些常用方法的控制器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -77,11 +82,45 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 接收并处理GamingMessage
|
/// 接收并处理GamingMessage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="username">发送此消息的账号</param>
|
/// <param name="model">发送此消息的客户端</param>
|
||||||
/// <param name="type">消息类型</param>
|
/// <param name="type">消息类型</param>
|
||||||
/// <param name="data">消息参数</param>
|
/// <param name="data">消息参数</param>
|
||||||
/// <returns>底层会将字典中的数据发送给客户端</returns>
|
/// <returns>底层会将字典中的数据发送给客户端</returns>
|
||||||
public abstract Task<Dictionary<string, object>> GamingMessageHandler(string username, GamingType type, Dictionary<string, object> data);
|
public abstract Task<Dictionary<string, object>> GamingMessageHandler(IServerModel model, GamingType type, Dictionary<string, object> data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动匿名服务器监听
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual bool StartAnonymousServer(IServerModel model, Dictionary<string, object> data)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 结束匿名服务器监听
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual void CloseAnonymousServer(IServerModel model)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 接收并处理匿名服务器监听消息<para/>
|
||||||
|
/// 此方法为可选实现,可以帮助 RESTful API 处理不需要验证的 WebSocket 请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">发送此消息的客户端</param>
|
||||||
|
/// <param name="data">消息参数</param>
|
||||||
|
/// <returns>底层会将字典中的数据发送给客户端</returns>
|
||||||
|
public virtual async Task<Dictionary<string, object>> AnonymousGameServerHandler(IServerModel model, Dictionary<string, object> data)
|
||||||
|
{
|
||||||
|
await Task.Delay(1);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载标记
|
/// 加载标记
|
||||||
@ -129,13 +168,24 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <param name="clients"></param>
|
/// <param name="clients"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
protected virtual async Task SendGamingMessage(IEnumerable<IServerModel> clients, GamingType type, Dictionary<string, object> data)
|
/// <returns>发送失败的客户端</returns>
|
||||||
|
protected virtual async Task<List<IServerModel>> SendGamingMessage(IEnumerable<IServerModel> clients, GamingType type, Dictionary<string, object> data)
|
||||||
{
|
{
|
||||||
// 发送局内消息
|
// 发送局内消息
|
||||||
|
List<IServerModel> failedModels = [];
|
||||||
foreach (IServerModel s in clients)
|
foreach (IServerModel s in clients)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await s.Send(SocketMessageType.Gaming, type, data);
|
await s.Send(SocketMessageType.Gaming, type, data);
|
||||||
}
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Controller.Error(e);
|
||||||
|
failedModels.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failedModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -144,13 +194,48 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <param name="clients"></param>
|
/// <param name="clients"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="args"></param>
|
/// <param name="args"></param>
|
||||||
protected virtual async Task Send(IEnumerable<IServerModel> clients, SocketMessageType type, params object[] args)
|
/// <returns>发送失败的客户端</returns>
|
||||||
|
protected virtual async Task<List<IServerModel>> Send(IEnumerable<IServerModel> clients, SocketMessageType type, params object[] args)
|
||||||
{
|
{
|
||||||
// 发送消息
|
// 发送消息
|
||||||
|
List<IServerModel> failedModels = [];
|
||||||
foreach (IServerModel s in clients)
|
foreach (IServerModel s in clients)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await s.Send(type, args);
|
await s.Send(type, args);
|
||||||
}
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Controller.Error(e);
|
||||||
|
failedModels.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failedModels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 给客户端发送匿名服务器消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clients"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns>发送失败的客户端</returns>
|
||||||
|
protected virtual async Task<List<IServerModel>> SendAnonymousGameServerMessage(IEnumerable<IServerModel> clients, Dictionary<string, object> data)
|
||||||
|
{
|
||||||
|
List<IServerModel> failedModels = [];
|
||||||
|
foreach (IServerModel s in clients)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await s.Send(SocketMessageType.AnonymousGameServer, data);
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Controller.Error(e);
|
||||||
|
failedModels.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failedModels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendHeartBeat()
|
private async Task SendHeartBeat()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
if (_Socket != null)
|
if (_Socket != null)
|
||||||
@ -71,7 +73,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
|
|||||||
}
|
}
|
||||||
else if (_HTTPClient != null)
|
else if (_HTTPClient != null)
|
||||||
{
|
{
|
||||||
while (_HTTPClient.Instance?.State == System.Net.WebSockets.WebSocketState.Open)
|
while (_HTTPClient.WebSocket?.State == System.Net.WebSockets.WebSocketState.Open)
|
||||||
{
|
{
|
||||||
if (!SendingHeartBeat) _SendingHeartBeat = true;
|
if (!SendingHeartBeat) _SendingHeartBeat = true;
|
||||||
// 发送心跳包
|
// 发送心跳包
|
||||||
@ -86,6 +88,20 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
|
|||||||
}
|
}
|
||||||
_SendingHeartBeat = false;
|
_SendingHeartBeat = false;
|
||||||
}
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
if (_Socket != null)
|
||||||
|
{
|
||||||
|
_Socket.OnConnectionLost(e);
|
||||||
|
_Socket.Close();
|
||||||
|
}
|
||||||
|
if (_HTTPClient != null)
|
||||||
|
{
|
||||||
|
_HTTPClient.OnConnectionLost(e);
|
||||||
|
_HTTPClient.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void AddHeartBeatFaileds()
|
private void AddHeartBeatFaileds()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Interface.HTTP;
|
using Milimoe.FunGame.Core.Interface.HTTP;
|
||||||
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
@ -9,23 +10,28 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
{
|
{
|
||||||
public class HTTPClient : IHTTPClient
|
public class HTTPClient : IHTTPClient
|
||||||
{
|
{
|
||||||
public System.Net.WebSockets.ClientWebSocket? Instance { get; } = null;
|
public HttpClient Instance { get; }
|
||||||
|
public ClientWebSocket? WebSocket { get; } = null;
|
||||||
public SocketRuntimeType Runtime => SocketRuntimeType.Client;
|
public SocketRuntimeType Runtime => SocketRuntimeType.Client;
|
||||||
public Guid Token { get; set; } = Guid.Empty;
|
public Guid Token { get; set; } = Guid.Empty;
|
||||||
public string ServerAddress { get; } = "";
|
public string ServerAddress { get; } = "";
|
||||||
public int ServerPort { get; } = 0;
|
public int ServerPort { get; } = 0;
|
||||||
public string ServerName { get; } = "";
|
public string ServerName { get; } = "";
|
||||||
public string ServerNotice { get; } = "";
|
public string ServerNotice { get; } = "";
|
||||||
public bool Connected => Instance != null && Instance.State == WebSocketState.Open;
|
public bool Connected => WebSocket != null && WebSocket.State == WebSocketState.Open;
|
||||||
public bool Receiving => _receiving;
|
public bool Receiving => _receiving;
|
||||||
private HeartBeat HeartBeat { get; }
|
private HeartBeat HeartBeat { get; }
|
||||||
|
|
||||||
|
public event Action<System.Exception>? ConnectionLost;
|
||||||
|
public event Action? Closed;
|
||||||
|
|
||||||
private bool _receiving = false;
|
private bool _receiving = false;
|
||||||
private readonly HashSet<Action<SocketObject>> _boundEvents = [];
|
private readonly HashSet<Action<SocketObject>> _boundEvents = [];
|
||||||
|
|
||||||
private HTTPClient(ClientWebSocket instance, string serverAddress, int serverPort, params object[] args)
|
private HTTPClient(ClientWebSocket websocket, string serverAddress, int serverPort, params object[] args)
|
||||||
{
|
{
|
||||||
Instance = instance;
|
Instance = new();
|
||||||
|
WebSocket = websocket;
|
||||||
ServerAddress = serverAddress;
|
ServerAddress = serverAddress;
|
||||||
ServerPort = serverPort;
|
ServerPort = serverPort;
|
||||||
HeartBeat = new(this);
|
HeartBeat = new(this);
|
||||||
@ -55,8 +61,9 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
{
|
{
|
||||||
|
OnConnectionLost(e);
|
||||||
Close();
|
Close();
|
||||||
Api.Utility.TXTHelper.AppendErrorLog(e.GetErrorInfo());
|
TXTHelper.AppendErrorLog(e.GetErrorInfo());
|
||||||
throw new SocketWrongInfoException();
|
throw new SocketWrongInfoException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,13 +71,46 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
|
|
||||||
public async Task<SocketResult> Send(SocketMessageType type, params object[] objs)
|
public async Task<SocketResult> Send(SocketMessageType type, params object[] objs)
|
||||||
{
|
{
|
||||||
if (Instance != null)
|
if (WebSocket != null)
|
||||||
{
|
{
|
||||||
return await HTTPManager.Send(Instance, new(type, Token, objs));
|
return await HTTPManager.Send(WebSocket, new(type, Token, objs));
|
||||||
}
|
}
|
||||||
return SocketResult.NotSent;
|
return SocketResult.NotSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送 GET 请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<T?> HttpGet<T>(string url)
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = await Instance.GetAsync(url);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
string content = await response.Content.ReadAsStringAsync();
|
||||||
|
T? result = NetworkUtility.JsonDeserialize<T>(content);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送 POST 请求
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <param name="json"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<T?> HttpPost<T>(string url, string json)
|
||||||
|
{
|
||||||
|
HttpContent content = new StringContent(json, General.DefaultEncoding, "application/json");
|
||||||
|
HttpResponseMessage response = await Instance.PostAsync(url, content);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
string read = await response.Content.ReadAsStringAsync();
|
||||||
|
T? result = NetworkUtility.JsonDeserialize<T>(read);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddSocketObjectHandler(Action<SocketObject> method)
|
public void AddSocketObjectHandler(Action<SocketObject> method)
|
||||||
{
|
{
|
||||||
if (_boundEvents.Add(method))
|
if (_boundEvents.Add(method))
|
||||||
@ -85,23 +125,32 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
SocketManager.SocketReceive -= new SocketManager.SocketReceiveHandler(method);
|
SocketManager.SocketReceive -= new SocketManager.SocketReceiveHandler(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnConnectionLost(System.Exception e)
|
||||||
|
{
|
||||||
|
ConnectionLost?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
|
Instance.Dispose();
|
||||||
_receiving = false;
|
_receiving = false;
|
||||||
HeartBeat.StopSendingHeartBeat();
|
HeartBeat.StopSendingHeartBeat();
|
||||||
Instance?.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
WebSocket?.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||||
Instance?.Dispose();
|
WebSocket?.Dispose();
|
||||||
foreach (Action<SocketObject> method in _boundEvents.ToList())
|
foreach (Action<SocketObject> method in _boundEvents.ToList())
|
||||||
{
|
{
|
||||||
RemoveSocketObjectHandler(method);
|
RemoveSocketObjectHandler(method);
|
||||||
}
|
}
|
||||||
|
Closed?.Invoke();
|
||||||
|
ConnectionLost = null;
|
||||||
|
Closed = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartListening(params object[] args)
|
private async Task StartListening(params object[] args)
|
||||||
{
|
{
|
||||||
if (Instance != null && Instance.State == WebSocketState.Open)
|
if (WebSocket != null && WebSocket.State == WebSocketState.Open)
|
||||||
{
|
{
|
||||||
if (await HTTPManager.Send(Instance, new(SocketMessageType.Connect, Guid.Empty, args)) == SocketResult.Success && await HTTPManager.ReceiveMessage(this))
|
if (await HTTPManager.Send(WebSocket, new(SocketMessageType.Connect, Guid.Empty, args)) == SocketResult.Success && await HTTPManager.ReceiveMessage(this))
|
||||||
{
|
{
|
||||||
_receiving = true;
|
_receiving = true;
|
||||||
await Receive();
|
await Receive();
|
||||||
|
@ -19,6 +19,9 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
public bool Receiving => _receiving;
|
public bool Receiving => _receiving;
|
||||||
private HeartBeat HeartBeat { get; }
|
private HeartBeat HeartBeat { get; }
|
||||||
|
|
||||||
|
public event Action<System.Exception>? ConnectionLost;
|
||||||
|
public event Action? Closed;
|
||||||
|
|
||||||
private Task? _receivingTask;
|
private Task? _receivingTask;
|
||||||
private bool _receiving = false;
|
private bool _receiving = false;
|
||||||
private readonly HashSet<Action<SocketObject>> _boundEvents = [];
|
private readonly HashSet<Action<SocketObject>> _boundEvents = [];
|
||||||
@ -61,6 +64,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
{
|
{
|
||||||
|
OnConnectionLost(e);
|
||||||
|
Close();
|
||||||
Api.Utility.TXTHelper.AppendErrorLog(e.GetErrorInfo());
|
Api.Utility.TXTHelper.AppendErrorLog(e.GetErrorInfo());
|
||||||
throw new SocketWrongInfoException();
|
throw new SocketWrongInfoException();
|
||||||
}
|
}
|
||||||
@ -80,6 +85,11 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
SocketManager.SocketReceive -= new SocketManager.SocketReceiveHandler(method);
|
SocketManager.SocketReceive -= new SocketManager.SocketReceiveHandler(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnConnectionLost(System.Exception e)
|
||||||
|
{
|
||||||
|
ConnectionLost?.Invoke(e);
|
||||||
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
HeartBeat.StopSendingHeartBeat();
|
HeartBeat.StopSendingHeartBeat();
|
||||||
@ -89,6 +99,9 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
|
|||||||
{
|
{
|
||||||
RemoveSocketObjectHandler(method);
|
RemoveSocketObjectHandler(method);
|
||||||
}
|
}
|
||||||
|
Closed?.Invoke();
|
||||||
|
ConnectionLost = null;
|
||||||
|
Closed = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartReceiving(Task t)
|
public void StartReceiving(Task t)
|
||||||
|
@ -3,6 +3,23 @@
|
|||||||
*/
|
*/
|
||||||
namespace Milimoe.FunGame.Core.Library.Constant
|
namespace Milimoe.FunGame.Core.Library.Constant
|
||||||
{
|
{
|
||||||
|
public class CommonSet
|
||||||
|
{
|
||||||
|
public static string GetLogLevelPrefix(LogLevel level)
|
||||||
|
{
|
||||||
|
return level switch
|
||||||
|
{
|
||||||
|
LogLevel.Trace => "T/",
|
||||||
|
LogLevel.Debug => "D/",
|
||||||
|
LogLevel.Info => "I/",
|
||||||
|
LogLevel.Warning => "W/",
|
||||||
|
LogLevel.Error => "E/",
|
||||||
|
LogLevel.Critical => "C/",
|
||||||
|
_ => "I/"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配合 <see cref="InterfaceMethod"/> <see cref="InterfaceType"/> 使用,也别忘了修改 <see cref="Api.Utility.Implement"/>
|
/// 配合 <see cref="InterfaceMethod"/> <see cref="InterfaceType"/> 使用,也别忘了修改 <see cref="Api.Utility.Implement"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -49,6 +66,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
public const string StartGame = "StartGame";
|
public const string StartGame = "StartGame";
|
||||||
public const string EndGame = "EndGame";
|
public const string EndGame = "EndGame";
|
||||||
public const string Gaming = "Gaming";
|
public const string Gaming = "Gaming";
|
||||||
|
public const string AnonymousGameServer = "AnonymousGameServer";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将通信类型的枚举转换为字符串
|
/// 将通信类型的枚举转换为字符串
|
||||||
|
@ -77,7 +77,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
MatchRoom,
|
MatchRoom,
|
||||||
StartGame,
|
StartGame,
|
||||||
EndGame,
|
EndGame,
|
||||||
Gaming
|
Gaming,
|
||||||
|
AnonymousGameServer
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -809,4 +810,14 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Immediate,
|
Immediate,
|
||||||
Progressive
|
Progressive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
Trace,
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Critical
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,9 @@ namespace Milimoe.FunGame.Core.Service
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uri"></param>
|
/// <param name="uri"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static async Task<System.Net.WebSockets.ClientWebSocket?> Connect(Uri uri)
|
internal static async Task<ClientWebSocket?> Connect(Uri uri)
|
||||||
{
|
{
|
||||||
System.Net.WebSockets.ClientWebSocket socket = new();
|
ClientWebSocket socket = new();
|
||||||
await socket.ConnectAsync(uri, CancellationToken.None);
|
await socket.ConnectAsync(uri, CancellationToken.None);
|
||||||
if (socket.State == WebSocketState.Open)
|
if (socket.State == WebSocketState.Open)
|
||||||
{
|
{
|
||||||
@ -55,7 +55,7 @@ namespace Milimoe.FunGame.Core.Service
|
|||||||
/// <param name="socket"></param>
|
/// <param name="socket"></param>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static async Task<SocketResult> Send(System.Net.WebSockets.ClientWebSocket socket, SocketObject obj)
|
internal static async Task<SocketResult> Send(ClientWebSocket socket, SocketObject obj)
|
||||||
{
|
{
|
||||||
if (socket != null)
|
if (socket != null)
|
||||||
{
|
{
|
||||||
@ -176,12 +176,12 @@ namespace Milimoe.FunGame.Core.Service
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static async Task<bool> ReceiveMessage(HTTPClient client)
|
internal static async Task<bool> ReceiveMessage(HTTPClient client)
|
||||||
{
|
{
|
||||||
if (client.Instance is null) return false;
|
if (client.WebSocket is null) return false;
|
||||||
|
|
||||||
byte[] buffer = new byte[General.SocketByteSize];
|
byte[] buffer = new byte[General.SocketByteSize];
|
||||||
WebSocketReceiveResult result = await client.Instance.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
WebSocketReceiveResult result = await client.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
string msg = General.DefaultEncoding.GetString(buffer).Replace("\0", "").Trim();
|
string msg = General.DefaultEncoding.GetString(buffer).Replace("\0", "").Trim();
|
||||||
SocketObject[] objs = await GetSocketObjects(client.Instance, result, msg);
|
SocketObject[] objs = await GetSocketObjects(client.WebSocket, result, msg);
|
||||||
|
|
||||||
foreach (SocketObject obj in objs)
|
foreach (SocketObject obj in objs)
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ namespace Milimoe.FunGame.Core.Service
|
|||||||
}
|
}
|
||||||
else if (obj.SocketType == SocketMessageType.Disconnect)
|
else if (obj.SocketType == SocketMessageType.Disconnect)
|
||||||
{
|
{
|
||||||
await client.Instance.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, CancellationToken.None);
|
await client.WebSocket.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, CancellationToken.None);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user