diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationAttachmentService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationAttachmentService.cs index 8020ebf5..848cb474 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationAttachmentService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationAttachmentService.cs @@ -3,5 +3,7 @@ namespace BotSharp.Abstraction.Conversations; public interface IConversationAttachmentService { string GetDirectory(string conversationId); + IEnumerable GetConversationFiles(string conversationId, string messageId); + string? GetMessageFile(string conversationId, string messageId, string fileType, int index); void SaveConversationFiles(List files); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/OutputFileModel.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/OutputFileModel.cs new file mode 100644 index 00000000..962b01e1 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/OutputFileModel.cs @@ -0,0 +1,13 @@ +namespace BotSharp.Abstraction.Files.Models; + +public class OutputFileModel +{ + [JsonPropertyName("file_url")] + public string FileUrl { get; set; } + + [JsonPropertyName("file_name")] + public string FileName { get; set; } + + [JsonPropertyName("file_type")] + public string FileType { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationAttachmentService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationAttachmentService.cs index f5bc7bcd..22e1158c 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationAttachmentService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationAttachmentService.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Http; using System.IO; using System.IO.Enumeration; using System.Threading; @@ -12,6 +13,7 @@ public class ConversationAttachmentService : IConversationAttachmentService private const string CONVERSATION_FOLDER = "conversations"; private const string FILE_FOLDER = "files"; + private const string SEPARATOR = "."; public ConversationAttachmentService( BotSharpDatabaseSettings dbSettings, @@ -32,22 +34,60 @@ public class ConversationAttachmentService : IConversationAttachmentService return dir; } - public string GetConversationFileDirectory(string conversationId) + public IEnumerable GetConversationFiles(string conversationId, string messageId) { - var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER); - if (!Directory.Exists(dir)) + var outputFiles = new List(); + if (string.IsNullOrEmpty(conversationId) || string.IsNullOrEmpty(messageId)) { - Directory.CreateDirectory(dir); + return outputFiles; } - return dir; + + var context = _services.GetRequiredService(); + var request = context.HttpContext.Request; + var host = $"{request.Scheme}{Uri.SchemeDelimiter}{request.Host.Value}"; + var dir = GetConversationFileDirectory(conversationId); + + foreach (var file in Directory.GetFiles(dir)) + { + var fileName = file.Split(Path.DirectorySeparatorChar).Last(); + var splits = fileName.Split('.'); + var fileMsgId = splits.First(); + + if (fileMsgId != messageId) continue; + + var index = splits[1]; + var fileType = splits.Last(); + var model = new OutputFileModel() + { + FileUrl = $"{host}/conversation/{conversationId}/file/{messageId}/type/{fileType}/{index}", + FileName = fileName, + FileType = fileType + }; + outputFiles.Add(model); + } + return outputFiles; + } + + public string? GetMessageFile(string conversationId, string messageId, string fileType, int index) + { + var targetFile = $"{messageId}{SEPARATOR}{index}.{fileType}"; + var dir = GetConversationFileDirectory(conversationId); + var files = Directory.GetFiles(dir); + var found = files.FirstOrDefault(f => + { + var fileName = f.Split(Path.DirectorySeparatorChar).Last(); + return fileName.IsEqualTo(targetFile); + }); + + return found; } public void SaveConversationFiles(List files) { if (files.IsNullOrEmpty()) return; - var converationId = files.First().ConversationId; - var dir = GetConversationFileDirectory(converationId); + var conversationId = files.First().ConversationId; + var dir = GetConversationFileDirectory(conversationId); for (int i = 0; i < files.Count; i++) { @@ -67,12 +107,23 @@ public class ConversationAttachmentService : IConversationAttachmentService continue; } - var fileName = $"{file.MessageId}-{i+1}{parsedFormat}"; + var fileName = $"{file.MessageId}{SEPARATOR}{i+1}{parsedFormat}"; Thread.Sleep(100); File.WriteAllBytes(Path.Combine(dir, fileName), bytes); } } + #region Private methods + private string GetConversationFileDirectory(string conversationId) + { + var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + return dir; + } + private string GetFileType(string data) { if (string.IsNullOrEmpty(data)) @@ -122,4 +173,5 @@ public class ConversationAttachmentService : IConversationAttachmentService } return parsed; } + #endregion } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index a20f9b6b..5940bdbb 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,6 +1,8 @@ using BotSharp.Abstraction.Routing; using Newtonsoft.Json.Serialization; using Newtonsoft.Json; +using BotSharp.Abstraction.Files.Models; +using Microsoft.AspNetCore.Hosting; namespace BotSharp.OpenAPI.Controllers; @@ -315,4 +317,31 @@ public class ConversationController : ControllerBase return BadRequest(new { message = "Invalid file." }); } + + [HttpGet("/conversation/{conversationId}/files/{messageId}")] + public IEnumerable GetConversationFiles([FromRoute] string conversationId, [FromRoute] string messageId) + { + var attachment = _services.GetRequiredService(); + return attachment.GetConversationFiles(conversationId, messageId); + } + + [AllowAnonymous] + [HttpGet("/conversation/{conversationId}/file/{messageId}/type/{type}/{index}")] + public async Task GetMessageFile([FromRoute] string conversationId, [FromRoute] string messageId, + [FromRoute] string type, [FromRoute] int index, [FromQuery] string token) + { + var attachment = _services.GetRequiredService(); + var file = attachment.GetMessageFile(conversationId, messageId, type, index); + if (System.IO.File.Exists(file)) + { + using Stream stream = System.IO.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); + var bytes = new byte[stream.Length]; + stream.Read(bytes, 0, (int)stream.Length); + return File(bytes, "application/octet-stream", Path.GetFileName(file)); + } + else + { + return NotFound(); + } + } }