summary refs log tree commit diff
path: root/SystemdCtl.Client/Abstractions/StreamingHttpClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'SystemdCtl.Client/Abstractions/StreamingHttpClient.cs')
-rw-r--r--SystemdCtl.Client/Abstractions/StreamingHttpClient.cs143
1 files changed, 143 insertions, 0 deletions
diff --git a/SystemdCtl.Client/Abstractions/StreamingHttpClient.cs b/SystemdCtl.Client/Abstractions/StreamingHttpClient.cs
new file mode 100644
index 0000000..ee39588
--- /dev/null
+++ b/SystemdCtl.Client/Abstractions/StreamingHttpClient.cs
@@ -0,0 +1,143 @@
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Net.Http.Headers;
+using System.Reflection;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using ArcaneLibs.Extensions;
+using Microsoft.AspNetCore.Components.WebAssembly.Http;
+
+namespace SystemdCtl.Client.Abstractions;
+
+public class StreamingHttpClient : HttpClient
+{
+    public Dictionary<string, string> AdditionalQueryParameters { get; set; } = new();
+    internal string? AssertedUserId { get; set; }
+
+    private JsonSerializerOptions GetJsonSerializerOptions(JsonSerializerOptions? options = null)
+    {
+        options ??= new JsonSerializerOptions();
+        options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
+        return options;
+    }
+
+    public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+    {
+        if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null");
+        if (!request.RequestUri.IsAbsoluteUri) request.RequestUri = new Uri(BaseAddress, request.RequestUri);
+        // if (AssertedUserId is not null) request.RequestUri = request.RequestUri.AddQuery("user_id", AssertedUserId);
+        foreach (var (key, value) in AdditionalQueryParameters)
+        {
+            request.RequestUri = request.RequestUri.AddQuery(key, value);
+        }
+
+        Console.WriteLine($"Sending request to {request.RequestUri}");
+
+        try
+        {
+            var webAssemblyEnableStreamingResponseKey =
+                new HttpRequestOptionsKey<bool>("WebAssemblyEnableStreamingResponse");
+            request.Options.Set(webAssemblyEnableStreamingResponseKey, true);
+        }
+        catch (Exception e)
+        {
+            Console.WriteLine("Failed to set browser response streaming:");
+            Console.WriteLine(e);
+        }
+        
+        HttpResponseMessage responseMessage;
+        // try {
+        responseMessage = await base.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
+        // }
+        // catch (Exception e) {
+        // if (requestSettings is { Retries: 0 }) throw;
+        // typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)
+        // ?.SetValue(request, 0);
+        // await Task.Delay(requestSettings?.RetryDelay ?? 2500, cancellationToken);
+        // if(requestSettings is not null) requestSettings.Retries--;
+        // return await SendAsync(request, cancellationToken);
+        // throw;
+        // }
+
+        if (responseMessage.IsSuccessStatusCode) return responseMessage;
+
+        //error handling
+        // var content = await responseMessage.Content.ReadAsStringAsync(cancellationToken);
+        // typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)
+        // ?.SetValue(request, 0);
+        // return await SendAsync(request, cancellationToken);
+        return responseMessage;
+    }
+
+    // GetAsync
+    public Task<HttpResponseMessage> GetAsync([StringSyntax("Uri")] string? requestUri, CancellationToken? cancellationToken = null)
+    {
+        return SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken ?? CancellationToken.None);
+    }
+
+    // GetFromJsonAsync
+    public async Task<T> GetFromJsonAsync<T>(string requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default)
+    {
+        options = GetJsonSerializerOptions(options);
+        // Console.WriteLine($"GetFromJsonAsync called for {requestUri} with json options {options?.ToJson(ignoreNull:true)} and cancellation token {cancellationToken}");
+        var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
+        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+        var response = await SendAsync(request, cancellationToken);
+        response.EnsureSuccessStatusCode();
+        await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
+
+        return await JsonSerializer.DeserializeAsync<T>(responseStream, options, cancellationToken: cancellationToken) ??
+               throw new InvalidOperationException("Failed to deserialize response");
+    }
+
+    // GetStreamAsync
+    public new async Task<Stream> GetStreamAsync(string requestUri, CancellationToken cancellationToken = default)
+    {
+        var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
+        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+        var response = await SendAsync(request, cancellationToken);
+        response.EnsureSuccessStatusCode();
+        return await response.Content.ReadAsStreamAsync(cancellationToken);
+    }
+
+    public async Task<HttpResponseMessage> PutAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
+        CancellationToken cancellationToken = default) where T : notnull
+    {
+        options = GetJsonSerializerOptions(options);
+        var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
+        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+        Console.WriteLine($"Sending PUT {requestUri}");
+        request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options),
+            Encoding.UTF8, "application/json");
+        return await SendAsync(request, cancellationToken);
+    }
+
+    public async Task<HttpResponseMessage> PostAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
+        CancellationToken cancellationToken = default) where T : notnull
+    {
+        options ??= new();
+        options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
+        var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
+        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+        request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options),
+            Encoding.UTF8, "application/json");
+        return await SendAsync(request, cancellationToken);
+    }
+
+    public async IAsyncEnumerable<T?> GetAsyncEnumerableFromJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, JsonSerializerOptions? options = null)
+    {
+        options = GetJsonSerializerOptions(options);
+        var res = await GetAsync(requestUri);
+        var result = JsonSerializer.DeserializeAsyncEnumerable<T>(await res.Content.ReadAsStreamAsync(), options);
+        await foreach (var resp in result)
+        {
+            yield return resp;
+        }
+    }
+
+    public IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+        [StringSyntax("Uri")] string? requestUri,
+        CancellationToken cancellationToken = default(CancellationToken)) =>
+        GetAsyncEnumerableFromJsonAsync<TValue>(requestUri);
+}
\ No newline at end of file