-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace UAPIModule.Abstraction | ||
{ | ||
public interface INetworkLoadingHandler | ||
{ | ||
void ShowLoading(); | ||
void HideLoading(); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using UAPIModule.SharedTypes; | ||
using UnityEngine; | ||
|
||
namespace UAPIModule.Assets | ||
{ | ||
[CreateAssetMenu(fileName = nameof(APIConfig), menuName = "UAPIModule/" + nameof(APIConfig), order = 1)] | ||
public class APIConfig : ScriptableObject | ||
{ | ||
[field: SerializeField, Tooltip("The base URL configuration for the API request.")] | ||
public BaseURLConfig BaseURLConfig { get; private set; } | ||
|
||
[field: SerializeField, Tooltip("The endpoint of the API request.")] | ||
public string Endpoint { get; private set; } | ||
|
||
[field: SerializeField, Tooltip("The HTTP method type (GET, POST, PUT, etc.) for the API request.")] | ||
public HTTPRequestMethod MethodType { get; private set; } | ||
|
||
[field: SerializeField, Tooltip("The headers for the API request.")] | ||
public HttpRequestParams Headers { get; private set; } | ||
|
||
[field: SerializeField, Tooltip("Indicates whether the API request needs an authorization header.")] | ||
public bool NeedsAuthHeader { get; private set; } | ||
|
||
[field: SerializeField, Tooltip("The timeout duration for the API request in milliseconds.")] | ||
public int Timeout { get; private set; } = 10000; | ||
|
||
[field: SerializeField, Tooltip("Indicates whether to use the 'Bearer' prefix in the authorization header.")] | ||
public bool UseBearerPrefix { get; private set; } = true; | ||
|
||
public APIConfigData CreateConfigData() => | ||
new(BaseURLConfig, Endpoint, MethodType, Headers, NeedsAuthHeader, Timeout, UseBearerPrefix); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using UnityEngine; | ||
|
||
namespace UAPIModule.Assets | ||
{ | ||
[CreateAssetMenu(fileName = nameof(BaseURLConfig), menuName = "UAPIModule/" + nameof(BaseURLConfig))] | ||
public class BaseURLConfig : ScriptableObject | ||
{ | ||
[field: SerializeField] public string BaseURL { get; private set; } | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using UnityEngine; | ||
|
||
namespace UAPIModule.Assets | ||
{ | ||
[CreateAssetMenu(fileName = nameof(HttpRequestParams), menuName = "UAPIModule/" + nameof(HttpRequestParams))] | ||
public class HttpRequestParams : ScriptableObject | ||
{ | ||
[field: SerializeField] public List<KeyValueItem> Parameters { private set; get; } | ||
|
||
public bool HasEmptyParams() => | ||
Parameters.Exists(keyValueItems => | ||
string.IsNullOrEmpty(keyValueItems.key) || string.IsNullOrEmpty(keyValueItems.value)); | ||
|
||
public void AddParam(string key, string value) | ||
{ | ||
if (Parameters.Exists(keyValueItems => keyValueItems.key == key)) return; | ||
Parameters.Add(new KeyValueItem() { key = key, value = value }); | ||
} | ||
|
||
[ContextMenu("Add Default Header Params")] | ||
public void AddDefaultHeaderParams() | ||
{ | ||
AddParam("Content-Type", "application/json"); | ||
AddParam("Accept", "application/json"); | ||
} | ||
|
||
[Serializable] | ||
public class KeyValueItem | ||
{ | ||
public string key; | ||
public string value; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using Cysharp.Threading.Tasks; | ||
using Newtonsoft.Json; | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using UAPIModule.Abstraction; | ||
using UAPIModule.Assets; | ||
using UAPIModule.SharedTypes; | ||
|
||
namespace UAPIModule | ||
{ | ||
public abstract class RequestSender<T> : RequestSenderBase where T : class | ||
{ | ||
protected RequestSender(INetworkLoadingHandler loadingHandler) : base(loadingHandler) | ||
{ | ||
} | ||
|
||
public async UniTask<NetworkResponse<T>> SendRequest(APIConfig config, RequestFeedbackConfig feedbackConfig, RequestSendConfig sendConfig) | ||
{ | ||
return await SendRequest(config.CreateConfigData(), feedbackConfig, sendConfig); | ||
} | ||
|
||
public async UniTask<NetworkResponse<T>> SendRequest(APIConfigData config, RequestFeedbackConfig feedbackConfig, RequestSendConfig sendConfig) | ||
{ | ||
if (httpClient == null) | ||
{ | ||
throw new InvalidOperationException("HttpClient is not initialized."); | ||
} | ||
|
||
var cancellationTokenSource = new CancellationTokenSource(config.Timeout); | ||
|
||
try | ||
{ | ||
var response = await SendRequestInternal(config, feedbackConfig, sendConfig, cancellationTokenSource.Token); | ||
string responseBody = await response.Content.ReadAsStringAsync(); | ||
|
||
var networkResponse = new NetworkResponse<T> | ||
{ | ||
isSuccessful = response.IsSuccessStatusCode, | ||
statusCode = (long)response.StatusCode, | ||
errorMessage = response.IsSuccessStatusCode ? null : response.ReasonPhrase, | ||
data = response.IsSuccessStatusCode ? JsonConvert.DeserializeObject<T>(responseBody) : null | ||
}; | ||
|
||
if (!networkResponse.isSuccessful) | ||
{ | ||
networkResponse.errorMessage = responseBody; | ||
} | ||
|
||
requestLogger.LogResponse(networkResponse, config.BaseURLConfig.BaseURL + config.Endpoint); | ||
|
||
return networkResponse; | ||
} | ||
catch (TimeoutException e) | ||
{ | ||
return HandleError((long)HTTPResponseCodes.REQUEST_TIMEOUT_408, e.Message, config.BaseURLConfig.BaseURL + config.Endpoint); | ||
} | ||
catch (HttpRequestException e) | ||
{ | ||
return HandleError((long)HTTPResponseCodes.SERVER_ERROR_500, GetErrorMessage(e), config.BaseURLConfig.BaseURL + config.Endpoint); | ||
} | ||
catch (Exception e) | ||
{ | ||
return HandleError((long)HTTPResponseCodes.SERVER_ERROR_500, e.Message, config.BaseURLConfig.BaseURL + config.Endpoint); | ||
} | ||
} | ||
|
||
private NetworkResponse<T> HandleError(long statusCode, string errorMessage, string url) | ||
{ | ||
var errorResponse = new NetworkResponse<T> | ||
{ | ||
isSuccessful = false, | ||
statusCode = statusCode, | ||
errorMessage = errorMessage | ||
}; | ||
|
||
requestLogger.LogResponse(errorResponse, url); | ||
return errorResponse; | ||
} | ||
|
||
private string GetErrorMessage(HttpRequestException e) | ||
{ | ||
string errorResponseBody = e.Message; | ||
if (e.Data.Contains("ResponseBody")) | ||
{ | ||
errorResponseBody = e.Data["ResponseBody"].ToString(); | ||
} | ||
return errorResponseBody; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using Cysharp.Threading.Tasks; | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using UAPIModule.Abstraction; | ||
using UAPIModule.Assets; | ||
using UAPIModule.SharedTypes; | ||
|
||
namespace UAPIModule | ||
{ | ||
public abstract class RequestSender : RequestSenderBase | ||
{ | ||
protected RequestSender(INetworkLoadingHandler loadingHandler) : base(loadingHandler) | ||
{ | ||
} | ||
|
||
public async UniTask<NetworkResponse> SendRequest(APIConfig config, RequestFeedbackConfig feedbackConfig, RequestSendConfig sendConfig) | ||
{ | ||
return await SendRequest(config.CreateConfigData(), feedbackConfig, sendConfig); | ||
} | ||
|
||
public async UniTask<NetworkResponse> SendRequest(APIConfigData config, RequestFeedbackConfig feedbackConfig, RequestSendConfig sendConfig) | ||
{ | ||
if (httpClient == null) | ||
{ | ||
throw new InvalidOperationException("HttpClient is not initialized."); | ||
} | ||
|
||
var cancellationTokenSource = new CancellationTokenSource(config.Timeout); | ||
|
||
try | ||
{ | ||
var response = await SendRequestInternal(config, feedbackConfig, sendConfig, cancellationTokenSource.Token); | ||
string responseBody = await response.Content.ReadAsStringAsync(); | ||
|
||
var networkResponse = new NetworkResponse | ||
{ | ||
isSuccessful = response.IsSuccessStatusCode, | ||
statusCode = (long)response.StatusCode, | ||
errorMessage = response.IsSuccessStatusCode ? null : response.ReasonPhrase, | ||
}; | ||
|
||
if (!networkResponse.isSuccessful) | ||
{ | ||
networkResponse.errorMessage = responseBody; | ||
} | ||
|
||
requestLogger.LogResponse(networkResponse, config.BaseURLConfig.BaseURL + config.Endpoint); | ||
|
||
return networkResponse; | ||
} | ||
catch (TimeoutException e) | ||
{ | ||
return HandleError((long)HTTPResponseCodes.REQUEST_TIMEOUT_408, e.Message, config.BaseURLConfig.BaseURL + config.Endpoint); | ||
} | ||
catch (HttpRequestException e) | ||
{ | ||
return HandleError((long)HTTPResponseCodes.SERVER_ERROR_500, GetErrorMessage(e), config.BaseURLConfig.BaseURL + config.Endpoint); | ||
} | ||
catch (Exception e) | ||
{ | ||
return HandleError((long)HTTPResponseCodes.SERVER_ERROR_500, e.Message, config.BaseURLConfig.BaseURL + config.Endpoint); | ||
} | ||
} | ||
|
||
private NetworkResponse HandleError(long statusCode, string errorMessage, string url) | ||
{ | ||
var errorResponse = new NetworkResponse | ||
{ | ||
isSuccessful = false, | ||
statusCode = statusCode, | ||
errorMessage = errorMessage | ||
}; | ||
|
||
requestLogger.LogResponse(errorResponse, url); | ||
return errorResponse; | ||
} | ||
|
||
private string GetErrorMessage(HttpRequestException e) | ||
{ | ||
string errorResponseBody = e.Message; | ||
if (e.Data.Contains("ResponseBody")) | ||
{ | ||
errorResponseBody = e.Data["ResponseBody"].ToString(); | ||
} | ||
return errorResponseBody; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.