You've already forked CC-Framework.BriskGameServer
Initial Brisk Unity SDK project
This commit is contained in:
253
Assets/BriskSdk/Runtime/Core/BriskHttpClient.cs
Normal file
253
Assets/BriskSdk/Runtime/Core/BriskHttpClient.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
public sealed class BriskHttpClient
|
||||
{
|
||||
private readonly BriskContext _context;
|
||||
|
||||
public BriskHttpClient(BriskContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public Task<Dictionary<string, object>> GetDataAsync(string path, Dictionary<string, string> query = null, bool auth = false)
|
||||
{
|
||||
return SendForDictionaryAsync(UnityWebRequest.kHttpVerbGET, path, query, null, auth);
|
||||
}
|
||||
|
||||
public Task<object> GetRawDataAsync(string path, Dictionary<string, string> query = null, bool auth = false)
|
||||
{
|
||||
return SendRawJsonAsync(UnityWebRequest.kHttpVerbGET, path, query, null, auth);
|
||||
}
|
||||
|
||||
public Task<Dictionary<string, object>> PostJsonAsync(string path, object body, bool auth = false)
|
||||
{
|
||||
return SendForDictionaryAsync(UnityWebRequest.kHttpVerbPOST, path, null, body, auth);
|
||||
}
|
||||
|
||||
public Task<object> PostJsonRawAsync(string path, object body, bool auth = false)
|
||||
{
|
||||
return SendRawJsonAsync(UnityWebRequest.kHttpVerbPOST, path, null, body, auth);
|
||||
}
|
||||
|
||||
public Task<object> PostJsonRawAsync(string path, object body, bool auth, Dictionary<string, string> query)
|
||||
{
|
||||
return SendRawJsonAsync(UnityWebRequest.kHttpVerbPOST, path, query, body, auth);
|
||||
}
|
||||
|
||||
public Task<object> SendPutJsonRawAsync(string path, object body, bool auth = false)
|
||||
{
|
||||
return SendRawJsonAsync(UnityWebRequest.kHttpVerbPUT, path, null, body, auth);
|
||||
}
|
||||
|
||||
public Task<object> SendDeleteJsonRawAsync(string path, Dictionary<string, string> query = null, bool auth = false)
|
||||
{
|
||||
return SendRawJsonAsync(UnityWebRequest.kHttpVerbDELETE, path, query, null, auth);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, object>> PostMultipartAsync(string path, List<IMultipartFormSection> formSections, bool auth = false)
|
||||
{
|
||||
using (var request = UnityWebRequest.Post(BuildUrl(path, null), formSections))
|
||||
{
|
||||
if (auth)
|
||||
{
|
||||
AddAuthorizationHeader(request);
|
||||
}
|
||||
|
||||
request.SetRequestHeader("Accept", "application/json");
|
||||
await SendRequestAsync(request);
|
||||
return ParseEnvelope(request) as Dictionary<string, object> ?? new Dictionary<string, object>();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BriskBinaryResponse> GetBytesAsync(string path, Dictionary<string, string> query = null, bool auth = false)
|
||||
{
|
||||
using (var request = BuildRequest(UnityWebRequest.kHttpVerbGET, path, query, null, auth))
|
||||
{
|
||||
await SendRequestAsync(request);
|
||||
EnsureSuccessOrThrow(request);
|
||||
return new BriskBinaryResponse
|
||||
{
|
||||
Bytes = request.downloadHandler != null ? request.downloadHandler.data : Array.Empty<byte>(),
|
||||
Headers = request.GetResponseHeaders() ?? new Dictionary<string, string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, object>> SendForDictionaryAsync(string method, string path, Dictionary<string, string> query, object body, bool auth)
|
||||
{
|
||||
var data = await SendRawJsonAsync(method, path, query, body, auth);
|
||||
return data as Dictionary<string, object> ?? new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private async Task<object> SendRawJsonAsync(string method, string path, Dictionary<string, string> query, object body, bool auth)
|
||||
{
|
||||
using (var request = BuildRequest(method, path, query, body, auth))
|
||||
{
|
||||
await SendRequestAsync(request);
|
||||
return ParseEnvelope(request);
|
||||
}
|
||||
}
|
||||
|
||||
private UnityWebRequest BuildRequest(string method, string path, Dictionary<string, string> query, object body, bool auth)
|
||||
{
|
||||
var url = BuildUrl(path, query);
|
||||
var request = new UnityWebRequest(url, method)
|
||||
{
|
||||
downloadHandler = new DownloadHandlerBuffer()
|
||||
};
|
||||
|
||||
request.SetRequestHeader("Accept", "application/json");
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
var json = BriskJson.Serialize(body);
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
request.uploadHandler = new UploadHandlerRaw(bytes);
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
}
|
||||
|
||||
if (auth)
|
||||
{
|
||||
AddAuthorizationHeader(request);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private async Task SendRequestAsync(UnityWebRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var operation = request.SendWebRequest();
|
||||
var taskSource = new TaskCompletionSource<bool>();
|
||||
operation.completed += _ => taskSource.TrySetResult(true);
|
||||
await taskSource.Task;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new BriskNetworkException("Failed to send request.", exception);
|
||||
}
|
||||
|
||||
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.DataProcessingError)
|
||||
{
|
||||
throw new BriskNetworkException(request.error ?? "Network error.");
|
||||
}
|
||||
}
|
||||
|
||||
private object ParseEnvelope(UnityWebRequest request)
|
||||
{
|
||||
var httpStatus = (int)request.responseCode;
|
||||
var responseText = request.downloadHandler != null ? request.downloadHandler.text : null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(responseText))
|
||||
{
|
||||
if (httpStatus >= 200 && httpStatus < 300)
|
||||
{
|
||||
return new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
throw new BriskHttpException(httpStatus, request.error ?? "HTTP error.");
|
||||
}
|
||||
|
||||
var payload = BriskJson.Deserialize(responseText) as Dictionary<string, object>;
|
||||
if (payload == null)
|
||||
{
|
||||
throw new BriskHttpException(httpStatus, "Invalid JSON response.");
|
||||
}
|
||||
|
||||
var code = BriskValueReader.GetInt(payload, "code");
|
||||
var message = BriskValueReader.GetString(payload, "message") ?? request.error ?? "Request failed.";
|
||||
if (code != 0 || httpStatus < 200 || httpStatus >= 300)
|
||||
{
|
||||
throw BriskErrorClassifier.Classify(httpStatus, code, message);
|
||||
}
|
||||
|
||||
if (BriskValueReader.TryGetValue(payload, "data", out var dataValue))
|
||||
{
|
||||
return dataValue;
|
||||
}
|
||||
|
||||
return new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private void EnsureSuccessOrThrow(UnityWebRequest request)
|
||||
{
|
||||
var httpStatus = (int)request.responseCode;
|
||||
if (httpStatus >= 200 && httpStatus < 300)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw CreateExceptionFromResponse(request);
|
||||
}
|
||||
|
||||
private BriskException CreateExceptionFromResponse(UnityWebRequest request)
|
||||
{
|
||||
var httpStatus = (int)request.responseCode;
|
||||
var responseText = request.downloadHandler != null ? request.downloadHandler.text : null;
|
||||
if (!string.IsNullOrWhiteSpace(responseText))
|
||||
{
|
||||
var payload = BriskJson.Deserialize(responseText) as Dictionary<string, object>;
|
||||
if (payload != null)
|
||||
{
|
||||
var code = BriskValueReader.GetInt(payload, "code");
|
||||
var message = BriskValueReader.GetString(payload, "message") ?? request.error ?? "Request failed.";
|
||||
return BriskErrorClassifier.Classify(httpStatus, code, message);
|
||||
}
|
||||
}
|
||||
|
||||
return new BriskHttpException(httpStatus, request.error ?? "HTTP error.");
|
||||
}
|
||||
|
||||
private void AddAuthorizationHeader(UnityWebRequest request)
|
||||
{
|
||||
var token = _context.Session.AccessToken;
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
throw new BriskAuthExpiredException("Missing access token.");
|
||||
}
|
||||
|
||||
request.SetRequestHeader("Authorization", "Bearer " + token);
|
||||
}
|
||||
|
||||
private string BuildUrl(string path, Dictionary<string, string> query)
|
||||
{
|
||||
var trimmedPath = path.StartsWith("/") ? path : "/" + path;
|
||||
var url = _context.Options.BaseUrl + trimmedPath;
|
||||
if (query == null || query.Count == 0)
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
var builder = new StringBuilder(url);
|
||||
var first = true;
|
||||
foreach (var pair in query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pair.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
builder.Append('?');
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append('&');
|
||||
}
|
||||
|
||||
builder.Append(UnityWebRequest.EscapeURL(pair.Key));
|
||||
builder.Append('=');
|
||||
builder.Append(UnityWebRequest.EscapeURL(pair.Value));
|
||||
first = false;
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user