Skip to content

Commit

Permalink
Symlink fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
rogerfar committed Apr 9, 2024
1 parent 949bd7c commit 367e195
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 134 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.66] - 2024-04-08
### Changed
- Symlink fixes and improvements.

## [2.0.65] - 2024-04-07
### Added
- Added option to configure the buffersize for the internal downloader.
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/navbar/navbar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<a class="navbar-item" routerLink="profile"> Profile </a>
<a class="navbar-item" (click)="logout()"> Logout </a>
<hr class="navbar-divider" />
<a href="https://github.com/rogerfar/rdt-client" target="_blank" class="navbar-item">Version 2.0.65</a>
<a href="https://github.com/rogerfar/rdt-client" target="_blank" class="navbar-item">Version 2.0.66</a>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rdt-client",
"version": "2.0.65",
"version": "2.0.66",
"description": "This is a web interface to manage your torrents on Real-Debrid.",
"main": "index.js",
"dependencies": {
Expand Down
36 changes: 1 addition & 35 deletions server/RdtClient.Data/Data/DownloadData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,25 +185,7 @@ public async Task UpdateError(Guid downloadId, String? error)

await TorrentData.VoidCache();
}

public async Task UpdateErrors(Dictionary<Guid, String> downloadIds)
{
foreach (var entry in downloadIds)
{
var dbDownload = await dataContext.Downloads
.FirstOrDefaultAsync(m => m.DownloadId == entry.Key);

if (dbDownload == null)
{
continue;
}

dbDownload.Error = entry.Value;
}

await dataContext.SaveChangesAsync();
}


public async Task UpdateRetryCount(Guid downloadId, Int32 retryCount)
{
var dbDownload = await dataContext.Downloads
Expand Down Expand Up @@ -236,22 +218,6 @@ public async Task UpdateRemoteId(Guid downloadId, String remoteId)
await dataContext.SaveChangesAsync();
}

public async Task UpdateRemoteIds(Dictionary<Guid, String> remoteIds)
{
foreach (var entry in remoteIds)
{
var dbDownload = await dataContext.Downloads.FirstOrDefaultAsync(m => m.DownloadId == entry.Key);
if (dbDownload == null)
{
continue;
}

dbDownload.RemoteId = entry.Value;
}

await dataContext.SaveChangesAsync();
}

public async Task DeleteForTorrent(Guid torrentId)
{
var downloads = await dataContext.Downloads
Expand Down
2 changes: 1 addition & 1 deletion server/RdtClient.Service/Services/DownloadClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async Task<String> Start()
Data.Enums.DownloadClient.Internal => new InternalDownloader(download.Link, filePath),
Data.Enums.DownloadClient.Bezzad => new BezzadDownloader(download.Link, filePath),
Data.Enums.DownloadClient.Aria2c => new Aria2cDownloader(download.RemoteId, download.Link, filePath, downloadPath),
Data.Enums.DownloadClient.Symlink => new SymlinkDownloader(download.Link, filePath),
Data.Enums.DownloadClient.Symlink => new SymlinkDownloader(download.Link, filePath, downloadPath),
_ => throw new($"Unknown download client {Settings.Get.DownloadClient}")
};

Expand Down
151 changes: 93 additions & 58 deletions server/RdtClient.Service/Services/Downloaders/SymlinkDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace RdtClient.Service.Services.Downloaders;

public class SymlinkDownloader(String uri, String path) : IDownloader
public class SymlinkDownloader(String uri, String destinationPath, String path) : IDownloader
{
public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
Expand All @@ -11,83 +11,118 @@ public class SymlinkDownloader(String uri, String path) : IDownloader

private readonly ILogger _logger = Log.ForContext<SymlinkDownloader>();

private const Int32 MaxRetries = 10;

public async Task<String> Download()
{
_logger.Debug($"Starting symlink resolving of {uri}, writing to path: {path}");

var filePath = new DirectoryInfo(path);

var fileName = filePath.Name;
var fileExtension = filePath.Extension;
var directoryName = Path.GetDirectoryName(filePath.FullName) ?? throw new($"Cannot get directory name for file {filePath.FullName}");
var fileDirectory = Path.GetFileName(directoryName) ?? throw new($"Cannot get directory name for file {directoryName}");
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName) ?? throw new($"Cannot get directory name for file {fileName}");
var fileDirectoryWithoutExtension = Path.GetFileNameWithoutExtension(fileDirectory) ?? throw new($"Cannot get directory name for file {fileDirectory}");

String[] folders =
[
fileNameWithoutExtension,
fileDirectoryWithoutExtension,
fileName,
fileDirectory
];

List<String> unWantedExtensions =
[
"zip",
"rar",
"tar"
];

if (unWantedExtensions.Any(m => fileExtension == m))
try
{
throw new($"Cant handle compressed files with symlink downloader");
}
var filePath = new FileInfo(path);

var rcloneMountPath = Settings.Get.DownloadClient.RcloneMountPath.TrimEnd(['\\', '/']);
var fileName = filePath.Name;
var fileExtension = filePath.Extension;
var pathWithoutFileName = path.Replace(fileName, "").TrimEnd(['\\', '/']);
var searchPath = Path.Combine(rcloneMountPath, pathWithoutFileName);

List<String> unWantedExtensions =
[
"zip",
"rar",
"tar"
];

if (unWantedExtensions.Any(m => fileExtension == m))
{
throw new($"Cant handle compressed files with symlink downloader");
}

DownloadProgress?.Invoke(this, new()
{
BytesDone = 0,
BytesTotal = 0,
Speed = 0
});
DownloadProgress?.Invoke(this,
new()
{
BytesDone = 0,
BytesTotal = 0,
Speed = 0
});

FileInfo? file = null;
var potentialFilePaths = new List<String>();

var tries = 1;
var directoryInfo = new DirectoryInfo(searchPath);
while (directoryInfo.Parent != null)
{
potentialFilePaths.Add(directoryInfo.FullName + @"\");
directoryInfo = directoryInfo.Parent;

while (file == null && tries <= 10)
{
_logger.Debug($"Searching {Settings.Get.DownloadClient.RcloneMountPath} for {fileName} (attempt #{tries})...");
if (directoryInfo.FullName == rcloneMountPath)
{
break;
}
}

var dirInfo = new DirectoryInfo(Settings.Get.DownloadClient.RcloneMountPath);
file = dirInfo.EnumerateDirectories().FirstOrDefault(dir => folders.Contains(dir.Name))?.EnumerateFiles().FirstOrDefault(x => x.Name == fileName);
FileInfo? file = null;

if (file == null)
for (var retryCount = 0; retryCount < MaxRetries; retryCount++)
{
await Task.Delay(1000 * tries);

tries++;
DownloadProgress?.Invoke(this,
new()
{
BytesDone = retryCount,
BytesTotal = 10,
Speed = 1
});

_logger.Debug($"Searching {Settings.Get.DownloadClient.RcloneMountPath} for {fileName} (attempt #{retryCount})...");

foreach (var potentialFilePath in potentialFilePaths)
{
var potentialFilePathWithFileName = Path.Combine(potentialFilePath, fileName);

if (File.Exists(potentialFilePathWithFileName))
{
file = new(potentialFilePathWithFileName);
break;
}
}

if (file == null)
{
await Task.Delay(1000 * retryCount);
}
else
{
break;
}
}
}

if (file == null)
{
throw new("Could not find file from rclone mount!");
}
if (file == null)
{
throw new("Could not find file from rclone mount!");
}

_logger.Debug($"Found {file.FullName} after #{tries} attempts");
_logger.Debug($"Found {file.FullName} at {file.FullName}");

var result = TryCreateSymbolicLink(file.FullName, filePath.FullName);
var result = TryCreateSymbolicLink(file.FullName, destinationPath);

if (!result)
{
throw new("Could not find file from rclone mount!");
}
if (!result)
{
throw new("Could not find file from rclone mount!");
}

DownloadComplete?.Invoke(this, new());
DownloadComplete?.Invoke(this, new());

return file.FullName;
return file.FullName;
}
catch (Exception ex)
{
DownloadComplete?.Invoke(this, new()
{
Error = ex.Message
});

throw;
}
}

public Task Cancel()
Expand Down
14 changes: 2 additions & 12 deletions server/RdtClient.Service/Services/Downloads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,7 @@ public async Task UpdateError(Guid downloadId, String? error)
{
await downloadData.UpdateError(downloadId, error);
}

public async Task UpdateErrors(Dictionary<Guid, String> downloadIds)
{
await downloadData.UpdateErrors(downloadIds);
}


public async Task UpdateRetryCount(Guid downloadId, Int32 retryCount)
{
await downloadData.UpdateRetryCount(downloadId, retryCount);
Expand All @@ -79,12 +74,7 @@ public async Task UpdateRemoteId(Guid downloadId, String remoteId)
{
await downloadData.UpdateRemoteId(downloadId, remoteId);
}

public async Task UpdateRemoteIds(Dictionary<Guid, String> downloadIds)
{
await downloadData.UpdateRemoteIds(downloadIds);
}


public async Task DeleteForTorrent(Guid torrentId)
{
await downloadData.DeleteForTorrent(torrentId);
Expand Down
30 changes: 5 additions & 25 deletions server/RdtClient.Service/Services/TorrentRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ public class TorrentRunner(ILogger<TorrentRunner> logger, Torrents torrents, Dow
public static readonly ConcurrentDictionary<Guid, DownloadClient> ActiveDownloadClients = new();
public static readonly ConcurrentDictionary<Guid, UnpackClient> ActiveUnpackClients = new();

private readonly Dictionary<Guid, String> _aggregatedDownloadResults = [];
private readonly Dictionary<Guid, String> _aggregatedDownloadErrors = [];

private readonly HttpClient _httpClient = new()
{
Timeout = TimeSpan.FromSeconds(10)
Expand Down Expand Up @@ -334,27 +331,24 @@ public async Task Tick()
.OrderBy(m => m.DownloadQueued)
.ToList();

_aggregatedDownloadResults.Clear();
_aggregatedDownloadErrors.Clear();

Log($"Currently {queuedDownloads.Count} queued downloads and {ActiveDownloadClients.Count} total active downloads", torrent);

foreach (var download in queuedDownloads)
{
Log($"Processing to download", download, torrent);

if (ActiveDownloadClients.Count >= settingDownloadLimit)
if (ActiveDownloadClients.Count >= settingDownloadLimit && torrent.DownloadClient != Data.Enums.DownloadClient.Symlink)
{
Log($"Not starting download because there are already the max number of downloads active", download, torrent);

continue;
return;
}

if (ActiveDownloadClients.ContainsKey(download.DownloadId))
{
Log($"Not starting download because this download is already active", download, torrent);

continue;
return;
}

try
Expand All @@ -376,7 +370,7 @@ public async Task Tick()
download.Error = ex.Message;
download.Completed = DateTimeOffset.UtcNow;

continue;
return;
}

Log($"Marking download as started", download, torrent);
Expand Down Expand Up @@ -413,32 +407,18 @@ public async Task Tick()

if (download.RemoteId != remoteId)
{
_aggregatedDownloadResults.Add(download.DownloadId, remoteId);
await downloads.UpdateRemoteId(download.DownloadId, remoteId);
}
}
catch (Exception ex)
{
LogError($"Unable to start download: {ex.Message}", download, torrent);
_aggregatedDownloadErrors.Add(download.DownloadId, ex.Message);
}

Log($"Started download", download, torrent);
}
}

if (_aggregatedDownloadResults.Count > 0)
{
await downloads.UpdateRemoteIds(_aggregatedDownloadResults);
}

if (_aggregatedDownloadErrors.Count > 0)
{
await downloads.UpdateErrors(_aggregatedDownloadErrors);
}

_aggregatedDownloadResults.Clear();
_aggregatedDownloadErrors.Clear();

// Check if there are any unpacks that are queued and can be started.
var queuedUnpacks = torrent.Downloads
.Where(m => m.Completed == null && m.UnpackingQueued != null && m.UnpackingStarted == null && m.Error == null)
Expand Down
2 changes: 1 addition & 1 deletion server/RdtClient.Web/RdtClient.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
<Version>2.0.65</Version>
<Version>2.0.66</Version>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
Expand Down

0 comments on commit 367e195

Please sign in to comment.