73 lines
No EOL
2.7 KiB
C#
73 lines
No EOL
2.7 KiB
C#
using System.Net;
|
|
using System.Text.Json;
|
|
using System.Threading.RateLimiting;
|
|
using Humanizer;
|
|
using NodaTime;
|
|
using Polly;
|
|
using Remora.Rest.Json.Policies;
|
|
|
|
namespace Catalogger.Backend.Services;
|
|
|
|
public class PluralkitApiService(ILogger logger)
|
|
{
|
|
private const string UserAgent = "Catalogger.NET (https://codeberg.org/starshine/catalogger)";
|
|
private const string ApiBaseUrl = "https://api.pluralkit.me/v2";
|
|
private readonly HttpClient _client = new();
|
|
private readonly ILogger _logger = logger.ForContext<PluralkitApiService>();
|
|
|
|
private readonly ResiliencePipeline _pipeline = new ResiliencePipelineBuilder()
|
|
.AddRateLimiter(new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions()
|
|
{
|
|
Window = 1.Seconds(),
|
|
PermitLimit = 2,
|
|
QueueLimit = 64,
|
|
}))
|
|
.AddTimeout(20.Seconds())
|
|
.Build();
|
|
|
|
private async Task<T?> DoRequestAsync<T>(string path, bool allowNotFound = false,
|
|
CancellationToken ct = default) where T : class
|
|
{
|
|
var req = new HttpRequestMessage(HttpMethod.Get, $"{ApiBaseUrl}{path}");
|
|
req.Headers.Add("User-Agent", UserAgent);
|
|
|
|
_logger.Debug("Requesting {Path} from PluralKit API", path);
|
|
|
|
var resp = await _client.SendAsync(req, ct);
|
|
if (resp.StatusCode == HttpStatusCode.NotFound && allowNotFound)
|
|
{
|
|
_logger.Debug("PluralKit API path {Path} returned 404 but 404 response is valid", path);
|
|
return null;
|
|
}
|
|
|
|
if (!resp.IsSuccessStatusCode)
|
|
{
|
|
_logger.Error("Received non-200 status code {StatusCode} from PluralKit API path {Path}", resp.StatusCode,
|
|
req);
|
|
throw new CataloggerError("Non-200 status code from PluralKit API");
|
|
}
|
|
|
|
return await resp.Content.ReadFromJsonAsync<T>(new JsonSerializerOptions
|
|
{ PropertyNamingPolicy = new SnakeCaseNamingPolicy() }, ct) ??
|
|
throw new CataloggerError("JSON response from PluralKit API was null");
|
|
}
|
|
|
|
public async Task<PkMessage?> GetPluralKitMessageAsync(ulong id, CancellationToken ct = default) =>
|
|
await DoRequestAsync<PkMessage>($"/messages/{id}", allowNotFound: true, ct);
|
|
|
|
public async Task<PkSystem> GetPluralKitSystemAsync(ulong id, CancellationToken ct = default) =>
|
|
(await DoRequestAsync<PkSystem>($"/systems/{id}", allowNotFound: false, ct))!;
|
|
|
|
public record PkMessage(
|
|
ulong Id,
|
|
ulong Original,
|
|
ulong Sender,
|
|
ulong Channel,
|
|
ulong Guild,
|
|
PkSystem? System,
|
|
PkMember? Member);
|
|
|
|
public record PkSystem(string Id, Guid Uuid, string? Name, string? Tag, Instant? Created);
|
|
|
|
public record PkMember(string Id, Guid Uuid, string Name, string? DisplayName);
|
|
} |