rdt-client/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs
2021-10-24 09:38:55 -06:00

171 lines
4.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Timers;
using Aria2NET;
using RdtClient.Data.Models.Internal;
namespace RdtClient.Service.Services.Downloaders
{
public class Aria2cDownloader : IDownloader
{
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete;
public event EventHandler<DownloadProgressEventArgs> DownloadProgress;
private const Int32 RetryCount = 5;
private readonly String _uri;
private readonly String _filePath;
private readonly Aria2NetClient _aria2NetClient;
private readonly Timer _timer;
private String _gid;
public Aria2cDownloader(String gid, String uri, String filePath, DbSettings settings)
{
_gid = gid;
_uri = uri;
_filePath = filePath;
_aria2NetClient = new Aria2NetClient(settings.Aria2cUrl, settings.Aria2cSecret);
_timer = new Timer();
_timer.Elapsed += OnTimedEvent;
_timer.Interval = 1000;
_timer.Enabled = false;
}
public async Task<String> Download()
{
var path = Path.GetDirectoryName(_filePath);
var fileName = Path.GetFileName(_filePath);
if (_gid != null)
{
try
{
await _aria2NetClient.TellStatus(_gid);
}
catch
{
_gid = null;
}
}
var retryCount = 0;
while(true)
{
try
{
_gid ??= await _aria2NetClient.AddUri(new List<String>
{
_uri
},
new Dictionary<String, Object>
{
{
"dir", path
},
{
"out", fileName
}
});
break;
}
catch
{
if (retryCount >= RetryCount)
{
throw;
}
await Task.Delay(retryCount * 1000);
retryCount++;
}
}
// Add a delay to prevent sending too many Add requests to Aria2 at the same time.
await Task.Delay(1000);
_timer.Start();
return _gid;
}
public async Task Cancel()
{
_timer.Stop();
if (String.IsNullOrWhiteSpace(_gid))
{
return;
}
try
{
await _aria2NetClient.ForceRemove(_gid);
}
catch
{
// ignored
}
try
{
await _aria2NetClient.RemoveDownloadResult(_gid);
}
catch
{
// ignored
}
}
private async void OnTimedEvent(Object source, ElapsedEventArgs e)
{
if (_gid == null)
{
return;
}
try
{
var status = await _aria2NetClient.TellStatus(_gid);
if (!String.IsNullOrWhiteSpace(status.ErrorMessage) || status.Status == "error")
{
await Cancel();
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs
{
Error = $"{status.ErrorCode}: {status.ErrorMessage}"
});
return;
}
if (status.Status == "complete" || status.Status == "removed")
{
await Cancel();
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs());
return;
}
DownloadProgress?.Invoke(this, new DownloadProgressEventArgs
{
BytesDone = status.CompletedLength,
BytesTotal = status.TotalLength,
Speed = status.DownloadSpeed
});
}
catch
{
await Cancel();
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs());
}
}
}
}