123 lines
4.1 KiB
C#
123 lines
4.1 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Best.HTTP;
|
|
using IchniOnline.Online.Network.Models;
|
|
using UnityEngine;
|
|
|
|
namespace IchniOnline.Online.Network
|
|
{
|
|
/// <summary>
|
|
/// BestHTTP-based API client singleton for IchniOnline backend communication.
|
|
/// Pure HTTP layer — no business logic.
|
|
/// </summary>
|
|
public class IchniOnlineApiClient
|
|
{
|
|
private static IchniOnlineApiClient _instance;
|
|
public static IchniOnlineApiClient Instance => _instance ??= new IchniOnlineApiClient();
|
|
|
|
public string BaseUrl { get; set; } = "http://localhost:53734";
|
|
public string JwtToken { get; set; }
|
|
|
|
private IchniOnlineApiClient() { }
|
|
|
|
public async Task<ApiResult<T>> GetAsync<T>(string endpoint)
|
|
{
|
|
string url = BuildUrl(endpoint);
|
|
var request = new HTTPRequest(new Uri(url), HTTPMethods.Get);
|
|
AddAuthHeader(request);
|
|
|
|
try
|
|
{
|
|
var resp = await request.GetHTTPResponseAsync();
|
|
return ProcessResponse<T>(resp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
|
|
}
|
|
}
|
|
|
|
public async Task<ApiResult<T>> PostAsync<T>(string endpoint, object body)
|
|
{
|
|
string url = BuildUrl(endpoint);
|
|
var request = new HTTPRequest(new Uri(url), HTTPMethods.Post);
|
|
request.SetHeader("Content-Type", "application/json");
|
|
AddAuthHeader(request);
|
|
|
|
if (body != null)
|
|
{
|
|
string jsonBody = JsonUtility.ToJson(body);
|
|
request.UploadSettings.UploadStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonBody));
|
|
}
|
|
|
|
try
|
|
{
|
|
var resp = await request.GetHTTPResponseAsync();
|
|
return ProcessResponse<T>(resp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
|
|
}
|
|
}
|
|
|
|
private string BuildUrl(string endpoint)
|
|
{
|
|
if (string.IsNullOrEmpty(BaseUrl))
|
|
throw new InvalidOperationException("BaseUrl is not configured.");
|
|
|
|
string baseUrl = BaseUrl.TrimEnd('/');
|
|
string path = endpoint.StartsWith("/") ? endpoint : $"/{endpoint}";
|
|
return baseUrl + path;
|
|
}
|
|
|
|
private void AddAuthHeader(HTTPRequest request)
|
|
{
|
|
if (!string.IsNullOrEmpty(JwtToken))
|
|
{
|
|
request.SetHeader("Authorization", $"Bearer {JwtToken}");
|
|
}
|
|
}
|
|
|
|
private ApiResult<T> ProcessResponse<T>(HTTPResponse resp)
|
|
{
|
|
string json = resp.DataAsText;
|
|
|
|
if (resp.StatusCode >= 200 && resp.StatusCode < 300)
|
|
{
|
|
if (string.IsNullOrEmpty(json))
|
|
{
|
|
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Empty response body");
|
|
}
|
|
|
|
var response = JsonUtility.FromJson(json, typeof(GlobalResponse<T>)) as GlobalResponse<T>;
|
|
if (response == null)
|
|
{
|
|
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Failed to parse response JSON");
|
|
}
|
|
|
|
if (response.Code == ResponseCode.Ok)
|
|
{
|
|
return ApiResult<T>.Ok(response.Data);
|
|
}
|
|
|
|
return ApiResult<T>.Fail(response.Code, response.Message);
|
|
}
|
|
|
|
// Non-2xx: try to parse server error body
|
|
if (!string.IsNullOrEmpty(json))
|
|
{
|
|
var errorResponse = JsonUtility.FromJson(json, typeof(GlobalResponseBase)) as GlobalResponseBase;
|
|
if (errorResponse != null)
|
|
{
|
|
return ApiResult<T>.Fail(errorResponse.Code, errorResponse.Message);
|
|
}
|
|
}
|
|
|
|
return ApiResult<T>.Fail(ResponseCode.InternalServerError, $"HTTP error {resp.StatusCode}");
|
|
}
|
|
}
|
|
}
|