using System.Globalization;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace OpenNest.Data;
/// Wire conventions shared by the nest server's HTTP clients.
internal static class NestServerHttp
{
/// The server's JSON shape: camel-case names and enum names.
public static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) },
};
/// Guards a write on the revision the caller last read.
public static void AddIfMatch(HttpRequestMessage request, int expectedRevision) =>
request.Headers.IfMatch.Add(new EntityTagHeaderValue($"\"{expectedRevision.ToString(CultureInfo.InvariantCulture)}\""));
/// Throws an naming the action, status and the start of the body.
public static async Task EnsureSuccessAsync(HttpResponseMessage response, string action, CancellationToken cancellationToken)
{
if (response.IsSuccessStatusCode)
return;
var detail = "";
try
{
detail = await response.Content.ReadAsStringAsync(cancellationToken);
}
catch (Exception ex) when (ex is IOException or InvalidOperationException)
{
// The status code is the useful part; the body is best-effort.
}
if (detail.Length > 200)
detail = detail[..200] + "…";
throw new IOException(
$"Could not {action} on the nest server: HTTP {(int)response.StatusCode} {response.ReasonPhrase}. {detail}".TrimEnd());
}
}