Skip to content
This repository was archived by the owner on Aug 11, 2024. It is now read-only.

Commit 11badd2

Browse files
Dev/rest api updates (#819)
* updated rest api * fixed some formatting * sorted some methods * Added progress callbacks * updated license * sorted out all the signatures
1 parent f030b23 commit 11badd2

2 files changed

Lines changed: 145 additions & 33 deletions

File tree

XRTK-Core/Packages/com.xrtk.core/Runtime/Utilities/WebRequestRest/Response.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) XRTK. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

44
namespace XRTK.Utilities.WebRequestRest
@@ -31,10 +31,10 @@ public struct Response
3131
/// <summary>
3232
/// Constructor.
3333
/// </summary>
34-
/// <param name="successful"></param>
35-
/// <param name="responseBody"></param>
36-
/// <param name="responseData"></param>
37-
/// <param name="responseCode"></param>
34+
/// <param name="successful">Was the REST call successful?</param>
35+
/// <param name="responseBody">Response body from the resource.</param>
36+
/// <param name="responseData">Response data from the resource.</param>
37+
/// <param name="responseCode">Response code from the resource.</param>
3838
public Response(bool successful, string responseBody, byte[] responseData, long responseCode)
3939
{
4040
Successful = successful;
@@ -43,4 +43,4 @@ public Response(bool successful, string responseBody, byte[] responseData, long
4343
ResponseCode = responseCode;
4444
}
4545
}
46-
}
46+
}

XRTK-Core/Packages/com.xrtk.core/Runtime/Utilities/WebRequestRest/Rest.cs

Lines changed: 139 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) XRTK. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

44
using System;
55
using System.Collections.Generic;
66
using System.Linq;
77
using System.Text;
8+
using System.Threading;
89
using System.Threading.Tasks;
910
using UnityEngine;
1011
using UnityEngine.Networking;
1112
using XRTK.Utilities.Async;
1213

1314
namespace XRTK.Utilities.WebRequestRest
1415
{
15-
1616
/// <summary>
1717
/// REST Class for CRUD Transactions.
1818
/// </summary>
@@ -55,13 +55,14 @@ public static string GetBearerOAuthToken(string authToken)
5555
/// </summary>
5656
/// <param name="query">Finalized Endpoint Query with parameters.</param>
5757
/// <param name="headers">Optional header information for the request.</param>
58+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
5859
/// <param name="timeout">Optional time in seconds before request expires.</param>
5960
/// <returns>The response data.</returns>
60-
public static async Task<Response> GetAsync(string query, Dictionary<string, string> headers = null, int timeout = -1)
61+
public static async Task<Response> GetAsync(string query, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
6162
{
6263
using (var webRequest = UnityWebRequest.Get(query))
6364
{
64-
return await ProcessRequestAsync(webRequest, timeout, headers);
65+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
6566
}
6667
}
6768

@@ -74,13 +75,14 @@ public static async Task<Response> GetAsync(string query, Dictionary<string, str
7475
/// </summary>
7576
/// <param name="query">Finalized Endpoint Query with parameters.</param>
7677
/// <param name="headers">Optional header information for the request.</param>
78+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
7779
/// <param name="timeout">Optional time in seconds before request expires.</param>
7880
/// <returns>The response data.</returns>
79-
public static async Task<Response> PostAsync(string query, Dictionary<string, string> headers = null, int timeout = -1)
81+
public static async Task<Response> PostAsync(string query, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
8082
{
8183
using (var webRequest = UnityWebRequest.Post(query, null as string))
8284
{
83-
return await ProcessRequestAsync(webRequest, timeout, headers);
85+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
8486
}
8587
}
8688

@@ -90,13 +92,14 @@ public static async Task<Response> PostAsync(string query, Dictionary<string, st
9092
/// <param name="query">Finalized Endpoint Query with parameters.</param>
9193
/// <param name="formData">Form Data.</param>
9294
/// <param name="headers">Optional header information for the request.</param>
95+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
9396
/// <param name="timeout">Optional time in seconds before request expires.</param>
9497
/// <returns>The response data.</returns>
95-
public static async Task<Response> PostAsync(string query, WWWForm formData, Dictionary<string, string> headers = null, int timeout = -1)
98+
public static async Task<Response> PostAsync(string query, WWWForm formData, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
9699
{
97100
using (var webRequest = UnityWebRequest.Post(query, formData))
98101
{
99-
return await ProcessRequestAsync(webRequest, timeout, headers);
102+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
100103
}
101104
}
102105

@@ -106,9 +109,10 @@ public static async Task<Response> PostAsync(string query, WWWForm formData, Dic
106109
/// <param name="query">Finalized Endpoint Query with parameters.</param>
107110
/// <param name="jsonData">JSON data for the request.</param>
108111
/// <param name="headers">Optional header information for the request.</param>
112+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
109113
/// <param name="timeout">Optional time in seconds before request expires.</param>
110114
/// <returns>The response data.</returns>
111-
public static async Task<Response> PostAsync(string query, string jsonData, Dictionary<string, string> headers = null, int timeout = -1)
115+
public static async Task<Response> PostAsync(string query, string jsonData, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
112116
{
113117
using (var webRequest = UnityWebRequest.Post(query, "POST"))
114118
{
@@ -117,26 +121,27 @@ public static async Task<Response> PostAsync(string query, string jsonData, Dict
117121
webRequest.downloadHandler = new DownloadHandlerBuffer();
118122
webRequest.SetRequestHeader("Content-Type", "application/json");
119123
webRequest.SetRequestHeader("Accept", "application/json");
120-
return await ProcessRequestAsync(webRequest, timeout, headers);
124+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
121125
}
122126
}
123127

124128
/// <summary>
125129
/// Rest POST.
126130
/// </summary>
127131
/// <param name="query">Finalized Endpoint Query with parameters.</param>
128-
/// <param name="headers">Optional header information for the request.</param>
129132
/// <param name="bodyData">The raw data to post.</param>
133+
/// <param name="headers">Optional header information for the request.</param>
134+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
130135
/// <param name="timeout">Optional time in seconds before request expires.</param>
131136
/// <returns>The response data.</returns>
132-
public static async Task<Response> PostAsync(string query, byte[] bodyData, Dictionary<string, string> headers = null, int timeout = -1)
137+
public static async Task<Response> PostAsync(string query, byte[] bodyData, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
133138
{
134139
using (var webRequest = UnityWebRequest.Post(query, "POST"))
135140
{
136141
webRequest.uploadHandler = new UploadHandlerRaw(bodyData);
137142
webRequest.downloadHandler = new DownloadHandlerBuffer();
138143
webRequest.SetRequestHeader("Content-Type", "application/octet-stream");
139-
return await ProcessRequestAsync(webRequest, timeout, headers);
144+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
140145
}
141146
}
142147

@@ -150,14 +155,15 @@ public static async Task<Response> PostAsync(string query, byte[] bodyData, Dict
150155
/// <param name="query">Finalized Endpoint Query with parameters.</param>
151156
/// <param name="jsonData">Data to be submitted.</param>
152157
/// <param name="headers">Optional header information for the request.</param>
158+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
153159
/// <param name="timeout">Optional time in seconds before request expires.</param>
154160
/// <returns>The response data.</returns>
155-
public static async Task<Response> PutAsync(string query, string jsonData, Dictionary<string, string> headers = null, int timeout = -1)
161+
public static async Task<Response> PutAsync(string query, string jsonData, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
156162
{
157163
using (var webRequest = UnityWebRequest.Put(query, jsonData))
158164
{
159165
webRequest.SetRequestHeader("Content-Type", "application/json");
160-
return await ProcessRequestAsync(webRequest, timeout, headers);
166+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
161167
}
162168
}
163169

@@ -167,14 +173,15 @@ public static async Task<Response> PutAsync(string query, string jsonData, Dicti
167173
/// <param name="query">Finalized Endpoint Query with parameters.</param>
168174
/// <param name="bodyData">Data to be submitted.</param>
169175
/// <param name="headers">Optional header information for the request.</param>
176+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
170177
/// <param name="timeout">Optional time in seconds before request expires.</param>
171178
/// <returns>The response data.</returns>
172-
public static async Task<Response> PutAsync(string query, byte[] bodyData, Dictionary<string, string> headers = null, int timeout = -1)
179+
public static async Task<Response> PutAsync(string query, byte[] bodyData, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
173180
{
174181
using (var webRequest = UnityWebRequest.Put(query, bodyData))
175182
{
176183
webRequest.SetRequestHeader("Content-Type", "application/octet-stream");
177-
return await ProcessRequestAsync(webRequest, timeout, headers);
184+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
178185
}
179186
}
180187

@@ -187,19 +194,100 @@ public static async Task<Response> PutAsync(string query, byte[] bodyData, Dicti
187194
/// </summary>
188195
/// <param name="query">Finalized Endpoint Query with parameters.</param>
189196
/// <param name="headers">Optional header information for the request.</param>
197+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
190198
/// <param name="timeout">Optional time in seconds before request expires.</param>
191199
/// <returns>The response data.</returns>
192-
public static async Task<Response> DeleteAsync(string query, Dictionary<string, string> headers = null, int timeout = -1)
200+
public static async Task<Response> DeleteAsync(string query, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
193201
{
194202
using (var webRequest = UnityWebRequest.Delete(query))
195203
{
196-
return await ProcessRequestAsync(webRequest, timeout, headers);
204+
return await ProcessRequestAsync(webRequest, headers, progress, timeout);
197205
}
198206
}
199207

200208
#endregion DELETE
201209

202-
private static async Task<Response> ProcessRequestAsync(UnityWebRequest webRequest, int timeout, Dictionary<string, string> headers = null)
210+
#region Get Multimedia Content
211+
212+
/// <summary>
213+
/// Download a <see cref="Texture2D"/> from the provided <see cref="url"/>.
214+
/// </summary>
215+
/// <param name="url">The url to download the <see cref="Texture2D"/> from.</param>
216+
/// <param name="headers">Optional header information for the request.</param>
217+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
218+
/// <param name="timeout">Optional time in seconds before request expires.</param>
219+
/// <returns>A new <see cref="Texture2D"/> instance.</returns>
220+
public static async Task<Texture2D> DownloadTextureAsync(string url, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
221+
{
222+
using (var webRequest = UnityWebRequestTexture.GetTexture(url))
223+
{
224+
var response = await ProcessRequestAsync(webRequest, headers, progress, timeout);
225+
226+
if (!response.Successful)
227+
{
228+
Debug.LogError($"Failed to download texture from \"{url}\"!");
229+
230+
return null;
231+
}
232+
233+
return ((DownloadHandlerTexture)webRequest.downloadHandler).texture;
234+
}
235+
}
236+
237+
/// <summary>
238+
/// Download a <see cref="AudioClip"/> from the provided <see cref="url"/>.
239+
/// </summary>
240+
/// <param name="url">The url to download the <see cref="AudioClip"/> from.</param>
241+
/// <param name="audioType"><see cref="AudioType"/> to download.</param>
242+
/// <param name="headers">Optional header information for the request.</param>
243+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
244+
/// <param name="timeout">Optional time in seconds before request expires.</param>
245+
/// <returns>A new <see cref="AudioClip"/> instance.</returns>
246+
public static async Task<AudioClip> DownloadAudioClipAsync(string url, AudioType audioType, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
247+
{
248+
using (var webRequest = UnityWebRequestMultimedia.GetAudioClip(url, audioType))
249+
{
250+
var response = await ProcessRequestAsync(webRequest, headers, progress, timeout);
251+
252+
if (!response.Successful)
253+
{
254+
Debug.LogError($"Failed to download audio clip from \"{url}\"!");
255+
256+
return null;
257+
}
258+
259+
return ((DownloadHandlerAudioClip)webRequest.downloadHandler).audioClip;
260+
}
261+
}
262+
263+
/// <summary>
264+
/// Download a <see cref="AssetBundle"/> from the provided <see cref="url"/>.
265+
/// </summary>
266+
/// <param name="url">The url to download the <see cref="AssetBundle"/> from.</param>
267+
/// <param name="headers">Optional header information for the request.</param>
268+
/// <param name="progress">Optional <see cref="IProgress{T}"/> handler.</param>
269+
/// <param name="timeout">Optional time in seconds before request expires.</param>
270+
/// <returns>A new <see cref="AssetBundle"/> instance.</returns>
271+
public static async Task<AssetBundle> DownloadAssetBundleAsync(string url, Dictionary<string, string> headers = null, IProgress<float> progress = null, int timeout = -1)
272+
{
273+
using (var webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url))
274+
{
275+
var response = await ProcessRequestAsync(webRequest, headers, progress, timeout);
276+
277+
if (!response.Successful)
278+
{
279+
Debug.LogError($"Failed to download asset bundle from \"{url}\"!");
280+
281+
return null;
282+
}
283+
284+
return ((DownloadHandlerAssetBundle)webRequest.downloadHandler).assetBundle;
285+
}
286+
}
287+
288+
#endregion Get Multimedia Content
289+
290+
private static async Task<Response> ProcessRequestAsync(UnityWebRequest webRequest, Dictionary<string, string> headers, IProgress<float> progress, int timeout)
203291
{
204292
if (timeout > 0)
205293
{
@@ -214,31 +302,55 @@ private static async Task<Response> ProcessRequestAsync(UnityWebRequest webReque
214302
}
215303
}
216304

305+
var isUpload = webRequest.method == UnityWebRequest.kHttpVerbPOST ||
306+
webRequest.method == UnityWebRequest.kHttpVerbPUT;
307+
217308
// HACK: Workaround for extra quotes around boundary.
218-
if (webRequest.method == UnityWebRequest.kHttpVerbPOST ||
219-
webRequest.method == UnityWebRequest.kHttpVerbPUT)
309+
if (isUpload)
220310
{
221-
string contentType = webRequest.GetRequestHeader("Content-Type");
311+
var contentType = webRequest.GetRequestHeader("Content-Type");
312+
222313
if (contentType != null)
223314
{
224315
contentType = contentType.Replace("\"", "");
225316
webRequest.SetRequestHeader("Content-Type", contentType);
226317
}
227318
}
228319

320+
var backgroundThread = new Thread(async () =>
321+
{
322+
await Awaiters.UnityMainThread;
323+
324+
while (!webRequest.isDone)
325+
{
326+
progress?.Report(isUpload ? webRequest.uploadProgress : webRequest.downloadProgress * 100f);
327+
328+
await Awaiters.UnityMainThread;
329+
}
330+
})
331+
{
332+
IsBackground = true
333+
};
334+
335+
backgroundThread.Start();
229336
await webRequest.SendWebRequest();
337+
backgroundThread.Join();
338+
progress?.Report(100f);
230339

231340
if (webRequest.isNetworkError || webRequest.isHttpError)
232341
{
233-
if (webRequest.responseCode == 401) { return new Response(false, "Invalid Credentials", null, webRequest.responseCode); }
342+
if (webRequest.responseCode == 401)
343+
{
344+
return new Response(false, "Invalid Credentials", null, webRequest.responseCode);
345+
}
234346

235347
if (webRequest.GetResponseHeaders() == null)
236348
{
237-
return new Response(false, "Device Unavailable", null, webRequest.responseCode);
349+
return new Response(false, "Invalid Headers", null, webRequest.responseCode);
238350
}
239351

240-
string responseHeaders = webRequest.GetResponseHeaders().Aggregate(string.Empty, (current, header) => $"\n{header.Key}: {header.Value}");
241-
Debug.LogError($"REST Error: {webRequest.responseCode}\n{webRequest.downloadHandler?.text}{responseHeaders}");
352+
var responseHeaders = webRequest.GetResponseHeaders().Aggregate(string.Empty, (current, header) => $"\n{header.Key}: {header.Value}");
353+
Debug.LogError($"REST Error {webRequest.responseCode}:{webRequest.downloadHandler?.text}{responseHeaders}");
242354
return new Response(false, $"{responseHeaders}\n{webRequest.downloadHandler?.text}", webRequest.downloadHandler?.data, webRequest.responseCode);
243355
}
244356

0 commit comments

Comments
 (0)