From c2b8c1e8c9bcf27d7f77e0ca282b9eefdd7b0538 Mon Sep 17 00:00:00 2001 From: "Simon (Darkside) Jackson" Date: Mon, 8 Jan 2024 17:51:52 +0000 Subject: [PATCH] Release V1.0.7 (#43) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Prep for release * Auto increment pre-release version to 1.0.1 [skip ci] * disable tagging for development upversion * Apply V2 workflows (#19) Co-authored-by: Simon Jackson * Auto increment pre-release version to 1.0.1-pre-release.1 [skip ci] * Auto increment pre-release version to 1.0.2 [skip ci] * Fix prefab attribute does not render label (#21) * Auto increment pre-release version to 1.0.2-pre.1 [skip ci] * Auto increment pre-release version to 1.0.3 [skip ci] * Updated Rest features (#23) * Updating Rest utilities, added cancellation token to all calls. Plus clean up * Added Unit Tests to Rest functionality * Standardised overload options into a new RestArgs struct * Rationalised implementations for standards * Added overloaded Download function to return a byte[] or file string contents * Fix new script icon * Update workflow to multi-version for test * Updated PostForm following 2022 testing * Include uGUI dependency for the UI extensions in the package * Extract Canvas dependencies from the utility package * Final review and cleanup * Update Readme --------- Co-authored-by: Simon Jackson * Auto increment pre-release version to 1.0.3-pre.1 [skip ci] * Auto increment pre-release version to 1.0.4 [skip ci] * Next release updates (#27) * Initial commit for next round of updates - Changed fixed use of verbs to use the constants from UnityWebRequest definition. - #26 Added additional exception handling to log instead of throw, returns a Failed response instead - #25 Added the ability to set global override parameters - Added the ability to set a preferred download location, either globally or per call. Default is Temp * Auto increment pre-release version to 1.0.4-pre.1 [skip ci] * Add CODEOWNERS * Update for 1.0.4 release (#29) * Auto increment pre-release version to 1.0.4-pre.2 [skip ci] * Address comments * Auto increment pre-release version to 1.0.5 [skip ci] * Added logging utilities for projects (#31) * Added logging utilities for projects * Address review comments * Auto increment pre-release version to 1.0.5-pre.1 [skip ci] * Extended the Unity File helper with an additional option to get all files and not just Unity's own files. (#32) Updated the GuidRegenerator to use all files as it should not be limited when working with a path. * Auto increment pre-release version to 1.0.5-pre.2 [skip ci] * Fix ambiguous call (#34) Co-authored-by: Dino Fejzagic * Auto increment pre-release version to 1.0.5-pre.3 [skip ci] * Added a new Calculate Bounds extension and updated documentation for all (#35) * Auto increment pre-release version to 1.0.5-pre.4 [skip ci] * Update docs and readme for release (#36) * Auto increment pre-release version to 1.0.5-pre.5 [skip ci] * Auto increment pre-release version to 1.0.6 [skip ci] * Added audio streaming (#38) * Added audio streaming --------- Authored-by: Rony Portelli * Auto increment pre-release version to 1.0.7 [skip ci] * Deprecate the Rest utilities as this is not providing value to the toolkit (#42) * Update readme, remove mention of rest * Remove Rest classes and folders * Clean up Rest Tests --------- Co-authored-by: Dino Fejzagić * Auto increment pre-release version to 1.0.7-pre.1 [skip ci] --------- Co-authored-by: realitycollectivebuildbot Co-authored-by: Simon Jackson Co-authored-by: Dino Fejzagić Co-authored-by: Dino Fejzagic Co-authored-by: Rony Portelli --- README.md | 1 - Runtime/Utilities/WebRequestRest.meta | 10 - Runtime/Utilities/WebRequestRest/Response.cs | 51 - .../Utilities/WebRequestRest/Response.cs.meta | 11 - Runtime/Utilities/WebRequestRest/Rest.cs | 892 ------------------ Runtime/Utilities/WebRequestRest/Rest.cs.meta | 11 - Runtime/Utilities/WebRequestRest/RestArgs.cs | 23 - .../Utilities/WebRequestRest/RestArgs.cs.meta | 11 - Tests/Rest.meta | 8 - Tests/Rest/RestTests.cs | 248 ----- Tests/Rest/RestTests.cs.meta | 11 - package.json | 2 +- 12 files changed, 1 insertion(+), 1278 deletions(-) delete mode 100644 Runtime/Utilities/WebRequestRest.meta delete mode 100644 Runtime/Utilities/WebRequestRest/Response.cs delete mode 100644 Runtime/Utilities/WebRequestRest/Response.cs.meta delete mode 100644 Runtime/Utilities/WebRequestRest/Rest.cs delete mode 100644 Runtime/Utilities/WebRequestRest/Rest.cs.meta delete mode 100644 Runtime/Utilities/WebRequestRest/RestArgs.cs delete mode 100644 Runtime/Utilities/WebRequestRest/RestArgs.cs.meta delete mode 100644 Tests/Rest.meta delete mode 100644 Tests/Rest/RestTests.cs delete mode 100644 Tests/Rest/RestTests.cs.meta diff --git a/README.md b/README.md index ba05023..4cc3854 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ A collection of useful utilities for Unity Projects by the Reality Collective. ### Utilities -* Rest - A collection of Rest based tools to make making and using Rest calls in Unity very easy. * Async - A collection of Asynchronous and CoRoutine helpers for working with Sync -> Async code. ### Extensions diff --git a/Runtime/Utilities/WebRequestRest.meta b/Runtime/Utilities/WebRequestRest.meta deleted file mode 100644 index 1bad23c..0000000 --- a/Runtime/Utilities/WebRequestRest.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: 98c410670aab4d8a854f82ab750405c2 -folderAsset: yes -timeCreated: 1522521931 -licenseType: Pro -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Utilities/WebRequestRest/Response.cs b/Runtime/Utilities/WebRequestRest/Response.cs deleted file mode 100644 index 3503148..0000000 --- a/Runtime/Utilities/WebRequestRest/Response.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Reality Collective. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -namespace RealityCollective.Utilities.WebRequestRest -{ - /// - /// Response to a REST Call. - /// - public struct Response - { - /// - /// Was the REST call successful? - /// - public bool Successful { get; } - - /// - /// Response body from the resource. - /// - public string ResponseBody { get; } - - /// - /// Response data from the resource. - /// - public byte[] ResponseData { get; } - - /// - /// Response code from the resource. - /// - public long ResponseCode { get; } - - /// - /// Constructor. - /// - /// Was the REST call successful? - /// Response body from the resource. - /// Response data from the resource. - /// Response code from the resource. - public Response(bool successful, string responseBody, byte[] responseData, long responseCode) - { - Successful = successful; - ResponseBody = responseBody; - ResponseData = responseData; - ResponseCode = responseCode; - } - - /// - /// Failure response type - /// - public static Response Failure => new Response(false, string.Empty, null, -1); - } -} diff --git a/Runtime/Utilities/WebRequestRest/Response.cs.meta b/Runtime/Utilities/WebRequestRest/Response.cs.meta deleted file mode 100644 index 2da9ec3..0000000 --- a/Runtime/Utilities/WebRequestRest/Response.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a6dbf318d00547d38e4c22727c2b8d4a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Utilities/WebRequestRest/Rest.cs b/Runtime/Utilities/WebRequestRest/Rest.cs deleted file mode 100644 index 960146c..0000000 --- a/Runtime/Utilities/WebRequestRest/Rest.cs +++ /dev/null @@ -1,892 +0,0 @@ -// Copyright (c) Reality Collective. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -using RealityCollective.Utilities.Async; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.Networking; -using UnityEngine.ResourceManagement.ResourceProviders; - -namespace RealityCollective.Utilities.WebRequestRest -{ - /// - /// REST Class for CRUD Transactions. - /// - public static class Rest - { - #region Global Properties - public static string DownloadLocation = Application.temporaryCachePath; - public static Dictionary Headers = new Dictionary(); - public static IProgress Progress = null; - public static int Timeout = 0; - public static CancellationToken CancellationToken; - public static bool ReadResponseData = false; - public static CertificateHandler CertificateHandler = null; - public static bool DisposeCertificateHandlerOnDispose = true; - public static bool ForceDownload = false; - #endregion - - #region Authentication - - /// - /// Gets the Basic auth header. - /// - /// The Username. - /// The password. - /// The Basic authorization header encoded to base 64. - public static string GetBasicAuthentication(string username, string password) - { - return $"Basic {Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}"))}"; - } - - /// - /// Gets the Bearer auth header. - /// - /// OAuth Token to be used. - /// The Bearer authorization header. - public static string GetBearerOAuthToken(string authToken) - { - return $"Bearer {authToken}"; - } - - #endregion Authentication - - #region GET - - /// - /// Rest GET. - /// - /// Finalized Endpoint Query with parameters. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task GetAsync(string query, RestArgs getArgs = default) - { - using var webRequest = UnityWebRequest.Get(query); - try - { - return await ProcessRequestAsync(webRequest, getArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Get", query, ex)); - return Response.Failure; - } - } - - #endregion GET - - #region POST - - /// - /// Rest POST. - /// - /// Finalized Endpoint Query with parameters. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task PostAsync(string query, RestArgs postArgs = default) - { -#if UNITY_2022_2_OR_NEWER - using var webRequest = UnityWebRequest.PostWwwForm(query, null); -#else - using var webRequest = UnityWebRequest.Post(query, null as string); -#endif - try - { - return await ProcessRequestAsync(webRequest, postArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Post", query, ex)); - return Response.Failure; - } - } - - /// - /// Rest POST. - /// - /// Finalized Endpoint Query with parameters. - /// Form Data. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task PostAsync(string query, WWWForm formData, RestArgs postArgs = default) - { - - using var webRequest = UnityWebRequest.Post(query, formData); - try - { - return await ProcessRequestAsync(webRequest, postArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Post form", query, ex)); - return Response.Failure; - } - } - - /// - /// Rest POST. - /// - /// Finalized Endpoint Query with parameters. - /// JSON data for the request. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task PostAsync(string query, string jsonData, RestArgs postArgs = default) - { -#if UNITY_2022_2_OR_NEWER - using var webRequest = UnityWebRequest.PostWwwForm(query, UnityWebRequest.kHttpVerbPOST); -#else - using var webRequest = UnityWebRequest.Post(query, UnityWebRequest.kHttpVerbPOST); -#endif - var data = new UTF8Encoding().GetBytes(jsonData); - webRequest.uploadHandler = new UploadHandlerRaw(data); - webRequest.downloadHandler = new DownloadHandlerBuffer(); - webRequest.SetRequestHeader("Content-Type", "application/json"); - webRequest.SetRequestHeader("Accept", "application/json"); - try - { - return await ProcessRequestAsync(webRequest, postArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Post json", query, ex)); - return Response.Failure; - } - } - - /// - /// Rest POST. - /// - /// Finalized Endpoint Query with parameters. - /// The raw data to post. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task PostAsync(string query, byte[] bodyData, RestArgs postArgs = default) - { -#if UNITY_2022_2_OR_NEWER - using var webRequest = UnityWebRequest.PostWwwForm(query, UnityWebRequest.kHttpVerbPOST); -#else - using var webRequest = UnityWebRequest.Post(query, UnityWebRequest.kHttpVerbPOST); -#endif - webRequest.uploadHandler = new UploadHandlerRaw(bodyData); - webRequest.downloadHandler = new DownloadHandlerBuffer(); - webRequest.SetRequestHeader("Content-Type", "application/octet-stream"); - try - { - return await ProcessRequestAsync(webRequest, postArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Post Bytes", query, ex)); - return Response.Failure; - } - } - - #endregion POST - - #region PUT - - /// - /// Rest PUT. - /// - /// Finalized Endpoint Query with parameters. - /// Data to be submitted. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task PutAsync(string query, string jsonData, RestArgs putArgs = default) - { - using var webRequest = UnityWebRequest.Put(query, jsonData); - webRequest.SetRequestHeader("Content-Type", "application/json"); - try - { - return await ProcessRequestAsync(webRequest, putArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Put json", query, ex)); - return Response.Failure; - } - } - - /// - /// Rest PUT. - /// - /// Finalized Endpoint Query with parameters. - /// Data to be submitted. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task PutAsync(string query, byte[] bodyData, RestArgs putArgs = default) - { - using var webRequest = UnityWebRequest.Put(query, bodyData); - webRequest.SetRequestHeader("Content-Type", "application/octet-stream"); - try - { - return await ProcessRequestAsync(webRequest, putArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Put bytes", query, ex)); - return Response.Failure; - } - } - - #endregion PUT - - #region DELETE - - /// - /// Rest DELETE. - /// - /// Finalized Endpoint Query with parameters. - /// Optional additional argumens for the Rest request, . - /// The response data. - public static async Task DeleteAsync(string query, RestArgs deleteArgs = default) - { - using var webRequest = UnityWebRequest.Delete(query); - try - { - return await ProcessRequestAsync(webRequest, deleteArgs); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorRequest("Delete", query, ex)); - return Response.Failure; - } - } - - #endregion DELETE - - #region Get Multimedia Content - - #region Download Cache - - private const string DOWNLOAD_CACHE = "download_cache"; - - /// - /// Generates a based on the string. - /// - /// The string to generate the . - /// A new that represents the string. - private static Guid GenerateGuid(string @string) - { - using MD5 md5 = MD5.Create(); - return new Guid(md5.ComputeHash(Encoding.Default.GetBytes(@string))); - } - - /// - /// The download cache directory.
- ///
- public static string DownloadCacheDirectory - => Path.Combine(Application.temporaryCachePath, DOWNLOAD_CACHE); - - /// - /// Creates the if it does not exist. - /// - public static void ValidateCacheDirectory(string DownloadDirectory) - { - if (!Directory.Exists(DownloadDirectory)) - { - Directory.CreateDirectory(DownloadDirectory); - } - } - - /// - /// Try to get a file out of the download cache by uri reference. - /// - /// The uri key of the item. - /// The file path to the cached item. - /// True, if the item was in cache, otherwise false. - public static bool TryGetDownloadCacheItem(string uri, out string filePath, string downloadDirectory = "", bool forceDownload = false) - { - var downloadLocation = string.IsNullOrEmpty(downloadDirectory) ? DownloadCacheDirectory : downloadDirectory; - ValidateCacheDirectory(downloadLocation); - bool exists; - - if (TryGetFileNameFromUrl(uri, out var fileName)) - { - filePath = Path.Combine(downloadLocation, fileName); - exists = File.Exists(filePath); - } - else - { - filePath = Path.Combine(downloadLocation, GenerateGuid(uri).ToString()); - exists = File.Exists(filePath); - } - - if (exists) - { - if (forceDownload) - { - return !TryDeleteCacheItem(uri, downloadDirectory); - } -#if UNITY_STANDALONE || UNITY_WSA || UNITY_EDITOR_WIN - filePath = $"{Path.GetFullPath(filePath)}"; -#else - filePath = $"file://{Path.GetFullPath(filePath)}"; -#endif - } - - return exists; - } - - /// - /// Try to delete the cached item at the uri. - /// - /// The uri key of the item. - /// True, if the cached item was successfully deleted. - public static bool TryDeleteCacheItem(string uri, string downloadDirectory = "") - { - if (!TryGetDownloadCacheItem(uri, out var filePath, downloadDirectory)) - { - return false; - } - - try - { - File.Delete(filePath); - } - catch (Exception e) - { - Debug.LogError(GenerateErrorRequest("Delete file", uri, e)); - } - - return !File.Exists(filePath); - } - - /// - /// Deletes all the files in the download cache. - /// - public static void DeleteDownloadCache() - { - if (Directory.Exists(DownloadCacheDirectory)) - { - Directory.Delete(DownloadCacheDirectory, true); - } - } - - /// - /// Find the filename based on the url. - /// - /// The url to parse to try to guess file name. - /// The filename if found. - /// True, if a valid filename is found. - private static bool TryGetFileNameFromUrl(string url, out string fileName) - { - var baseUrl = url.Split('?')[0]; - var index = baseUrl.LastIndexOf('/') + 1; - fileName = baseUrl.Substring(index, baseUrl.Length - index); - return Path.HasExtension(fileName); - } - -#endregion Download Cache - - /// - /// Download a from the provided . - /// - /// The url to download the from. - /// Optional, file name to download (including extension). - /// Optional additional argumens for the Rest request, . - /// A new instance. - public static async Task DownloadTextureAsync(string url, string fileName = null, RestArgs downloadTextureArgs = default) - { - await Awaiters.UnityMainThread; - var downloadLocation = string.IsNullOrEmpty(downloadTextureArgs.DownloadLocation) ? DownloadLocation : downloadTextureArgs.DownloadLocation; - - bool isCached; - string cachePath; - - if (string.IsNullOrWhiteSpace(fileName)) - { - TryGetFileNameFromUrl(url, out fileName); - } - - if (url.Contains("file://")) - { - isCached = true; - cachePath = url; - } - else - { - isCached = TryGetDownloadCacheItem(fileName, out cachePath, downloadLocation, ForceDownload || downloadTextureArgs.ForceDownload); - } - - using var webRequest = UnityWebRequestTexture.GetTexture(url); - var response = await ProcessRequestAsync(webRequest, downloadTextureArgs); - - if (!response.Successful) - { - Debug.LogError(GenerateErrorMessage("texture", url, response)); - return null; - } - - var downloadHandler = (DownloadHandlerTexture)webRequest.downloadHandler; - - if (!isCached && !File.Exists(cachePath)) - { - try - { - using var fileStream = File.OpenWrite(cachePath); - await fileStream.WriteAsync(downloadHandler.data, 0, downloadHandler.data.Length, CancellationToken.None); - } - catch (Exception e) - { - Debug.LogError(GenerateErrorMessage("texture", url, e)); - } - } - - return downloadHandler.texture; - } - - /// - /// Download a from the provided . - /// - /// The url to download the from. - /// to download. - /// Optional, file name to download (including extension). - /// Optional additional argumens for the Rest request, . - /// A new instance. - public static async Task DownloadAudioClipAsync(string url, AudioType audioType, string fileName = "", RestArgs downloadAudioClipArgs = default) - { - await Awaiters.UnityMainThread; - var downloadLocation = string.IsNullOrEmpty(downloadAudioClipArgs.DownloadLocation) ? DownloadLocation : downloadAudioClipArgs.DownloadLocation; - - if (string.IsNullOrWhiteSpace(fileName)) - { - TryGetFileNameFromUrl(url, out fileName); - } - - bool isCached; - string cachePath; - - if (url.Contains("file://")) - { - isCached = true; - cachePath = url; - } - else - { - isCached = TryGetDownloadCacheItem(fileName, out cachePath, downloadLocation, ForceDownload || downloadAudioClipArgs.ForceDownload); - } - - if (isCached) - { - url = cachePath; - } - - using var webRequest = UnityWebRequestMultimedia.GetAudioClip(url, audioType); - var response = await ProcessRequestAsync(webRequest, downloadAudioClipArgs); - - if (!response.Successful) - { - Debug.LogError(GenerateErrorMessage("audio clip", url, response)); - return null; - } - - var downloadHandler = (DownloadHandlerAudioClip)webRequest.downloadHandler; - - if (!isCached && !File.Exists(cachePath)) - { - try - { - using var fileStream = File.OpenWrite(cachePath); - await fileStream.WriteAsync(downloadHandler.data, 0, downloadHandler.data.Length, CancellationToken.None); - } - catch (Exception e) - { - Debug.LogError(GenerateErrorMessage("audio clip", url, e)); - } - } - - return downloadHandler.audioClip; - } - - /// - /// Download a from the provided . - /// - /// The url to download the from. - /// Asset bundle request options. - /// Optional additional argumens for the Rest request, . - /// A new instance. - public static async Task DownloadAssetBundleAsync(string url, AssetBundleRequestOptions options, RestArgs downloadAssetBundleArgs = default) - { - await Awaiters.UnityMainThread; - - UnityWebRequest webRequest; - - if (options == null) - { - webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url); - } - else - { - if (!string.IsNullOrEmpty(options.Hash)) - { - CachedAssetBundle cachedBundle = new CachedAssetBundle(options.BundleName, Hash128.Parse(options.Hash)); -#if ENABLE_CACHING - if (options.UseCrcForCachedBundle || !Caching.IsVersionCached(cachedBundle)) - { - webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url, cachedBundle, options.Crc); - } - else - { - webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url, cachedBundle); - } -#else - webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url, cachedBundle, options.Crc); -#endif - } - else - { - webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url, options.Crc); - } - - if (options.Timeout > 0) - { - webRequest.timeout = options.Timeout; - } - - if (options.RedirectLimit > 0) - { - webRequest.redirectLimit = options.RedirectLimit; - } - -#if !UNITY_2019_3_OR_NEWER - webRequest.chunkedTransfer = options.ChunkedTransfer; -#endif - } - - using (webRequest) - { - Response response; - - try - { - if (downloadAssetBundleArgs.Timeout == 0 && options?.Timeout > 0) - { - downloadAssetBundleArgs.Timeout = options.Timeout; - } - response = await ProcessRequestAsync(webRequest, downloadAssetBundleArgs); - } - catch (Exception e) - { - Debug.LogError(GenerateErrorRequest("Asset bundle download", url, e)); - throw; - } - - if (!response.Successful) - { - Debug.LogError(GenerateErrorMessage("asset bundle", url, response)); - return null; - } - - var downloadHandler = (DownloadHandlerAssetBundle)webRequest.downloadHandler; - return downloadHandler.assetBundle; - } - } - - /// - /// Download a file from the provided . - /// - /// The url to download the file from. - /// Optional file name to download (including extension). - /// Optional additional argumens for the Rest request, . - /// The path to the downloaded file. - public static async Task DownloadFileAsync(string url, string fileName = null, RestArgs downloadFileArgs = default) - { - await Awaiters.UnityMainThread; - var downloadLocation = string.IsNullOrEmpty(downloadFileArgs.DownloadLocation) ? DownloadLocation : downloadFileArgs.DownloadLocation; - - if (string.IsNullOrWhiteSpace(fileName)) - { - TryGetFileNameFromUrl(url, out fileName); - } - - if (TryGetDownloadCacheItem(fileName, out var filePath, downloadLocation, ForceDownload || downloadFileArgs.ForceDownload)) - { - return filePath; - } - - using var webRequest = UnityWebRequest.Get(url); - using var fileDownloadHandler = new DownloadHandlerFile(filePath) - { - removeFileOnAbort = true - }; - - webRequest.downloadHandler = fileDownloadHandler; - try - { - var response = await ProcessRequestAsync(webRequest, downloadFileArgs); - if (!response.Successful) - { - Debug.LogError(GenerateErrorMessage("file", url, response)); - return null; - } - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorMessage("file", url, ex)); - return null; - } - - return filePath; - } - - /// - /// Download a file from the provided and return its contents as a . - /// - /// The url to download the file from. - /// Optional file name to download (including extension). - /// Optional additional argumens for the Rest request, . - /// The path to the downloaded file. - /// Intended for use where you need the raw contents of the target file - public static async Task DownloadFileBytesAsync(string url, string fileName = null, RestArgs downloadFileArgs = default) - { - byte[] bytes = null; - await Awaiters.UnityMainThread; - var downloadLocation = string.IsNullOrEmpty(downloadFileArgs.DownloadLocation) ? DownloadLocation : downloadFileArgs.DownloadLocation; - - if (string.IsNullOrWhiteSpace(fileName)) - { - TryGetFileNameFromUrl(url, out fileName); - } - - if (!TryGetDownloadCacheItem(fileName, out var filePath, downloadLocation)) - { - filePath = await DownloadFileAsync(url, fileName, downloadFileArgs); - } - - if (File.Exists(filePath)) - { - try - { - bytes = File.ReadAllBytes(filePath); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorMessage("File as Bytes", url, ex)); - } - } - - return bytes; - } - - /// - /// Download a file from the provided and return its contents as a . - /// - /// The url to download the file from. - /// Optional file name to download (including extension). - /// Optional additional argumens for the Rest request, . - /// The path to the downloaded file. - /// Intended for use in configuration/json files. - public static async Task DownloadFileStringAsync(string url, string fileName = null, RestArgs downloadFileArgs = default) - { - string fileContents = null; - await Awaiters.UnityMainThread; - var downloadLocation = string.IsNullOrEmpty(downloadFileArgs.DownloadLocation) ? DownloadLocation : downloadFileArgs.DownloadLocation; - - if (string.IsNullOrWhiteSpace(fileName)) - { - TryGetFileNameFromUrl(url, out fileName); - } - - if (!TryGetDownloadCacheItem(fileName, out string filePath, downloadLocation)) - { - filePath = await DownloadFileAsync(url, fileName, downloadFileArgs); - } - - if (File.Exists(filePath)) - { - try - { - using var sr = new StreamReader(filePath); - fileContents = sr.ReadToEnd(); - } - catch (Exception ex) - { - Debug.LogError(GenerateErrorMessage("File as String", url, ex)); - } - } - - return fileContents; - } - -#endregion Get Multimedia Content - - #region Private Functions - - private static async Task ProcessRequestAsync(UnityWebRequest webRequest, RestArgs processArgs) - { - await Awaiters.UnityMainThread; - - var timeout = Timeout + processArgs.Timeout; - if (timeout > 0) - { - webRequest.timeout = timeout; - } - - // Use defaults - if (Headers.Count > 0) - { - foreach (var header in Headers) - { - webRequest.SetRequestHeader(header.Key, header.Value); - } - } - - // Apply overrides if supplied - if (processArgs.Headers != null) - { - foreach (var header in processArgs.Headers) - { - webRequest.SetRequestHeader(header.Key, header.Value); - } - } - - var isUpload = webRequest.method == UnityWebRequest.kHttpVerbPOST || - webRequest.method == UnityWebRequest.kHttpVerbPUT; - - if (isUpload) - { - var contentType = webRequest.GetRequestHeader("Content-Type"); - - if (contentType != null) - { - contentType = contentType.Replace("\"", ""); - webRequest.SetRequestHeader("Content-Type", contentType); - } - } - - webRequest.disposeCertificateHandlerOnDispose = true; - webRequest.disposeDownloadHandlerOnDispose = true; - webRequest.disposeUploadHandlerOnDispose = true; - - Thread backgroundThread = null; - - if (Progress != null || processArgs.Progress != null) - { - async void ProgressReportingThread() - { - try - { - await Awaiters.UnityMainThread; - - while (!webRequest.isDone) - { - // Update default progress if set - Progress?.Report(isUpload ? webRequest.uploadProgress : webRequest.downloadProgress * 100f); - - processArgs.Progress?.Report(isUpload ? webRequest.uploadProgress : webRequest.downloadProgress * 100f); - - if (CancellationToken.IsCancellationRequested || processArgs.CancellationToken.IsCancellationRequested) - { - webRequest.Abort(); - } - - await Awaiters.UnityMainThread; - } - } - catch (Exception) - { - // Throw away - } - } - - backgroundThread = new Thread(ProgressReportingThread) - { - IsBackground = true - }; - } - - backgroundThread?.Start(); - - try - { - // Use defaults - if (CertificateHandler != null) - { - webRequest.certificateHandler = CertificateHandler; - webRequest.disposeCertificateHandlerOnDispose = DisposeCertificateHandlerOnDispose; - } - // Apply overrides if supplied - if (processArgs.CertificateHandler != null) - { - webRequest.certificateHandler = processArgs.CertificateHandler; - webRequest.disposeCertificateHandlerOnDispose = processArgs.DisposeCertificateHandlerOnDispose; - } - await webRequest.SendWebRequest(); - } - catch (Exception e) - { - Debug.LogError($"{nameof(Rest)}.{nameof(ProcessRequestAsync)}::Send Web Request Failed! {e}"); - } - - backgroundThread?.Join(); - Progress?.Report(100f); - processArgs.Progress?.Report(100f); - - if (webRequest.result == - UnityWebRequest.Result.ConnectionError || webRequest.result == UnityWebRequest.Result.ProtocolError) - { - if (webRequest.responseCode == 401) - { - return new Response(false, "Invalid Credentials", null, webRequest.responseCode); - } - - if (webRequest.GetResponseHeaders() == null) - { - return new Response(false, "Invalid Headers", null, webRequest.responseCode); - } - - var responseHeaders = webRequest.GetResponseHeaders().Aggregate(string.Empty, (_, header) => $"\n{header.Key}: {header.Value}"); - Debug.LogError($"REST Error {webRequest.responseCode}:{webRequest.downloadHandler?.text}{responseHeaders}"); - return new Response(false, $"{responseHeaders}\n{webRequest.downloadHandler?.text}", null, webRequest.responseCode); - } - - if (!string.IsNullOrEmpty(webRequest.downloadHandler?.error)) - { - return new Response(false, webRequest.downloadHandler.error, webRequest.downloadHandler.data, webRequest.responseCode); - } - - if (ReadResponseData || processArgs.ReadResponseData) - { - return new Response(true, webRequest.downloadHandler?.text, webRequest.downloadHandler?.data, webRequest.responseCode); - } - - switch (webRequest.downloadHandler) - { - case DownloadHandlerFile _: - case DownloadHandlerScript _: - case DownloadHandlerTexture _: - case DownloadHandlerAudioClip _: - case DownloadHandlerAssetBundle _: - return new Response(true, null, null, webRequest.responseCode); - case DownloadHandlerBuffer _: - return new Response(true, webRequest.downloadHandler?.text, webRequest.downloadHandler?.data, webRequest.responseCode); - default: - return new Response(true, webRequest.downloadHandler?.text, webRequest.downloadHandler?.data, webRequest.responseCode); - } - } - - private static string GenerateErrorMessage(string typeName, string url, Response response) - { - return $"Failed to download {typeName} from \"{url}\"!\n{response.ResponseCode}:{response.ResponseBody}"; - } - - private static string GenerateErrorMessage(string typeName, string url, Exception exception) - { - return $"Failed to download {typeName} from \"{url}\"!\n{exception.Message}\n{exception.StackTrace}"; - } - - private static string GenerateErrorRequest(string requestName, string url, Exception exception) - { - return $"A failure occured in a {requestName} call targetting \"{url}\"!\n{exception.Message}\n{exception.StackTrace}"; - } - #endregion Private Functions - } -} \ No newline at end of file diff --git a/Runtime/Utilities/WebRequestRest/Rest.cs.meta b/Runtime/Utilities/WebRequestRest/Rest.cs.meta deleted file mode 100644 index 86c706d..0000000 --- a/Runtime/Utilities/WebRequestRest/Rest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 12890992a4e44113951d54815484da67 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Utilities/WebRequestRest/RestArgs.cs b/Runtime/Utilities/WebRequestRest/RestArgs.cs deleted file mode 100644 index 6276ad6..0000000 --- a/Runtime/Utilities/WebRequestRest/RestArgs.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Reality Collective. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using UnityEngine.Networking; - -namespace RealityCollective.Utilities.WebRequestRest -{ - public struct RestArgs - { - public string DownloadLocation; - public Dictionary Headers; - public IProgress Progress; - public int Timeout; - public CancellationToken CancellationToken; - public bool ReadResponseData; - public CertificateHandler CertificateHandler; - public bool DisposeCertificateHandlerOnDispose; - public bool ForceDownload; - } -} diff --git a/Runtime/Utilities/WebRequestRest/RestArgs.cs.meta b/Runtime/Utilities/WebRequestRest/RestArgs.cs.meta deleted file mode 100644 index 033f622..0000000 --- a/Runtime/Utilities/WebRequestRest/RestArgs.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 615b391074810234e8123c22de6794fe -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Tests/Rest.meta b/Tests/Rest.meta deleted file mode 100644 index 959d1cd..0000000 --- a/Tests/Rest.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f838482214b5e9141bad631a94a74374 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Tests/Rest/RestTests.cs b/Tests/Rest/RestTests.cs deleted file mode 100644 index f36268d..0000000 --- a/Tests/Rest/RestTests.cs +++ /dev/null @@ -1,248 +0,0 @@ -using NUnit.Framework; -using RealityCollective.Extensions; -using RealityCollective.Utilities.Async; -using RealityCollective.Utilities.WebRequestRest; -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Security.AccessControl; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; - -namespace RealityCollective.Utilities.Tests.Extensions -{ - public class RestTests - { - #region Get Request - - [Test] - public async void Test_01_01_GetRequest() - { - string getURL = "https://httpbin.org/get"; - - await Rest.GetAsync(getURL).ContinueWith((response) => - { - Assert.IsNotNull(response.Result, "No result returned from Get request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Get request, result code was [{response.Result.ResponseCode}]"); - Assert.IsNotEmpty(response.Result.ResponseBody, "Returned Get result was empty"); - var resultText = System.Text.Encoding.Default.GetString(response.Result.ResponseData); - Assert.IsTrue(response.Result.ResponseBody == resultText, "Returned Text does not match Get response data"); - }); - } - - [Test] - public async void Test_01_02_GetRequestWithHeaders() - { - string getURL = "https://httpbin.org/get"; - Dictionary Headers = new Dictionary(); - Headers.Add("Content-Type", "application/json"); - - await Rest.GetAsync(getURL, new RestArgs() { Headers = Headers }).ContinueWith((response) => - { - Assert.IsNotNull(response.Result, "No result returned from Get request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Get request, result code was [{response.Result.ResponseCode}]"); - Assert.IsNotEmpty(response.Result.ResponseBody, "Returned Get result was empty"); - Assert.IsTrue(response.Result.ResponseBody.Contains("application/json"), "Get header was missing"); - }); - } - #endregion Get Request - - #region Post Request - - [Test] - public async void Test_02_01_PostRequest() - { - string postURL = "https://httpbin.org/post?data='The Result that was intended'"; - - await Rest.PostAsync(postURL).ContinueWith((response) => - { - Assert.IsNotNull(response.Result, "No result returned from Post request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Post request, result code was [{response.Result.ResponseCode}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("The Result that was intended"), "Returned Post string was not as expected"); - }); - } - - [Test] - public async void Test_02_02_PostRequestWithHeaders() - { - string postURL = "https://httpbin.org/post?data='The Result that was intended with headers'"; - - Dictionary Headers = new Dictionary(); - Headers.Add("Content-Type", "application/json"); - - await Rest.PostAsync(postURL, new RestArgs() { Headers = Headers }).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Post request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Post request, result code was [{response.Result.ResponseCode}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("The Result that was intended"), "Returned Post string was not as expected"); - Assert.IsTrue(response.Result.ResponseBody.Contains("application/json"), "Post header was missing"); - }); - } - - [Test] - public async void Test_02_03_PostFormRequest() - { - string postURL = "https://httpbin.org/post"; - WWWForm form = new WWWForm(); - form.AddField("MyForm", "MyData"); - - await Rest.PostAsync(postURL, form).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Get request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from request, result code was [{response.Result.ResponseCode}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("MyForm"), "Post MyForm Parameter was missing"); - Assert.IsTrue(response.Result.ResponseBody.Contains("MyData"), "Post MyData value was missing"); - }); - } - - [Serializable] - struct myJson { public string MyJsonProperty; } - - [Test] - public async void Test_02_04_PostJSONRequest() - { - string postURL = "https://httpbin.org/post"; - var input = new myJson() { MyJsonProperty = "MyJsonValue" }; - var json = JsonUtility.ToJson(input); - - await Rest.PostAsync(postURL, json).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Get request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Post request, result code was [{response.Result.ResponseCode}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("MyJsonProperty"),$"JSON Property was not found in th Post response\n[{response.Result.ResponseBody}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("MyJsonValue"), $"JSON Value was not found in the Post response\n[{response.Result.ResponseBody}]"); - }); - } - - [Test] - public async void Test_02_05_PostBytesRequest() - { - string postURL = "https://httpbin.org/post"; - string postString = "My word in my bond"; - var postBytes = Encoding.UTF8.GetBytes(postString); - - await Rest.PostAsync(postURL, postBytes).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Post request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Post request, result code was [{response.Result.ResponseCode}]"); - Assert.IsNotNull(response.Result.ResponseData, "No data returned from Post request"); - - var outputString = Encoding.UTF8.GetString(response.Result.ResponseData); - Assert.IsTrue(outputString.Contains(postString), "The decoded Post message does not match the input string"); - }); - } - #endregion Post Request - - #region Put Request - - [Test] - public async void Test_03_01_PutRequest() - { - string putURL = "https://httpbin.org/put?data='The Result that was intended'"; - var input = new myJson() { MyJsonProperty = "MyJsonValue" }; - var json = JsonUtility.ToJson(input); - - await Rest.PutAsync(putURL, json).ContinueWith((response) => - { - Assert.IsNotNull(response.Result, "No result returned from Put request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Put request, result code was [{response.Result.ResponseCode}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("The Result that was intended"), "Returned Put string was not as expected"); - }); - } - - [Test] - public async void Test_03_02_PutRequestWithHeaders() - { - string putURL = "https://httpbin.org/put?data='The Result that was intended with headers'"; - var input = new myJson() { MyJsonProperty = "MyJsonValue" }; - var json = JsonUtility.ToJson(input); - - Dictionary Headers = new Dictionary(); - Headers.Add("Content-Type", "application/json"); - - await Rest.PutAsync(putURL, json, new RestArgs() { Headers = Headers }).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Put request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Put request, result code was [{response.Result.ResponseCode}]"); - Assert.IsTrue(response.Result.ResponseBody.Contains("The Result that was intended"), "Returned Put string was not as expected"); - Assert.IsTrue(response.Result.ResponseBody.Contains("application/json"), "Put header was missing"); - }); - } - - [Test] - public async void Test_03_03_PutBytesRequest() - { - string putURL = "https://httpbin.org/put"; - string putString = "My word in my bond"; - var postBytes = Encoding.UTF8.GetBytes(putString); - - await Rest.PutAsync(putURL, postBytes).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Get request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Put request, result code was [{response.Result.ResponseCode}]"); - Assert.IsNotNull(response.Result.ResponseData, "No data returned from Put request"); - - var outputString = Encoding.UTF8.GetString(response.Result.ResponseData); - Assert.IsTrue(outputString.Contains(putString), "The decoded Put message does not match the input string"); - }); - } - #endregion Put Request - - #region Delete Request - - [Test] - public async void Test_04_01_DeleteRequest() - { - string putURL = "https://httpbin.org/delete?data='The Result that was intended'"; - - await Rest.DeleteAsync(putURL).ContinueWith((response) => - { - Assert.IsNotNull(response.Result, "No result returned from Delete request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Delete request, result code was [{response.Result.ResponseCode}]"); - }); - } - - [Test] - public async void Test_04_02_DeleteRequestWithHeaders() - { - string putURL = "https://httpbin.org/delete?data='The Result that was intended with headers'"; - - Dictionary Headers = new Dictionary(); - Headers.Add("Content-Type", "application/json"); - - await Rest.DeleteAsync(putURL, new RestArgs() { Headers = Headers }).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Delete request"); - Assert.IsTrue(response.Result.ResponseCode == 200, $"Bad result from Delete request, result code was [{response.Result.ResponseCode}]"); - }); - } - #endregion Delete Request - - #region Download Handlers - - [Test] - public async void Test_05_01_DownloadTexture() - { - string textureURL = "https://httpbin.org/image/jpeg"; - - await Rest.DownloadTextureAsync(textureURL).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from Texture request"); - }); - } - - [Test] - public async void Test_05_02_DownloadFile() - { - string fileURL = "https://httpbin.org/image/jpeg"; - - await Rest.DownloadFileAsync(fileURL).ContinueWith((response) => - { - Assert.IsNotNull(response, "No result returned from File request"); - }); - } - #endregion Download Handlers - - } -} \ No newline at end of file diff --git a/Tests/Rest/RestTests.cs.meta b/Tests/Rest/RestTests.cs.meta deleted file mode 100644 index 00a0aae..0000000 --- a/Tests/Rest/RestTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ea427a26a924a5d49801d89cbf5cbca6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/package.json b/package.json index 723811e..7d92233 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "Unity", "Tools" ], - "version": "1.0.5", + "version": "1.0.7-pre.1", "unity": "2020.3", "homepage": "https://realitycollective.io", "bugs": {