using MediatR; using BuildFlow.Domain.Interfaces; using File.Application.Features.Files.Commands; using File.Application.Features.Files.Queries; namespace BuildFlow.Host; /// /// 进程内文件存储实现,替代 rag-backend 原有的 HTTP 版 FileStorageClient。 /// 通过 MediatR 查询/命令调用 file-system 模块的处理器( / /// ),而非直接注入 file 的 Infrastructure 类型(IS3StorageService)。 /// 这样 rag 模块对 file 的依赖从「直接引用 Infrastructure 类型」降级为「发 MediatR 消息」, /// 实现模块间解耦——rag 只依赖消息契约,不感知 file 的存储实现细节。 /// /// 注册为 IFileStorageClient 的同接口覆盖(后注册者胜出),HTTP 版自动被取代; /// 本类只在 BuildFlow Host 中参与 DI,不影响模块级测试或设计时工具。 /// public class InProcessFileStorageClient(IMediator mediator) : IFileStorageClient { public async Task UploadAsync( string bucket, string objectKey, Stream content, string contentType, string? authToken, // 进程内调用无需鉴权,token 忽略 CancellationToken ct = default) { // 通过 MediatR 命令调用 file 模块的 UploadFileCommandHandler(它内部走 IS3StorageService) await mediator.Send(new UploadFileCommand(bucket, objectKey, content, contentType, content.Length), ct); } public async Task DownloadAsync( string bucket, string objectKey, string? authToken, // 同上,忽略 CancellationToken ct = default) { // 通过 MediatR 查询调用 file 模块的 DownloadFileQueryHandler。 // 注意:DownloadFileQuery 把对象 buffer 成 byte[](file 模块的查询契约),这里包成 MemoryStream 还原成 Stream。 // 文档处理场景下文件多为 MB 级,内存拷贝可接受;如需真正的流式,可在 file 模块加一个返回 Stream 的查询。 var result = await mediator.Send(new DownloadFileQuery(bucket, objectKey), ct); return new MemoryStream(result.Data); } }