| | | 1 | | using System.Security.Cryptography; |
| | | 2 | | using Services.FileStorageServices; |
| | | 3 | | |
| | | 4 | | namespace Services.OzonHandoverServices; |
| | | 5 | | |
| | | 6 | | /// <summary>Скачивает краткоживущие фото realFBS и кладёт их в общее файловое хранилище.</summary> |
| | | 7 | | public sealed class OzonHandoverPhotoStorage : IOzonHandoverPhotoStorage |
| | | 8 | | { |
| | | 9 | | public const string HttpClientName = "OzonHandoverPhotos"; |
| | | 10 | | |
| | | 11 | | private readonly IHttpClientFactory _httpClientFactory; |
| | | 12 | | private readonly IServerFileStorage _storage; |
| | | 13 | | |
| | 27 | 14 | | public OzonHandoverPhotoStorage(IHttpClientFactory httpClientFactory, IServerFileStorage storage) |
| | | 15 | | { |
| | 27 | 16 | | _httpClientFactory = httpClientFactory; |
| | 27 | 17 | | _storage = storage; |
| | 27 | 18 | | } |
| | | 19 | | |
| | | 20 | | public async Task<OzonHandoverStoredPhoto> DownloadAndStoreAsync(string sourceUrl, string batchKey, string itemKey, |
| | | 21 | | int sequence, CancellationToken cancellationToken = default) |
| | | 22 | | { |
| | 25 | 23 | | if (!Uri.TryCreate(sourceUrl, UriKind.Absolute, out var uri) || uri.Scheme != Uri.UriSchemeHttps) |
| | 7 | 24 | | throw new InvalidOperationException("URL фотографии должен быть абсолютным HTTPS-адресом."); |
| | | 25 | | |
| | 18 | 26 | | using var response = await _httpClientFactory.CreateClient(HttpClientName) |
| | 18 | 27 | | .GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); |
| | 17 | 28 | | response.EnsureSuccessStatusCode(); |
| | | 29 | | |
| | 14 | 30 | | var contentType = response.Content.Headers.ContentType?.MediaType; |
| | 14 | 31 | | if (contentType is not null && !contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) |
| | 4 | 32 | | throw new InvalidOperationException("По URL фотографии получен не графический файл."); |
| | | 33 | | |
| | 10 | 34 | | var extension = contentType?.ToLowerInvariant() switch |
| | 10 | 35 | | { |
| | 3 | 36 | | "image/png" => ".png", |
| | 2 | 37 | | "image/webp" => ".webp", |
| | 1 | 38 | | "image/gif" => ".gif", |
| | 4 | 39 | | _ => ".jpg" |
| | 10 | 40 | | }; |
| | 10 | 41 | | var path = $"ozon-handover/photos/{Hash(batchKey)}/{Hash(itemKey)}/{sequence:D2}{extension}"; |
| | 10 | 42 | | await using var content = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); |
| | 10 | 43 | | await _storage.UploadAsync(new ServerFileUpload(path, content, contentType, Overwrite: true), cancellationToken) |
| | 10 | 44 | | .ConfigureAwait(false); |
| | 10 | 45 | | return new OzonHandoverStoredPhoto(path, contentType); |
| | 10 | 46 | | } |
| | | 47 | | |
| | | 48 | | public async Task<Stream> OpenReadAsync(string storagePath, CancellationToken cancellationToken = default) |
| | | 49 | | { |
| | 2 | 50 | | var download = await _storage.OpenReadAsync(storagePath, cancellationToken).ConfigureAwait(false); |
| | 2 | 51 | | return download.Content; |
| | 2 | 52 | | } |
| | | 53 | | |
| | 20 | 54 | | private static string Hash(string value) => Convert.ToHexString(SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(v |
| | | 55 | | } |