HTTPRequestAsyncExtensions.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #if CSHARP_7_OR_LATER
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using BestHTTP.Logger;
  7. using UnityEngine;
  8. namespace BestHTTP
  9. {
  10. public sealed class AsyncHTTPException : Exception
  11. {
  12. /// <summary>
  13. /// Status code of the server's response.
  14. /// </summary>
  15. public int StatusCode;
  16. /// <summary>
  17. /// Content sent by the server.
  18. /// </summary>
  19. public string Content;
  20. public AsyncHTTPException(string message)
  21. : base(message)
  22. {
  23. }
  24. public AsyncHTTPException(string message, Exception innerException)
  25. : base(message, innerException)
  26. {
  27. }
  28. public AsyncHTTPException(int statusCode, string message, string content)
  29. :base(message)
  30. {
  31. this.StatusCode = statusCode;
  32. this.Content = content;
  33. }
  34. public override string ToString()
  35. {
  36. return string.Format("StatusCode: {0}, Message: {1}, Content: {2}, StackTrace: {3}", this.StatusCode, this.Message, this.Content, this.StackTrace);
  37. }
  38. }
  39. public static class HTTPRequestAsyncExtensions
  40. {
  41. public static Task<HTTPResponse> GetHTTPResponseAsync(this HTTPRequest request, CancellationToken token = default)
  42. {
  43. return CreateTask<HTTPResponse>(request, token, (req, resp, tcs) =>
  44. {
  45. switch (req.State)
  46. {
  47. // The request finished without any problem.
  48. case HTTPRequestStates.Finished:
  49. tcs.TrySetResult(resp);
  50. break;
  51. // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
  52. case HTTPRequestStates.Error:
  53. VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
  54. tcs.TrySetException(CreateException("No Exception", null, req.Exception));
  55. break;
  56. // The request aborted, initiated by the user.
  57. case HTTPRequestStates.Aborted:
  58. VerboseLogging(request, "Request Aborted!");
  59. tcs.TrySetCanceled();
  60. break;
  61. // Connecting to the server is timed out.
  62. case HTTPRequestStates.ConnectionTimedOut:
  63. VerboseLogging(request, "Connection Timed Out!");
  64. tcs.TrySetException(CreateException("Connection Timed Out!"));
  65. break;
  66. // The request didn't finished in the given time.
  67. case HTTPRequestStates.TimedOut:
  68. VerboseLogging(request, "Processing the request Timed Out!");
  69. tcs.TrySetException(CreateException("Processing the request Timed Out!"));
  70. break;
  71. }
  72. });
  73. }
  74. public static Task<string> GetAsStringAsync(this HTTPRequest request, CancellationToken token = default)
  75. {
  76. return CreateTask<string>(request, token, (req, resp, tcs) =>
  77. {
  78. switch (req.State)
  79. {
  80. // The request finished without any problem.
  81. case HTTPRequestStates.Finished:
  82. if (resp.IsSuccess)
  83. tcs.TrySetResult(resp.DataAsText);
  84. else
  85. tcs.TrySetException(CreateException("Request finished Successfully, but the server sent an error.", resp));
  86. break;
  87. // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
  88. case HTTPRequestStates.Error:
  89. VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
  90. tcs.TrySetException(CreateException("No Exception", null, req.Exception));
  91. break;
  92. // The request aborted, initiated by the user.
  93. case HTTPRequestStates.Aborted:
  94. VerboseLogging(request, "Request Aborted!");
  95. tcs.TrySetCanceled();
  96. break;
  97. // Connecting to the server is timed out.
  98. case HTTPRequestStates.ConnectionTimedOut:
  99. VerboseLogging(request, "Connection Timed Out!");
  100. tcs.TrySetException(CreateException("Connection Timed Out!"));
  101. break;
  102. // The request didn't finished in the given time.
  103. case HTTPRequestStates.TimedOut:
  104. VerboseLogging(request, "Processing the request Timed Out!");
  105. tcs.TrySetException(CreateException("Processing the request Timed Out!"));
  106. break;
  107. }
  108. });
  109. }
  110. public static Task<Texture2D> GetAsTexture2DAsync(this HTTPRequest request, CancellationToken token = default)
  111. {
  112. return CreateTask<Texture2D>(request, token, (req, resp, tcs) =>
  113. {
  114. switch (req.State)
  115. {
  116. // The request finished without any problem.
  117. case HTTPRequestStates.Finished:
  118. if (resp.IsSuccess)
  119. tcs.TrySetResult(resp.DataAsTexture2D);
  120. else
  121. tcs.TrySetException(CreateException("Request finished Successfully, but the server sent an error.", resp));
  122. break;
  123. // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
  124. case HTTPRequestStates.Error:
  125. VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
  126. tcs.TrySetException(CreateException("No Exception", null, req.Exception));
  127. break;
  128. // The request aborted, initiated by the user.
  129. case HTTPRequestStates.Aborted:
  130. VerboseLogging(request, "Request Aborted!");
  131. tcs.TrySetCanceled();
  132. break;
  133. // Connecting to the server is timed out.
  134. case HTTPRequestStates.ConnectionTimedOut:
  135. VerboseLogging(request, "Connection Timed Out!");
  136. tcs.TrySetException(CreateException("Connection Timed Out!"));
  137. break;
  138. // The request didn't finished in the given time.
  139. case HTTPRequestStates.TimedOut:
  140. VerboseLogging(request, "Processing the request Timed Out!");
  141. tcs.TrySetException(CreateException("Processing the request Timed Out!"));
  142. break;
  143. }
  144. });
  145. }
  146. public static Task<byte[]> GetRawDataAsync(this HTTPRequest request, CancellationToken token = default)
  147. {
  148. return CreateTask<byte[]>(request, token, (req, resp, tcs) =>
  149. {
  150. switch (req.State)
  151. {
  152. // The request finished without any problem.
  153. case HTTPRequestStates.Finished:
  154. if (resp.IsSuccess)
  155. tcs.TrySetResult(resp.Data);
  156. else
  157. tcs.TrySetException(CreateException("Request finished Successfully, but the server sent an error.", resp));
  158. break;
  159. // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
  160. case HTTPRequestStates.Error:
  161. VerboseLogging(request, "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
  162. tcs.TrySetException(CreateException("No Exception", null, req.Exception));
  163. break;
  164. // The request aborted, initiated by the user.
  165. case HTTPRequestStates.Aborted:
  166. VerboseLogging(request, "Request Aborted!");
  167. tcs.TrySetCanceled();
  168. break;
  169. // Connecting to the server is timed out.
  170. case HTTPRequestStates.ConnectionTimedOut:
  171. VerboseLogging(request, "Connection Timed Out!");
  172. tcs.TrySetException(CreateException("Connection Timed Out!"));
  173. break;
  174. // The request didn't finished in the given time.
  175. case HTTPRequestStates.TimedOut:
  176. VerboseLogging(request, "Processing the request Timed Out!");
  177. tcs.TrySetException(CreateException("Processing the request Timed Out!"));
  178. break;
  179. }
  180. });
  181. }
  182. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  183. public static Task<T> CreateTask<T>(HTTPRequest request, CancellationToken token, Action<HTTPRequest, HTTPResponse, TaskCompletionSource<T>> callback)
  184. {
  185. HTTPManager.Setup();
  186. var tcs = new TaskCompletionSource<T>();
  187. request.Callback = (req, resp) =>
  188. {
  189. if (token.IsCancellationRequested)
  190. tcs.SetCanceled();
  191. else
  192. callback(req, resp, tcs);
  193. };
  194. if (token.CanBeCanceled)
  195. token.Register((state) => (state as HTTPRequest)?.Abort(), request);
  196. if (request.State == HTTPRequestStates.Initial)
  197. request.Send();
  198. return tcs.Task;
  199. }
  200. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  201. public static void VerboseLogging(HTTPRequest request, string str)
  202. {
  203. HTTPManager.Logger.Verbose("HTTPRequestAsyncExtensions", str, request.Context);
  204. }
  205. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  206. public static Exception CreateException(string errorMessage, HTTPResponse resp = null, Exception ex = null)
  207. {
  208. if (resp != null)
  209. return new AsyncHTTPException(resp.StatusCode, resp.Message, resp.DataAsText);
  210. else if (ex != null)
  211. return new AsyncHTTPException(ex.Message, ex);
  212. else
  213. return new AsyncHTTPException(errorMessage);
  214. }
  215. }
  216. }
  217. #endif