Skip to content

Commit

Permalink
com.utilities.rest 2.4.0 (#56)
Browse files Browse the repository at this point in the history
- Refactored Multimedia downloaders
  - Added Debugging flag for http requests
  - Fixed downloading for webgl
  • Loading branch information
StephenHodgson authored Dec 13, 2023
1 parent 8717e9d commit 6374dcf
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 221 deletions.
173 changes: 111 additions & 62 deletions Utilities.Rest/Packages/com.utilities.rest/Runtime/Rest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -429,34 +429,22 @@ public static async Task<Response> DeleteAsync(

#region Download Cache

private const string DOWNLOAD_CACHE = "download_cache";
private const string download_cache = nameof(download_cache);

private static IDownloadCache cache;

private static IDownloadCache Cache
{
get
=> cache ??= Application.platform switch
{
if (cache != null)
{
return cache;
}

cache = Application.platform switch
{
RuntimePlatform.WebGLPlayer => new NoOpDownloadCache(),
_ => new DiskDownloadCache()
};

return cache;
}
}
RuntimePlatform.WebGLPlayer => new NoOpDownloadCache(),
_ => new DiskDownloadCache()
};

/// <summary>
/// The download cache directory.<br/>
/// </summary>
public static string DownloadCacheDirectory
=> Path.Combine(Application.temporaryCachePath, DOWNLOAD_CACHE);
=> Path.Combine(Application.temporaryCachePath, download_cache);

/// <summary>
/// Creates the <see cref="DownloadCacheDirectory"/> if it doesn't exist.
Expand Down Expand Up @@ -510,19 +498,31 @@ public static bool TryGetFileNameFromUrl(string url, out string fileName)

#endregion Download Cache

[Obsolete("use new overload with debug support")]
public static async Task<Texture2D> DownloadTextureAsync(
string url,
string fileName = null,
RestParameters parameters = null,
CancellationToken cancellationToken = default)
{
return await DownloadTextureAsync(url, fileName, parameters, false, cancellationToken);
}

/// <summary>
/// Download a <see cref="Texture2D"/> from the provided <see cref="url"/>.
/// </summary>
/// <param name="url">The url to download the <see cref="Texture2D"/> from.</param>
/// <param name="fileName">Optional, file name to download (including extension).</param>
/// <param name="parameters">Optional, <see cref="RestParameters"/>.</param>
/// <param name="debug">Optional, debug http request.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns>A new <see cref="Texture2D"/> instance.</returns>
public static async Task<Texture2D> DownloadTextureAsync(
string url,
string fileName = null,
RestParameters parameters = null,
CancellationToken cancellationToken = default)
string url,
string fileName = null,
RestParameters parameters = null,
bool debug = false,
CancellationToken cancellationToken = default)
{
await Awaiters.UnityMainThread;

Expand All @@ -549,28 +549,22 @@ public static async Task<Texture2D> DownloadTextureAsync(
url = cachePath;
}

using var webRequest = UnityWebRequestTexture.GetTexture(url);
parameters ??= new RestParameters();
parameters.DisposeDownloadHandler = false;
var response = await webRequest.SendAsync(parameters, cancellationToken);

if (!response.Successful)
{
throw new RestException(response, $"Failed to download texture from \"{url}\"!");
}

Texture2D texture;
var downloadHandler = (DownloadHandlerTexture)webRequest.downloadHandler;
parameters ??= new RestParameters();
parameters.DisposeDownloadHandler = true;
using var webRequest = UnityWebRequestTexture.GetTexture(url);

try
{
var response = await webRequest.SendAsync(parameters, cancellationToken);
response.Validate(debug);

if (!isCached)
{
await Cache.WriteCacheItemAsync(downloadHandler.data, cachePath, cancellationToken);
await Cache.WriteCacheItemAsync(webRequest.downloadHandler.data, cachePath, cancellationToken).ConfigureAwait(true);
}

await Awaiters.UnityMainThread;
texture = downloadHandler.texture;
texture = ((DownloadHandlerTexture)webRequest.downloadHandler).texture;

if (texture == null)
{
Expand All @@ -579,27 +573,45 @@ public static async Task<Texture2D> DownloadTextureAsync(
}
finally
{
downloadHandler.Dispose();
webRequest.downloadHandler?.Dispose();
}

texture.name = Path.GetFileNameWithoutExtension(cachePath);
return texture;
}

[Obsolete("Use new overload with debug support")]
public static async Task<AudioClip> DownloadAudioClipAsync(
string url,
AudioType audioType,
RestParameters parameters = null,
CancellationToken cancellationToken = default)
{
return await DownloadAudioClipAsync(url, audioType, httpMethod: UnityWebRequest.kHttpVerbGET, parameters: parameters, cancellationToken: cancellationToken);
}

/// <summary>
/// Download a <see cref="AudioClip"/> from the provided <see cref="url"/>.
/// </summary>
/// <param name="url">The url to download the <see cref="AudioClip"/> from.</param>
/// <param name="audioType"><see cref="AudioType"/> to download.</param>
/// <param name="fileName">Optional, file name to download (including extension).</param>
/// <param name="httpMethod">Optional, must be either GET or POST.</param>
/// <param name="jsonData">Optional, json payload. Only <see cref="jsonData"/> OR <see cref="payload"/> can be supplied.</param>
/// <param name="payload">Optional, raw byte payload. Only <see cref="payload"/> OR <see cref="jsonData"/> can be supplied.</param>
/// <param name="parameters">Optional, <see cref="RestParameters"/>.</param>
/// <param name="debug">Optional, debug http request.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns>A new <see cref="AudioClip"/> instance.</returns>
public static async Task<AudioClip> DownloadAudioClipAsync(
string url,
AudioType audioType,
string httpMethod = UnityWebRequest.kHttpVerbGET,
string fileName = null,
string jsonData = null,
byte[] payload = null,
RestParameters parameters = null,
bool debug = false,
CancellationToken cancellationToken = default)
{
await Awaiters.UnityMainThread;
Expand Down Expand Up @@ -627,21 +639,53 @@ public static async Task<AudioClip> DownloadAudioClipAsync(
url = cachePath;
}

using var webRequest = UnityWebRequestMultimedia.GetAudioClip(url, audioType);
parameters ??= new RestParameters();
parameters.DisposeDownloadHandler = false;
var response = await webRequest.SendAsync(parameters, cancellationToken);
UploadHandler uploadHandler = null;
using var downloadHandler = new DownloadHandlerAudioClip(url, audioType);

if (!response.Successful)
if (httpMethod == UnityWebRequest.kHttpVerbPOST)
{
throw new RestException(response, $"Failed to download audio clip from \"{url}\"!");
if (!string.IsNullOrWhiteSpace(jsonData))
{
if (payload != null)
{
throw new ArgumentException($"{nameof(payload)} and {nameof(jsonData)} cannot be supplied in the same request. Choose either one or the other.", nameof(jsonData));
}

payload = new UTF8Encoding().GetBytes(jsonData);

var jsonHeaders = new Dictionary<string, string>
{
{ "Content-Type", "application/json" }
};

if (parameters is { Headers: not null })
{
foreach (var header in parameters.Headers)
{
jsonHeaders.Add(header.Key, header.Value);
}
}

if (parameters != null)
{
parameters.Headers = jsonHeaders;
}
}

uploadHandler = new UploadHandlerRaw(payload);
}

AudioClip clip;
var downloadHandler = (DownloadHandlerAudioClip)webRequest.downloadHandler;
parameters ??= new RestParameters();
parameters.DisposeUploadHandler = false;
parameters.DisposeDownloadHandler = false;
using var webRequest = new UnityWebRequest(url, httpMethod, downloadHandler, uploadHandler);

try
{
var response = await webRequest.SendAsync(parameters, cancellationToken);
response.Validate(debug);

if (!isCached)
{
await Cache.WriteCacheItemAsync(downloadHandler.data, cachePath, cancellationToken);
Expand All @@ -650,24 +694,23 @@ public static async Task<AudioClip> DownloadAudioClipAsync(
await Awaiters.UnityMainThread;
clip = downloadHandler.audioClip;

if (clip == null ||
clip.loadState == AudioDataLoadState.Failed ||
clip.loadState == AudioDataLoadState.Unloaded)
if (clip == null)
{
throw new RestException(response, $"Failed to load audio clip from \"{url}\"!");
throw new RestException(response, $"Failed to download audio clip from \"{url}\"!");
}
}
finally
{
downloadHandler.Dispose();
uploadHandler?.Dispose();
}

clip.name = Path.GetFileNameWithoutExtension(cachePath);
return clip;
}

/// <summary>
/// Download a <see cref="AudioClip"/> from the provided <see cref="url"/>.
/// Stream a <see cref="AudioClip"/> from the provided <see cref="url"/>.
/// </summary>
/// <param name="url">The url to download the <see cref="AudioClip"/> from.</param>
/// <param name="audioType"><see cref="AudioType"/> to download.</param>
Expand All @@ -680,7 +723,7 @@ public static async Task<AudioClip> DownloadAudioClipAsync(
/// <param name="parameters">Optional, <see cref="RestParameters"/>.</param>
/// <param name="debug">Optional, debug http request.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns>Raw downloaded bytes from the stream.</returns>
/// <returns>A new <see cref="AudioClip"/> instance.</returns>
public static async Task<AudioClip> StreamAudioAsync(
string url,
AudioType audioType,
Expand Down Expand Up @@ -748,9 +791,8 @@ public static async Task<AudioClip> StreamAudioAsync(
parameters.DisposeUploadHandler = false;
parameters.DisposeDownloadHandler = false;
using var downloadHandler = new DownloadHandlerAudioClip(url, audioType);
downloadHandler.streamAudio = true; // BUG: Due to a Unity bug this is actually totally non-functional... https://forum.unity.com/threads/downloadhandleraudioclip-streamaudio-is-ignored.699908/
downloadHandler.streamAudio = true; // BUG: Due to a Unity bug this does not work with mp3s of indeterminate length. https://forum.unity.com/threads/downloadhandleraudioclip-streamaudio-is-ignored.699908/
using var webRequest = new UnityWebRequest(url, httpMethod, downloadHandler, uploadHandler);

IProgress<Progress> progress = null;

if (parameters.Progress != null)
Expand Down Expand Up @@ -894,19 +936,31 @@ public static async Task<AssetBundle> DownloadAssetBundleAsync(

#endif // UNITY_ADDRESSABLES

[Obsolete("use new overload with debug support")]
public static async Task<string> DownloadFileAsync(
string url,
string fileName = null,
RestParameters parameters = null,
CancellationToken cancellationToken = default)
{
return await DownloadFileAsync(url, fileName, parameters, false, cancellationToken);
}

/// <summary>
/// Download a file from the provided <see cref="url"/>.
/// </summary>
/// <param name="url">The url to download the file from.</param>
/// <param name="fileName">Optional, file name to download (including extension).</param>
/// <param name="parameters">Optional, <see cref="RestParameters"/>.</param>
/// <param name="debug">Optional, debug http request.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns>The path to the downloaded file.</returns>
public static async Task<string> DownloadFileAsync(
string url,
string fileName = null,
RestParameters parameters = null,
CancellationToken cancellationToken = default)
string url,
string fileName = null,
RestParameters parameters = null,
bool debug = false,
CancellationToken cancellationToken = default)
{
await Awaiters.UnityMainThread;

Expand All @@ -925,12 +979,7 @@ public static async Task<string> DownloadFileAsync(
fileDownloadHandler.removeFileOnAbort = true;
webRequest.downloadHandler = fileDownloadHandler;
var response = await webRequest.SendAsync(parameters, cancellationToken);

if (!response.Successful)
{
throw new RestException(response, $"Failed to download file from \"{url}\"!");
}

response.Validate(debug);
return filePath;
}

Expand Down
2 changes: 1 addition & 1 deletion Utilities.Rest/Packages/com.utilities.rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "Utilities.Rest",
"description": "This package contains useful RESTful utilities for the Unity Game Engine.",
"keywords": [],
"version": "2.3.1",
"version": "2.4.0",
"unity": "2021.3",
"documentationUrl": "https://github.com/RageAgainstThePixel/com.utilities.rest#documentation",
"changelogUrl": "https://github.com/RageAgainstThePixel/com.utilities.rest/releases",
Expand Down
2 changes: 1 addition & 1 deletion Utilities.Rest/Packages/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dependencies": {
"com.unity.ide.rider": "3.0.26",
"com.unity.ide.rider": "3.0.27",
"com.unity.ide.visualstudio": "2.0.22",
"com.utilities.buildpipeline": "1.1.9"
},
Expand Down
Loading

0 comments on commit 6374dcf

Please sign in to comment.