Terminal Box.com replacement of deprecated WebClient/OAuth

Creating of the new OAuthHelper for HttpClient.
Removal of manual assembly of the multipart post.
This commit is contained in:
Marcelo C.
2025-03-20 15:23:31 -03:00
parent 6e77079f24
commit 3fd663e923
16 changed files with 534 additions and 306 deletions
@@ -38,7 +38,7 @@ namespace Duplicati.Library;
public class JsonWebHelperHttpClient(HttpClient httpClient)
{
/// <summary>
/// HttpClient reference
/// HttpClient reference for inheritors
/// </summary>
protected readonly HttpClient _httpClient = httpClient;
@@ -62,7 +62,36 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
return request;
}
/// <summary>
/// Performs a multipart post and parses the response as JSON
/// </summary>
/// <returns>The parsed JSON item.</returns>
/// <param name="url">The url to post to.</param>
/// <param name="cancellationToken">Token to cancel the operation.</param>
/// <param name="parts">The multipart items.</param>
/// <typeparam name="T">The return type parameter.</typeparam>
public virtual async Task<T> PostMultipartAndGetJsonDataAsync<T>(string url, CancellationToken cancellationToken, MultipartContent parts)
{
using var response = await PostMultipartAsync(url, cancellationToken, parts).ConfigureAwait(false);
return ReadJsonResponse<T>(response);
}
/// <summary>
/// Performs a multipart post
/// </summary>
/// <returns>The response.</returns>
/// <param name="url">The url to post to.</param>
/// <param name="cancellationToken">Token to cancel the operation.</param>
/// <param name="parts">The multipart items.</param>
protected virtual async Task<HttpResponseMessage> PostMultipartAsync(string url, CancellationToken cancellationToken, MultipartContent parts)
{
using var req = CreateRequest(url, "POST");
req.Content = parts;
return await _httpClient.SendAsync(req, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Execute Get request and return response and deserializes JSON response into the given type
/// </summary>
@@ -72,7 +101,7 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
/// <typeparam name="T">Destination Type</typeparam>
protected virtual async Task<T> GetJsonDataAsync<T>(string url, CancellationToken cancellationToken, Action<HttpRequestMessage> setup = null)
{
var req = CreateRequest(url);
using var req = CreateRequest(url);
if (setup != null)
setup(req);
@@ -103,6 +132,26 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
}
).ConfigureAwait(false);
}
/// <summary>
/// Executes a web request and json-deserializes the results as the specified type
/// </summary>
/// <returns>The deserialized JSON data.</returns>
/// <param name="url">The remote URL</param>
/// <param name="cancellationToken">Token to cancel the operation.</param>
/// <typeparam name="T">The type of data to return.</typeparam>
public virtual async Task<T> GetJsonDataAsync<T>(string url, CancellationToken cancellationToken)
{
return await GetJsonDataAsync<T>(
url,
cancellationToken,
request =>
{
request.Method = HttpMethod.Get;
}
).ConfigureAwait(false);
}
/// <summary>
/// Reads the JSON response from the server and deserializes it into the given type
@@ -113,7 +162,7 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
protected virtual async Task<T> ReadJsonResponseAsync<T>(HttpRequestMessage req, CancellationToken cancellationToken)
{
using var resp = await GetResponseAsync(req, cancellationToken).ConfigureAwait(false);
return await ReadJsonResponsAsync<T>(resp, cancellationToken).ConfigureAwait(false);
return await ReadJsonResponseAsync<T>(resp, cancellationToken).ConfigureAwait(false);
}
/// <summary>
@@ -151,7 +200,7 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
/// <typeparam name="T">Type to cast to</typeparam>
/// <returns></returns>
/// <exception cref="IOException">Exception when failing to deserialize the JSON to the Type</exception>
protected virtual async Task<T> ReadJsonResponsAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken)
protected virtual async Task<T> ReadJsonResponseAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken)
{
await using var rs = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
await using var ps = new StreamPeekReader(rs);
@@ -171,13 +220,22 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
}
}
/// <summary>
/// Use this method to register an exception handler,
/// which can throw another, more meaningful exception
/// </summary>
public virtual async Task AttemptParseAndThrowExceptionAsync(Exception ex, HttpResponseMessage responseContext = null, CancellationToken cancellationToken = default)
{
}
/// <summary>
/// Use this method to register an exception handler,
/// which can throw another, more meaningful exception
/// </summary>
public virtual void AttemptParseAndThrowException(Exception ex, HttpResponseMessage responseContext = null)
{
}
/// <summary>
@@ -186,13 +244,14 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
/// <param name="req">Request object</param>
/// <param name="cancellationToken">Cancellation Token</param>
/// <returns></returns>
private async Task<HttpResponseMessage> GetResponseAsync(HttpRequestMessage req, CancellationToken cancellationToken)
public async Task<HttpResponseMessage> GetResponseAsync(HttpRequestMessage req, CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
try
{
response = await _httpClient.SendAsync(req, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response;
}
catch (Exception ex)
@@ -277,6 +336,5 @@ public class JsonWebHelperHttpClient(HttpClient httpClient)
return source.Read(buffer, offset, count) + br;
}
}
}