Обнновлено до .net10

This commit is contained in:
FrigaT
2026-04-10 15:05:32 +03:00
parent 11d0b0d72f
commit 8444fc5f8e
386 changed files with 6361 additions and 7164 deletions

View File

@@ -1,60 +1,56 @@
using YandexMusic.API.Models.Common;
using System.Text.Json;
using System.Text.Json.Serialization;
using YandexMusic.API.Models.Common;
namespace YandexMusic.API.Common.Providers
namespace YandexMusic.API.Common.Providers;
/// <summary>Базовый провайдер HTTP-запросов с общей логикой десериализации.</summary>
public abstract class CommonRequestProvider : IRequestProvider
{
public class CommonRequestProvider : IRequestProvider
/// <summary>Хранилище данных авторизации.</summary>
protected readonly AuthStorage storage;
/// <summary>Настройки сериализации JSON (регистронезависимые, поддержка enum-строк).</summary>
private static readonly JsonSerializerOptions JsonOptions = new()
{
#region Поля
PropertyNameCaseInsensitive = true,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
};
protected AuthStorage storage;
/// <summary>Инициализирует новый экземпляр провайдера.</summary>
/// <param name="authStorage">Хранилище авторизации.</param>
protected CommonRequestProvider(AuthStorage authStorage)
{
storage = authStorage;
}
#endregion Поля
/// <summary>Выполняет HTTP-запрос и возвращает ответ.</summary>
public abstract Task<HttpResponseMessage> GetWebResponseAsync(
HttpRequestMessage message,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead);
/// <summary>Преобразует HTTP-ответ в объект типа T.</summary>
public virtual async Task<T> GetDataFromResponseAsync<T>(
YandexMusicApi api,
HttpResponseMessage response)
{
var json = await response.Content.ReadAsStringAsync();
public CommonRequestProvider(AuthStorage authStorage)
if (!response.IsSuccessStatusCode)
{
storage = authStorage;
var error = JsonSerializer.Deserialize<YErrorResponse>(json, JsonOptions);
throw error ?? new Exception("Ошибка десериализации ответа с ошибкой.");
}
#region IRequestProvider
public virtual Task<HttpResponseMessage> GetWebResponseAsync(HttpRequestMessage message, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
try
{
throw new NotImplementedException();
// Если нужен контекст выполнения, он добавляется через кастомный конвертер
return JsonSerializer.Deserialize<T>(json, JsonOptions)
?? throw new JsonException("Десериализация вернула null");
}
public virtual async Task<T> GetDataFromResponseAsync<T>(YandexMusicApi api, HttpResponseMessage response)
catch (Exception ex)
{
string result = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
YErrorResponse exception = JsonConvert.DeserializeObject<YErrorResponse>(result);
throw exception ?? new Exception("Ошибка десериализации ответа с ошибкой.");
}
try
{
JsonSerializerSettings settings = new()
{
Converters = new List<JsonConverter> {
new YExecutionContextConverter(api, storage)
}
};
return storage.Debug != null
? storage.Debug.Deserialize<T>(response.RequestMessage?.RequestUri?.AbsolutePath, result, settings)
: JsonConvert.DeserializeObject<T>(result, settings);
}
catch (Exception ex)
{
throw new Exception($"Ошибка десериализации {ex}");
}
throw new Exception($"Ошибка десериализации: {ex.Message}", ex);
}
#endregion IRequestProvider
}
}

View File

@@ -1,69 +1,45 @@
using System.Net;
using YandexMusic.API.Models.Common;
namespace YandexMusic.API.Common.Providers;
namespace YandexMusic.API.Common.Providers
/// <summary>Стандартный провайдер HTTP-запросов с использованием HttpClient.</summary>
public class DefaultRequestProvider : CommonRequestProvider
{
/// <summary>
/// Стандартный провайдер запросов
/// </summary>
public class DefaultRequestProvider : CommonRequestProvider
/// <summary>Инициализирует новый экземпляр провайдера.</summary>
/// <param name="authStorage">Хранилище авторизации.</param>
public DefaultRequestProvider(AuthStorage authStorage) : base(authStorage) { }
/// <summary>Выполняет HTTP-запрос и возвращает ответ.</summary>
/// <param name="message">HTTP-запрос.</param>
/// <param name="completionOption">Опция завершения запроса.</param>
/// <returns>HTTP-ответ.</returns>
public override async Task<HttpResponseMessage> GetWebResponseAsync(
HttpRequestMessage message,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
{
#region Вспомогательные функции
private Exception ProcessException(Exception ex)
using var handler = new SocketsHttpHandler
{
if (ex is not WebException webException)
return ex;
Proxy = storage.Context.WebProxy,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
UseCookies = true,
CookieContainer = storage.Context.Cookies,
AllowAutoRedirect = true,
MaxAutomaticRedirections = 10
};
if (webException.Response is null)
return ex;
using var client = new HttpClient(handler);
Stream s = webException.Response.GetResponseStream();
if (s is null)
return ex;
using StreamReader sr = new(s);
string result = sr.ReadToEnd();
YErrorResponse exception = JsonConvert.DeserializeObject<YErrorResponse>(result);
return exception ?? ex;
}
#endregion Вспомогательные функции
public DefaultRequestProvider(AuthStorage authStorage) : base(authStorage)
try
{
return await client.SendAsync(message, completionOption);
}
#region IRequestProvider
public override Task<HttpResponseMessage> GetWebResponseAsync(HttpRequestMessage message,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
catch (HttpRequestException ex)
{
try
{
HttpClient client = new(new SocketsHttpHandler
{
Proxy = storage.Context.WebProxy,
AutomaticDecompression = DecompressionMethods.GZip,
UseCookies = true,
CookieContainer = storage.Context.Cookies,
});
// Пытаемся извлечь тело ошибки, если оно доступно
if (ex.InnerException == null)
throw;
return client.SendAsync(message, completionOption);
}
catch (Exception ex)
{
throw ProcessException(ex);
}
throw new Exception($"Ошибка HTTP-запроса: {ex.Message}", ex);
}
#endregion IRequestProvider
}
}

View File

@@ -9,7 +9,6 @@
public MockRequestProvider(AuthStorage authStorage) : base(authStorage)
{
storage = authStorage;
}