201 lines
7.4 KiB
C#
201 lines
7.4 KiB
C#
using Microsoft.Extensions.Logging;
|
|
|
|
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
using MongoDB.Driver.GridFS;
|
|
|
|
using DomainResults.Common;
|
|
|
|
namespace DataProviders.Abstractions {
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
public abstract class BucketDataProviderBase : DataProviderBase<BucketDataProviderBase> {
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="logger"></param>
|
|
/// <param name="client"></param>
|
|
public BucketDataProviderBase(
|
|
ILogger<BucketDataProviderBase> logger,
|
|
IMongoClient client
|
|
) : base (logger, client){ }
|
|
|
|
#region Upload
|
|
private protected (Guid?, IDomainResult) Upload(Guid siteId, Guid userId, BucketFile file, string bucketName) =>
|
|
UploadAsync(siteId, userId, file, bucketName).Result;
|
|
|
|
private protected Task<(Guid?, IDomainResult)> UploadAsync(Guid siteId, Guid userId, BucketFile file, string bucketName) =>
|
|
UploadAsyncCore(siteId, userId, file, bucketName);
|
|
#endregion
|
|
|
|
#region Upload many
|
|
private protected (List<Guid>?, IDomainResult) UploadMany(Guid siteId, Guid userId, List<BucketFile> files, string bucketName) =>
|
|
UploadAsync(siteId, userId, files, bucketName).Result;
|
|
|
|
private protected Task<(List<Guid>?, IDomainResult)> UploadAsync(Guid siteId, Guid userId, List<BucketFile> files, string bucketName) =>
|
|
UploadManyAsyncCore(siteId, userId, files, bucketName);
|
|
#endregion
|
|
|
|
#region Download
|
|
private protected (List<BucketFile>?, IDomainResult) Download(FilterDefinition<GridFSFileInfo> filter, string bucketName) =>
|
|
DownloadAsync(filter, bucketName).Result;
|
|
|
|
private protected Task<(List<BucketFile>?, IDomainResult)> DownloadAsync(FilterDefinition<GridFSFileInfo> filter, string bucketName) =>
|
|
DownloadAsyncCore(filter, bucketName);
|
|
#endregion
|
|
|
|
#region Delete
|
|
private protected IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
|
|
DeleteOneAsync(siteId, userId, fileId, bucketName).Result;
|
|
|
|
private protected Task<IDomainResult> DeleteOneAsync(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
|
|
DeleteOneAsyncCore(siteId, userId, fileId, bucketName);
|
|
#endregion
|
|
|
|
#region Delete many
|
|
private protected IDomainResult DeleteMany(Guid siteId, Guid userId, string bucketName) =>
|
|
DeleteManyAsync(siteId, userId, bucketName).Result;
|
|
|
|
private protected Task<IDomainResult> DeleteManyAsync(Guid siteId, Guid userId, string bucketName) =>
|
|
DeleteManyAsyncCore(siteId, userId, bucketName);
|
|
#endregion
|
|
|
|
#region Core methods
|
|
private GridFSBucket CreateBucket(string bucketName) => new GridFSBucket(_client.GetDatabase(_databaseName), new GridFSBucketOptions {
|
|
BucketName = bucketName,
|
|
ChunkSizeBytes = 1048576, // 1MB
|
|
WriteConcern = WriteConcern.WMajority,
|
|
ReadPreference = ReadPreference.Secondary
|
|
});
|
|
|
|
private async Task<(Guid?, IDomainResult)> UploadAsyncCore(Guid siteId, Guid userId, BucketFile file, string bucketName) {
|
|
var (list, result) = await UploadManyAsyncCore(siteId, userId, new List<BucketFile> { file }, bucketName);
|
|
|
|
if (!result.IsSuccess || list == null)
|
|
return (null, result);
|
|
|
|
return (list.First(), result);
|
|
}
|
|
|
|
public async Task<(List<Guid>?, IDomainResult)> UploadManyAsyncCore(Guid siteId, Guid userId, List<BucketFile> files, string bucketName) {
|
|
var options = new GridFSUploadOptions {
|
|
ChunkSizeBytes = 64512, // 63KB
|
|
};
|
|
|
|
try {
|
|
var bucket = CreateBucket(bucketName);
|
|
|
|
var result = new List<Guid>();
|
|
foreach (var file in files) {
|
|
|
|
options.Metadata = new BsonDocument {
|
|
{ "siteId", $"{siteId}"},
|
|
{ "userId", $"{userId}"},
|
|
{ "fileName", file.Name },
|
|
{ "contentType", file.ContentType },
|
|
{ "private", true }
|
|
};
|
|
|
|
var fileId = Guid.NewGuid();
|
|
await bucket.UploadFromBytesAsync($"{fileId}", file.Bytes, options);
|
|
result.Add(fileId);
|
|
}
|
|
|
|
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>?>();
|
|
}
|
|
}
|
|
|
|
private async Task<(List<BucketFile>?, IDomainResult)> DownloadAsyncCore(FilterDefinition<GridFSFileInfo> filter, string bucketName) {
|
|
try {
|
|
var sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime);
|
|
|
|
var bucket = CreateBucket(bucketName);
|
|
|
|
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 fileName = fileInfo.Metadata["fileName"].ToString() ?? "";
|
|
if (fileName == null)
|
|
return IDomainResult.Failed<List<BucketFile>?>();
|
|
|
|
var contentType = fileInfo.Metadata["contentType"].ToString() ?? "";
|
|
if (contentType == null)
|
|
return IDomainResult.Failed<List<BucketFile>?>();
|
|
|
|
var bytes = await bucket.DownloadAsBytesByNameAsync($"{fileInfo.Filename}", new GridFSDownloadByNameOptions {
|
|
Revision = -1
|
|
});
|
|
|
|
if (bytes == null)
|
|
return IDomainResult.Failed<List<BucketFile>?>();
|
|
|
|
result.Add(new BucketFile(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>?>();
|
|
}
|
|
}
|
|
|
|
private Task<IDomainResult> DeleteOneAsyncCore(Guid siteId, Guid userId, Guid fileId, string bucketName) =>
|
|
DeleteAsyncCore(siteId, userId, Builders<GridFSFileInfo>.Filter.And(
|
|
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
|
|
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["userId"], $"{userId}"),
|
|
Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, $"{fileId}")
|
|
), bucketName);
|
|
|
|
private Task<IDomainResult> DeleteManyAsyncCore(Guid siteId, Guid userId, string bucketName) =>
|
|
DeleteAsyncCore(siteId, userId, Builders<GridFSFileInfo>.Filter.And(
|
|
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"),
|
|
Builders<GridFSFileInfo>.Filter.Eq(x => x.Metadata["userId"], $"{userId}")
|
|
), bucketName);
|
|
|
|
private async Task<IDomainResult> DeleteAsyncCore(Guid siteId, Guid userId, FilterDefinition<GridFSFileInfo> filter, string bucketName) {
|
|
try {
|
|
var bucket = CreateBucket(bucketName);
|
|
|
|
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
|
|
}
|
|
}
|