diff --git a/server/RdtClient.Data/Data/DataContext.cs b/server/RdtClient.Data/Data/DataContext.cs index 3b7f817..4827be2 100644 --- a/server/RdtClient.Data/Data/DataContext.cs +++ b/server/RdtClient.Data/Data/DataContext.cs @@ -4,6 +4,8 @@ using RdtClient.Data.Models.Data; namespace RdtClient.Data.Data; +#nullable disable + public class DataContext : IdentityDbContext { public DataContext(DbContextOptions options) : base(options) diff --git a/server/RdtClient.Data/Data/DownloadData.cs b/server/RdtClient.Data/Data/DownloadData.cs index 5bf1c6f..27f80de 100644 --- a/server/RdtClient.Data/Data/DownloadData.cs +++ b/server/RdtClient.Data/Data/DownloadData.cs @@ -20,7 +20,7 @@ public class DownloadData .ToListAsync(); } - public async Task GetById(Guid downloadId) + public async Task GetById(Guid downloadId) { return await _dataContext.Downloads .Include(m => m.Torrent) @@ -28,7 +28,7 @@ public class DownloadData .FirstOrDefaultAsync(m => m.DownloadId == downloadId); } - public async Task Get(Guid torrentId, String path) + public async Task Get(Guid torrentId, String path) { return await _dataContext.Downloads .Include(m => m.Torrent) @@ -176,7 +176,7 @@ public class DownloadData await TorrentData.VoidCache(); } - public async Task UpdateError(Guid downloadId, String error) + public async Task UpdateError(Guid downloadId, String? error) { var dbDownload = await _dataContext.Downloads .FirstOrDefaultAsync(m => m.DownloadId == downloadId); @@ -243,6 +243,11 @@ public class DownloadData var dbDownload = await _dataContext.Downloads .FirstOrDefaultAsync(m => m.DownloadId == downloadId); + if (dbDownload == null) + { + throw new Exception($"Cannot find download with ID {downloadId}"); + } + dbDownload.RetryCount = 0; dbDownload.Link = null; dbDownload.Added = DateTimeOffset.UtcNow; diff --git a/server/RdtClient.Data/Data/SettingData.cs b/server/RdtClient.Data/Data/SettingData.cs index e9d3135..40a7d26 100644 --- a/server/RdtClient.Data/Data/SettingData.cs +++ b/server/RdtClient.Data/Data/SettingData.cs @@ -13,16 +13,16 @@ public class SettingData public static DbSettings Get { get; } = new DbSettings(); + public static IList GetAll() + { + return GetSettings(Get, null).ToList(); + } + public SettingData(DataContext dataContext) { _dataContext = dataContext; } - public IList GetAll() - { - return GetSettings(Get, null).ToList(); - } - public async Task Update(IList settings) { var dbSettings = await _dataContext.Settings.ToListAsync(); @@ -33,7 +33,7 @@ public class SettingData if (setting != null) { - dbSetting.Value = setting.Value.ToString(); + dbSetting.Value = setting.Value?.ToString(); } } @@ -42,7 +42,7 @@ public class SettingData await ResetCache(); } - public async Task Update(String settingId, Object value) + public async Task Update(String settingId, Object? value) { var dbSetting = await _dataContext.Settings.FirstOrDefaultAsync(m => m.SettingId == settingId); @@ -51,7 +51,7 @@ public class SettingData return; } - dbSetting.Value = value.ToString(); + dbSetting.Value = value?.ToString(); await _dataContext.SaveChangesAsync(); @@ -97,7 +97,7 @@ public class SettingData } } - private static IEnumerable GetSettings(Object defaultSetting, String parent) + private static IEnumerable GetSettings(Object defaultSetting, String? parent) { var result = new List(); @@ -105,8 +105,8 @@ public class SettingData foreach (var property in properties) { - var displayName = (DisplayNameAttribute) Attribute.GetCustomAttribute(property, typeof(DisplayNameAttribute)); - var description = (DescriptionAttribute) Attribute.GetCustomAttribute(property, typeof(DescriptionAttribute)); + var displayName = Attribute.GetCustomAttribute(property, typeof(DisplayNameAttribute)) as DisplayNameAttribute; + var description = Attribute.GetCustomAttribute(property, typeof(DescriptionAttribute)) as DescriptionAttribute; var propertyName = property.Name; if (parent != null) @@ -137,7 +137,7 @@ public class SettingData { var enumMember = property.PropertyType.GetMember(e.ToString()).First(); var enumDescriptionAttribute = enumMember.GetCustomAttribute(); - var enumName = enumDescriptionAttribute?.Description ?? Enum.GetName(property.PropertyType, e); + var enumName = enumDescriptionAttribute?.Description ?? Enum.GetName(property.PropertyType, e) ?? "Unknown value"; settingProperty.EnumValues.Add((Int32)(Object)e, enumName); } } @@ -149,7 +149,7 @@ public class SettingData settingProperty.Type = "Object"; result.Add(settingProperty); - var childResults = GetSettings(property.GetValue(defaultSetting), propertyName); + var childResults = GetSettings(property.GetValue(defaultSetting)!, propertyName); result.AddRange(childResults); } } @@ -157,7 +157,7 @@ public class SettingData return result; } - private static void SetSettings(IList settings, Object defaultSetting, String parent) + private static void SetSettings(IList settings, Object defaultSetting, String? parent) { var properties = defaultSetting.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); @@ -180,14 +180,18 @@ public class SettingData { if (property.PropertyType.IsEnum) { - var newValue = Enum.Parse(property.PropertyType, setting.Value); + var newValue = Enum.Parse(property.PropertyType, setting.Value ?? "0"); property.SetValue(defaultSetting, newValue); } else { var converter = TypeDescriptor.GetConverter(property.PropertyType); - if (converter.IsValid(setting.Value)) + if (setting.Value == null) + { + property.SetValue(defaultSetting, null); + } + else if (converter.IsValid(setting.Value)) { var newValue = converter.ConvertFrom(setting.Value); property.SetValue(defaultSetting, newValue); @@ -201,7 +205,7 @@ public class SettingData } else { - SetSettings(settings, property.GetValue(defaultSetting), propertyName); + SetSettings(settings, property.GetValue(defaultSetting)!, propertyName); } } } diff --git a/server/RdtClient.Data/Data/TorrentData.cs b/server/RdtClient.Data/Data/TorrentData.cs index 0191e66..8330eee 100644 --- a/server/RdtClient.Data/Data/TorrentData.cs +++ b/server/RdtClient.Data/Data/TorrentData.cs @@ -5,7 +5,8 @@ namespace RdtClient.Data.Data; public class TorrentData { - private static IList _torrentCache; + private static IList? _torrentCache; + private static readonly SemaphoreSlim TorrentCacheLock = new(1, 1); private readonly DataContext _dataContext; @@ -34,7 +35,7 @@ public class TorrentData } } - public async Task GetById(Guid torrentId) + public async Task GetById(Guid torrentId) { var dbTorrent = await _dataContext.Torrents .AsNoTracking() @@ -54,7 +55,7 @@ public class TorrentData return dbTorrent; } - public async Task GetByHash(String hash) + public async Task GetByHash(String hash) { var dbTorrent = await _dataContext.Torrents .AsNoTracking() @@ -76,7 +77,7 @@ public class TorrentData public async Task Add(String realDebridId, String hash, - String fileOrMagnetContents, + String? fileOrMagnetContents, Boolean isFile, Torrent torrent) { @@ -129,12 +130,8 @@ public class TorrentData dbTorrent.RdEnded = torrent.RdEnded; dbTorrent.RdSpeed = torrent.RdSpeed; dbTorrent.RdSeeders = torrent.RdSeeders; - - if (torrent.Files != null) - { - dbTorrent.RdFiles = torrent.RdFiles; - } - + dbTorrent.RdFiles = torrent.RdFiles; + await _dataContext.SaveChangesAsync(); await VoidCache(); @@ -160,7 +157,7 @@ public class TorrentData await VoidCache(); } - public async Task UpdateCategory(Guid torrentId, String category) + public async Task UpdateCategory(Guid torrentId, String? category) { var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId); @@ -176,7 +173,7 @@ public class TorrentData await VoidCache(); } - public async Task UpdateComplete(Guid torrentId, String error, DateTimeOffset? datetime, Boolean retry) + public async Task UpdateComplete(Guid torrentId, String? error, DateTimeOffset? datetime, Boolean retry) { var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId); diff --git a/server/RdtClient.Data/Data/UserData.cs b/server/RdtClient.Data/Data/UserData.cs index d1d2964..41c2702 100644 --- a/server/RdtClient.Data/Data/UserData.cs +++ b/server/RdtClient.Data/Data/UserData.cs @@ -12,7 +12,7 @@ public class UserData _dataContext = dataContext; } - public async Task GetUser() + public async Task GetUser() { return await _dataContext.Users.FirstOrDefaultAsync(); } diff --git a/server/RdtClient.Data/DiConfig.cs b/server/RdtClient.Data/DiConfig.cs index 5d27e6c..4b4903b 100644 --- a/server/RdtClient.Data/DiConfig.cs +++ b/server/RdtClient.Data/DiConfig.cs @@ -9,6 +9,11 @@ public static class DiConfig { public static void Config(IServiceCollection services, AppSettings appSettings) { + if (String.IsNullOrWhiteSpace(appSettings.Database?.Path)) + { + throw new Exception("Invalid database path found in appSettings"); + } + var connectionString = $"Data Source={appSettings.Database.Path}"; services.AddDbContext(options => options.UseSqlite(connectionString)); diff --git a/server/RdtClient.Data/Enums/DownloadClient.cs b/server/RdtClient.Data/Enums/DownloadClient.cs index 183ae5f..97bf59e 100644 --- a/server/RdtClient.Data/Enums/DownloadClient.cs +++ b/server/RdtClient.Data/Enums/DownloadClient.cs @@ -1,8 +1,15 @@ -namespace RdtClient.Data.Enums; +using System.ComponentModel; + +namespace RdtClient.Data.Enums; public enum DownloadClient { + [Description("Simple Downloader")] Simple, + + [Description("Multi-Part Downloader")] MultiPart, + + [Description("Aria2c")] Aria2c } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/Data/Download.cs b/server/RdtClient.Data/Models/Data/Download.cs index 7de058b..e8e54b1 100644 --- a/server/RdtClient.Data/Models/Data/Download.cs +++ b/server/RdtClient.Data/Models/Data/Download.cs @@ -11,10 +11,10 @@ public class Download public Guid TorrentId { get; set; } [ForeignKey("TorrentId")] - public Torrent Torrent { get; set; } + public Torrent? Torrent { get; set; } - public String Path { get; set; } - public String Link { get; set; } + public String Path { get; set; } = null!; + public String? Link { get; set; } public DateTimeOffset Added { get; set; } public DateTimeOffset? DownloadQueued { get; set; } @@ -27,9 +27,9 @@ public class Download public Int32 RetryCount { get; set; } - public String Error { get; set; } + public String? Error { get; set; } - public String RemoteId { get; set; } + public String? RemoteId { get; set; } [NotMapped] public Int64 BytesTotal { get; set; } diff --git a/server/RdtClient.Data/Models/Data/Setting.cs b/server/RdtClient.Data/Models/Data/Setting.cs index 099cec9..2408663 100644 --- a/server/RdtClient.Data/Models/Data/Setting.cs +++ b/server/RdtClient.Data/Models/Data/Setting.cs @@ -5,7 +5,7 @@ namespace RdtClient.Data.Models.Data; public class Setting { [Key] - public String SettingId { get; set; } + public String SettingId { get; set; } = null!; - public String Value { get; set; } + public String? Value { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/Data/Torrent.cs b/server/RdtClient.Data/Models/Data/Torrent.cs index bdc9480..1282975 100644 --- a/server/RdtClient.Data/Models/Data/Torrent.cs +++ b/server/RdtClient.Data/Models/Data/Torrent.cs @@ -11,21 +11,21 @@ public class Torrent [Key] public Guid TorrentId { get; set; } - public String Hash { get; set; } + public String Hash { get; set; } = null!; - public String Category { get; set; } + public String? Category { get; set; } public TorrentDownloadAction DownloadAction { get; set; } public TorrentFinishedAction FinishedAction { get; set; } public Int32 DownloadMinSize { get; set; } - public String DownloadManualFiles { get; set; } + public String? DownloadManualFiles { get; set; } public DateTimeOffset Added { get; set; } public DateTimeOffset? FilesSelected { get; set; } public DateTimeOffset? Completed { get; set; } public DateTimeOffset? Retry { get; set; } - public String FileOrMagnet { get; set; } + public String? FileOrMagnet { get; set; } public Boolean IsFile { get; set; } public Int32? Priority { get; set; } @@ -35,24 +35,24 @@ public class Torrent public Int32 DeleteOnError { get; set; } public Int32 Lifetime { get; set; } - public String Error { get; set; } + public String? Error { get; set; } [InverseProperty("Torrent")] - public IList Downloads { get; set; } + public IList Downloads { get; set; } = new List(); - public String RdId { get; set; } - public String RdName { get; set; } - public Int64 RdSize { get; set; } - public String RdHost { get; set; } - public Int64 RdSplit { get; set; } - public Int64 RdProgress { get; set; } - public TorrentStatus RdStatus { get; set; } - public String RdStatusRaw { get; set; } - public DateTimeOffset RdAdded { get; set; } + public String? RdId { get; set; } + public String? RdName { get; set; } + public Int64? RdSize { get; set; } + public String? RdHost { get; set; } + public Int64? RdSplit { get; set; } + public Int64? RdProgress { get; set; } + public TorrentStatus? RdStatus { get; set; } + public String? RdStatusRaw { get; set; } + public DateTimeOffset? RdAdded { get; set; } public DateTimeOffset? RdEnded { get; set; } public Int64? RdSpeed { get; set; } public Int64? RdSeeders { get; set; } - public String RdFiles { get; set; } + public String? RdFiles { get; set; } [NotMapped] public IList Files @@ -66,7 +66,7 @@ public class Torrent try { - return JsonSerializer.Deserialize>(RdFiles); + return JsonSerializer.Deserialize>(RdFiles) ?? new List(); } catch { diff --git a/server/RdtClient.Data/Models/Internal/AppSettings.cs b/server/RdtClient.Data/Models/Internal/AppSettings.cs index fe03ef2..190ce2b 100644 --- a/server/RdtClient.Data/Models/Internal/AppSettings.cs +++ b/server/RdtClient.Data/Models/Internal/AppSettings.cs @@ -2,25 +2,25 @@ public class AppSettings { - public AppSettingsLogging Logging { get; set; } - public AppSettingsDatabase Database { get; set; } + public AppSettingsLogging? Logging { get; set; } + public AppSettingsDatabase? Database { get; set; } public Int32 Port { get; set; } } public class AppSettingsLogging { - public AppSettingsLoggingFile File { get; set; } + public AppSettingsLoggingFile? File { get; set; } } public class AppSettingsLoggingFile { - public String Path { get; set; } + public String? Path { get; set; } public Int64 FileSizeLimitBytes { get; set; } public Int32 MaxRollingFiles { get; set; } } public class AppSettingsDatabase { - public String Path { get; set; } + public String? Path { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/Internal/Profile.cs b/server/RdtClient.Data/Models/Internal/Profile.cs index e440a88..f09d77a 100644 --- a/server/RdtClient.Data/Models/Internal/Profile.cs +++ b/server/RdtClient.Data/Models/Internal/Profile.cs @@ -2,9 +2,9 @@ public class Profile { - public String Provider { get; set; } - public String UserName { get; set; } + public String? Provider { get; set; } + public String? UserName { get; set; } public DateTimeOffset? Expiration { get; set; } - public String CurrentVersion { get; set; } - public String LatestVersion { get; set; } + public String? CurrentVersion { get; set; } + public String? LatestVersion { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/Internal/SettingProperty.cs b/server/RdtClient.Data/Models/Internal/SettingProperty.cs index 13930a3..82e0d9b 100644 --- a/server/RdtClient.Data/Models/Internal/SettingProperty.cs +++ b/server/RdtClient.Data/Models/Internal/SettingProperty.cs @@ -2,10 +2,10 @@ public class SettingProperty { - public String Key { get; set; } - public Object Value { get; set; } - public String DisplayName { get; set; } - public String Description { get; set; } - public String Type { get; set; } - public Dictionary EnumValues { get; set; } + public String Key { get; set; } = default!; + public Object? Value { get; set; } + public String? DisplayName { get; set; } + public String? Description { get; set; } + public String Type { get; set; } = default!; + public Dictionary? EnumValues { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/QBittorrent/AppBuildInfo.cs b/server/RdtClient.Data/Models/QBittorrent/AppBuildInfo.cs index 6fb8e44..28547a2 100644 --- a/server/RdtClient.Data/Models/QBittorrent/AppBuildInfo.cs +++ b/server/RdtClient.Data/Models/QBittorrent/AppBuildInfo.cs @@ -5,20 +5,20 @@ namespace RdtClient.Data.Models.QBittorrent; public class AppBuildInfo { [JsonPropertyName("bitness")] - public Int64 Bitness { get; set; } + public Int64? Bitness { get; set; } [JsonPropertyName("boost")] - public String Boost { get; set; } + public String? Boost { get; set; } [JsonPropertyName("libtorrent")] - public String Libtorrent { get; set; } + public String? Libtorrent { get; set; } [JsonPropertyName("openssl")] - public String Openssl { get; set; } + public String? Openssl { get; set; } [JsonPropertyName("qt")] - public String Qt { get; set; } + public String? Qt { get; set; } [JsonPropertyName("zlib")] - public String Zlib { get; set; } + public String? Zlib { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/QBittorrent/AppPreferences.cs b/server/RdtClient.Data/Models/QBittorrent/AppPreferences.cs index 2d761ea..208361b 100644 --- a/server/RdtClient.Data/Models/QBittorrent/AppPreferences.cs +++ b/server/RdtClient.Data/Models/QBittorrent/AppPreferences.cs @@ -5,424 +5,424 @@ namespace RdtClient.Data.Models.QBittorrent; public class AppPreferences { [JsonPropertyName("add_trackers")] - public String AddTrackers { get; set; } + public String? AddTrackers { get; set; } [JsonPropertyName("add_trackers_enabled")] - public Boolean AddTrackersEnabled { get; set; } + public Boolean? AddTrackersEnabled { get; set; } [JsonPropertyName("alt_dl_limit")] - public Int64 AltDlLimit { get; set; } + public Int64? AltDlLimit { get; set; } [JsonPropertyName("alt_up_limit")] - public Int64 AltUpLimit { get; set; } + public Int64? AltUpLimit { get; set; } [JsonPropertyName("alternative_webui_enabled")] - public Boolean AlternativeWebuiEnabled { get; set; } + public Boolean? AlternativeWebuiEnabled { get; set; } [JsonPropertyName("alternative_webui_path")] - public String AlternativeWebuiPath { get; set; } + public String? AlternativeWebuiPath { get; set; } [JsonPropertyName("announce_ip")] - public String AnnounceIp { get; set; } + public String? AnnounceIp { get; set; } [JsonPropertyName("announce_to_all_tiers")] - public Boolean AnnounceToAllTiers { get; set; } + public Boolean? AnnounceToAllTiers { get; set; } [JsonPropertyName("announce_to_all_trackers")] - public Boolean AnnounceToAllTrackers { get; set; } + public Boolean? AnnounceToAllTrackers { get; set; } [JsonPropertyName("anonymous_mode")] - public Boolean AnonymousMode { get; set; } + public Boolean? AnonymousMode { get; set; } [JsonPropertyName("async_io_threads")] - public Int64 AsyncIoThreads { get; set; } + public Int64? AsyncIoThreads { get; set; } [JsonPropertyName("auto_delete_mode")] - public Int64 AutoDeleteMode { get; set; } + public Int64? AutoDeleteMode { get; set; } [JsonPropertyName("auto_tmm_enabled")] - public Boolean AutoTmmEnabled { get; set; } + public Boolean? AutoTmmEnabled { get; set; } [JsonPropertyName("autorun_enabled")] - public Boolean AutorunEnabled { get; set; } + public Boolean? AutorunEnabled { get; set; } [JsonPropertyName("autorun_program")] - public String AutorunProgram { get; set; } + public String? AutorunProgram { get; set; } [JsonPropertyName("banned_IPs")] - public String BannedIPs { get; set; } + public String? BannedIPs { get; set; } [JsonPropertyName("bittorrent_protocol")] - public Int64 BittorrentProtocol { get; set; } + public Int64? BittorrentProtocol { get; set; } [JsonPropertyName("bypass_auth_subnet_whitelist")] - public String BypassAuthSubnetWhitelist { get; set; } + public String? BypassAuthSubnetWhitelist { get; set; } [JsonPropertyName("bypass_auth_subnet_whitelist_enabled")] - public Boolean BypassAuthSubnetWhitelistEnabled { get; set; } + public Boolean? BypassAuthSubnetWhitelistEnabled { get; set; } [JsonPropertyName("bypass_local_auth")] - public Boolean BypassLocalAuth { get; set; } + public Boolean? BypassLocalAuth { get; set; } [JsonPropertyName("category_changed_tmm_enabled")] - public Boolean CategoryChangedTmmEnabled { get; set; } + public Boolean? CategoryChangedTmmEnabled { get; set; } [JsonPropertyName("checking_memory_use")] - public Int64 CheckingMemoryUse { get; set; } + public Int64? CheckingMemoryUse { get; set; } [JsonPropertyName("create_subfolder_enabled")] - public Boolean CreateSubfolderEnabled { get; set; } + public Boolean? CreateSubfolderEnabled { get; set; } [JsonPropertyName("current_interface_address")] - public String CurrentInterfaceAddress { get; set; } + public String? CurrentInterfaceAddress { get; set; } [JsonPropertyName("current_network_interface")] - public String CurrentNetworkInterface { get; set; } + public String? CurrentNetworkInterface { get; set; } [JsonPropertyName("dht")] - public Boolean Dht { get; set; } + public Boolean? Dht { get; set; } [JsonPropertyName("disk_cache")] - public Int64 DiskCache { get; set; } + public Int64? DiskCache { get; set; } [JsonPropertyName("disk_cache_ttl")] - public Int64 DiskCacheTtl { get; set; } + public Int64? DiskCacheTtl { get; set; } [JsonPropertyName("dl_limit")] - public Int64 DlLimit { get; set; } + public Int64? DlLimit { get; set; } [JsonPropertyName("dont_count_slow_torrents")] - public Boolean DontCountSlowTorrents { get; set; } + public Boolean? DontCountSlowTorrents { get; set; } [JsonPropertyName("dyndns_domain")] - public String DyndnsDomain { get; set; } + public String? DyndnsDomain { get; set; } [JsonPropertyName("dyndns_enabled")] - public Boolean DyndnsEnabled { get; set; } + public Boolean? DyndnsEnabled { get; set; } [JsonPropertyName("dyndns_password")] - public String DyndnsPassword { get; set; } + public String? DyndnsPassword { get; set; } [JsonPropertyName("dyndns_service")] - public Int64 DyndnsService { get; set; } + public Int64? DyndnsService { get; set; } [JsonPropertyName("dyndns_username")] - public String DyndnsUsername { get; set; } + public String? DyndnsUsername { get; set; } [JsonPropertyName("embedded_tracker_port")] - public Int64 EmbeddedTrackerPort { get; set; } + public Int64? EmbeddedTrackerPort { get; set; } [JsonPropertyName("enable_coalesce_read_write")] - public Boolean EnableCoalesceReadWrite { get; set; } + public Boolean? EnableCoalesceReadWrite { get; set; } [JsonPropertyName("enable_embedded_tracker")] - public Boolean EnableEmbeddedTracker { get; set; } + public Boolean? EnableEmbeddedTracker { get; set; } [JsonPropertyName("enable_multi_connections_from_same_ip")] - public Boolean EnableMultiConnectionsFromSameIp { get; set; } + public Boolean? EnableMultiConnectionsFromSameIp { get; set; } [JsonPropertyName("enable_os_cache")] - public Boolean EnableOsCache { get; set; } + public Boolean? EnableOsCache { get; set; } [JsonPropertyName("enable_piece_extent_affinity")] - public Boolean EnablePieceExtentAffinity { get; set; } + public Boolean? EnablePieceExtentAffinity { get; set; } [JsonPropertyName("enable_super_seeding")] - public Boolean EnableSuperSeeding { get; set; } + public Boolean? EnableSuperSeeding { get; set; } [JsonPropertyName("enable_upload_suggestions")] - public Boolean EnableUploadSuggestions { get; set; } + public Boolean? EnableUploadSuggestions { get; set; } [JsonPropertyName("encryption")] - public Int64 Encryption { get; set; } + public Int64? Encryption { get; set; } [JsonPropertyName("export_dir")] - public String ExportDir { get; set; } + public String? ExportDir { get; set; } [JsonPropertyName("export_dir_fin")] - public String ExportDirFin { get; set; } + public String? ExportDirFin { get; set; } [JsonPropertyName("file_pool_size")] - public Int64 FilePoolSize { get; set; } + public Int64? FilePoolSize { get; set; } [JsonPropertyName("incomplete_files_ext")] - public Boolean IncompleteFilesExt { get; set; } + public Boolean? IncompleteFilesExt { get; set; } [JsonPropertyName("ip_filter_enabled")] - public Boolean IpFilterEnabled { get; set; } + public Boolean? IpFilterEnabled { get; set; } [JsonPropertyName("ip_filter_path")] - public String IpFilterPath { get; set; } + public String? IpFilterPath { get; set; } [JsonPropertyName("ip_filter_trackers")] - public Boolean IpFilterTrackers { get; set; } + public Boolean? IpFilterTrackers { get; set; } [JsonPropertyName("limit_lan_peers")] - public Boolean LimitLanPeers { get; set; } + public Boolean? LimitLanPeers { get; set; } [JsonPropertyName("limit_tcp_overhead")] - public Boolean LimitTcpOverhead { get; set; } + public Boolean? LimitTcpOverhead { get; set; } [JsonPropertyName("limit_utp_rate")] - public Boolean LimitUtpRate { get; set; } + public Boolean? LimitUtpRate { get; set; } [JsonPropertyName("listen_port")] - public Int64 ListenPort { get; set; } + public Int64? ListenPort { get; set; } [JsonPropertyName("locale")] - public String Locale { get; set; } + public String? Locale { get; set; } [JsonPropertyName("lsd")] - public Boolean Lsd { get; set; } + public Boolean? Lsd { get; set; } [JsonPropertyName("mail_notification_auth_enabled")] - public Boolean MailNotificationAuthEnabled { get; set; } + public Boolean? MailNotificationAuthEnabled { get; set; } [JsonPropertyName("mail_notification_email")] - public String MailNotificationEmail { get; set; } + public String? MailNotificationEmail { get; set; } [JsonPropertyName("mail_notification_enabled")] - public Boolean MailNotificationEnabled { get; set; } + public Boolean? MailNotificationEnabled { get; set; } [JsonPropertyName("mail_notification_password")] - public String MailNotificationPassword { get; set; } + public String? MailNotificationPassword { get; set; } [JsonPropertyName("mail_notification_sender")] - public String MailNotificationSender { get; set; } + public String? MailNotificationSender { get; set; } [JsonPropertyName("mail_notification_smtp")] - public String MailNotificationSmtp { get; set; } + public String? MailNotificationSmtp { get; set; } [JsonPropertyName("mail_notification_ssl_enabled")] - public Boolean MailNotificationSslEnabled { get; set; } + public Boolean? MailNotificationSslEnabled { get; set; } [JsonPropertyName("mail_notification_username")] - public String MailNotificationUsername { get; set; } + public String? MailNotificationUsername { get; set; } [JsonPropertyName("max_active_downloads")] - public Int64 MaxActiveDownloads { get; set; } + public Int64? MaxActiveDownloads { get; set; } [JsonPropertyName("max_active_torrents")] - public Int64 MaxActiveTorrents { get; set; } + public Int64? MaxActiveTorrents { get; set; } [JsonPropertyName("max_active_uploads")] - public Int64 MaxActiveUploads { get; set; } + public Int64? MaxActiveUploads { get; set; } [JsonPropertyName("max_connec")] - public Int64 MaxConnec { get; set; } + public Int64? MaxConnec { get; set; } [JsonPropertyName("max_connec_per_torrent")] - public Int64 MaxConnecPerTorrent { get; set; } + public Int64? MaxConnecPerTorrent { get; set; } [JsonPropertyName("max_ratio")] - public Int64 MaxRatio { get; set; } + public Int64? MaxRatio { get; set; } [JsonPropertyName("max_ratio_act")] - public Int64 MaxRatioAct { get; set; } + public Int64? MaxRatioAct { get; set; } [JsonPropertyName("max_ratio_enabled")] - public Boolean MaxRatioEnabled { get; set; } + public Boolean? MaxRatioEnabled { get; set; } [JsonPropertyName("max_seeding_time")] - public Int64 MaxSeedingTime { get; set; } + public Int64? MaxSeedingTime { get; set; } [JsonPropertyName("max_seeding_time_enabled")] - public Boolean MaxSeedingTimeEnabled { get; set; } + public Boolean? MaxSeedingTimeEnabled { get; set; } [JsonPropertyName("max_uploads")] - public Int64 MaxUploads { get; set; } + public Int64? MaxUploads { get; set; } [JsonPropertyName("max_uploads_per_torrent")] - public Int64 MaxUploadsPerTorrent { get; set; } + public Int64? MaxUploadsPerTorrent { get; set; } [JsonPropertyName("outgoing_ports_max")] - public Int64 OutgoingPortsMax { get; set; } + public Int64? OutgoingPortsMax { get; set; } [JsonPropertyName("outgoing_ports_min")] - public Int64 OutgoingPortsMin { get; set; } + public Int64? OutgoingPortsMin { get; set; } [JsonPropertyName("pex")] - public Boolean Pex { get; set; } + public Boolean? Pex { get; set; } [JsonPropertyName("preallocate_all")] - public Boolean PreallocateAll { get; set; } + public Boolean? PreallocateAll { get; set; } [JsonPropertyName("proxy_auth_enabled")] - public Boolean ProxyAuthEnabled { get; set; } + public Boolean? ProxyAuthEnabled { get; set; } [JsonPropertyName("proxy_ip")] - public String ProxyIp { get; set; } + public String? ProxyIp { get; set; } [JsonPropertyName("proxy_password")] - public String ProxyPassword { get; set; } + public String? ProxyPassword { get; set; } [JsonPropertyName("proxy_peer_connections")] - public Boolean ProxyPeerConnections { get; set; } + public Boolean? ProxyPeerConnections { get; set; } [JsonPropertyName("proxy_port")] - public Int64 ProxyPort { get; set; } + public Int64? ProxyPort { get; set; } [JsonPropertyName("proxy_torrents_only")] - public Boolean ProxyTorrentsOnly { get; set; } + public Boolean? ProxyTorrentsOnly { get; set; } [JsonPropertyName("proxy_type")] - public Int64 ProxyType { get; set; } + public Int64? ProxyType { get; set; } [JsonPropertyName("proxy_username")] - public String ProxyUsername { get; set; } + public String? ProxyUsername { get; set; } [JsonPropertyName("queueing_enabled")] - public Boolean QueueingEnabled { get; set; } + public Boolean? QueueingEnabled { get; set; } [JsonPropertyName("random_port")] - public Boolean RandomPort { get; set; } + public Boolean? RandomPort { get; set; } [JsonPropertyName("recheck_completed_torrents")] - public Boolean RecheckCompletedTorrents { get; set; } + public Boolean? RecheckCompletedTorrents { get; set; } [JsonPropertyName("resolve_peer_countries")] - public Boolean ResolvePeerCountries { get; set; } + public Boolean? ResolvePeerCountries { get; set; } [JsonPropertyName("rss_auto_downloading_enabled")] - public Boolean RssAutoDownloadingEnabled { get; set; } + public Boolean? RssAutoDownloadingEnabled { get; set; } [JsonPropertyName("rss_max_articles_per_feed")] - public Int64 RssMaxArticlesPerFeed { get; set; } + public Int64? RssMaxArticlesPerFeed { get; set; } [JsonPropertyName("rss_processing_enabled")] - public Boolean RssProcessingEnabled { get; set; } + public Boolean? RssProcessingEnabled { get; set; } [JsonPropertyName("rss_refresh_interval")] - public Int64 RssRefreshInterval { get; set; } + public Int64? RssRefreshInterval { get; set; } [JsonPropertyName("save_path")] - public String SavePath { get; set; } + public String? SavePath { get; set; } [JsonPropertyName("save_path_changed_tmm_enabled")] - public Boolean SavePathChangedTmmEnabled { get; set; } + public Boolean? SavePathChangedTmmEnabled { get; set; } [JsonPropertyName("save_resume_data_interval")] - public Int64 SaveResumeDataInterval { get; set; } + public Int64? SaveResumeDataInterval { get; set; } [JsonPropertyName("scan_dirs")] - public ScanDirs ScanDirs { get; set; } + public ScanDirs? ScanDirs { get; set; } [JsonPropertyName("schedule_from_hour")] - public Int64 ScheduleFromHour { get; set; } + public Int64? ScheduleFromHour { get; set; } [JsonPropertyName("schedule_from_min")] - public Int64 ScheduleFromMin { get; set; } + public Int64? ScheduleFromMin { get; set; } [JsonPropertyName("schedule_to_hour")] - public Int64 ScheduleToHour { get; set; } + public Int64? ScheduleToHour { get; set; } [JsonPropertyName("schedule_to_min")] - public Int64 ScheduleToMin { get; set; } + public Int64? ScheduleToMin { get; set; } [JsonPropertyName("scheduler_days")] - public Int64 SchedulerDays { get; set; } + public Int64? SchedulerDays { get; set; } [JsonPropertyName("scheduler_enabled")] - public Boolean SchedulerEnabled { get; set; } + public Boolean? SchedulerEnabled { get; set; } [JsonPropertyName("send_buffer_low_watermark")] - public Int64 SendBufferLowWatermark { get; set; } + public Int64? SendBufferLowWatermark { get; set; } [JsonPropertyName("send_buffer_watermark")] - public Int64 SendBufferWatermark { get; set; } + public Int64? SendBufferWatermark { get; set; } [JsonPropertyName("send_buffer_watermark_factor")] - public Int64 SendBufferWatermarkFactor { get; set; } + public Int64? SendBufferWatermarkFactor { get; set; } [JsonPropertyName("slow_torrent_dl_rate_threshold")] - public Int64 SlowTorrentDlRateThreshold { get; set; } + public Int64? SlowTorrentDlRateThreshold { get; set; } [JsonPropertyName("slow_torrent_inactive_timer")] - public Int64 SlowTorrentInactiveTimer { get; set; } + public Int64? SlowTorrentInactiveTimer { get; set; } [JsonPropertyName("slow_torrent_ul_rate_threshold")] - public Int64 SlowTorrentUlRateThreshold { get; set; } + public Int64? SlowTorrentUlRateThreshold { get; set; } [JsonPropertyName("socket_backlog_size")] - public Int64 SocketBacklogSize { get; set; } + public Int64? SocketBacklogSize { get; set; } [JsonPropertyName("start_paused_enabled")] - public Boolean StartPausedEnabled { get; set; } + public Boolean? StartPausedEnabled { get; set; } [JsonPropertyName("stop_tracker_timeout")] - public Int64 StopTrackerTimeout { get; set; } + public Int64? StopTrackerTimeout { get; set; } [JsonPropertyName("temp_path")] - public String TempPath { get; set; } + public String? TempPath { get; set; } [JsonPropertyName("temp_path_enabled")] - public Boolean TempPathEnabled { get; set; } + public Boolean? TempPathEnabled { get; set; } [JsonPropertyName("torrent_changed_tmm_enabled")] - public Boolean TorrentChangedTmmEnabled { get; set; } + public Boolean? TorrentChangedTmmEnabled { get; set; } [JsonPropertyName("up_limit")] - public Int64 UpLimit { get; set; } + public Int64? UpLimit { get; set; } [JsonPropertyName("upload_choking_algorithm")] - public Int64 UploadChokingAlgorithm { get; set; } + public Int64? UploadChokingAlgorithm { get; set; } [JsonPropertyName("upload_slots_behavior")] - public Int64 UploadSlotsBehavior { get; set; } + public Int64? UploadSlotsBehavior { get; set; } [JsonPropertyName("upnp")] - public Boolean Upnp { get; set; } + public Boolean? Upnp { get; set; } [JsonPropertyName("upnp_lease_duration")] - public Int64 UpnpLeaseDuration { get; set; } + public Int64? UpnpLeaseDuration { get; set; } [JsonPropertyName("use_https")] - public Boolean UseHttps { get; set; } + public Boolean? UseHttps { get; set; } [JsonPropertyName("utp_tcp_mixed_mode")] - public Int64 UtpTcpMixedMode { get; set; } + public Int64? UtpTcpMixedMode { get; set; } [JsonPropertyName("web_ui_address")] - public String WebUiAddress { get; set; } + public String? WebUiAddress { get; set; } [JsonPropertyName("web_ui_ban_duration")] - public Int64 WebUiBanDuration { get; set; } + public Int64? WebUiBanDuration { get; set; } [JsonPropertyName("web_ui_clickjacking_protection_enabled")] - public Boolean WebUiClickjackingProtectionEnabled { get; set; } + public Boolean? WebUiClickjackingProtectionEnabled { get; set; } [JsonPropertyName("web_ui_csrf_protection_enabled")] - public Boolean WebUiCsrfProtectionEnabled { get; set; } + public Boolean? WebUiCsrfProtectionEnabled { get; set; } [JsonPropertyName("web_ui_domain_list")] - public String WebUiDomainList { get; set; } + public String? WebUiDomainList { get; set; } [JsonPropertyName("web_ui_host_header_validation_enabled")] - public Boolean WebUiHostHeaderValidationEnabled { get; set; } + public Boolean? WebUiHostHeaderValidationEnabled { get; set; } [JsonPropertyName("web_ui_https_cert_path")] - public String WebUiHttpsCertPath { get; set; } + public String? WebUiHttpsCertPath { get; set; } [JsonPropertyName("web_ui_https_key_path")] - public String WebUiHttpsKeyPath { get; set; } + public String? WebUiHttpsKeyPath { get; set; } [JsonPropertyName("web_ui_max_auth_fail_count")] - public Int64 WebUiMaxAuthFailCount { get; set; } + public Int64? WebUiMaxAuthFailCount { get; set; } [JsonPropertyName("web_ui_port")] - public Int64 WebUiPort { get; set; } + public Int64? WebUiPort { get; set; } [JsonPropertyName("web_ui_secure_cookie_enabled")] - public Boolean WebUiSecureCookieEnabled { get; set; } + public Boolean? WebUiSecureCookieEnabled { get; set; } [JsonPropertyName("web_ui_session_timeout")] - public Int64 WebUiSessionTimeout { get; set; } + public Int64? WebUiSessionTimeout { get; set; } [JsonPropertyName("web_ui_upnp")] - public Boolean WebUiUpnp { get; set; } + public Boolean? WebUiUpnp { get; set; } [JsonPropertyName("web_ui_username")] - public String WebUiUsername { get; set; } + public String? WebUiUsername { get; set; } } public class ScanDirs diff --git a/server/RdtClient.Data/Models/QBittorrent/SyncMetaData.cs b/server/RdtClient.Data/Models/QBittorrent/SyncMetaData.cs index 43ef650..d644d73 100644 --- a/server/RdtClient.Data/Models/QBittorrent/SyncMetaData.cs +++ b/server/RdtClient.Data/Models/QBittorrent/SyncMetaData.cs @@ -5,98 +5,98 @@ namespace RdtClient.Data.Models.QBittorrent; public class SyncMetaData { [JsonPropertyName("categories")] - public IDictionary Categories { get; set; } + public IDictionary? Categories { get; set; } [JsonPropertyName("full_update")] - public Boolean FullUpdate { get; set; } + public Boolean? FullUpdate { get; set; } [JsonPropertyName("rid")] - public Int64 Rid { get; set; } + public Int64? Rid { get; set; } [JsonPropertyName("server_state")] - public SyncMetaDataServerState ServerState { get; set; } + public SyncMetaDataServerState? ServerState { get; set; } [JsonPropertyName("tags")] - public IList Tags { get; set; } + public IList? Tags { get; set; } [JsonPropertyName("torrents")] - public IDictionary Torrents { get; set; } + public IDictionary? Torrents { get; set; } [JsonPropertyName("trackers")] - public IDictionary> Trackers { get; set; } + public IDictionary>? Trackers { get; set; } } public class SyncMetaDataServerState { [JsonPropertyName("alltime_dl")] - public Int64 AlltimeDl { get; set; } + public Int64? AlltimeDl { get; set; } [JsonPropertyName("alltime_ul")] - public Int64 AlltimeUl { get; set; } + public Int64? AlltimeUl { get; set; } [JsonPropertyName("average_time_queue")] - public Int64 AverageTimeQueue { get; set; } + public Int64? AverageTimeQueue { get; set; } [JsonPropertyName("connection_status")] - public String ConnectionStatus { get; set; } + public String? ConnectionStatus { get; set; } [JsonPropertyName("dht_nodes")] - public Int64 DhtNodes { get; set; } + public Int64? DhtNodes { get; set; } [JsonPropertyName("dl_info_data")] - public Int64 DlInfoData { get; set; } + public Int64? DlInfoData { get; set; } [JsonPropertyName("dl_info_speed")] - public Int64 DlInfoSpeed { get; set; } + public Int64? DlInfoSpeed { get; set; } [JsonPropertyName("dl_rate_limit")] - public Int64 DlRateLimit { get; set; } + public Int64? DlRateLimit { get; set; } [JsonPropertyName("free_space_on_disk")] - public Int64 FreeSpaceOnDisk { get; set; } + public Int64? FreeSpaceOnDisk { get; set; } [JsonPropertyName("global_ratio")] - public String GlobalRatio { get; set; } + public String? GlobalRatio { get; set; } [JsonPropertyName("queued_io_jobs")] - public Int64 QueuedIoJobs { get; set; } + public Int64? QueuedIoJobs { get; set; } [JsonPropertyName("queueing")] - public Boolean Queueing { get; set; } + public Boolean? Queueing { get; set; } [JsonPropertyName("read_cache_hits")] - public String ReadCacheHits { get; set; } + public String? ReadCacheHits { get; set; } [JsonPropertyName("read_cache_overload")] - public String ReadCacheOverload { get; set; } + public String? ReadCacheOverload { get; set; } [JsonPropertyName("refresh_interval")] - public Int64 RefreshInterval { get; set; } + public Int64? RefreshInterval { get; set; } [JsonPropertyName("total_buffers_size")] - public Int64 TotalBuffersSize { get; set; } + public Int64? TotalBuffersSize { get; set; } [JsonPropertyName("total_peer_connections")] - public Int64 TotalPeerConnections { get; set; } + public Int64? TotalPeerConnections { get; set; } [JsonPropertyName("total_queued_size")] - public Int64 TotalQueuedSize { get; set; } + public Int64? TotalQueuedSize { get; set; } [JsonPropertyName("total_wasted_session")] - public Int64 TotalWastedSession { get; set; } + public Int64? TotalWastedSession { get; set; } [JsonPropertyName("up_info_data")] - public Int64 UpInfoData { get; set; } + public Int64? UpInfoData { get; set; } [JsonPropertyName("up_info_speed")] - public Int64 UpInfoSpeed { get; set; } + public Int64? UpInfoSpeed { get; set; } [JsonPropertyName("up_rate_limit")] - public Int64 UpRateLimit { get; set; } + public Int64? UpRateLimit { get; set; } [JsonPropertyName("use_alt_speed_limits")] - public Boolean UseAltSpeedLimits { get; set; } + public Boolean? UseAltSpeedLimits { get; set; } [JsonPropertyName("write_cache_overload")] - public String WriteCacheOverload { get; set; } + public String? WriteCacheOverload { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/QBittorrent/TorrentCategory.cs b/server/RdtClient.Data/Models/QBittorrent/TorrentCategory.cs index 7923e50..c458fed 100644 --- a/server/RdtClient.Data/Models/QBittorrent/TorrentCategory.cs +++ b/server/RdtClient.Data/Models/QBittorrent/TorrentCategory.cs @@ -5,8 +5,8 @@ namespace RdtClient.Data.Models.QBittorrent; public class TorrentCategory { [JsonPropertyName("name")] - public String Name { get; set; } + public String? Name { get; set; } [JsonPropertyName("savePath")] - public String SavePath { get; set; } + public String? SavePath { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/QBittorrent/TorrentFileItem.cs b/server/RdtClient.Data/Models/QBittorrent/TorrentFileItem.cs index cef9dca..d6345a2 100644 --- a/server/RdtClient.Data/Models/QBittorrent/TorrentFileItem.cs +++ b/server/RdtClient.Data/Models/QBittorrent/TorrentFileItem.cs @@ -5,5 +5,5 @@ namespace RdtClient.Data.Models.QBittorrent; public class TorrentFileItem { [JsonPropertyName("name")] - public String Name { get; set; } + public String? Name { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/QBittorrent/TorrentInfo.cs b/server/RdtClient.Data/Models/QBittorrent/TorrentInfo.cs index 882281c..40dd329 100644 --- a/server/RdtClient.Data/Models/QBittorrent/TorrentInfo.cs +++ b/server/RdtClient.Data/Models/QBittorrent/TorrentInfo.cs @@ -5,10 +5,10 @@ namespace RdtClient.Data.Models.QBittorrent; public class TorrentInfo { [JsonPropertyName("added_on")] - public Int64 AddedOn { get; set; } + public Int64? AddedOn { get; set; } [JsonPropertyName("amount_left")] - public Int64 AmountLeft { get; set; } + public Int64? AmountLeft { get; set; } [JsonPropertyName("auto_tmm")] public Boolean AutoTmm { get; set; } @@ -17,31 +17,31 @@ public class TorrentInfo public Decimal Availability { get; set; } [JsonPropertyName("category")] - public String Category { get; set; } + public String? Category { get; set; } [JsonPropertyName("completed")] - public Int64 Completed { get; set; } + public Int64? Completed { get; set; } [JsonPropertyName("completion_on")] public Int64? CompletionOn { get; set; } [JsonPropertyName("content_path")] - public String ContentPath { get; set; } + public String? ContentPath { get; set; } [JsonPropertyName("dl_limit")] - public Int64 DlLimit { get; set; } + public Int64? DlLimit { get; set; } [JsonPropertyName("dlspeed")] - public Int64 Dlspeed { get; set; } + public Int64? Dlspeed { get; set; } [JsonPropertyName("downloaded")] - public Int64 Downloaded { get; set; } + public Int64? Downloaded { get; set; } [JsonPropertyName("downloaded_session")] - public Int64 DownloadedSession { get; set; } + public Int64? DownloadedSession { get; set; } [JsonPropertyName("eta")] - public Int64 Eta { get; set; } + public Int64? Eta { get; set; } [JsonPropertyName("f_l_piece_prio")] public Boolean FlPiecePrio { get; set; } @@ -50,89 +50,89 @@ public class TorrentInfo public Boolean ForceStart { get; set; } [JsonPropertyName("hash")] - public String Hash { get; set; } + public String Hash { get; set; } = default!; [JsonPropertyName("last_activity")] - public Int64 LastActivity { get; set; } + public Int64? LastActivity { get; set; } [JsonPropertyName("magnet_uri")] - public String MagnetUri { get; set; } + public String? MagnetUri { get; set; } [JsonPropertyName("max_ratio")] - public Int64 MaxRatio { get; set; } + public Int64? MaxRatio { get; set; } [JsonPropertyName("max_seeding_time")] - public Int64 MaxSeedingTime { get; set; } + public Int64? MaxSeedingTime { get; set; } [JsonPropertyName("name")] - public String Name { get; set; } + public String? Name { get; set; } [JsonPropertyName("num_complete")] - public Int64 NumComplete { get; set; } + public Int64? NumComplete { get; set; } [JsonPropertyName("num_incomplete")] - public Int64 NumIncomplete { get; set; } + public Int64? NumIncomplete { get; set; } [JsonPropertyName("num_leechs")] - public Int64 NumLeechs { get; set; } + public Int64? NumLeechs { get; set; } [JsonPropertyName("num_seeds")] - public Int64 NumSeeds { get; set; } + public Int64? NumSeeds { get; set; } [JsonPropertyName("priority")] - public Int64 Priority { get; set; } + public Int64? Priority { get; set; } [JsonPropertyName("progress")] public Single Progress { get; set; } [JsonPropertyName("ratio")] - public Int64 Ratio { get; set; } + public Int64? Ratio { get; set; } [JsonPropertyName("ratio_limit")] - public Int64 RatioLimit { get; set; } + public Int64? RatioLimit { get; set; } [JsonPropertyName("save_path")] - public String SavePath { get; set; } + public String? SavePath { get; set; } [JsonPropertyName("seeding_time_limit")] - public Int64 SeedingTimeLimit { get; set; } + public Int64? SeedingTimeLimit { get; set; } [JsonPropertyName("seen_complete")] - public Int64 SeenComplete { get; set; } + public Int64? SeenComplete { get; set; } [JsonPropertyName("seq_dl")] public Boolean SeqDl { get; set; } [JsonPropertyName("size")] - public Int64 Size { get; set; } + public Int64? Size { get; set; } [JsonPropertyName("state")] - public String State { get; set; } + public String? State { get; set; } [JsonPropertyName("super_seeding")] public Boolean SuperSeeding { get; set; } [JsonPropertyName("tags")] - public String Tags { get; set; } + public String? Tags { get; set; } [JsonPropertyName("time_active")] - public Int64 TimeActive { get; set; } + public Int64? TimeActive { get; set; } [JsonPropertyName("total_size")] - public Int64 TotalSize { get; set; } + public Int64? TotalSize { get; set; } [JsonPropertyName("tracker")] - public String Tracker { get; set; } + public String? Tracker { get; set; } [JsonPropertyName("up_limit")] - public Int64 UpLimit { get; set; } + public Int64? UpLimit { get; set; } [JsonPropertyName("uploaded")] - public Int64 Uploaded { get; set; } + public Int64? Uploaded { get; set; } [JsonPropertyName("uploaded_session")] - public Int64 UploadedSession { get; set; } + public Int64? UploadedSession { get; set; } [JsonPropertyName("upspeed")] - public Int64 Upspeed { get; set; } + public Int64? Upspeed { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/QBittorrent/TorrentProperties.cs b/server/RdtClient.Data/Models/QBittorrent/TorrentProperties.cs index 1486966..f4ec0bd 100644 --- a/server/RdtClient.Data/Models/QBittorrent/TorrentProperties.cs +++ b/server/RdtClient.Data/Models/QBittorrent/TorrentProperties.cs @@ -5,101 +5,101 @@ namespace RdtClient.Data.Models.QBittorrent; public class TorrentProperties { [JsonPropertyName("addition_date")] - public Int64 AdditionDate { get; set; } + public Int64? AdditionDate { get; set; } [JsonPropertyName("comment")] - public String Comment { get; set; } + public String? Comment { get; set; } [JsonPropertyName("completion_date")] - public Int64 CompletionDate { get; set; } + public Int64? CompletionDate { get; set; } [JsonPropertyName("created_by")] - public String CreatedBy { get; set; } + public String? CreatedBy { get; set; } [JsonPropertyName("creation_date")] - public Int64 CreationDate { get; set; } + public Int64? CreationDate { get; set; } [JsonPropertyName("dl_limit")] - public Int64 DlLimit { get; set; } + public Int64? DlLimit { get; set; } [JsonPropertyName("dl_speed")] - public Int64 DlSpeed { get; set; } + public Int64? DlSpeed { get; set; } [JsonPropertyName("dl_speed_avg")] - public Int64 DlSpeedAvg { get; set; } + public Int64? DlSpeedAvg { get; set; } [JsonPropertyName("eta")] - public Int64 Eta { get; set; } + public Int64? Eta { get; set; } [JsonPropertyName("last_seen")] - public Int64 LastSeen { get; set; } + public Int64? LastSeen { get; set; } [JsonPropertyName("nb_connections")] - public Int64 NbConnections { get; set; } + public Int64? NbConnections { get; set; } [JsonPropertyName("nb_connections_limit")] - public Int64 NbConnectionsLimit { get; set; } + public Int64? NbConnectionsLimit { get; set; } [JsonPropertyName("peers")] - public Int64 Peers { get; set; } + public Int64? Peers { get; set; } [JsonPropertyName("peers_total")] - public Int64 PeersTotal { get; set; } + public Int64? PeersTotal { get; set; } [JsonPropertyName("piece_size")] - public Int64 PieceSize { get; set; } + public Int64? PieceSize { get; set; } [JsonPropertyName("pieces_have")] - public Int64 PiecesHave { get; set; } + public Int64? PiecesHave { get; set; } [JsonPropertyName("pieces_num")] - public Int64 PiecesNum { get; set; } + public Int64? PiecesNum { get; set; } [JsonPropertyName("reannounce")] - public Int64 Reannounce { get; set; } + public Int64? Reannounce { get; set; } [JsonPropertyName("save_path")] - public String SavePath { get; set; } + public String? SavePath { get; set; } [JsonPropertyName("seeding_time")] - public Int64 SeedingTime { get; set; } + public Int64? SeedingTime { get; set; } [JsonPropertyName("seeds")] - public Int64 Seeds { get; set; } + public Int64? Seeds { get; set; } [JsonPropertyName("seeds_total")] - public Int64 SeedsTotal { get; set; } + public Int64? SeedsTotal { get; set; } [JsonPropertyName("share_ratio")] - public Int64 ShareRatio { get; set; } + public Int64? ShareRatio { get; set; } [JsonPropertyName("time_elapsed")] - public Int64 TimeElapsed { get; set; } + public Int64? TimeElapsed { get; set; } [JsonPropertyName("total_downloaded")] - public Int64 TotalDownloaded { get; set; } + public Int64? TotalDownloaded { get; set; } [JsonPropertyName("total_downloaded_session")] - public Int64 TotalDownloadedSession { get; set; } + public Int64? TotalDownloadedSession { get; set; } [JsonPropertyName("total_size")] - public Int64 TotalSize { get; set; } + public Int64? TotalSize { get; set; } [JsonPropertyName("total_uploaded")] - public Int64 TotalUploaded { get; set; } + public Int64? TotalUploaded { get; set; } [JsonPropertyName("total_uploaded_session")] - public Int64 TotalUploadedSession { get; set; } + public Int64? TotalUploadedSession { get; set; } [JsonPropertyName("total_wasted")] - public Int64 TotalWasted { get; set; } + public Int64? TotalWasted { get; set; } [JsonPropertyName("up_limit")] - public Int64 UpLimit { get; set; } + public Int64? UpLimit { get; set; } [JsonPropertyName("up_speed")] - public Int64 UpSpeed { get; set; } + public Int64? UpSpeed { get; set; } [JsonPropertyName("up_speed_avg")] - public Int64 UpSpeedAvg { get; set; } + public Int64? UpSpeedAvg { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/TorrentClient/TorrentClientAvailableFile.cs b/server/RdtClient.Data/Models/TorrentClient/TorrentClientAvailableFile.cs index 77bab25..6629ecb 100644 --- a/server/RdtClient.Data/Models/TorrentClient/TorrentClientAvailableFile.cs +++ b/server/RdtClient.Data/Models/TorrentClient/TorrentClientAvailableFile.cs @@ -2,7 +2,7 @@ public class TorrentClientAvailableFile { - public String Filename { get; set; } + public String Filename { get; set; } = default!; public Int64 Filesize { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/TorrentClient/TorrentClientFile.cs b/server/RdtClient.Data/Models/TorrentClient/TorrentClientFile.cs index c8add53..62bf096 100644 --- a/server/RdtClient.Data/Models/TorrentClient/TorrentClientFile.cs +++ b/server/RdtClient.Data/Models/TorrentClient/TorrentClientFile.cs @@ -3,7 +3,7 @@ public class TorrentClientFile { public Int64 Id { get; set; } - public String Path { get; set; } + public String Path { get; set; } = default!; public Int64 Bytes { get; set; } public Boolean Selected { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/Models/TorrentClient/TorrentClientTorrent.cs b/server/RdtClient.Data/Models/TorrentClient/TorrentClientTorrent.cs index 971faa3..64be22d 100644 --- a/server/RdtClient.Data/Models/TorrentClient/TorrentClientTorrent.cs +++ b/server/RdtClient.Data/Models/TorrentClient/TorrentClientTorrent.cs @@ -2,20 +2,20 @@ public class TorrentClientTorrent { - public String Id { get; set; } - public String Filename { get; set; } - public String OriginalFilename { get; set; } - public String Hash { get; set; } + public String Id { get; set; } = default!; + public String Filename { get; set; } = default!; + public String? OriginalFilename { get; set; } = default!; + public String Hash { get; set; } = default!; public Int64 Bytes { get; set; } public Int64 OriginalBytes { get; set; } - public String Host { get; set; } + public String? Host { get; set; } public Int64 Split { get; set; } public Int64 Progress { get; set; } - public String Status { get; set; } + public String? Status { get; set; } = default!; public Int64 StatusCode { get; set; } public DateTimeOffset Added { get; set; } - public List Files { get; set; } - public List Links { get; set; } + public List? Files { get; set; } + public List? Links { get; set; } public DateTimeOffset? Ended { get; set; } public Int64? Speed { get; set; } public Int64? Seeders { get; set; } diff --git a/server/RdtClient.Data/Models/TorrentClient/TorrentClientUser.cs b/server/RdtClient.Data/Models/TorrentClient/TorrentClientUser.cs index 5cf751e..c1d8355 100644 --- a/server/RdtClient.Data/Models/TorrentClient/TorrentClientUser.cs +++ b/server/RdtClient.Data/Models/TorrentClient/TorrentClientUser.cs @@ -2,6 +2,6 @@ public class TorrentClientUser { - public String Username { get; set; } + public String? Username { get; set; } public DateTimeOffset? Expiration { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Data/RdtClient.Data.csproj b/server/RdtClient.Data/RdtClient.Data.csproj index 920b04b..3126c22 100644 --- a/server/RdtClient.Data/RdtClient.Data.csproj +++ b/server/RdtClient.Data/RdtClient.Data.csproj @@ -2,25 +2,21 @@ net6.0 - disable + enable enable latest - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - diff --git a/server/RdtClient.Service/BackgroundServices/Startup.cs b/server/RdtClient.Service/BackgroundServices/Startup.cs index b978336..40cb1ae 100644 --- a/server/RdtClient.Service/BackgroundServices/Startup.cs +++ b/server/RdtClient.Service/BackgroundServices/Startup.cs @@ -32,7 +32,7 @@ public class Startup : IHostedService var settings = scope.ServiceProvider.GetRequiredService(); await settings.Seed(); await settings.ResetCache(); - await settings.Clean(); + await Settings.Clean(); Ready = true; } diff --git a/server/RdtClient.Service/BackgroundServices/UpdateChecker.cs b/server/RdtClient.Service/BackgroundServices/UpdateChecker.cs index e084b18..1e87c2d 100644 --- a/server/RdtClient.Service/BackgroundServices/UpdateChecker.cs +++ b/server/RdtClient.Service/BackgroundServices/UpdateChecker.cs @@ -8,8 +8,8 @@ namespace RdtClient.Service.BackgroundServices; public class UpdateChecker : BackgroundService { - public static String CurrentVersion { get; private set; } - public static String LatestVersion { get; private set; } + public static String? CurrentVersion { get; private set; } + public static String? LatestVersion { get; private set; } private readonly ILogger _logger; @@ -53,7 +53,13 @@ public class UpdateChecker : BackgroundService return; } - var latestRelease = gitHubReleases.First().Name; + var latestRelease = gitHubReleases.FirstOrDefault(m => m.Name != null)?.Name; + + if (latestRelease == null) + { + _logger.LogWarning($"Unable to find latest version on GitHub"); + return; + } if (latestRelease != CurrentVersion) { @@ -77,5 +83,5 @@ public class UpdateChecker : BackgroundService public class GitHubReleasesResponse { [JsonProperty("name")] - public String Name { get; set; } + public String? Name { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Service/DiConfig.cs b/server/RdtClient.Service/DiConfig.cs index 8fbab83..fc66f51 100644 --- a/server/RdtClient.Service/DiConfig.cs +++ b/server/RdtClient.Service/DiConfig.cs @@ -23,5 +23,6 @@ public static class DiConfig services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); + services.AddHostedService(); } } \ No newline at end of file diff --git a/server/RdtClient.Service/GlobalSuppressions.cs b/server/RdtClient.Service/GlobalSuppressions.cs new file mode 100644 index 0000000..ce1143b --- /dev/null +++ b/server/RdtClient.Service/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "CA2254:Template should be a static expression", Justification = "Bug in Serilog", Scope = "NamespaceAndDescendants", Target = "N:RdtClient.Service")] diff --git a/server/RdtClient.Service/Helpers/DownloadHelper.cs b/server/RdtClient.Service/Helpers/DownloadHelper.cs index 7a385ef..a027180 100644 --- a/server/RdtClient.Service/Helpers/DownloadHelper.cs +++ b/server/RdtClient.Service/Helpers/DownloadHelper.cs @@ -5,11 +5,11 @@ namespace RdtClient.Service.Helpers; public static class DownloadHelper { - public static String GetDownloadPath(String downloadPath, Torrent torrent, Download download) + public static String? GetDownloadPath(String downloadPath, Torrent torrent, Download download) { var fileUrl = download.Link; - if (String.IsNullOrWhiteSpace(fileUrl)) + if (String.IsNullOrWhiteSpace(fileUrl) || torrent.RdName == null) { return null; } diff --git a/server/RdtClient.Service/Helpers/JsonModelBinder.cs b/server/RdtClient.Service/Helpers/JsonModelBinder.cs index 9357090..f7722b6 100644 --- a/server/RdtClient.Service/Helpers/JsonModelBinder.cs +++ b/server/RdtClient.Service/Helpers/JsonModelBinder.cs @@ -16,7 +16,7 @@ public class JsonModelBinder : IModelBinder { bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); - var valueAsString = valueProviderResult.FirstValue; + var valueAsString = valueProviderResult.FirstValue ?? ""; var result = Newtonsoft.Json.JsonConvert.DeserializeObject(valueAsString, bindingContext.ModelType); if (result != null) { diff --git a/server/RdtClient.Service/Helpers/SettingsHelper.cs b/server/RdtClient.Service/Helpers/SettingsHelper.cs deleted file mode 100644 index 4c11329..0000000 --- a/server/RdtClient.Service/Helpers/SettingsHelper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using RdtClient.Data.Models.Data; - -namespace RdtClient.Service.Helpers; - -public static class SettingsHelper -{ - public static String GetString(this IList settings, String key) - { - var setting = settings.FirstOrDefault(m => m.SettingId == key); - - if (setting == null) - { - throw new Exception($"Setting with key {key} not found"); - } - - return setting.Value; - } - - public static Int32 GetNumber(this IList settings, String key) - { - var setting = settings.FirstOrDefault(m => m.SettingId == key); - - if (setting == null) - { - throw new Exception($"Setting with key {key} not found"); - } - - return Int32.Parse(setting.Value); - } -} \ No newline at end of file diff --git a/server/RdtClient.Service/RdtClient.Service.csproj b/server/RdtClient.Service/RdtClient.Service.csproj index 7fe3d39..d96c756 100644 --- a/server/RdtClient.Service/RdtClient.Service.csproj +++ b/server/RdtClient.Service/RdtClient.Service.csproj @@ -2,18 +2,18 @@ net6.0 - disable + enable enable latest - - - + + + - + diff --git a/server/RdtClient.Service/Services/Authentication.cs b/server/RdtClient.Service/Services/Authentication.cs index 6489509..11195a4 100644 --- a/server/RdtClient.Service/Services/Authentication.cs +++ b/server/RdtClient.Service/Services/Authentication.cs @@ -37,7 +37,7 @@ public class Authentication return result; } - public async Task GetUser() + public async Task GetUser() { return await _userData.GetUser(); } diff --git a/server/RdtClient.Service/Services/DownloadClient.cs b/server/RdtClient.Service/Services/DownloadClient.cs index e310cea..42b2f22 100644 --- a/server/RdtClient.Service/Services/DownloadClient.cs +++ b/server/RdtClient.Service/Services/DownloadClient.cs @@ -12,7 +12,17 @@ public class DownloadClient private readonly Download _download; private readonly Torrent _torrent; - public IDownloader Downloader; + public IDownloader? Downloader; + + public Data.Enums.DownloadClient Type { get; set; } + + public Boolean Finished { get; private set; } + + public String? Error { get; private set; } + + public Int64 Speed { get; private set; } + public Int64 BytesTotal { get; private set; } + public Int64 BytesDone { get; private set; } public DownloadClient(Download download, Torrent torrent, String destinationPath) { @@ -21,17 +31,7 @@ public class DownloadClient _destinationPath = destinationPath; } - public Data.Enums.DownloadClient Type { get; set; } - - public Boolean Finished { get; private set; } - - public String Error { get; private set; } - - public Int64 Speed { get; private set; } - public Int64 BytesTotal { get; private set; } - public Int64 BytesDone { get; private set; } - - public async Task Start(DbSettings settings) + public async Task Start(DbSettings settings) { BytesDone = 0; BytesTotal = 0; @@ -39,13 +39,18 @@ public class DownloadClient try { + if (_download.Link == null) + { + throw new Exception($"Invalid download link"); + } + var filePath = DownloadHelper.GetDownloadPath(_destinationPath, _torrent, _download); if (filePath == null) { throw new Exception("Invalid download path"); } - + await FileHelper.Delete(filePath); Type = settings.DownloadClient.Client; diff --git a/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs b/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs index c5482ef..f5b7684 100644 --- a/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs +++ b/server/RdtClient.Service/Services/Downloaders/Aria2cDownloader.cs @@ -6,8 +6,8 @@ namespace RdtClient.Service.Services.Downloaders; public class Aria2cDownloader : IDownloader { - public event EventHandler DownloadComplete; - public event EventHandler DownloadProgress; + public event EventHandler? DownloadComplete; + public event EventHandler? DownloadProgress; private const Int32 RetryCount = 5; @@ -17,9 +17,9 @@ public class Aria2cDownloader : IDownloader private readonly String _uri; private readonly String _filePath; - private String _gid; + private String? _gid; - public Aria2cDownloader(String gid, String uri, String filePath, DbSettings settings) + public Aria2cDownloader(String? gid, String uri, String filePath, DbSettings settings) { _logger = Log.ForContext(); _gid = gid; @@ -34,9 +34,15 @@ public class Aria2cDownloader : IDownloader _aria2NetClient = new Aria2NetClient(settings.DownloadClient.Aria2cUrl, settings.DownloadClient.Aria2cSecret, httpClient, 10); } - public async Task Download() + public async Task Download() { var path = Path.GetDirectoryName(_filePath); + + if (path == null) + { + throw new Exception($"Invalid file path {_filePath}"); + } + var fileName = Path.GetFileName(_filePath); _logger.Debug($"Starting download of {_uri}, writing to path: {path}, fileName: {fileName}"); @@ -60,7 +66,7 @@ public class Aria2cDownloader : IDownloader { try { - await _aria2NetClient.TellStatus(_gid); + await _aria2NetClient.TellStatusAsync(_gid); return _gid; } @@ -70,23 +76,23 @@ public class Aria2cDownloader : IDownloader } } - _gid ??= await _aria2NetClient.AddUri(new List - { - _uri - }, - new Dictionary - { - { - "dir", path - }, - { - "out", fileName - } - }); + _gid ??= await _aria2NetClient.AddUriAsync(new List + { + _uri + }, + new Dictionary + { + { + "dir", path + }, + { + "out", fileName + } + }); _logger.Debug($"Added download to Aria2, received ID {_gid}"); - await _aria2NetClient.TellStatus(_gid); + await _aria2NetClient.TellStatusAsync(_gid); _logger.Debug($"Download with ID {_gid} found in Aria2"); @@ -124,7 +130,7 @@ public class Aria2cDownloader : IDownloader try { - await _aria2NetClient.Pause(_gid); + await _aria2NetClient.PauseAsync(_gid); } catch { @@ -143,7 +149,7 @@ public class Aria2cDownloader : IDownloader try { - await _aria2NetClient.Unpause(_gid); + await _aria2NetClient.UnpauseAsync(_gid); } catch { @@ -228,7 +234,7 @@ public class Aria2cDownloader : IDownloader try { - await _aria2NetClient.ForceRemove(_gid); + await _aria2NetClient.ForceRemoveAsync(_gid); } catch { @@ -237,7 +243,7 @@ public class Aria2cDownloader : IDownloader try { - await _aria2NetClient.RemoveDownloadResult(_gid); + await _aria2NetClient.RemoveDownloadResultAsync(_gid); } catch { @@ -247,11 +253,11 @@ public class Aria2cDownloader : IDownloader private async Task CheckIfAdded() { - var allDownloads = await _aria2NetClient.TellAll(); + var allDownloads = await _aria2NetClient.TellAllAsync(); - foreach (var download in allDownloads.Where(m => m.Files != null)) + foreach (var download in allDownloads) { - foreach (var file in download.Files.Where(m => m.Uris != null)) + foreach (var file in download.Files) { if (file.Uris.Any(uri => uri.Uri == _uri)) { diff --git a/server/RdtClient.Service/Services/Downloaders/IDownloader.cs b/server/RdtClient.Service/Services/Downloaders/IDownloader.cs index 6354023..2205e23 100644 --- a/server/RdtClient.Service/Services/Downloaders/IDownloader.cs +++ b/server/RdtClient.Service/Services/Downloaders/IDownloader.cs @@ -2,7 +2,7 @@ public class DownloadCompleteEventArgs { - public String Error { get; set; } + public String? Error { get; set; } } public class DownloadProgressEventArgs @@ -14,9 +14,9 @@ public class DownloadProgressEventArgs public interface IDownloader { - event EventHandler DownloadComplete; - event EventHandler DownloadProgress; - Task Download(); + event EventHandler? DownloadComplete; + event EventHandler? DownloadProgress; + Task Download(); Task Cancel(); Task Pause(); Task Resume(); diff --git a/server/RdtClient.Service/Services/Downloaders/MultiDownloader.cs b/server/RdtClient.Service/Services/Downloaders/MultiDownloader.cs index 0eea16e..09315e0 100644 --- a/server/RdtClient.Service/Services/Downloaders/MultiDownloader.cs +++ b/server/RdtClient.Service/Services/Downloaders/MultiDownloader.cs @@ -7,8 +7,8 @@ namespace RdtClient.Service.Services.Downloaders; public class MultiDownloader : IDownloader { - public event EventHandler DownloadComplete; - public event EventHandler DownloadProgress; + public event EventHandler? DownloadComplete; + public event EventHandler? DownloadProgress; private readonly DownloadService _downloadService; private readonly String _filePath; @@ -94,7 +94,7 @@ public class MultiDownloader : IDownloader _downloadService.DownloadFileCompleted += (_, args) => { - String error = null; + String? error = null; if (args.Cancelled) { @@ -113,7 +113,7 @@ public class MultiDownloader : IDownloader }; } - public async Task Download() + public async Task Download() { _logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}"); diff --git a/server/RdtClient.Service/Services/Downloaders/SimpleDownloader.cs b/server/RdtClient.Service/Services/Downloaders/SimpleDownloader.cs index e50f269..691dc5c 100644 --- a/server/RdtClient.Service/Services/Downloaders/SimpleDownloader.cs +++ b/server/RdtClient.Service/Services/Downloaders/SimpleDownloader.cs @@ -7,8 +7,8 @@ public class SimpleDownloader : IDownloader { private const Int32 BufferSize = 8 * 1024; - public event EventHandler DownloadComplete; - public event EventHandler DownloadProgress; + public event EventHandler? DownloadComplete; + public event EventHandler? DownloadProgress; private readonly String _uri; private readonly String _filePath; @@ -30,7 +30,7 @@ public class SimpleDownloader : IDownloader _filePath = filePath; } - public Task Download() + public Task Download() { _logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}"); @@ -39,7 +39,7 @@ public class SimpleDownloader : IDownloader await StartDownloadTask(); }); - return Task.FromResult(null); + return Task.FromResult(null); } public Task Cancel() @@ -86,6 +86,7 @@ public class SimpleDownloader : IDownloader while (readSize > 0 && !_cancelled) { // ReSharper disable once ConvertToUsingDeclaration +#pragma warning disable IDE0063 // Use simple 'using' statement using (var innerCts = new CancellationTokenSource(1000)) { readSize = await destinationStream.ReadAsync(buffer.AsMemory(0, buffer.Length), innerCts.Token).ConfigureAwait(false); @@ -115,6 +116,7 @@ public class SimpleDownloader : IDownloader } } } +#pragma warning restore IDE0063 // Use simple 'using' statement } break; diff --git a/server/RdtClient.Service/Services/Downloads.cs b/server/RdtClient.Service/Services/Downloads.cs index be55e0b..9acc847 100644 --- a/server/RdtClient.Service/Services/Downloads.cs +++ b/server/RdtClient.Service/Services/Downloads.cs @@ -17,12 +17,12 @@ public class Downloads return await _downloadData.GetForTorrent(torrentId); } - public async Task GetById(Guid downloadId) + public async Task GetById(Guid downloadId) { return await _downloadData.GetById(downloadId); } - public async Task Get(Guid torrentId, String path) + public async Task Get(Guid torrentId, String path) { return await _downloadData.Get(torrentId, path); } @@ -67,7 +67,7 @@ public class Downloads await _downloadData.UpdateCompleted(downloadId, dateTime); } - public async Task UpdateError(Guid downloadId, String error) + public async Task UpdateError(Guid downloadId, String? error) { await _downloadData.UpdateError(downloadId, error); } diff --git a/server/RdtClient.Service/Services/QBittorrent.cs b/server/RdtClient.Service/Services/QBittorrent.cs index e97c559..035fc09 100644 --- a/server/RdtClient.Service/Services/QBittorrent.cs +++ b/server/RdtClient.Service/Services/QBittorrent.cs @@ -1,6 +1,5 @@ using RdtClient.Data.Enums; using RdtClient.Data.Models.Data; -using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.QBittorrent; namespace RdtClient.Service.Services; @@ -178,7 +177,7 @@ public class QBittorrent WebUiUsername = "" }; - var savePath = AppDefaultSavePath(); + var savePath = Settings.AppDefaultSavePath; preferences.SavePath = savePath; preferences.TempPath = $"{savePath}temp{Path.DirectorySeparatorChar}"; @@ -193,21 +192,9 @@ public class QBittorrent return preferences; } - public String AppDefaultSavePath() - { - var downloadPath = Settings.Get.DownloadClient.MappedPath; - - downloadPath = downloadPath.TrimEnd('\\') - .TrimEnd('/'); - - downloadPath += Path.DirectorySeparatorChar; - - return downloadPath; - } - public async Task> TorrentInfo() { - var savePath = AppDefaultSavePath(); + var savePath = Settings.AppDefaultSavePath; var results = new List(); @@ -241,9 +228,9 @@ public class QBittorrent speed = (Int32) torrent.Downloads.Average(m => m.Speed); } - var progress = (bytesDone / (Single)bytesTotal); + var progress = (bytesDone / (Single?)bytesTotal); - if (!Single.IsNormal(progress)) + if (progress == null || !Single.IsNormal(progress.Value)) { progress = 0; } @@ -276,7 +263,7 @@ public class QBittorrent NumLeechs = 100, NumSeeds = 100, Priority = ++prio, - Progress = progress, + Progress = (Single) progress, Ratio = 1, RatioLimit = 1, SavePath = downloadPath, @@ -325,7 +312,7 @@ public class QBittorrent return results; } - public async Task> TorrentFileContents(String hash) + public async Task?> TorrentFileContents(String hash) { var results = new List(); @@ -349,9 +336,9 @@ public class QBittorrent return results; } - public async Task TorrentProperties(String hash) + public async Task TorrentProperties(String hash) { - var savePath = AppDefaultSavePath(); + var savePath = Settings.AppDefaultSavePath; var torrent = await _torrents.GetByHash(hash); @@ -428,7 +415,7 @@ public class QBittorrent await _torrents.Delete(torrent.TorrentId, true, true, deleteFiles); } - public async Task TorrentsAddMagnet(String magnetLink, String category, Int32? priority) + public async Task TorrentsAddMagnet(String magnetLink, String? category, Int32? priority) { var torrent = new Torrent { @@ -446,7 +433,7 @@ public class QBittorrent await _torrents.UploadMagnet(magnetLink, torrent); } - public async Task TorrentsAddFile(Byte[] fileBytes, String category, Int32? priority) + public async Task TorrentsAddFile(Byte[] fileBytes, String? category, Int32? priority) { var torrent = new Torrent { @@ -464,7 +451,7 @@ public class QBittorrent await _torrents.UploadFile(fileBytes, torrent); } - public async Task TorrentsSetCategory(String hash, String category) + public async Task TorrentsSetCategory(String hash, String? category) { await _torrents.UpdateCategory(hash, category); } @@ -474,7 +461,7 @@ public class QBittorrent var torrents = await _torrents.Get(); var torrentsToGroup = torrents.Where(m => !String.IsNullOrWhiteSpace(m.Category)) - .Select(m => m.Category.ToLower()) + .Select(m => m.Category!.ToLower()) .ToList(); var categoryList = (Settings.Get.General.Categories ?? "") @@ -494,14 +481,14 @@ public class QBittorrent m => new TorrentCategory { Name = m, - SavePath = Path.Combine(AppDefaultSavePath(), m) + SavePath = Path.Combine(Settings.AppDefaultSavePath, m) }); } return results; } - public async Task CategoryCreate(String category) + public async Task CategoryCreate(String? category) { if (category == null) { @@ -528,7 +515,7 @@ public class QBittorrent await _settings.Update("General:Categories", categoriesSetting); } - public async Task CategoryRemove(String category) + public async Task CategoryRemove(String? category) { if (category == null) { diff --git a/server/RdtClient.Service/Services/RdtHub.cs b/server/RdtClient.Service/Services/RdtHub.cs index 3db5c33..e8545af 100644 --- a/server/RdtClient.Service/Services/RdtHub.cs +++ b/server/RdtClient.Service/Services/RdtHub.cs @@ -15,7 +15,7 @@ public class RdtHub : Hub await base.OnConnectedAsync(); } - public override async Task OnDisconnectedAsync(Exception exception) + public override async Task OnDisconnectedAsync(Exception? exception) { Users.TryRemove(Context.ConnectionId, out _); await base.OnDisconnectedAsync(exception); diff --git a/server/RdtClient.Service/Services/Settings.cs b/server/RdtClient.Service/Services/Settings.cs index a4bf65a..9a6659f 100644 --- a/server/RdtClient.Service/Services/Settings.cs +++ b/server/RdtClient.Service/Services/Settings.cs @@ -1,11 +1,7 @@ -using System.Diagnostics; -using Aria2NET; -using RdtClient.Data.Data; +using RdtClient.Data.Data; using RdtClient.Data.Enums; -using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Internal; using RdtClient.Service.Helpers; -using RdtClient.Service.Services.Downloaders; using Serilog.Core; using Serilog.Events; @@ -24,9 +20,19 @@ public class Settings public static DbSettings Get => SettingData.Get; - public IList GetAll() + public static String AppDefaultSavePath { - return _settingData.GetAll(); + get + { + var downloadPath = Get.DownloadClient.MappedPath; + + downloadPath = downloadPath.TrimEnd('\\') + .TrimEnd('/'); + + downloadPath += Path.DirectorySeparatorChar; + + return downloadPath; + } } public async Task Update(IList settings) @@ -34,137 +40,12 @@ public class Settings await _settingData.Update(settings); } - public async Task Update(String settingId, Object value) + public async Task Update(String settingId, Object? value) { await _settingData.Update(settingId, value); } - public async Task TestPath(String path) - { - if (String.IsNullOrWhiteSpace(path)) - { - throw new Exception("Path is not set"); - } - - path = path.TrimEnd('/').TrimEnd('\\'); - - if (!Directory.Exists(path)) - { - throw new Exception($"Path {path} does not exist"); - } - - var testFile = $"{path}/test.txt"; - - await File.WriteAllTextAsync(testFile, "RealDebridClient Test File, you can remove this file."); - - await FileHelper.Delete(testFile); - } - - public async Task TestDownloadSpeed(CancellationToken cancellationToken) - { - var downloadPath = Get.DownloadClient.DownloadPath; - - var testFilePath = Path.Combine(downloadPath, "testDefault.rar"); - - await FileHelper.Delete(testFilePath); - - var download = new Download - { - Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar", - Torrent = new Torrent - { - RdName = "" - } - }; - - var downloadClient = new DownloadClient(download, download.Torrent, downloadPath); - - await downloadClient.Start(Get); - - var httpClient = new HttpClient - { - Timeout = TimeSpan.FromSeconds(10) - }; - - while (!downloadClient.Finished) - { - await Task.Delay(1000, CancellationToken.None); - - if (cancellationToken.IsCancellationRequested) - { - await downloadClient.Cancel(); - } - - if (downloadClient.Downloader is Aria2cDownloader aria2Downloader) - { - var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, httpClient, 1); - - var allDownloads = await aria2NetClient.TellAll(cancellationToken); - - await aria2Downloader.Update(allDownloads); - } - - if (downloadClient.BytesDone > 1024 * 1024 * 50) - { - await downloadClient.Cancel(); - - break; - } - } - - await FileHelper.Delete(testFilePath); - - await Clean(); - - return downloadClient.Speed; - } - - public async Task TestWriteSpeed() - { - var downloadPath = Get.DownloadClient.DownloadPath; - - var testFilePath = Path.Combine(downloadPath, "test.tmp"); - - await FileHelper.Delete(testFilePath); - - const Int32 testFileSize = 64 * 1024 * 1024; - - var watch = new Stopwatch(); - - watch.Start(); - - var rnd = new Random(); - - await using var fileStream = new FileStream(testFilePath, FileMode.Create, FileAccess.Write, FileShare.Write); - - var buffer = new Byte[64 * 1024]; - - while (fileStream.Length < testFileSize) - { - rnd.NextBytes(buffer); - - await fileStream.WriteAsync(buffer.AsMemory(0, buffer.Length)); - } - - watch.Stop(); - - var writeSpeed = fileStream.Length / watch.Elapsed.TotalSeconds; - - fileStream.Close(); - - await FileHelper.Delete(testFilePath); - - return writeSpeed; - } - - public async Task GetAria2cVersion(String url, String secret) - { - var client = new Aria2NetClient(url, secret); - - return await client.GetVersion(); - } - - public async Task Clean() + public static async Task Clean() { try { diff --git a/server/RdtClient.Service/Services/ThrottledStream.cs b/server/RdtClient.Service/Services/ThrottledStream.cs index c625097..fe25462 100644 --- a/server/RdtClient.Service/Services/ThrottledStream.cs +++ b/server/RdtClient.Service/Services/ThrottledStream.cs @@ -6,9 +6,9 @@ /// public class ThrottledStream : Stream { - public Int64 Speed => (Int64)_bandwidth.AverageSpeed; + public Int64 Speed => (Int64) (_bandwidth?.AverageSpeed ?? 0); - private Bandwidth _bandwidth; + private Bandwidth? _bandwidth; private Int64 _bandwidthLimit; private readonly Stream _baseStream; @@ -90,7 +90,6 @@ public class ThrottledStream : Stream public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count) { Throttle(count).Wait(); - return _baseStream.Read(buffer, offset, count); } @@ -100,8 +99,13 @@ public class ThrottledStream : Stream CancellationToken cancellationToken) { await Throttle(count).ConfigureAwait(false); + return await _baseStream.ReadAsync(new Memory(buffer, offset, count), cancellationToken).ConfigureAwait(false); + } - return await _baseStream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = new CancellationToken()) + { + await Throttle(buffer.Length).ConfigureAwait(false); + return await base.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); } /// @@ -115,7 +119,13 @@ public class ThrottledStream : Stream public override async Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken) { await Throttle(count).ConfigureAwait(false); - await _baseStream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + await _baseStream.WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).ConfigureAwait(false); + } + + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = new CancellationToken()) + { + await Throttle(buffer.Length).ConfigureAwait(false); + await base.WriteAsync(buffer, cancellationToken).ConfigureAwait(false); } private async Task Throttle(Int32 transmissionVolume) @@ -124,9 +134,8 @@ public class ThrottledStream : Stream if (BandwidthLimit > 0 && transmissionVolume > 0) { // Calculate the time to sleep. - _bandwidth.CalculateSpeed(transmissionVolume); - - await Sleep(_bandwidth.PopSpeedRetrieveTime()).ConfigureAwait(false); + _bandwidth!.CalculateSpeed(transmissionVolume); + await Sleep(_bandwidth!.PopSpeedRetrieveTime()).ConfigureAwait(false); } } @@ -139,7 +148,7 @@ public class ThrottledStream : Stream } /// - public override String ToString() + public override String? ToString() { return _baseStream.ToString(); } diff --git a/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs index 0b7a20a..efb9334 100644 --- a/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs +++ b/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs @@ -70,14 +70,14 @@ public class AllDebridTorrentClient : ITorrentClient Status = torrent.Status, StatusCode = torrent.StatusCode, Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate), - Files = (torrent.Links ?? new List()).Select((m, i) => new TorrentClientFile + Files = torrent.Links.Select((m, i) => new TorrentClientFile { Path = m.Filename, Bytes = m.Size, Id = i, Selected = true, }).ToList(), - Links = (torrent.Links ?? new List()).Select(m => m.LinkUrl.ToString()).ToList(), + Links = torrent.Links.Select(m => m.LinkUrl.ToString()).ToList(), Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate), Speed = torrent.DownloadSpeed, Seeders = torrent.Seeders @@ -94,6 +94,11 @@ public class AllDebridTorrentClient : ITorrentClient { var user = await GetClient().User.GetAsync(); + if (user == null) + { + throw new Exception("Unable to get user"); + } + return new TorrentClientUser { Username = user.Username, @@ -105,14 +110,38 @@ public class AllDebridTorrentClient : ITorrentClient { var result = await GetClient().Magnet.UploadMagnetAsync(magnetLink); - return result.Id.ToString(); + if (result?.Id == null) + { + throw new Exception("Unable to add magnet link"); + } + + var resultId = result.Id.ToString(); + + if (resultId == null) + { + throw new Exception($"Invalid responseID {result.Id}"); + } + + return resultId; } public async Task AddFile(Byte[] bytes) { var result = await GetClient().Magnet.UploadFileAsync(bytes); - return result.Id.ToString(); + if (result?.Id == null) + { + throw new Exception("Unable to add torrent file"); + } + + var resultId = result.Id.ToString(); + + if (resultId == null) + { + throw new Exception($"Invalid responseID {result.Id}"); + } + + return resultId; } public async Task> GetAvailableFiles(String hash) @@ -143,6 +172,11 @@ public class AllDebridTorrentClient : ITorrentClient { var result = await GetClient().Magnet.StatusAsync(torrentId); + if (result == null) + { + throw new Exception($"Unable to find magnet with ID {torrentId}"); + } + return Map(result); } @@ -155,13 +189,23 @@ public class AllDebridTorrentClient : ITorrentClient { var result = await GetClient().Links.DownloadLinkAsync(link); + if (result.Link == null) + { + throw new Exception("Invalid result link"); + } + return result.Link; } - public async Task UpdateData(Torrent torrent, TorrentClientTorrent torrentClientTorrent) + public async Task UpdateData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent) { try { + if (torrent.RdId == null) + { + return torrent; + } + torrentClientTorrent ??= await GetInfo(torrent.RdId); if (!String.IsNullOrWhiteSpace(torrentClientTorrent.Filename)) @@ -231,10 +275,20 @@ public class AllDebridTorrentClient : ITorrentClient return torrent; } - public async Task> GetDownloadLinks(Torrent torrent) + public async Task?> GetDownloadLinks(Torrent torrent) { + if (torrent.RdId == null) + { + return null; + } + var magnet = await GetClient().Magnet.StatusAsync(torrent.RdId); + if (magnet == null) + { + return null; + } + var links = magnet.Links; Log($"Getting download links", torrent); @@ -262,11 +316,6 @@ public class AllDebridTorrentClient : ITorrentClient foreach (var link in links) { - if (link.Files == null) - { - continue; - } - var fileList = GetFiles(link.Files, ""); Log($"{link.Filename} ({link.Size}b) {link.LinkUrl}, contains files:{Environment.NewLine}{String.Join(Environment.NewLine, fileList)}"); @@ -332,7 +381,7 @@ public class AllDebridTorrentClient : ITorrentClient return result; } - private void Log(String message, Torrent torrent = null) + private void Log(String message, Torrent? torrent = null) { if (torrent != null) { diff --git a/server/RdtClient.Service/Services/TorrentClients/ITorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/ITorrentClient.cs index b05cdd9..da4aa39 100644 --- a/server/RdtClient.Service/Services/TorrentClients/ITorrentClient.cs +++ b/server/RdtClient.Service/Services/TorrentClients/ITorrentClient.cs @@ -11,9 +11,8 @@ public interface ITorrentClient Task AddFile(Byte[] bytes); Task> GetAvailableFiles(String hash); Task SelectFiles(Torrent torrent); - Task GetInfo(String torrentId); Task Delete(String torrentId); Task Unrestrict(String link); - Task UpdateData(Torrent torrent, TorrentClientTorrent torrentClientTorrent); - Task> GetDownloadLinks(Torrent torrent); + Task UpdateData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent); + Task?> GetDownloadLinks(Torrent torrent); } \ No newline at end of file diff --git a/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs b/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs index 55157ce..02ce967 100644 --- a/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs +++ b/server/RdtClient.Service/Services/TorrentClients/RealDebridTorrentClient.cs @@ -141,11 +141,11 @@ public class RealDebridTorrentClient : ITorrentClient var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values); - var groups = files.GroupBy(m => $"{m.Filename}-{m.Filesize}"); + var groups = files.Where(m => m.Filename != null).GroupBy(m => $"{m.Filename}-{m.Filesize}"); var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile { - Filename = m.First().Filename, + Filename = m.First().Filename!, Filesize = m.First().Filesize } ).ToList(); @@ -211,7 +211,7 @@ public class RealDebridTorrentClient : ITorrentClient Log("", torrent); - await GetClient().Torrents.SelectFilesAsync(torrent.RdId, fileIds.ToArray()); + await GetClient().Torrents.SelectFilesAsync(torrent.RdId!, fileIds.ToArray()); } public async Task GetInfo(String torrentId) @@ -230,23 +230,28 @@ public class RealDebridTorrentClient : ITorrentClient { var result = await GetClient().Unrestrict.LinkAsync(link); + if (result.Download == null) + { + throw new Exception($"Unrestrict returned an invalid download"); + } + return result.Download; } - public async Task UpdateData(Data.Models.Data.Torrent torrent, TorrentClientTorrent torrentClientTorrent) + public async Task UpdateData(Data.Models.Data.Torrent torrent, TorrentClientTorrent? torrentClientTorrent) { try { - if (torrent == null) + if (torrent.RdId == null) { - return null; + return torrent; } var rdTorrent = await GetInfo(torrent.RdId); if (rdTorrent == null) { - return torrent; + throw new Exception($"Resource not found"); } if (!String.IsNullOrWhiteSpace(rdTorrent.Filename)) @@ -302,10 +307,7 @@ public class RealDebridTorrentClient : ITorrentClient { if (ex.Message == "Resource not found") { - if (torrent != null) - { - torrent.RdStatusRaw = "deleted"; - } + torrent.RdStatusRaw = "deleted"; } else { @@ -316,10 +318,20 @@ public class RealDebridTorrentClient : ITorrentClient return torrent; } - public async Task> GetDownloadLinks(Data.Models.Data.Torrent torrent) + public async Task?> GetDownloadLinks(Data.Models.Data.Torrent torrent) { + if (torrent.RdId == null) + { + return null; + } + var rdTorrent = await GetInfo(torrent.RdId); + if (rdTorrent.Links == null) + { + return null; + } + var downloadLinks = rdTorrent.Links.Where(m => !String.IsNullOrWhiteSpace(m)).ToList(); Log($"Found {downloadLinks.Count} links", torrent); @@ -360,7 +372,7 @@ public class RealDebridTorrentClient : ITorrentClient return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value); } - private void Log(String message, Data.Models.Data.Torrent torrent = null) + private void Log(String message, Data.Models.Data.Torrent? torrent = null) { if (torrent != null) { diff --git a/server/RdtClient.Service/Services/TorrentRunner.cs b/server/RdtClient.Service/Services/TorrentRunner.cs index 556a2de..83b222c 100644 --- a/server/RdtClient.Service/Services/TorrentRunner.cs +++ b/server/RdtClient.Service/Services/TorrentRunner.cs @@ -121,7 +121,7 @@ public class TorrentRunner var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, _httpClient, 1); - var allDownloads = await aria2NetClient.TellAll(); + var allDownloads = await aria2NetClient.TellAllAsync(); Log($"Found {allDownloads.Count} Aria2 downloads"); @@ -162,7 +162,7 @@ public class TorrentRunner { // Retry the download if an error is encountered. Log($"Download reported an error: {downloadClient.Error}", download, download.Torrent); - Log($"Download retry count {download.RetryCount}/{download.Torrent.DownloadRetryAttempts}, torrent retry count {download.Torrent.RetryCount}/{download.Torrent.TorrentRetryAttempts}", download, download.Torrent); + Log($"Download retry count {download.RetryCount}/{download.Torrent!.DownloadRetryAttempts}, torrent retry count {download.Torrent.RetryCount}/{download.Torrent.TorrentRetryAttempts}", download, download.Torrent); if (download.RetryCount < download.Torrent.DownloadRetryAttempts) { @@ -570,7 +570,7 @@ public class TorrentRunner } } - private void Log(String message, Download download, Torrent torrent) + private void Log(String message, Download? download, Torrent? torrent) { if (download != null) { @@ -585,7 +585,7 @@ public class TorrentRunner _logger.LogDebug(message); } - private void Log(String message, Torrent torrent = null) + private void Log(String message, Torrent? torrent = null) { if (torrent != null) { diff --git a/server/RdtClient.Service/Services/Torrents.cs b/server/RdtClient.Service/Services/Torrents.cs index d7d4361..c5aad57 100644 --- a/server/RdtClient.Service/Services/Torrents.cs +++ b/server/RdtClient.Service/Services/Torrents.cs @@ -42,7 +42,7 @@ public class Torrents { Provider.RealDebrid => realDebridTorrentClient, Provider.AllDebrid => allDebridTorrentClient, - _ => null + _ => throw new Exception("Invalid Provider") }; } @@ -72,7 +72,7 @@ public class Torrents return torrents; } - public async Task GetByHash(String hash) + public async Task GetByHash(String hash) { var torrent = await _torrentData.GetByHash(hash); @@ -84,7 +84,7 @@ public class Torrents return torrent; } - public async Task UpdateCategory(String hash, String category) + public async Task UpdateCategory(String hash, String? category) { var torrent = await _torrentData.GetByHash(hash); @@ -256,7 +256,7 @@ public class Torrents await _torrentData.Delete(torrentId); } - if (deleteRdTorrent) + if (deleteRdTorrent && torrent.RdId != null) { Log($"Deleting RealDebrid Torrent", torrent); @@ -495,14 +495,17 @@ public class Torrents await Task.Delay(100); } - var downloadPath = DownloadPath(download.Torrent); + var downloadPath = DownloadPath(download.Torrent!); - var filePath = DownloadHelper.GetDownloadPath(downloadPath, download.Torrent, download); + var filePath = DownloadHelper.GetDownloadPath(downloadPath, download.Torrent!, download); + + if (filePath != null) + { + Log($"Deleting {filePath}", download, download.Torrent); + + await FileHelper.Delete(filePath); + } - Log($"Deleting {filePath}", download, download.Torrent); - - await FileHelper.Delete(filePath); - Log($"Resetting", download, download.Torrent); await _downloads.Reset(downloadId); @@ -510,7 +513,7 @@ public class Torrents await _torrentData.UpdateComplete(download.TorrentId, null, null, false); } - public async Task UpdateComplete(Guid torrentId, String error, DateTimeOffset datetime, Boolean retry) + public async Task UpdateComplete(Guid torrentId, String? error, DateTimeOffset datetime, Boolean retry) { await _torrentData.UpdateComplete(torrentId, error, datetime, retry); } @@ -542,7 +545,7 @@ public class Torrents await _torrentData.UpdateError(torrentId, error); } - public async Task GetById(Guid torrentId) + public async Task GetById(Guid torrentId) { var torrent = await _torrentData.GetById(torrentId); @@ -630,6 +633,12 @@ public class Torrents } var torrent = await _torrentData.GetById(torrentId); + + if (torrent == null) + { + throw new Exception($"Cannot find Torrent with ID {torrentId}"); + } + var downloads = await _downloads.GetForTorrent(torrentId); var fileName = Settings.Get.General.RunOnTorrentCompleteFileName; @@ -638,7 +647,7 @@ public class Torrents Log($"Parsing external program {fileName} with arguments {arguments}", torrent); var downloadPath = DownloadPath(torrent); - var torrentPath = Path.Combine(downloadPath, torrent.RdName); + var torrentPath = Path.Combine(downloadPath, torrent.RdName ?? "Unknown"); arguments = arguments.Replace("%N", $"\"{torrent.RdName}\""); arguments = arguments.Replace("%L", $"\"{torrent.Category}\""); @@ -646,7 +655,7 @@ public class Torrents arguments = arguments.Replace("%R", $"\"{downloadPath}\""); arguments = arguments.Replace("%D", $"\"{torrentPath}\""); arguments = arguments.Replace("%C", downloads.Count.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", "")); - arguments = arguments.Replace("%Z", torrent.RdSize.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", "")); + arguments = arguments.Replace("%Z", torrent.RdSize?.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", "")); arguments = arguments.Replace("%I", torrent.Hash); Log($"Executing external program {fileName} with arguments {arguments}", torrent); @@ -707,7 +716,7 @@ public class Torrents } } - private async Task UpdateTorrentClientData(Torrent torrent, TorrentClientTorrent torrentClientTorrent = null) + private async Task UpdateTorrentClientData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent = null) { try { @@ -736,7 +745,7 @@ public class Torrents } } - private void Log(String message, Data.Models.Data.Download download, Torrent torrent) + private void Log(String message, Data.Models.Data.Download? download, Torrent? torrent) { if (download != null) { @@ -751,7 +760,7 @@ public class Torrents _logger.LogDebug(message); } - private void Log(String message, Torrent torrent = null) + private void Log(String message, Torrent? torrent = null) { if (torrent != null) { diff --git a/server/RdtClient.Service/Services/UnpackClient.cs b/server/RdtClient.Service/Services/UnpackClient.cs index 5d16a45..6994d03 100644 --- a/server/RdtClient.Service/Services/UnpackClient.cs +++ b/server/RdtClient.Service/Services/UnpackClient.cs @@ -10,7 +10,7 @@ public class UnpackClient { public Boolean Finished { get; private set; } - public String Error { get; private set; } + public String? Error { get; private set; } public Int64 BytesTotal { get; private set; } public Int64 BytesDone { get; private set; } @@ -21,14 +21,14 @@ public class UnpackClient private Boolean _cancelled; - private RarArchiveEntry _rarCurrentEntry; - private Dictionary _rarfileStatus; + private RarArchiveEntry? _rarCurrentEntry; + private Dictionary? _rarfileStatus; public UnpackClient(Download download, String destinationPath) { _download = download; _destinationPath = destinationPath; - _torrent = download.Torrent; + _torrent = download.Torrent ?? throw new Exception($"Torrent is null"); } public void Start() @@ -91,7 +91,7 @@ public class UnpackClient if (!entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"\")) && !entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"/"))) { - extractPath = Path.Combine(_destinationPath, _torrent.RdName); + extractPath = Path.Combine(_destinationPath, _torrent.RdName!); } if (entries.Any(m => m.Key.Contains(".r00"))) @@ -129,14 +129,14 @@ public class UnpackClient } } - private void ArchiveOnCompressedBytesRead(Object sender, CompressedBytesReadEventArgs e) + private void ArchiveOnCompressedBytesRead(Object? sender, CompressedBytesReadEventArgs e) { if (_rarCurrentEntry == null) { return; } - _rarfileStatus[_rarCurrentEntry.Key] = e.CompressedBytesRead; + _rarfileStatus![_rarCurrentEntry.Key] = e.CompressedBytesRead; BytesDone = _rarfileStatus.Sum(m => m.Value); } diff --git a/server/RdtClient.Web/Controllers/AuthController.cs b/server/RdtClient.Web/Controllers/AuthController.cs index 09eb5fc..875bb79 100644 --- a/server/RdtClient.Web/Controllers/AuthController.cs +++ b/server/RdtClient.Web/Controllers/AuthController.cs @@ -1,7 +1,5 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using RdtClient.Data.Models.Data; -using RdtClient.Data.Models.Internal; using RdtClient.Service.Services; namespace RdtClient.Web.Controllers; @@ -41,14 +39,24 @@ public class AuthController : Controller [AllowAnonymous] [Route("Create")] [HttpPost] - public async Task Create([FromBody] AuthControllerLoginRequest request) + public async Task Create([FromBody] AuthControllerLoginRequest? request) { + if (request == null) + { + return BadRequest(); + } + var user = await _authentication.GetUser(); if (user != null) { return StatusCode(401); } + + if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password)) + { + return BadRequest("Invalid UserName or Password"); + } var registerResult = await _authentication.Register(request.UserName, request.Password); @@ -65,8 +73,13 @@ public class AuthController : Controller [AllowAnonymous] [Route("SetupProvider")] [HttpPost] - public async Task SetupProvider([FromBody] AuthControllerSetupProviderRequest request) + public async Task SetupProvider([FromBody] AuthControllerSetupProviderRequest? request) { + if (request == null) + { + return BadRequest(); + } + if (!String.IsNullOrEmpty(Settings.Get.Provider.ApiKey)) { return StatusCode(401); @@ -81,8 +94,13 @@ public class AuthController : Controller [AllowAnonymous] [Route("Login")] [HttpPost] - public async Task Login([FromBody] AuthControllerLoginRequest request) + public async Task Login([FromBody] AuthControllerLoginRequest? request) { + if (request == null) + { + return BadRequest(); + } + var user = await _authentication.GetUser(); if (user == null) @@ -90,6 +108,11 @@ public class AuthController : Controller return StatusCode(402); } + if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password)) + { + return BadRequest("Invalid credentials"); + } + var result = await _authentication.Login(request.UserName, request.Password); if (!result.Succeeded) @@ -110,8 +133,18 @@ public class AuthController : Controller [Route("Update")] [HttpPost] - public async Task Update([FromBody] AuthControllerUpdateRequest request) + public async Task Update([FromBody] AuthControllerUpdateRequest? request) { + if (request == null) + { + return BadRequest(); + } + + if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password)) + { + return BadRequest("Invalid UserName or Password"); + } + var updateResult = await _authentication.Update(request.UserName, request.Password); if (!updateResult.Succeeded) @@ -125,18 +158,18 @@ public class AuthController : Controller public class AuthControllerLoginRequest { - public String UserName { get; set; } - public String Password { get; set; } + public String? UserName { get; set; } + public String? Password { get; set; } } public class AuthControllerSetupProviderRequest { public Int32 Provider { get; set; } - public String Token { get; set; } + public String? Token { get; set; } } public class AuthControllerUpdateRequest { - public String UserName { get; set; } - public String Password { get; set; } + public String? UserName { get; set; } + public String? Password { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Web/Controllers/QBittorrentController.cs b/server/RdtClient.Web/Controllers/QBittorrentController.cs index 7432eca..e9775c6 100644 --- a/server/RdtClient.Web/Controllers/QBittorrentController.cs +++ b/server/RdtClient.Web/Controllers/QBittorrentController.cs @@ -26,6 +26,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task AuthLogin([FromQuery] QBAuthLoginRequest request) { + if (String.IsNullOrWhiteSpace(request.UserName) || String.IsNullOrEmpty(request.Password)) + { + return Ok("Fails."); + } + var result = await _qBittorrent.AuthLogin(request.UserName, request.Password); if (result) @@ -121,7 +126,7 @@ public class QBittorrentController : Controller [HttpPost] public ActionResult AppDefaultSavePath() { - var result = _qBittorrent.AppDefaultSavePath(); + var result = Settings.AppDefaultSavePath; return Ok(result); } @@ -154,6 +159,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task>> TorrentsFiles([FromQuery] QBTorrentsHashRequest request) { + if (String.IsNullOrWhiteSpace(request.Hash)) + { + return BadRequest(); + } + var result = await _qBittorrent.TorrentFileContents(request.Hash); if (result == null) @@ -177,6 +187,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task>> TorrentsProperties([FromQuery] QBTorrentsHashRequest request) { + if (String.IsNullOrWhiteSpace(request.Hash)) + { + return BadRequest(); + } + var result = await _qBittorrent.TorrentProperties(request.Hash); if (result == null) @@ -200,6 +215,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task TorrentsPause([FromQuery] QBTorrentsHashesRequest request) { + if (String.IsNullOrWhiteSpace(request.Hashes)) + { + return BadRequest(); + } + var hashes = request.Hashes.Split("|"); foreach (var hash in hashes) @@ -223,6 +243,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task TorrentsResume([FromQuery] QBTorrentsHashesRequest request) { + if (String.IsNullOrWhiteSpace(request.Hashes)) + { + return BadRequest(); + } + var hashes = request.Hashes.Split("|"); foreach (var hash in hashes) @@ -255,6 +280,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task TorrentsDelete([FromQuery] QBTorrentsDeleteRequest request) { + if (String.IsNullOrWhiteSpace(request.Hashes)) + { + return BadRequest(); + } + var hashes = request.Hashes.Split("|"); foreach (var hash in hashes) @@ -278,6 +308,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task TorrentsAdd([FromQuery] QBTorrentsAddRequest request) { + if (String.IsNullOrWhiteSpace(request.Urls)) + { + return BadRequest(); + } + var urls = request.Urls.Split("\n"); foreach (var url in urls) @@ -294,7 +329,7 @@ public class QBittorrentController : Controller } else { - throw new Exception($"Invalid torrent link format {url}"); + return BadRequest($"Invalid torrent link format {url}"); } } @@ -332,6 +367,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task TorrentsSetCategory([FromQuery] QBTorrentsSetCategoryRequest request) { + if (String.IsNullOrWhiteSpace(request.Hashes)) + { + return BadRequest(); + } + var hashes = request.Hashes.Split("|"); foreach (var hash in hashes) @@ -412,6 +452,11 @@ public class QBittorrentController : Controller [HttpGet] public async Task TorrentsTopPrio([FromQuery] QBTorrentsHashesRequest request) { + if (String.IsNullOrWhiteSpace(request.Hashes)) + { + return BadRequest(); + } + var hashes = request.Hashes.Split("|"); foreach (var hash in hashes) @@ -451,51 +496,50 @@ public class QBittorrentController : Controller public class QBAuthLoginRequest { - public String UserName { get; set; } - public String Password { get; set; } + public String? UserName { get; set; } + public String? Password { get; set; } } public class QBTorrentsInfoRequest { - public String Category { get; set; } + public String? Category { get; set; } } public class QBTorrentsHashRequest { - public String Hash { get; set; } - public String Category { get; set; } + public String? Hash { get; set; } } public class QBTorrentsDeleteRequest { - public String Hashes { get; set; } + public String? Hashes { get; set; } public Boolean DeleteFiles { get; set; } } public class QBTorrentsAddRequest { - public String Urls { get; set; } - public String Category { get; set; } + public String? Urls { get; set; } + public String? Category { get; set; } public Int32? Priority { get; set; } } public class QBTorrentsSetCategoryRequest { - public String Hashes { get; set; } - public String Category { get; set; } + public String? Hashes { get; set; } + public String? Category { get; set; } } public class QBTorrentsCreateCategoryRequest { - public String Category { get; set; } + public String? Category { get; set; } } public class QBTorrentsRemoveCategoryRequest { - public String Categories { get; set; } + public String? Categories { get; set; } } public class QBTorrentsHashesRequest { - public String Hashes { get; set; } + public String? Hashes { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Web/Controllers/SettingsController.cs b/server/RdtClient.Web/Controllers/SettingsController.cs index a4aafa1..a4309b5 100644 --- a/server/RdtClient.Web/Controllers/SettingsController.cs +++ b/server/RdtClient.Web/Controllers/SettingsController.cs @@ -1,7 +1,13 @@ -using Microsoft.AspNetCore.Authorization; +using System.Diagnostics; +using Aria2NET; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using RdtClient.Data.Data; +using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Internal; +using RdtClient.Service.Helpers; using RdtClient.Service.Services; +using RdtClient.Service.Services.Downloaders; namespace RdtClient.Web.Controllers; @@ -22,14 +28,19 @@ public class SettingsController : Controller [Route("")] public ActionResult Get() { - var result = _settings.GetAll(); + var result = SettingData.GetAll(); return Ok(result); } [HttpPut] [Route("")] - public async Task Update([FromBody] IList settings) + public async Task Update([FromBody] IList? settings) { + if (settings == null) + { + return BadRequest(); + } + await _settings.Update(settings); return Ok(); @@ -45,9 +56,30 @@ public class SettingsController : Controller [HttpPost] [Route("TestPath")] - public async Task TestPath([FromBody] SettingsControllerTestPathRequest request) + public async Task TestPath([FromBody] SettingsControllerTestPathRequest? request) { - await _settings.TestPath(request.Path); + if (request == null) + { + return BadRequest(); + } + + if (String.IsNullOrEmpty(request.Path)) + { + return BadRequest("Invalid path"); + } + + var path = request.Path.TrimEnd('/').TrimEnd('\\'); + + if (!Directory.Exists(path)) + { + throw new Exception($"Path {path} does not exist"); + } + + var testFile = $"{path}/test.txt"; + + await System.IO.File.WriteAllTextAsync(testFile, "RealDebridClient Test File, you can remove this file."); + + await FileHelper.Delete(testFile); return Ok(); } @@ -56,25 +88,120 @@ public class SettingsController : Controller [Route("TestDownloadSpeed")] public async Task TestDownloadSpeed(CancellationToken cancellationToken) { - var downloadSpeed = await _settings.TestDownloadSpeed(cancellationToken); + var downloadPath = Settings.Get.DownloadClient.DownloadPath; - return Ok(downloadSpeed); + var testFilePath = Path.Combine(downloadPath, "testDefault.rar"); + + await FileHelper.Delete(testFilePath); + + var download = new Download + { + Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar", + Torrent = new Torrent + { + RdName = "" + } + }; + + var downloadClient = new DownloadClient(download, download.Torrent, downloadPath); + + await downloadClient.Start(Settings.Get); + + var httpClient = new HttpClient + { + Timeout = TimeSpan.FromSeconds(10) + }; + + while (!downloadClient.Finished) + { + await Task.Delay(1000, CancellationToken.None); + + if (cancellationToken.IsCancellationRequested) + { + await downloadClient.Cancel(); + } + + if (downloadClient.Downloader is Aria2cDownloader aria2Downloader) + { + var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, httpClient, 1); + + var allDownloads = await aria2NetClient.TellAllAsync(cancellationToken); + + await aria2Downloader.Update(allDownloads); + } + + if (downloadClient.BytesDone > 1024 * 1024 * 50) + { + await downloadClient.Cancel(); + + break; + } + } + + await FileHelper.Delete(testFilePath); + + await Settings.Clean(); + + return Ok(downloadClient.Speed); } [HttpGet] [Route("TestWriteSpeed")] public async Task TestWriteSpeed() { - var writeSpeed = await _settings.TestWriteSpeed(); + var downloadPath = Settings.Get.DownloadClient.DownloadPath; + + var testFilePath = Path.Combine(downloadPath, "test.tmp"); + + await FileHelper.Delete(testFilePath); + + const Int32 testFileSize = 64 * 1024 * 1024; + + var watch = new Stopwatch(); + + watch.Start(); + + var rnd = new Random(); + + await using var fileStream = new FileStream(testFilePath, FileMode.Create, FileAccess.Write, FileShare.Write); + + var buffer = new Byte[64 * 1024]; + + while (fileStream.Length < testFileSize) + { + rnd.NextBytes(buffer); + + await fileStream.WriteAsync(buffer.AsMemory(0, buffer.Length)); + } + watch.Stop(); + + var writeSpeed = fileStream.Length / watch.Elapsed.TotalSeconds; + + fileStream.Close(); + + await FileHelper.Delete(testFilePath); + return Ok(writeSpeed); } [HttpPost] [Route("TestAria2cConnection")] - public async Task> TestAria2cConnection([FromBody] SettingsControllerTestAria2cConnectionRequest request) + public async Task> TestAria2cConnection([FromBody] SettingsControllerTestAria2cConnectionRequest? request) { - var version = await _settings.GetAria2cVersion(request.Url, request.Secret); + if (request == null) + { + return BadRequest(); + } + + if (String.IsNullOrEmpty(request.Url)) + { + return BadRequest("Invalid Url"); + } + + var client = new Aria2NetClient(request.Url, request.Secret); + + var version = await client.GetVersionAsync(); return Ok(version); } @@ -82,11 +209,11 @@ public class SettingsController : Controller public class SettingsControllerTestPathRequest { - public String Path { get; set; } + public String? Path { get; set; } } public class SettingsControllerTestAria2cConnectionRequest { - public String Url { get; set; } - public String Secret { get; set; } + public String? Url { get; set; } + public String? Secret { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Web/Controllers/TorrentsController.cs b/server/RdtClient.Web/Controllers/TorrentsController.cs index 1c97183..b625db5 100644 --- a/server/RdtClient.Web/Controllers/TorrentsController.cs +++ b/server/RdtClient.Web/Controllers/TorrentsController.cs @@ -67,22 +67,25 @@ public class TorrentsController : Controller [HttpPost] [Route("UploadFile")] - public async Task UploadFile([FromForm] IFormFile file, + public async Task UploadFile([FromForm] IFormFile? file, [ModelBinder(BinderType = typeof(JsonModelBinder))] - TorrentControllerUploadFileRequest formData) + TorrentControllerUploadFileRequest? formData) { if (!ModelState.IsValid) { - var errors = ModelState.Select(x => x.Value.Errors) - .Where(y => y.Count > 0) - .ToList(); - + var errors = ModelState.Select(x => x.Value?.Errors.Select(m => m.ErrorMessage)).ToList(); return BadRequest(errors); } + if (file == null || file.Length <= 0) { - throw new Exception("Invalid torrent file"); + return BadRequest("Invalid torrent file"); + } + + if (formData?.Torrent == null) + { + return BadRequest("Invalid Torrent"); } var fileStream = file.OpenReadStream(); @@ -100,17 +103,29 @@ public class TorrentsController : Controller [HttpPost] [Route("UploadMagnet")] - public async Task UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest request) + public async Task UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest? request) { + if (request == null) + { + return BadRequest(); + } + if (!ModelState.IsValid) { - var errors = ModelState.Select(x => x.Value.Errors) - .Where(y => y.Count > 0) - .ToList(); - + var errors = ModelState.Select(x => x.Value?.Errors.Select(m => m.ErrorMessage)).ToList(); return BadRequest(errors); } + if (String.IsNullOrEmpty(request.MagnetLink)) + { + return BadRequest("Invalid magnet link"); + } + + if (request.Torrent == null) + { + return BadRequest("Invalid Torrent"); + } + await _torrents.UploadMagnet(request.MagnetLink, request.Torrent); return Ok(); @@ -118,11 +133,11 @@ public class TorrentsController : Controller [HttpPost] [Route("CheckFiles")] - public async Task CheckFiles([FromForm] IFormFile file) + public async Task CheckFiles([FromForm] IFormFile? file) { if (file == null || file.Length <= 0) { - throw new Exception("Invalid torrent file"); + return BadRequest("Invalid torrent file"); } var fileStream = file.OpenReadStream(); @@ -142,8 +157,13 @@ public class TorrentsController : Controller [HttpPost] [Route("CheckFilesMagnet")] - public async Task CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest request) + public async Task CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest? request) { + if (request == null) + { + return BadRequest(); + } + var magnet = MagnetLink.Parse(request.MagnetLink); var result = await _torrents.GetAvailableFiles(magnet.InfoHash.ToHex()); @@ -153,8 +173,13 @@ public class TorrentsController : Controller [HttpPost] [Route("Delete/{torrentId:guid}")] - public async Task Delete(Guid torrentId, [FromBody] TorrentControllerDeleteRequest request) + public async Task Delete(Guid torrentId, [FromBody] TorrentControllerDeleteRequest? request) { + if (request == null) + { + return BadRequest(); + } + await _torrents.Delete(torrentId, request.DeleteData, request.DeleteRdTorrent, request.DeleteLocalFiles); return Ok(); @@ -181,8 +206,13 @@ public class TorrentsController : Controller [HttpPut] [Route("Update")] - public async Task Update([FromBody] Torrent torrent) + public async Task Update([FromBody] Torrent? torrent) { + if (torrent == null) + { + return BadRequest(); + } + await _torrents.Update(torrent); return Ok(); @@ -191,13 +221,13 @@ public class TorrentsController : Controller public class TorrentControllerUploadFileRequest { - public Torrent Torrent { get; set; } + public Torrent? Torrent { get; set; } } public class TorrentControllerUploadMagnetRequest { - public String MagnetLink { get; set; } - public Torrent Torrent { get; set; } + public String? MagnetLink { get; set; } + public Torrent? Torrent { get; set; } } public class TorrentControllerDeleteRequest @@ -209,5 +239,5 @@ public class TorrentControllerDeleteRequest public class TorrentControllerCheckFilesRequest { - public String MagnetLink { get; set; } + public String? MagnetLink { get; set; } } \ No newline at end of file diff --git a/server/RdtClient.Web/Program.cs b/server/RdtClient.Web/Program.cs index 1f423ce..6040cda 100644 --- a/server/RdtClient.Web/Program.cs +++ b/server/RdtClient.Web/Program.cs @@ -32,17 +32,20 @@ builder.WebHost.ConfigureKestrel(options => options.ListenAnyIP(appSettings.Port); }); -builder.Host.UseSerilog((_, lc) => lc.Enrich.FromLogContext() - .Enrich.WithExceptionDetails() - .WriteTo.File(appSettings.Logging.File.Path, - rollOnFileSizeLimit: true, - fileSizeLimitBytes: appSettings.Logging.File.FileSizeLimitBytes, - retainedFileCountLimit: appSettings.Logging.File.MaxRollingFiles, - outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}") - .WriteTo.Console() - .MinimumLevel.ControlledBy(Settings.LoggingLevelSwitch) - .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) - .MinimumLevel.Override("System.Net.Http", LogEventLevel.Warning)); +if (appSettings.Logging?.File?.Path != null) +{ + builder.Host.UseSerilog((_, lc) => lc.Enrich.FromLogContext() + .Enrich.WithExceptionDetails() + .WriteTo.File(appSettings.Logging.File.Path, + rollOnFileSizeLimit: true, + fileSizeLimitBytes: appSettings.Logging.File.FileSizeLimitBytes, + retainedFileCountLimit: appSettings.Logging.File.MaxRollingFiles, + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}") + .WriteTo.Console() + .MinimumLevel.ControlledBy(Settings.LoggingLevelSwitch) + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("System.Net.Http", LogEventLevel.Warning)); +} Serilog.Debugging.SelfLog.Enable(msg => { diff --git a/server/RdtClient.Web/RdtClient.Web.csproj b/server/RdtClient.Web/RdtClient.Web.csproj index 37e3ef2..eb94e03 100644 --- a/server/RdtClient.Web/RdtClient.Web.csproj +++ b/server/RdtClient.Web/RdtClient.Web.csproj @@ -5,7 +5,7 @@ Exe 94c24cba-f03f-4453-a671-3640b517c573 2.0.12 - disable + enable enable latest @@ -29,15 +29,15 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/server/RdtClient.sln.DotSettings b/server/RdtClient.sln.DotSettings index 6a860b7..777664e 100644 --- a/server/RdtClient.sln.DotSettings +++ b/server/RdtClient.sln.DotSettings @@ -179,6 +179,7 @@ QB US XML + Aria2c <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />