69 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			69 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using DysonNetwork.Shared.Auth;
 | 
						|
using DysonNetwork.Shared.Cache;
 | 
						|
using DysonNetwork.Shared.Proto;
 | 
						|
using Microsoft.EntityFrameworkCore;
 | 
						|
using NodaTime;
 | 
						|
 | 
						|
namespace DysonNetwork.Drive.Billing;
 | 
						|
 | 
						|
public class QuotaService(
 | 
						|
    AppDatabase db,
 | 
						|
    UsageService usage,
 | 
						|
    AccountService.AccountServiceClient accounts,
 | 
						|
    ICacheService cache
 | 
						|
)
 | 
						|
{
 | 
						|
    public async Task<(bool ok, long billable, long quota)> IsFileAcceptable(Guid accountId, double costMultiplier, long newFileSize)
 | 
						|
    {
 | 
						|
        // The billable unit is MiB
 | 
						|
        var billableUnit = (long)Math.Ceiling(newFileSize / 1024.0 / 1024.0 * costMultiplier);
 | 
						|
        var totalBillableUsage = await usage.GetTotalBillableUsage(accountId);
 | 
						|
        var quota = await GetQuota(accountId);
 | 
						|
        return (totalBillableUsage + billableUnit <= quota, billableUnit, quota);
 | 
						|
    }
 | 
						|
 | 
						|
    public async Task<long> GetQuota(Guid accountId)
 | 
						|
    {
 | 
						|
        var cacheKey = $"file:quota:{accountId}";
 | 
						|
        var cachedResult = await cache.GetAsync<long?>(cacheKey);
 | 
						|
        if (cachedResult.HasValue) return cachedResult.Value;
 | 
						|
        
 | 
						|
        var (based, extra) = await GetQuotaVerbose(accountId);
 | 
						|
        var quota = based + extra;
 | 
						|
        await cache.SetAsync(cacheKey, quota, expiry: TimeSpan.FromMinutes(30));
 | 
						|
        return quota;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public async Task<(long based, long extra)> GetQuotaVerbose(Guid accountId)
 | 
						|
    {
 | 
						|
        
 | 
						|
 | 
						|
        var response = await accounts.GetAccountAsync(new GetAccountRequest { Id = accountId.ToString() });
 | 
						|
        var perkSubscription = response.PerkSubscription;
 | 
						|
 | 
						|
        // The base quota is 1GiB, T1 is 5GiB, T2 is 10GiB, T3 is 15GiB
 | 
						|
        var basedQuota = 1L;
 | 
						|
        if (perkSubscription != null)
 | 
						|
        {
 | 
						|
            var privilege = PerkSubscriptionPrivilege.GetPrivilegeFromIdentifier(perkSubscription.Identifier);
 | 
						|
            basedQuota = privilege switch
 | 
						|
            {
 | 
						|
                1 => 5L,
 | 
						|
                2 => 10L,
 | 
						|
                3 => 15L,
 | 
						|
                _ => basedQuota
 | 
						|
            };
 | 
						|
        }
 | 
						|
        
 | 
						|
        // The based quota is in GiB, we need to convert it to MiB
 | 
						|
        basedQuota *= 1024L;
 | 
						|
        
 | 
						|
        var now = SystemClock.Instance.GetCurrentInstant();
 | 
						|
        var extraQuota = await db.QuotaRecords
 | 
						|
            .Where(e => e.AccountId == accountId)
 | 
						|
            .Where(e => !e.ExpiredAt.HasValue || e.ExpiredAt > now)
 | 
						|
            .SumAsync(e => e.Quota);
 | 
						|
        
 | 
						|
        return (basedQuota, extraQuota);
 | 
						|
    }
 | 
						|
} |