Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sql/add-disk-space-check.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- 添加磁盘空间暂存字段到订阅下载表
ALTER TABLE "AppRssSubscriptionDownloads" ADD COLUMN "IsPendingDueToLowDiskSpace" INTEGER NOT NULL DEFAULT 0;
2 changes: 2 additions & 0 deletions src/DFApp.Application.Contracts/Rss/RssSubscriptionDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ public class RssSubscriptionDownloadDto : EntityDto<long>

public string? DownloadStatusText { get; set; }

public bool IsPendingDueToLowDiskSpace { get; set; }

public string? ErrorMessage { get; set; }

public DateTime? DownloadStartTime { get; set; }
Expand Down
54 changes: 54 additions & 0 deletions src/DFApp.Application/Background/DiskSpaceCheckWorker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using DFApp.Rss;
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Quartz;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.DependencyInjection;

namespace DFApp.Background
{
/// <summary>
/// 磁盘空间检查后台任务,处理因空间不足而暂存的下载
/// </summary>
public class DiskSpaceCheckWorker : QuartzBackgroundWorkerBase, ITransientDependency
{
private readonly IRssSubscriptionService _rssSubscriptionService;

public DiskSpaceCheckWorker(
IRssSubscriptionService rssSubscriptionService)
{
_rssSubscriptionService = rssSubscriptionService;

JobDetail = JobBuilder
.Create<DiskSpaceCheckWorker>()
.WithIdentity(nameof(DiskSpaceCheckWorker))
.Build();

Trigger = TriggerBuilder
.Create()
.WithIdentity(nameof(DiskSpaceCheckWorker))
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(10)
.RepeatForever())
.Build();
}

public override async Task Execute(IJobExecutionContext context)
{
Logger.LogInformation("开始执行磁盘空间检查任务");

try
{
await _rssSubscriptionService.ProcessPendingDownloadsAsync();

Logger.LogInformation("磁盘空间检查任务完成");
}
catch (Exception ex)
{
Logger.LogError(ex, "磁盘空间检查任务执行失败");
}
}
}
}
95 changes: 95 additions & 0 deletions src/DFApp.Application/Rss/RssSubscriptionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
Expand Down Expand Up @@ -163,6 +164,9 @@ public async Task<List<RssSubscriptionMatchResult>> MatchSubscriptionsAsync(RssM
return results;
}

private const long MinDiskSpaceGB = 2;
private const long MinDiskSpaceBytes = MinDiskSpaceGB * 1024 * 1024 * 1024;

public async Task CreateDownloadTaskAsync(long subscriptionId, long rssMirrorItemId)
{
var subscription = await _rssSubscriptionRepository.GetAsync(subscriptionId);
Expand All @@ -178,6 +182,27 @@ public async Task CreateDownloadTaskAsync(long subscriptionId, long rssMirrorIte
return;
}

var availableSpace = GetAvailableDiskSpace();

if (availableSpace < MinDiskSpaceBytes)
{
_logger.LogWarning("磁盘空间不足 {MinGB} GB,暂存订阅 {SubscriptionName} 的下载: {Title}",
MinDiskSpaceGB, subscription.Name, item.Title);

var pendingRecord = new RssSubscriptionDownload
{
SubscriptionId = subscriptionId,
RssMirrorItemId = rssMirrorItemId,
Aria2Gid = string.Empty,
DownloadStatus = 0,
IsPendingDueToLowDiskSpace = true,
CreationTime = DateTime.Now
};

await _rssSubscriptionDownloadRepository.InsertAsync(pendingRecord);
return;
}

var downloadRequest = new AddDownloadRequestDto
{
Urls = new List<string> { item.Link },
Expand All @@ -203,5 +228,75 @@ public async Task CreateDownloadTaskAsync(long subscriptionId, long rssMirrorIte
_logger.LogInformation("订阅 {SubscriptionName} 自动下载: {Title} (GID: {Gid})",
subscription.Name, item.Title, result.Id);
}

private long GetAvailableDiskSpace()
{
try
{
var currentDirectory = Directory.GetCurrentDirectory();
var driveInfo = new DriveInfo(Path.GetPathRoot(currentDirectory)!);
return driveInfo.AvailableFreeSpace;
}
catch (Exception ex)
{
_logger.LogError(ex, "获取磁盘空间失败");
return 0;
}
}

public async Task ProcessPendingDownloadsAsync()
{
var availableSpace = GetAvailableDiskSpace();

if (availableSpace < MinDiskSpaceBytes)
{
_logger.LogInformation("磁盘空间不足 {MinGB} GB,跳过暂存下载处理", MinDiskSpaceGB);
return;
}

var pendingDownloads = await _rssSubscriptionDownloadRepository.GetListAsync(
d => d.IsPendingDueToLowDiskSpace && d.DownloadStatus == 0);

if (!pendingDownloads.Any())
{
return;
}

_logger.LogInformation("找到 {Count} 个暂存的下载任务", pendingDownloads.Count);

foreach (var download in pendingDownloads)
{
try
{
var subscription = await _rssSubscriptionRepository.GetAsync(download.SubscriptionId);
var item = await _rssMirrorItemRepository.GetAsync(download.RssMirrorItemId);

var downloadRequest = new AddDownloadRequestDto
{
Urls = new List<string> { item.Link },
VideoOnly = subscription.VideoOnly,
EnableKeywordFilter = subscription.EnableKeywordFilter,
SavePath = subscription.SavePath
};

var result = await _aria2Service.AddDownloadAsync(downloadRequest);

download.Aria2Gid = result.Id;
download.DownloadStatus = 1;
download.DownloadStartTime = DateTime.Now;
download.IsPendingDueToLowDiskSpace = false;

await _rssSubscriptionDownloadRepository.UpdateAsync(download);

_logger.LogInformation("已处理暂存下载: {Id} (GID: {Gid})", download.Id, result.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "处理暂存下载失败: {Id}", download.Id);
}
}

_logger.LogInformation("已处理 {Count} 个暂存下载任务", pendingDownloads.Count);
}
}
}
1 change: 1 addition & 0 deletions src/DFApp.Domain/Rss/IRssSubscriptionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public interface IRssSubscriptionService
{
Task<List<RssSubscriptionMatchResult>> MatchSubscriptionsAsync(RssMirrorItem item);
Task CreateDownloadTaskAsync(long subscriptionId, long rssMirrorItemId);
Task ProcessPendingDownloadsAsync();
}

public class RssSubscriptionMatchResult
Expand Down
2 changes: 2 additions & 0 deletions src/DFApp.Domain/Rss/RssSubscriptionDownload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class RssSubscriptionDownload : Entity<long>, IHasCreationTime

public DateTime? DownloadCompleteTime { get; set; }

public bool IsPendingDueToLowDiskSpace { get; set; }

public DateTime CreationTime { get; set; }

public Guid? CreatorId { get; set; }
Expand Down
Loading