XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEExtension.NetCore.ServerInteractive

[DLL] Server interaction extension, including user identity verification and querying in conjunction with AutoConfig

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Diagnostics;
using System.Net;
using System.Text;
using System.Text.Json;

namespace XFEExtension.NetCore.ServerInteractive.Utilities.Helpers;

/// <summary>服务器交互帮助类。</summary>
public static class InteractiveHelper
{
    private const int DefaultMaxResponseBytes = 8 * 1024 * 1024;
    private static readonly HttpClient s_client = new() { Timeout = Timeout.InfiniteTimeSpan };

    public static Task<(string, HttpStatusCode)> GetServerResponse(string requestAddress, string postBody)
        => GetServerResponse(new Uri(requestAddress, UriKind.Absolute), postBody, CancellationToken.None);

    public static async Task<(string, HttpStatusCode)> GetServerResponse(Uri requestAddress, string postBody,
        CancellationToken cancellationToken, TimeSpan? timeout = null, int maxResponseBytes = DefaultMaxResponseBytes)
    {
        using var timeoutSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        timeoutSource.CancelAfter(timeout ?? TimeSpan.FromSeconds(30));
        using var content = new StringContent(postBody, Encoding.UTF8, "application/json");
        using var response = await s_client.PostAsync(requestAddress, content, timeoutSource.Token).ConfigureAwait(false);
        await using var stream = await response.Content.ReadAsStreamAsync(timeoutSource.Token).ConfigureAwait(false);
        using var output = new MemoryStream();
        var buffer = new byte[16 * 1024];
        while (true)
        {
            var count = await stream.ReadAsync(buffer, timeoutSource.Token).ConfigureAwait(false);
            if (count == 0) break;
            if (output.Length + count > maxResponseBytes)
                throw new HttpRequestException($"服务器响应超过 {maxResponseBytes} 字节限制");
            await output.WriteAsync(buffer.AsMemory(0, count), timeoutSource.Token).ConfigureAwait(false);
        }
        return (Encoding.UTF8.GetString(output.GetBuffer(), 0, checked((int)output.Length)), response.StatusCode);
    }

    public static Task<(string, HttpStatusCode)> GetServerResponse(string requestAddress, object postBody, JsonSerializerOptions jsonSerializerOptions)
        => GetServerResponse(new Uri(requestAddress, UriKind.Absolute), JsonSerializer.Serialize(postBody, jsonSerializerOptions), CancellationToken.None);

    public static Task<(string, HttpStatusCode)> GetServerResponse(Uri requestAddress, object postBody,
        JsonSerializerOptions jsonSerializerOptions, CancellationToken cancellationToken)
        => GetServerResponse(requestAddress, JsonSerializer.Serialize(postBody, jsonSerializerOptions), cancellationToken);

    public static Uri BuildRequestUri(string baseAddress, string route)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(baseAddress);
        ArgumentException.ThrowIfNullOrWhiteSpace(route);
        var normalizedBase = baseAddress.EndsWith('/') ? baseAddress : $"{baseAddress}/";
        return new Uri(new Uri(normalizedBase, UriKind.Absolute), route.TrimStart('/'));
    }

    public static string GetStopWatchTime(Stopwatch stopwatch)
    {
        if (stopwatch.Elapsed.TotalSeconds > 1) return $"{stopwatch.Elapsed.TotalSeconds:F1} s";
        if (stopwatch.Elapsed.TotalMilliseconds > 1) return $"{stopwatch.Elapsed.TotalMilliseconds:F1} ms";
        return stopwatch.Elapsed.TotalMicroseconds > 1
            ? $"{stopwatch.Elapsed.TotalMicroseconds:F1} μs"
            : $"{stopwatch.Elapsed.TotalNanoseconds:F1} ns";
    }
}