Files
SDK-CSharp/Services/FileUploadService.cs

101 lines
3.6 KiB
C#

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<string> UploadFiles(string tempMsgId, string roomId, string userId, List<FileData> 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<string> UploadFiles(string tempMsgId, string roomId, string userId, List<FileData> 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<RegisterUploadReq, RegisterUploadResp>("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<ChunkUploadReq, object>("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<FinishUploadReq, object>("chat/finishUpload", finishReq);
}
}
}