feat: Add specialized client implementations for PDF operations
This commit is contained in:
124
DocumentService.Client/Clients/PdfAttachmentClient.cs
Normal file
124
DocumentService.Client/Clients/PdfAttachmentClient.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using DocumentService.Client.Interfaces;
|
||||
using DocumentService.Client.Models.Requests;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.IO.Compression;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace DocumentService.Client.Clients;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of PDF attachment client.
|
||||
/// </summary>
|
||||
public class PdfAttachmentClient(HttpClient httpClient, ILogger<PdfAttachmentClient> logger)
|
||||
: BaseDocumentClient(httpClient, logger), IPdfAttachmentClient
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<AttachmentCheckResult> CheckAttachmentsAsync(Stream pdfStream, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Logger.LogDebug("Checking PDF attachments from stream (multipart)");
|
||||
|
||||
var result = await SendMultipartAsync<AttachmentCheckResult>(
|
||||
"/api/pdf/attachments/check",
|
||||
pdfStream,
|
||||
"document.pdf",
|
||||
cancellationToken);
|
||||
|
||||
return result ?? throw new InvalidOperationException("API returned null response");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<AttachmentCheckResult> CheckAttachmentsAsync(byte[] pdfBytes, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Logger.LogDebug("Checking PDF attachments from byte array (Base64 JSON)");
|
||||
|
||||
var request = new CheckPdfAttachmentsRequest { Base64Pdf = ToBase64(pdfBytes) };
|
||||
|
||||
var result = await SendJsonAsync<CheckPdfAttachmentsRequest, AttachmentCheckResult>(
|
||||
"/api/pdf/attachments/check",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
return result ?? throw new InvalidOperationException("API returned null response");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Dictionary<string, Stream>> ExtractAttachmentsAsync(Stream pdfStream, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Logger.LogDebug("Extracting PDF attachments from stream (multipart)");
|
||||
|
||||
var zipStream = await SendMultipartForStreamAsync(
|
||||
"/api/pdf/attachments/extract",
|
||||
pdfStream,
|
||||
"document.pdf",
|
||||
cancellationToken);
|
||||
|
||||
return UnzipToStreams(zipStream);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Dictionary<string, Stream>> ExtractAttachmentsAsync(byte[] pdfBytes, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Logger.LogDebug("Extracting PDF attachments from byte array (Base64 JSON)");
|
||||
|
||||
var request = new ExtractPdfAttachmentsRequest { Base64Pdf = ToBase64(pdfBytes) };
|
||||
|
||||
var zipStream = await SendJsonForStreamAsync(
|
||||
"/api/pdf/attachments/extract",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
return UnzipToStreams(zipStream);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
public Task<Stream> AddAttachmentsAsync(Stream pdfStream, List<AttachmentRequestDto> attachments, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Logger.LogWarning("AddAttachments endpoint is not implemented yet in API");
|
||||
throw new NotImplementedException("API endpoint /api/pdf/attachments/add is not implemented yet");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
public Task<Stream> AddAttachmentsAsync(byte[] pdfBytes, List<AttachmentRequestDto> attachments, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Logger.LogWarning("AddAttachments endpoint is not implemented yet in API");
|
||||
throw new NotImplementedException("API endpoint /api/pdf/attachments/add is not implemented yet");
|
||||
}
|
||||
|
||||
// ?????????????????????????????????????????????????????????????????????????
|
||||
// Private helpers
|
||||
// ?????????????????????????????????????????????????????????????????????????
|
||||
|
||||
/// <summary>
|
||||
/// Reads a ZIP stream and returns a dictionary mapping each entry's full name
|
||||
/// to an in-memory <see cref="MemoryStream"/> containing the decompressed bytes.
|
||||
/// The caller owns the returned streams and is responsible for disposing them.
|
||||
/// </summary>
|
||||
private static Dictionary<string, Stream> UnzipToStreams(Stream zipStream)
|
||||
{
|
||||
var result = new Dictionary<string, Stream>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read, leaveOpen: false);
|
||||
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
// Skip directory entries (name ends with '/')
|
||||
if (string.IsNullOrEmpty(entry.Name))
|
||||
continue;
|
||||
|
||||
var ms = new MemoryStream((int)entry.Length);
|
||||
|
||||
using (var entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(ms);
|
||||
}
|
||||
|
||||
ms.Position = 0;
|
||||
result[entry.FullName] = ms;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user