You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
11 KiB
268 lines
11 KiB
8 months ago
|
#if CSHARP_7_OR_LATER
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Threading;
|
||
|
using System.Threading.Tasks;
|
||
|
using BestHTTP.Logger;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace BestHTTP
|
||
|
{
|
||
|
public sealed class AsyncHTTPException : Exception
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Status code of the server's response.
|
||
|
/// </summary>
|
||
|
public int StatusCode;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Content sent by the server.
|
||
|
/// </summary>
|
||
|
public string Content;
|
||
|
|
||
|
public AsyncHTTPException(string message)
|
||
|
: base(message)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public AsyncHTTPException(string message, Exception innerException)
|
||
|
: base(message, innerException)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public AsyncHTTPException(int statusCode, string message, string content)
|
||
|
:base(message)
|
||
|
{
|
||
|
this.StatusCode = statusCode;
|
||
|
this.Content = content;
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
return string.Format("StatusCode: {0}, Message: {1}, Content: {2}, StackTrace: {3}", this.StatusCode, this.Message, this.Content, this.StackTrace);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class HTTPRequestAsyncExtensions
|
||
|
{
|
||
|
public static Task<HTTPResponse> GetHTTPResponseAsync(this HTTPRequest request, CancellationToken token = default)
|
||
|
{
|
||
|
return CreateTask<HTTPResponse>(request, token, (req, resp, tcs) =>
|
||
|
{
|
||
|
switch (req.State)
|
||
|
{
|
||
|
// The request finished without any problem.
|
||
|
case HTTPRequestStates.Finished:
|
||
|
tcs.TrySetResult(resp);
|
||
|
break;
|
||
|
|
||
|
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||
|
case HTTPRequestStates.Error:
|
||
|
VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
|
||
|
|
||
|
tcs.TrySetException(CreateException("Request Finished with Error!", null, req.Exception));
|
||
|
break;
|
||
|
|
||
|
// The request aborted, initiated by the user.
|
||
|
case HTTPRequestStates.Aborted:
|
||
|
VerboseLogging(request, "Request Aborted!");
|
||
|
|
||
|
tcs.TrySetCanceled();
|
||
|
break;
|
||
|
|
||
|
// Connecting to the server is timed out.
|
||
|
case HTTPRequestStates.ConnectionTimedOut:
|
||
|
VerboseLogging(request, "Connection Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Connection Timed Out!"));
|
||
|
break;
|
||
|
|
||
|
// The request didn't finished in the given time.
|
||
|
case HTTPRequestStates.TimedOut:
|
||
|
VerboseLogging(request, "Processing the request Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Processing the request Timed Out!"));
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static Task<string> GetAsStringAsync(this HTTPRequest request, CancellationToken token = default)
|
||
|
{
|
||
|
return CreateTask<string>(request, token, (req, resp, tcs) =>
|
||
|
{
|
||
|
switch (req.State)
|
||
|
{
|
||
|
// The request finished without any problem.
|
||
|
case HTTPRequestStates.Finished:
|
||
|
if (resp.IsSuccess)
|
||
|
tcs.TrySetResult(resp.DataAsText);
|
||
|
else
|
||
|
tcs.TrySetException(CreateException("Request finished Successfully, but the server sent an error.", resp));
|
||
|
break;
|
||
|
|
||
|
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||
|
case HTTPRequestStates.Error:
|
||
|
VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
|
||
|
|
||
|
tcs.TrySetException(CreateException("Request Finished with Error!", null, req.Exception));
|
||
|
break;
|
||
|
|
||
|
// The request aborted, initiated by the user.
|
||
|
case HTTPRequestStates.Aborted:
|
||
|
VerboseLogging(request, "Request Aborted!");
|
||
|
|
||
|
tcs.TrySetCanceled();
|
||
|
break;
|
||
|
|
||
|
// Connecting to the server is timed out.
|
||
|
case HTTPRequestStates.ConnectionTimedOut:
|
||
|
VerboseLogging(request, "Connection Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Connection Timed Out!"));
|
||
|
break;
|
||
|
|
||
|
// The request didn't finished in the given time.
|
||
|
case HTTPRequestStates.TimedOut:
|
||
|
VerboseLogging(request, "Processing the request Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Processing the request Timed Out!"));
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static Task<Texture2D> GetAsTexture2DAsync(this HTTPRequest request, CancellationToken token = default)
|
||
|
{
|
||
|
return CreateTask<Texture2D>(request, token, (req, resp, tcs) =>
|
||
|
{
|
||
|
switch (req.State)
|
||
|
{
|
||
|
// The request finished without any problem.
|
||
|
case HTTPRequestStates.Finished:
|
||
|
if (resp.IsSuccess)
|
||
|
tcs.TrySetResult(resp.DataAsTexture2D);
|
||
|
else
|
||
|
tcs.TrySetException(CreateException("Request finished Successfully, but the server sent an error.", resp));
|
||
|
break;
|
||
|
|
||
|
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||
|
case HTTPRequestStates.Error:
|
||
|
VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
|
||
|
|
||
|
tcs.TrySetException(CreateException("Request Finished with Error!", null, req.Exception));
|
||
|
break;
|
||
|
|
||
|
// The request aborted, initiated by the user.
|
||
|
case HTTPRequestStates.Aborted:
|
||
|
VerboseLogging(request, "Request Aborted!");
|
||
|
|
||
|
tcs.TrySetCanceled();
|
||
|
break;
|
||
|
|
||
|
// Connecting to the server is timed out.
|
||
|
case HTTPRequestStates.ConnectionTimedOut:
|
||
|
VerboseLogging(request, "Connection Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Connection Timed Out!"));
|
||
|
break;
|
||
|
|
||
|
// The request didn't finished in the given time.
|
||
|
case HTTPRequestStates.TimedOut:
|
||
|
VerboseLogging(request, "Processing the request Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Processing the request Timed Out!"));
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public static Task<byte[]> GetRawDataAsync(this HTTPRequest request, CancellationToken token = default)
|
||
|
{
|
||
|
return CreateTask<byte[]>(request, token, (req, resp, tcs) =>
|
||
|
{
|
||
|
switch (req.State)
|
||
|
{
|
||
|
// The request finished without any problem.
|
||
|
case HTTPRequestStates.Finished:
|
||
|
if (resp.IsSuccess)
|
||
|
tcs.TrySetResult(resp.Data);
|
||
|
else
|
||
|
tcs.TrySetException(CreateException("Request finished Successfully, but the server sent an error.", resp));
|
||
|
break;
|
||
|
|
||
|
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||
|
case HTTPRequestStates.Error:
|
||
|
VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
|
||
|
|
||
|
tcs.TrySetException(CreateException("Request Finished with Error!", null, req.Exception));
|
||
|
break;
|
||
|
|
||
|
// The request aborted, initiated by the user.
|
||
|
case HTTPRequestStates.Aborted:
|
||
|
VerboseLogging(request, "Request Aborted!");
|
||
|
|
||
|
tcs.TrySetCanceled();
|
||
|
break;
|
||
|
|
||
|
// Connecting to the server is timed out.
|
||
|
case HTTPRequestStates.ConnectionTimedOut:
|
||
|
VerboseLogging(request, "Connection Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Connection Timed Out!"));
|
||
|
break;
|
||
|
|
||
|
// The request didn't finished in the given time.
|
||
|
case HTTPRequestStates.TimedOut:
|
||
|
VerboseLogging(request, "Processing the request Timed Out!");
|
||
|
|
||
|
tcs.TrySetException(CreateException("Processing the request Timed Out!"));
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||
|
public static Task<T> CreateTask<T>(HTTPRequest request, CancellationToken token, Action<HTTPRequest, HTTPResponse, TaskCompletionSource<T>> callback)
|
||
|
{
|
||
|
HTTPManager.Setup();
|
||
|
|
||
|
var tcs = new TaskCompletionSource<T>();
|
||
|
|
||
|
request.Callback = (req, resp) =>
|
||
|
{
|
||
|
if (token.IsCancellationRequested)
|
||
|
tcs.SetCanceled();
|
||
|
else
|
||
|
callback(req, resp, tcs);
|
||
|
};
|
||
|
|
||
|
if (token.CanBeCanceled)
|
||
|
token.Register((state) => (state as HTTPRequest)?.Abort(), request);
|
||
|
|
||
|
if (request.State == HTTPRequestStates.Initial)
|
||
|
request.Send();
|
||
|
|
||
|
return tcs.Task;
|
||
|
}
|
||
|
|
||
|
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||
|
public static void VerboseLogging(HTTPRequest request, string str)
|
||
|
{
|
||
|
HTTPManager.Logger.Verbose("HTTPRequestAsyncExtensions", str, request.Context);
|
||
|
}
|
||
|
|
||
|
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||
|
public static Exception CreateException(string errorMessage, HTTPResponse resp = null, Exception ex = null)
|
||
|
{
|
||
|
if (resp != null)
|
||
|
return new AsyncHTTPException(resp.StatusCode, resp.Message, resp.DataAsText);
|
||
|
else if (ex != null)
|
||
|
return new AsyncHTTPException(ex.Message, ex);
|
||
|
else
|
||
|
return new AsyncHTTPException(errorMessage);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|