| | | 1 | | using Microsoft.Extensions.Options; |
| | | 2 | | using Newtonsoft.Json.Linq; |
| | | 3 | | using Services.ApiServices.ApiSupplierRequestLog; |
| | | 4 | | |
| | | 5 | | namespace Services.ApiServices.FavoritPartsApi; |
| | | 6 | | |
| | | 7 | | /// <summary>Клиент легаси 1С HS-сервиса проценки FavoritParts (hs/hsprice/). |
| | | 8 | | /// Отдельный хост/путь от REST-сервиса корзины/заказов (ws/v1/), авторизация — query-параметры key |
| | | 9 | | /// и developerKey (документация проценки от 06.03.2023 знает только key, но требование ключа |
| | | 10 | | /// разработчика из документации заказов распространяется на сервис целиком, а лишний параметр |
| | | 11 | | /// проценка игнорирует). Ошибки — {"error": "..."} в теле при HTTP 200.</summary> |
| | | 12 | | public class FavoritPartsPriceHttpClient |
| | | 13 | | { |
| | | 14 | | private const string ProviderKey = "FavoritParts"; |
| | | 15 | | private readonly IHttpClientFactory _factory; |
| | | 16 | | private readonly IOptionsMonitor<FavoritPartsConfig> _config; |
| | | 17 | | private readonly ApiSupplierRequestLogStore _logs; |
| | | 18 | | private readonly string _providerKey; |
| | | 19 | | private readonly string _optionsName; |
| | | 20 | | |
| | 34 | 21 | | public FavoritPartsPriceHttpClient(IHttpClientFactory factory, IOptionsMonitor<FavoritPartsConfig> config, ApiSuppli |
| | 34 | 22 | | string providerKey = "FavoritParts", string optionsName = "") |
| | | 23 | | { |
| | 34 | 24 | | _factory = factory; |
| | 34 | 25 | | _config = config; |
| | 34 | 26 | | _logs = logs; |
| | 34 | 27 | | _providerKey = providerKey; |
| | 34 | 28 | | _optionsName = optionsName; |
| | 34 | 29 | | } |
| | | 30 | | |
| | | 31 | | public async Task<JToken> SearchAsync(string number, string? brand, bool analogues, CancellationToken ct = default) |
| | | 32 | | { |
| | 0 | 33 | | var config = string.IsNullOrEmpty(_optionsName) ? _config.CurrentValue : _config.Get(_optionsName); |
| | 0 | 34 | | if (string.IsNullOrWhiteSpace(config.ClientKey)) |
| | 0 | 35 | | throw new FavoritPartsApiException("Не настроен FavoritParts:ClientKey."); |
| | | 36 | | |
| | 0 | 37 | | var query = new Dictionary<string, string?> |
| | 0 | 38 | | { |
| | 0 | 39 | | ["key"] = config.ClientKey, |
| | 0 | 40 | | ["developerKey"] = config.DeveloperKey, |
| | 0 | 41 | | ["number"] = number, |
| | 0 | 42 | | ["brand"] = brand, |
| | 0 | 43 | | ["analogues"] = analogues ? "on" : null, |
| | 0 | 44 | | ["info"] = "on" |
| | 0 | 45 | | }; |
| | 0 | 46 | | var uri = BuildUri(config, "hs/hsprice/", query); |
| | | 47 | | |
| | 0 | 48 | | var timer = System.Diagnostics.Stopwatch.StartNew(); |
| | | 49 | | try |
| | | 50 | | { |
| | 0 | 51 | | using var response = await _factory.CreateClient("FavoritPartsPriceApi").GetAsync(uri, ct); |
| | 0 | 52 | | var text = await response.Content.ReadAsStringAsync(ct); |
| | 0 | 53 | | _logs.Add(_providerKey, HttpMethod.Get.Method, "hs/hsprice/", (int)response.StatusCode, timer, uri.Query, te |
| | | 54 | | |
| | 0 | 55 | | if (!response.IsSuccessStatusCode) |
| | 0 | 56 | | throw new FavoritPartsApiException($"FavoritParts (проценка) вернул HTTP {(int)response.StatusCode}.", ( |
| | | 57 | | |
| | | 58 | | JToken token; |
| | 0 | 59 | | try { token = JToken.Parse(text); } |
| | 0 | 60 | | catch (Exception ex) { throw new FavoritPartsApiException("FavoritParts (проценка) вернул невалидный JSON.", |
| | | 61 | | |
| | 0 | 62 | | if (token is JObject obj && obj["error"] is { Type: JTokenType.String } errorToken) |
| | 0 | 63 | | throw new FavoritPartsApiException(errorToken.Value<string>() ?? "FavoritParts (проценка) вернул ошибку. |
| | | 64 | | |
| | 0 | 65 | | return token; |
| | | 66 | | } |
| | 0 | 67 | | catch (FavoritPartsApiException) { throw; } |
| | 0 | 68 | | catch (Exception ex) |
| | | 69 | | { |
| | 0 | 70 | | _logs.Add(_providerKey, HttpMethod.Get.Method, "hs/hsprice/", null, timer, uri.Query, ex.Message); |
| | 0 | 71 | | throw new FavoritPartsApiException("Не удалось выполнить запрос к FavoritParts (проценка).", requestPath: "h |
| | | 72 | | } |
| | 0 | 73 | | } |
| | | 74 | | |
| | | 75 | | private static Uri BuildUri(FavoritPartsConfig config, string path, IReadOnlyDictionary<string, string?> query) |
| | | 76 | | { |
| | 0 | 77 | | var builder = new UriBuilder(config.BaseUrl.TrimEnd('/') + "/" + path.TrimStart('/')); |
| | 0 | 78 | | builder.Query = string.Join("&", query.Where(x => !string.IsNullOrWhiteSpace(x.Value)) |
| | 0 | 79 | | .Select(x => $"{Uri.EscapeDataString(x.Key)}={Uri.EscapeDataString(x.Value!)}")); |
| | 0 | 80 | | return builder.Uri; |
| | | 81 | | } |
| | | 82 | | } |