Skip to content

Commit

Permalink
Add package
Browse files Browse the repository at this point in the history
  • Loading branch information
UsefFarahmand authored Aug 5, 2024
1 parent 4fdf57e commit 0ac349c
Show file tree
Hide file tree
Showing 62 changed files with 1,575 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Runtime.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Runtime/Abstraction.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Runtime/Abstraction/INetworkLoadingHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace UAPIModule.Abstraction
{
public interface INetworkLoadingHandler
{
void ShowLoading();
void HideLoading();
}
}
11 changes: 11 additions & 0 deletions Runtime/Abstraction/INetworkLoadingHandler.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Runtime/Assets.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions Runtime/Assets/APIConfig.cs
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);
}
}
11 changes: 11 additions & 0 deletions Runtime/Assets/APIConfig.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Runtime/Assets/BaseURLConfig.cs
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; }
}
}
11 changes: 11 additions & 0 deletions Runtime/Assets/BaseURLConfig.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions Runtime/Assets/HTTPRequestParamsCard.cs
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;
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Assets/HTTPRequestParamsCard.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 91 additions & 0 deletions Runtime/GenericRequestSender.cs
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;
}
}
}
11 changes: 11 additions & 0 deletions Runtime/GenericRequestSender.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

89 changes: 89 additions & 0 deletions Runtime/RequestSender.cs
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;
}
}
}
11 changes: 11 additions & 0 deletions Runtime/RequestSender.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0ac349c

Please sign in to comment.