using System.IO; using System.Linq; using CRAWLER.Configuration; using Microsoft.Extensions.Configuration; namespace CRAWLER.Services; internal sealed class PdfStorageService { private readonly KtoPoveritClient _client; private readonly string _rootPath; public PdfStorageService(IConfiguration configuration, KtoPoveritClient client) { _client = client; var options = configuration.GetSection("Crawler").Get() ?? throw new InvalidOperationException("Раздел Crawler не найден в appsettings.json."); _rootPath = Environment.ExpandEnvironmentVariables(options.PdfStoragePath); Directory.CreateDirectory(_rootPath); } public async Task DownloadAsync(string sourceUrl, string registryNumber, string title, CancellationToken cancellationToken) { var bytes = await _client.GetBytesAsync(sourceUrl, cancellationToken); var fullPath = BuildTargetPath(registryNumber, title, sourceUrl); await File.WriteAllBytesAsync(fullPath, bytes, cancellationToken); return fullPath; } public async Task CopyFromLocalAsync(string sourcePath, string registryNumber, string title, CancellationToken cancellationToken) { var fullPath = BuildTargetPath(registryNumber, title, sourcePath); await using var sourceStream = File.Open(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read); await using var targetStream = File.Create(fullPath); await sourceStream.CopyToAsync(targetStream, cancellationToken); return fullPath; } public void TryDelete(string path) { try { if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) { File.Delete(path); } } catch { } } private string BuildTargetPath(string registryNumber, string title, string sourceIdentity) { var safeFolder = MakeSafePathSegment(string.IsNullOrWhiteSpace(registryNumber) ? "manual" : registryNumber); var folder = Path.Combine(_rootPath, safeFolder); Directory.CreateDirectory(folder); var baseName = MakeSafePathSegment(string.IsNullOrWhiteSpace(title) ? Path.GetFileNameWithoutExtension(sourceIdentity) : title); if (string.IsNullOrWhiteSpace(baseName)) { baseName = "document"; } var fullPath = Path.Combine(folder, baseName + ".pdf"); if (!File.Exists(fullPath)) { return fullPath; } var counter = 2; while (true) { var candidate = Path.Combine(folder, $"{baseName}-{counter}.pdf"); if (!File.Exists(candidate)) { return candidate; } counter++; } } private static string MakeSafePathSegment(string value) { var invalid = Path.GetInvalidFileNameChars(); var cleaned = new string((value ?? string.Empty).Select(ch => invalid.Contains(ch) ? '_' : ch).ToArray()).Trim(); return string.IsNullOrWhiteSpace(cleaned) ? "file" : cleaned; } }