using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Chtn.CSharp.SDK.Core; using Chtn.CSharp.SDK.Models.Media; using Chtn.CSharp.SDK.Models; namespace Chtn.CSharp.SDK.Services { public interface IFileUploadService { Task UploadFiles(string tempMsgId, string roomId, string userId, List files, IFileUploadProgressListener listener); } public class FileUploadService : IFileUploadService { private readonly ApiClient _apiClient; private readonly ApiClient _cdnClient; private const int MIN_CHUNK_SIZE = 25000000; public FileUploadService(ApiClient apiClient, ApiClient cdnClient) { _apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient)); _cdnClient = cdnClient ?? throw new ArgumentNullException(nameof(cdnClient)); } private int CalculateChunkSize(long totalSize) { long chunks = totalSize / MIN_CHUNK_SIZE; if (chunks == 0) return (int)totalSize; long chunkSize = (long)Math.Ceiling((double)totalSize / chunks); return (int)Math.Max(chunkSize, MIN_CHUNK_SIZE); } public async Task UploadFiles(string tempMsgId, string roomId, string userId, List files, IFileUploadProgressListener listener) { var registrations = files.Select(f => new FileUploadRegistration { FileId = f.FileId, Name = f.Name, Type = f.Type, Size = f.Data.Length }).ToList(); var regReq = new RegisterUploadReq { RoomId = roomId, UserId = userId, Files = registrations }; var resp = await _apiClient.PostAsync("chat/cdnRegisterUpload", regReq); string uploadId = resp.UploadId; for (int i = 0; i < files.Count; i++) { await UploadFileInternal(tempMsgId, uploadId, roomId, userId, files[i], registrations[i], listener); } await FinishUploadInternal(roomId, userId, uploadId); return uploadId; } private async Task UploadFileInternal(string tempMsgId, string uploadId, string roomId, string userId, FileData file, FileUploadRegistration registration, IFileUploadProgressListener listener) { int chunkSize = CalculateChunkSize(file.Data.Length); int totalChunks = (int)Math.Ceiling((double)file.Data.Length / chunkSize); for (int i = 0; i < totalChunks; i++) { int start = i * chunkSize; int length = (int)Math.Min(chunkSize, file.Data.Length - start); byte[] chunkData = new byte[length]; Array.Copy(file.Data, start, chunkData, 0, length); var chunkReq = new ChunkUploadReq { UploadId = uploadId, ChunkIndex = i, Data = chunkData }; await _cdnClient.PostAsync("chat/uploadChunk", chunkReq); listener?.FileProgressUpdate(tempMsgId, file.FileId, totalChunks, i); } } private async Task FinishUploadInternal(string roomId, string userId, string uploadId) { var finishReq = new FinishUploadReq { UploadId = uploadId }; await _cdnClient.PostAsync("chat/finishUpload", finishReq); } } }