Files
ichni_Official/Assets/Scripts/Online/Network/ApiClient.cs
2026-06-15 18:18:16 +08:00

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}");
}
}
}