✨ Some drive service changes
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NodaTime;
|
||||||
|
|
||||||
namespace DysonNetwork.Drive.Billing;
|
namespace DysonNetwork.Drive.Billing;
|
||||||
|
|
||||||
@@ -28,15 +29,21 @@ public class UsageService(AppDatabase db)
|
|||||||
{
|
{
|
||||||
public async Task<TotalUsageDetails> GetTotalUsage()
|
public async Task<TotalUsageDetails> GetTotalUsage()
|
||||||
{
|
{
|
||||||
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
var fileQuery = db.Files
|
||||||
|
.Where(f => !f.IsMarkedRecycle)
|
||||||
|
.Where(f => !f.ExpiredAt.HasValue || f.ExpiredAt > now)
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
var poolUsages = await db.Pools
|
var poolUsages = await db.Pools
|
||||||
.Select(p => new UsageDetails
|
.Select(p => new UsageDetails
|
||||||
{
|
{
|
||||||
PoolId = p.Id,
|
PoolId = p.Id,
|
||||||
PoolName = p.Name,
|
PoolName = p.Name,
|
||||||
UsageBytes = db.Files
|
UsageBytes = fileQuery
|
||||||
.Where(f => f.PoolId == p.Id)
|
.Where(f => f.PoolId == p.Id)
|
||||||
.Sum(f => f.Size),
|
.Sum(f => f.Size),
|
||||||
Cost = db.Files
|
Cost = fileQuery
|
||||||
.Where(f => f.PoolId == p.Id)
|
.Where(f => f.PoolId == p.Id)
|
||||||
.Sum(f => f.Size) / 1024.0 / 1024.0 *
|
.Sum(f => f.Size) / 1024.0 / 1024.0 *
|
||||||
(p.BillingConfig.CostMultiplier ?? 1.0),
|
(p.BillingConfig.CostMultiplier ?? 1.0),
|
||||||
@@ -75,13 +82,17 @@ public class UsageService(AppDatabase db)
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
var fileQuery = db.Files
|
||||||
|
.Where(f => !f.IsMarkedRecycle)
|
||||||
|
.Where(f => f.ExpiredAt.HasValue && f.ExpiredAt > now)
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
var usageBytes = await db.Files
|
var usageBytes = await fileQuery
|
||||||
.Where(f => f.PoolId == poolId)
|
|
||||||
.SumAsync(f => f.Size);
|
.SumAsync(f => f.Size);
|
||||||
|
|
||||||
var fileCount = await db.Files
|
var fileCount = await fileQuery
|
||||||
.Where(f => f.PoolId == poolId)
|
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
|
|
||||||
var cost = usageBytes / 1024.0 / 1024.0 *
|
var cost = usageBytes / 1024.0 / 1024.0 *
|
||||||
|
@@ -35,6 +35,7 @@ public class FileController(
|
|||||||
|
|
||||||
var file = await fs.GetFileAsync(id);
|
var file = await fs.GetFileAsync(id);
|
||||||
if (file is null) return NotFound();
|
if (file is null) return NotFound();
|
||||||
|
if (file.IsMarkedRecycle) return StatusCode(StatusCodes.Status410Gone, "The file has been recycled.");
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(file.StorageUrl)) return Redirect(file.StorageUrl);
|
if (!string.IsNullOrWhiteSpace(file.StorageUrl)) return Redirect(file.StorageUrl);
|
||||||
|
|
||||||
@@ -149,7 +150,7 @@ public class FileController(
|
|||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
|
|
||||||
if (pool.HasValue) query = query.Where(e => e.PoolId == pool);
|
if (pool.HasValue) query = query.Where(e => e.PoolId == pool);
|
||||||
|
|
||||||
var total = await query.CountAsync();
|
var total = await query.CountAsync();
|
||||||
Response.Headers.Append("X-Total", total.ToString());
|
Response.Headers.Append("X-Total", total.ToString());
|
||||||
|
|
||||||
|
@@ -153,25 +153,26 @@ public class FileService(
|
|||||||
IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.PolicyConfig.AllowEncryption
|
IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.PolicyConfig.AllowEncryption
|
||||||
};
|
};
|
||||||
|
|
||||||
var existingFile = await db.Files.AsNoTracking().FirstOrDefaultAsync(f => f.Hash == hash);
|
// TODO: Enable the feature later
|
||||||
file.StorageId = existingFile?.StorageId ?? file.Id;
|
// var existingFile = await db.Files.AsNoTracking().FirstOrDefaultAsync(f => f.Hash == hash);
|
||||||
|
// file.StorageId = existingFile?.StorageId ?? file.Id;
|
||||||
if (existingFile is not null)
|
//
|
||||||
{
|
// if (existingFile is not null)
|
||||||
file.FileMeta = existingFile.FileMeta;
|
// {
|
||||||
file.HasCompression = existingFile.HasCompression;
|
// file.FileMeta = existingFile.FileMeta;
|
||||||
file.SensitiveMarks = existingFile.SensitiveMarks;
|
// file.HasCompression = existingFile.HasCompression;
|
||||||
file.MimeType = existingFile.MimeType;
|
// file.SensitiveMarks = existingFile.SensitiveMarks;
|
||||||
file.UploadedAt = existingFile.UploadedAt;
|
// file.MimeType = existingFile.MimeType;
|
||||||
file.PoolId = existingFile.PoolId;
|
// file.UploadedAt = existingFile.UploadedAt;
|
||||||
|
// file.PoolId = existingFile.PoolId;
|
||||||
db.Files.Add(file);
|
//
|
||||||
await db.SaveChangesAsync();
|
// db.Files.Add(file);
|
||||||
// Since the file content is a duplicate, we can delete the new upload and we are done.
|
// await db.SaveChangesAsync();
|
||||||
await stream.DisposeAsync();
|
// // Since the file content is a duplicate, we can delete the new upload and we are done.
|
||||||
await store.DeleteFileAsync(file.Id, CancellationToken.None);
|
// await stream.DisposeAsync();
|
||||||
return file;
|
// await store.DeleteFileAsync(file.Id, CancellationToken.None);
|
||||||
}
|
// return file;
|
||||||
|
// }
|
||||||
|
|
||||||
// Extract metadata on the current thread for a faster initial response
|
// Extract metadata on the current thread for a faster initial response
|
||||||
if (!pool.PolicyConfig.NoMetadata)
|
if (!pool.PolicyConfig.NoMetadata)
|
||||||
@@ -540,11 +541,11 @@ public class FileService(
|
|||||||
|
|
||||||
public async Task DeleteFileAsync(CloudFile file)
|
public async Task DeleteFileAsync(CloudFile file)
|
||||||
{
|
{
|
||||||
await DeleteFileDataAsync(file);
|
|
||||||
|
|
||||||
db.Remove(file);
|
db.Remove(file);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
await _PurgeCacheAsync(file.Id);
|
await _PurgeCacheAsync(file.Id);
|
||||||
|
|
||||||
|
await DeleteFileDataAsync(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteFileDataAsync(CloudFile file)
|
public async Task DeleteFileDataAsync(CloudFile file)
|
||||||
@@ -559,17 +560,10 @@ public class FileService(
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
// Check if any of these files are referenced
|
// Check if any of these files are referenced
|
||||||
var anyReferenced = false;
|
|
||||||
if (sameOriginFiles.Count != 0)
|
if (sameOriginFiles.Count != 0)
|
||||||
{
|
return;
|
||||||
anyReferenced = await db.FileReferences
|
|
||||||
.Where(r => sameOriginFiles.Contains(r.FileId))
|
|
||||||
.AnyAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If any other file with the same storage ID is referenced, don't delete the actual file data
|
// If any other file with the same storage ID is referenced, don't delete the actual file data
|
||||||
if (anyReferenced) return;
|
|
||||||
|
|
||||||
var dest = await GetRemoteStorageConfig(file.PoolId.Value);
|
var dest = await GetRemoteStorageConfig(file.PoolId.Value);
|
||||||
if (dest is null) throw new InvalidOperationException($"No remote storage configured for pool {file.PoolId}");
|
if (dest is null) throw new InvalidOperationException($"No remote storage configured for pool {file.PoolId}");
|
||||||
var client = CreateMinioClient(dest);
|
var client = CreateMinioClient(dest);
|
||||||
|
Reference in New Issue
Block a user