1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
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;
namespace LibMatrix.Extensions;
public static class HttpClientExtensions {
public static async Task<bool> CheckSuccessStatus(this HttpClient hc, string url) {
//cors causes failure, try to catch
try {
var resp = await hc.GetAsync(url);
return resp.IsSuccessStatusCode;
}
catch (Exception e) {
Console.WriteLine($"Failed to check success status: {e.Message}");
return false;
}
}
}
public class MatrixHttpClient : HttpClient {
internal string? AssertedUserId { get; set; }
public override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken) {
if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null");
if (AssertedUserId is not null) request.RequestUri = request.RequestUri.AddQuery("user_id", AssertedUserId);
// 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);
}
var a = await base.SendAsync(request, cancellationToken);
if (a.IsSuccessStatusCode) return a;
//error handling
var content = await a.Content.ReadAsStringAsync(cancellationToken);
if (content.Length == 0)
throw new MatrixException() {
ErrorCode = "M_UNKNOWN",
Error = "Unknown error, server returned no content"
};
if (!content.StartsWith('{')) throw new InvalidDataException("Encountered invalid data:\n" + content);
//we have a matrix error
var ex = JsonSerializer.Deserialize<MatrixException>(content);
Debug.Assert(ex != null, nameof(ex) + " != null");
ex.RawContent = content;
// Console.WriteLine($"Failed to send request: {ex}");
if (ex?.RetryAfterMs is null) throw ex!;
//we have a ratelimit error
await Task.Delay(ex.RetryAfterMs.Value, cancellationToken);
typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)
?.SetValue(request, 0);
return await SendAsync(request, cancellationToken);
}
// GetFromJsonAsync
public async Task<T> GetFromJsonAsync<T>(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();
await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
#if DEBUG && false // This is only used for testing, so it's disabled by default
try {
await PostAsync("http://localhost:5116/validate/" + typeof(T).AssemblyQualifiedName, new StreamContent(responseStream), cancellationToken);
}
catch (Exception e) {
Console.WriteLine("[!!] Checking sync response failed: " + e);
}
#endif
return await JsonSerializer.DeserializeAsync<T>(responseStream, 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 new async Task<HttpResponseMessage> PutAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
CancellationToken cancellationToken = default) {
var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options ?? new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }),
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) {
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 ?? new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }),
Encoding.UTF8, "application/json");
return await SendAsync(request, cancellationToken);
}
}
|