reactredux/webapi/DataProviders/Abstractions/BucketDataProviderBase.cs

161 lines
5.1 KiB
C#

using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using DomainResults.Common;
using ExtensionMethods;
namespace DataProviders.Abstractions {
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BucketDataProviderBase : DataProviderBase<BucketDataProviderBase> {
private readonly GridFSBucket _bucket;
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="client"></param>
public BucketDataProviderBase(
ILogger<BucketDataProviderBase> logger,
IMongoClient client,
string bucketName
) : base (logger, client, "reactredux") {
_bucket = new GridFSBucket(_database, new GridFSBucketOptions {
BucketName = bucketName,
ChunkSizeBytes = 1048576, // 1MB
WriteConcern = WriteConcern.WMajority,
ReadPreference = ReadPreference.Secondary
});
}
#region Upload
public (Guid?, IDomainResult) Upload(BucketFile file) =>
UploadAsync(file).Result;
public async Task<(Guid?, IDomainResult)> UploadAsync(BucketFile file) {
var (list, result) = await UploadManyAsync(new List<BucketFile> { file });
if (!result.IsSuccess || list == null)
return (null, result);
return (list.First(), result);
}
#endregion
#region Upload many
public (List<Guid>?, IDomainResult) UploadMany(List<BucketFile> files) =>
UploadManyAsync(files).Result;
public async Task<(List<Guid>?, IDomainResult)> UploadManyAsync(List<BucketFile> files) {
var options = new GridFSUploadOptions {
ChunkSizeBytes = 64512, // 63KB
};
try {
var result = new List<Guid>();
foreach (var file in files) {
options.Metadata = new BsonDocument {
{ "siteId", $"{file.SiteId}"},
{ "userId", $"{file.UserId}"},
{ "published", file.Published.ToString() },
{ "fileName", file.Name },
{ "contentType", file.ContentType }
};
await _bucket.UploadFromBytesAsync($"{file.Id}", file.Bytes, options);
result.Add(file.Id);
}
return result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.Failed<List<Guid>?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed<List<Guid>?>();
}
}
#endregion
#region Download
private protected (List<BucketFile>?, IDomainResult) Download(FilterDefinition<GridFSFileInfo> filter) =>
DownloadAsync(filter).Result;
private protected async Task<(List<BucketFile>?, IDomainResult)> DownloadAsync(FilterDefinition<GridFSFileInfo> filter) {
try {
var sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime);
using var cursor = await _bucket.FindAsync(filter, new GridFSFindOptions {
Sort = sort,
});
var result = new List<BucketFile>();
// fileInfo either has the matching file information or is null
foreach (var fileInfo in await cursor.ToListAsync()) {
if (fileInfo == null)
return IDomainResult.NotFound<List<BucketFile>?>();
var id = fileInfo.Filename.ToGuid();
var userId = fileInfo.Metadata["userId"].ToString()?.ToNullableGuid();
var siteId = fileInfo.Metadata["siteId"].ToString()?.ToNullableGuid();
var published = fileInfo.Metadata["published"].ToString()?.ToNullableDateTime();
var fileName = fileInfo.Metadata["fileName"].ToString() ?? "";
var bytes = await _bucket.DownloadAsBytesByNameAsync($"{fileInfo.Filename}", new GridFSDownloadByNameOptions {
Revision = -1
});
var contentType = fileInfo.Metadata["contentType"].ToString() ?? "";
if (siteId == null || userId == null || bytes == null)
return IDomainResult.Failed<List<BucketFile>?>();
result.Add(new BucketFile(id, siteId.Value, userId.Value, published, fileName, bytes, contentType));
}
return result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.NotFound<List<BucketFile>?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed<List<BucketFile>?>();
}
}
#endregion
#region Delete
private protected IDomainResult Delete(FilterDefinition<GridFSFileInfo> filter) =>
DeleteAsync(filter).Result;
private protected async Task<IDomainResult> DeleteAsync(FilterDefinition<GridFSFileInfo> filter) {
try {
using var cursor = await _bucket.FindAsync(filter);
var count = 0;
foreach (var fileInfo in await cursor.ToListAsync()) {
await _bucket.DeleteAsync(fileInfo.Id);
count++;
}
return count > 0
? IDomainResult.Success()
: IDomainResult.NotFound();
}
catch (Exception ex) {
_logger.LogError(ex, "Bucket data provider error");
return IDomainResult.Failed();
}
}
#endregion
}
}