mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-04-21 19:49:34 +08:00
472 lines
19 KiB
C#
472 lines
19 KiB
C#
using Milimoe.FunGame.Core.Controller;
|
||
using Milimoe.FunGame.Core.Library.Common.Network;
|
||
using Milimoe.FunGame.Core.Library.Constant;
|
||
using Milimoe.FunGame.Core.Library.Exception;
|
||
|
||
namespace Milimoe.FunGame.Core.Api.Transmittal
|
||
{
|
||
/// <summary>
|
||
/// 需要配合 <see cref="DataRequestType"/> 使用<para/>
|
||
/// 如果是 <see cref="Model.Gaming"/> 的数据请求,则配合 <see cref="GamingType"/> 使用<para/>
|
||
/// 确保已添加对应的枚举
|
||
/// </summary>
|
||
public class DataRequest : IDisposable
|
||
{
|
||
/// <summary>
|
||
/// 数据请求结果
|
||
/// </summary>
|
||
public RequestResult Result => _worker != null ? _worker.Result : (_gamingWorker != null ? _gamingWorker.Result : RequestResult.Missing);
|
||
|
||
/// <summary>
|
||
/// 详细错误信息
|
||
/// </summary>
|
||
public string Error => _worker != null ? _worker.Error : (_gamingWorker != null ? _gamingWorker.Error : "");
|
||
|
||
/// <summary>
|
||
/// 是否已经关闭
|
||
/// </summary>
|
||
public bool IsDisposed => _isDisposed;
|
||
|
||
// 获取ResultData中key值对应的Json字符串
|
||
// -- 此索引器仅返回Json字符串,对象类型请使用反序列化方法GetResult<T>() --
|
||
// -- 当然也可以自己反序列化 --
|
||
// -- 基本类型可能有效,但仍建议使用反序列化方法 --
|
||
public object? this[string key]
|
||
{
|
||
get
|
||
{
|
||
if (_worker != null) return _worker.ResultData[key];
|
||
else if (_gamingWorker != null) return _gamingWorker.ResultData[key];
|
||
return null;
|
||
}
|
||
set
|
||
{
|
||
if (value != null) AddRequestData(key, value);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 私有的实现类
|
||
/// </summary>
|
||
private readonly SocketRequest? _worker;
|
||
|
||
/// <summary>
|
||
/// 私有的实现类(这是局内请求的)
|
||
/// </summary>
|
||
private readonly GamingRequest? _gamingWorker;
|
||
|
||
/// <summary>
|
||
/// 指示关闭的变量
|
||
/// </summary>
|
||
private bool _isDisposed = false;
|
||
|
||
/// <summary>
|
||
/// 基于本地已连接的 <see cref="Socket"/> 创建新的数据请求<para/>
|
||
/// 使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequest(DataRequestType)"/> 创建一个新的请求
|
||
/// 插件则使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequestForAddon(DataRequestType)"/> 创建一个新的请求<para/>
|
||
/// </summary>
|
||
/// <param name="socket"></param>
|
||
/// <param name="type"></param>
|
||
/// <param name="longRunning"></param>
|
||
/// <param name="runtime"></param>
|
||
internal DataRequest(Socket socket, DataRequestType type, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client)
|
||
{
|
||
_worker = new(socket, type, Guid.NewGuid(), longRunning, runtime);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基于本地已连接的 <see cref="HTTPClient"/> 创建新的数据请求<para/>
|
||
/// 使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequest(DataRequestType)"/> 创建一个新的请求<para/>
|
||
/// 插件则使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequestForAddon(DataRequestType)"/> 创建一个新的请求<para/>
|
||
/// 此数据请求只能调用异步方法 <see cref="SendRequestAsync"/> 请求数据
|
||
/// </summary>
|
||
/// <param name="client"></param>
|
||
/// <param name="type"></param>
|
||
/// <param name="longRunning"></param>
|
||
/// <param name="runtime"></param>
|
||
internal DataRequest(HTTPClient client, DataRequestType type, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client)
|
||
{
|
||
_worker = new(client, type, Guid.NewGuid(), longRunning, runtime);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基于本地已连接的 <see cref="Socket"/> 创建新的局内(<see cref="Model.Gaming"/>)数据请求<para/>
|
||
/// 使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequestForAddon(GamingType)"/> 创建一个新的请求<para/>
|
||
/// 此构造方法是给 <see cref="Library.Common.Addon.GameModule"/> 提供的
|
||
/// </summary>
|
||
/// <param name="socket"></param>
|
||
/// <param name="type"></param>
|
||
/// <param name="longRunning"></param>
|
||
/// <param name="runtime"></param>
|
||
internal DataRequest(Socket socket, GamingType type, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client)
|
||
{
|
||
_gamingWorker = new(socket, type, Guid.NewGuid(), longRunning, runtime);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基于本地已连接的 <see cref="HTTPClient"/> 创建新的局内(<see cref="Model.Gaming"/>)数据请求<para/>
|
||
/// 使用 <see cref="RunTimeController"/> 中的 <see cref="RunTimeController.NewDataRequestForAddon(GamingType)"/> 创建一个新的请求<para/>
|
||
/// 此构造方法是给 <see cref="Library.Common.Addon.GameModule"/> 提供的<para/>
|
||
/// 此数据请求只能调用异步方法 <see cref="SendRequestAsync"/> 请求数据
|
||
/// </summary>
|
||
/// <param name="client"></param>
|
||
/// <param name="type"></param>
|
||
/// <param name="longRunning"></param>
|
||
/// <param name="runtime"></param>
|
||
internal DataRequest(HTTPClient client, GamingType type, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client)
|
||
{
|
||
_gamingWorker = new(client, type, Guid.NewGuid(), longRunning, runtime);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加数据
|
||
/// </summary>
|
||
/// <param name="key"></param>
|
||
/// <param name="value"></param>
|
||
public void AddRequestData(string key, object value)
|
||
{
|
||
if (_worker != null)
|
||
{
|
||
if (!_worker.RequestData.TryAdd(key, value)) _worker.RequestData[key] = value;
|
||
}
|
||
else if (_gamingWorker != null)
|
||
{
|
||
if (!_gamingWorker.RequestData.TryAdd(key, value)) _gamingWorker.RequestData[key] = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 长时间运行的数据请求需要在使用完毕后自行关闭
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
Dispose(true);
|
||
GC.SuppressFinalize(this);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭时
|
||
/// </summary>
|
||
/// <param name="disposing"></param>
|
||
protected void Dispose(bool disposing)
|
||
{
|
||
if (!_isDisposed)
|
||
{
|
||
if (disposing)
|
||
{
|
||
_worker?.Dispose();
|
||
_gamingWorker?.Dispose();
|
||
}
|
||
}
|
||
_isDisposed = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向服务器发送数据请求
|
||
/// <para/>警告:<see cref="HTTPClient"/> 调用此方法将抛出异常。请调用并等待 <see cref="SendRequestAsync"/>
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
/// <exception cref="AsyncSendException"></exception>
|
||
public RequestResult SendRequest()
|
||
{
|
||
_worker?.SendRequest();
|
||
_gamingWorker?.SendRequest();
|
||
return Result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步向服务器发送数据请求
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task<RequestResult> SendRequestAsync()
|
||
{
|
||
if (_worker != null)
|
||
{
|
||
await _worker.SendRequestAsync();
|
||
}
|
||
else if (_gamingWorker != null)
|
||
{
|
||
await _gamingWorker.SendRequestAsync();
|
||
}
|
||
return Result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定key对应的反序列化对象
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="key"></param>
|
||
/// <returns></returns>
|
||
public T? GetResult<T>(string key)
|
||
{
|
||
if (_worker != null)
|
||
{
|
||
return GetDictionaryJsonObject<T>(_worker.ResultData, key);
|
||
}
|
||
else if (_gamingWorker != null)
|
||
{
|
||
return GetDictionaryJsonObject<T>(_gamingWorker.ResultData, key);
|
||
}
|
||
return default;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 常规数据请求
|
||
/// </summary>
|
||
private class SocketRequest : SocketHandlerController
|
||
{
|
||
public Dictionary<string, object> RequestData { get; } = [];
|
||
public Dictionary<string, object> ResultData => _ResultData;
|
||
public RequestResult Result => _Result;
|
||
public string Error => _Error;
|
||
|
||
private readonly Socket? Socket = null;
|
||
private readonly HTTPClient? HTTPClient = null;
|
||
private readonly DataRequestType RequestType = DataRequestType.UnKnown;
|
||
private readonly Guid RequestID = Guid.Empty;
|
||
private readonly bool IsLongRunning = false;
|
||
private readonly SocketRuntimeType RuntimeType = SocketRuntimeType.Client;
|
||
private Dictionary<string, object> _ResultData = [];
|
||
private RequestResult _Result = RequestResult.Missing;
|
||
private string _Error = "";
|
||
|
||
public SocketRequest(Socket? socket, DataRequestType type, Guid requestId, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client) : base(socket)
|
||
{
|
||
Socket = socket;
|
||
RequestType = type;
|
||
RequestID = requestId;
|
||
IsLongRunning = longRunning;
|
||
RuntimeType = runtime;
|
||
}
|
||
|
||
public SocketRequest(HTTPClient? client, DataRequestType type, Guid requestId, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client) : base(client)
|
||
{
|
||
HTTPClient = client;
|
||
RequestType = type;
|
||
RequestID = requestId;
|
||
IsLongRunning = longRunning;
|
||
RuntimeType = runtime;
|
||
}
|
||
|
||
public void SendRequest()
|
||
{
|
||
try
|
||
{
|
||
SetWorking();
|
||
if (RuntimeType == SocketRuntimeType.Addon)
|
||
{
|
||
if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true";
|
||
else RequestData.Add(SocketSet.Plugins_Mark, true);
|
||
}
|
||
else RequestData.Remove(SocketSet.Plugins_Mark);
|
||
if (Socket != null && Socket.Send(SocketMessageType.DataRequest, RequestType, RequestID, RequestData) == SocketResult.Success)
|
||
{
|
||
WaitForWorkDone();
|
||
}
|
||
else if (HTTPClient != null)
|
||
{
|
||
throw new AsyncSendException();
|
||
}
|
||
else throw new ConnectFailedException();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Working = false;
|
||
_Result = RequestResult.Fail;
|
||
_Error = e.GetErrorInfo();
|
||
}
|
||
}
|
||
|
||
public async Task SendRequestAsync()
|
||
{
|
||
try
|
||
{
|
||
SetWorking();
|
||
if (RuntimeType == SocketRuntimeType.Addon)
|
||
{
|
||
if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true";
|
||
else RequestData.Add(SocketSet.Plugins_Mark, true);
|
||
}
|
||
else RequestData.Remove(SocketSet.Plugins_Mark);
|
||
if (Socket != null && Socket.Send(SocketMessageType.DataRequest, RequestType, RequestID, RequestData) == SocketResult.Success)
|
||
{
|
||
await WaitForWorkDoneAsync();
|
||
}
|
||
else if (HTTPClient != null && await HTTPClient.Send(SocketMessageType.DataRequest, RequestType, RequestID, RequestData) == SocketResult.Success)
|
||
{
|
||
await WaitForWorkDoneAsync();
|
||
}
|
||
else throw new ConnectFailedException();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Working = false;
|
||
_Result = RequestResult.Fail;
|
||
_Error = e.GetErrorInfo();
|
||
}
|
||
}
|
||
|
||
public override void SocketHandler(SocketObject obj)
|
||
{
|
||
try
|
||
{
|
||
if (obj.SocketType == SocketMessageType.DataRequest)
|
||
{
|
||
DataRequestType type = obj.GetParam<DataRequestType>(0);
|
||
Guid id = obj.GetParam<Guid>(1);
|
||
if (type == RequestType && id == RequestID)
|
||
{
|
||
if (!IsLongRunning) Dispose();
|
||
ReceivedObject = obj;
|
||
Working = false;
|
||
_ResultData = obj.GetParam<Dictionary<string, object>>(2) ?? [];
|
||
_Result = RequestResult.Success;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Working = false;
|
||
_Result = RequestResult.Fail;
|
||
_Error = e.GetErrorInfo();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 游戏局内请求
|
||
/// </summary>
|
||
private class GamingRequest : SocketHandlerController
|
||
{
|
||
public Dictionary<string, object> RequestData { get; } = [];
|
||
public Dictionary<string, object> ResultData => _ResultData;
|
||
public RequestResult Result => _Result;
|
||
public string Error => _Error;
|
||
|
||
private readonly Socket? Socket = null;
|
||
private readonly HTTPClient? HTTPClient = null;
|
||
private readonly GamingType GamingType = GamingType.None;
|
||
private readonly Guid RequestID = Guid.Empty;
|
||
private readonly bool IsLongRunning = false;
|
||
private readonly SocketRuntimeType RuntimeType = SocketRuntimeType.Client;
|
||
private Dictionary<string, object> _ResultData = [];
|
||
private RequestResult _Result = RequestResult.Missing;
|
||
private string _Error = "";
|
||
|
||
public GamingRequest(Socket? socket, GamingType type, Guid requestId, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client) : base(socket)
|
||
{
|
||
Socket = socket;
|
||
GamingType = type;
|
||
RequestID = requestId;
|
||
IsLongRunning = longRunning;
|
||
RuntimeType = runtime;
|
||
}
|
||
|
||
public GamingRequest(HTTPClient? client, GamingType type, Guid requestId, bool longRunning = false, SocketRuntimeType runtime = SocketRuntimeType.Client) : base(client)
|
||
{
|
||
HTTPClient = client;
|
||
GamingType = type;
|
||
RequestID = requestId;
|
||
IsLongRunning = longRunning;
|
||
RuntimeType = runtime;
|
||
}
|
||
|
||
public void SendRequest()
|
||
{
|
||
try
|
||
{
|
||
SetWorking();
|
||
if (RuntimeType == SocketRuntimeType.Addon)
|
||
{
|
||
if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true";
|
||
else RequestData.Add(SocketSet.Plugins_Mark, true);
|
||
}
|
||
else RequestData.Remove(SocketSet.Plugins_Mark);
|
||
if (Socket != null && Socket.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success)
|
||
{
|
||
WaitForWorkDone();
|
||
}
|
||
else if (HTTPClient != null)
|
||
{
|
||
throw new AsyncSendException();
|
||
}
|
||
else throw new ConnectFailedException();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Working = false;
|
||
_Result = RequestResult.Fail;
|
||
_Error = e.GetErrorInfo();
|
||
}
|
||
}
|
||
|
||
public async Task SendRequestAsync()
|
||
{
|
||
try
|
||
{
|
||
SetWorking();
|
||
if (RuntimeType == SocketRuntimeType.Addon)
|
||
{
|
||
if (RequestData.ContainsKey(SocketSet.Plugins_Mark)) RequestData[SocketSet.Plugins_Mark] = "true";
|
||
else RequestData.Add(SocketSet.Plugins_Mark, true);
|
||
}
|
||
else RequestData.Remove(SocketSet.Plugins_Mark);
|
||
if (Socket != null && Socket.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success)
|
||
{
|
||
await WaitForWorkDoneAsync();
|
||
}
|
||
else if (HTTPClient != null && await HTTPClient.Send(SocketMessageType.GamingRequest, GamingType, RequestID, RequestData) == SocketResult.Success)
|
||
{
|
||
await WaitForWorkDoneAsync();
|
||
}
|
||
else throw new ConnectFailedException();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Working = false;
|
||
_Result = RequestResult.Fail;
|
||
_Error = e.GetErrorInfo();
|
||
}
|
||
}
|
||
|
||
public override void SocketHandler(SocketObject obj)
|
||
{
|
||
try
|
||
{
|
||
if (obj.SocketType == SocketMessageType.GamingRequest)
|
||
{
|
||
GamingType type = obj.GetParam<GamingType>(0);
|
||
Guid id = obj.GetParam<Guid>(1);
|
||
if (type == GamingType && id == RequestID)
|
||
{
|
||
if (!IsLongRunning) Dispose();
|
||
ReceivedObject = obj;
|
||
Working = false;
|
||
_ResultData = obj.GetParam<Dictionary<string, object>>(2) ?? [];
|
||
_Result = RequestResult.Success;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Working = false;
|
||
_Result = RequestResult.Fail;
|
||
_Error = e.GetErrorInfo();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 反序列化Dictionary中的Json对象
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="dict"></param>
|
||
/// <param name="key"></param>
|
||
/// <returns></returns>
|
||
public static T? GetDictionaryJsonObject<T>(Dictionary<string, object> dict, string key)
|
||
{
|
||
return Service.JsonManager.GetObject<T>(dict, key);
|
||
}
|
||
}
|
||
}
|