From f47d4631df4f74e3df591a5f38f1e2244f235015 Mon Sep 17 00:00:00 2001 From: Cucumberrbob <128094686+Cucumberrbob@users.noreply.github.com> Date: Thu, 6 Mar 2025 21:15:24 +0000 Subject: [PATCH] Add openapi compatible xmldoc to `SettingsController` also narrows types for `Update`, we onlu used the `Key` and `Value` properties, so that's all clients need to pass --- server/RdtClient.Data/Data/SettingData.cs | 2 +- .../Models/Internal/SettingKeyValuePair.cs | 15 +++ .../Models/Internal/SettingProperty.cs | 4 +- server/RdtClient.Service/Services/Settings.cs | 2 +- .../Controllers/SettingsController.cs | 124 ++++++++++++++++-- 5 files changed, 129 insertions(+), 18 deletions(-) create mode 100644 server/RdtClient.Data/Models/Internal/SettingKeyValuePair.cs diff --git a/server/RdtClient.Data/Data/SettingData.cs b/server/RdtClient.Data/Data/SettingData.cs index 7f3d4c8..cb1f294 100644 --- a/server/RdtClient.Data/Data/SettingData.cs +++ b/server/RdtClient.Data/Data/SettingData.cs @@ -16,7 +16,7 @@ public class SettingData(DataContext dataContext, ILogger logger) return GetSettings(Get, null); } - public async Task Update(IList settings) + public async Task Update(IList settings) { var dbSettings = await dataContext.Settings.ToListAsync(); diff --git a/server/RdtClient.Data/Models/Internal/SettingKeyValuePair.cs b/server/RdtClient.Data/Models/Internal/SettingKeyValuePair.cs new file mode 100644 index 0000000..2625436 --- /dev/null +++ b/server/RdtClient.Data/Models/Internal/SettingKeyValuePair.cs @@ -0,0 +1,15 @@ +namespace RdtClient.Data.Models.Internal; + +public class SettingKeyValuePair +{ + /// + /// The unique human-readable key identifying the setting + /// + /// General:LogLevel + /// "Provider:Default:ExcludeRegex + public String Key { get; set; } = default!; + /// + /// The value of the setting + /// + public Object? Value { get; set; } +} diff --git a/server/RdtClient.Data/Models/Internal/SettingProperty.cs b/server/RdtClient.Data/Models/Internal/SettingProperty.cs index 82e0d9b..23ae02c 100644 --- a/server/RdtClient.Data/Models/Internal/SettingProperty.cs +++ b/server/RdtClient.Data/Models/Internal/SettingProperty.cs @@ -1,9 +1,7 @@ namespace RdtClient.Data.Models.Internal; -public class SettingProperty +public class SettingProperty: SettingKeyValuePair { - 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!; diff --git a/server/RdtClient.Service/Services/Settings.cs b/server/RdtClient.Service/Services/Settings.cs index fcbbc7d..d170ed8 100644 --- a/server/RdtClient.Service/Services/Settings.cs +++ b/server/RdtClient.Service/Services/Settings.cs @@ -27,7 +27,7 @@ public class Settings(SettingData settingData) } } - public async Task Update(IList settings) + public async Task Update(IList settings) { await settingData.Update(settings); } diff --git a/server/RdtClient.Web/Controllers/SettingsController.cs b/server/RdtClient.Web/Controllers/SettingsController.cs index bd7f0e6..af080a9 100644 --- a/server/RdtClient.Web/Controllers/SettingsController.cs +++ b/server/RdtClient.Web/Controllers/SettingsController.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; using Aria2NET; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -11,21 +12,39 @@ using RdtClient.Service.Services.Downloaders; namespace RdtClient.Web.Controllers; +/// +/// Controller for managing application settings and performing system tests +/// [Authorize(Policy = "AuthSetting")] [Route("Api/Settings")] public class SettingsController(Settings settings, Torrents torrents) : Controller { + /// + /// Retrieves all application settings + /// + /// A collection of all configured settings + /// Returns the list of settings [HttpGet] [Route("")] - public ActionResult Get() + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public ActionResult> Get() { var result = SettingData.GetAll(); return Ok(result); } + /// + /// Updates multiple application settings + /// + /// List of setting properties to update + /// Success status + /// Settings were successfully updated + /// Invalid settings data provided [HttpPut] [Route("")] - public async Task Update([FromBody] IList? settings1) + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task Update([FromBody] IList? settings1) { if (settings1 == null) { @@ -33,20 +52,41 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll } await settings.Update(settings1); - + return Ok(); } + /// + /// Retrieves the profile information from the currently configured debrid service + /// + /// The profile information + /// The profile information [HttpGet] [Route("Profile")] + [ProducesResponseType(typeof(Profile), StatusCodes.Status200OK)] public async Task> Profile() { var profile = await torrents.GetProfile(); return Ok(profile); } - + + /// + /// Tests if a specified path is writable by attempting to create and delete a test file + /// + /// + /// Creates a test file in the specified directory to verify write permissions. + /// The test file is automatically deleted after the test completes. + /// + /// The path testing request containing the directory to test + /// Success status if the path is writable + /// The path is valid and writable + /// Invalid or empty path provided + /// Path does not exist or is not accessible [HttpPost] [Route("TestPath")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(typeof(String), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(String), StatusCodes.Status500InternalServerError)] public async Task TestPath([FromBody] SettingsControllerTestPathRequest? request) { if (request == null) @@ -69,14 +109,24 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll 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(); } - + + /// + /// Tests download speed by downloading a sample file and measuring throughput + /// + /// Token to cancel the operation + /// The measured download speed in bytes per second + /// Returns the measured download speed + /// + /// The test downloads a file up to 50MB and measures the download speed. + /// [HttpGet] [Route("TestDownloadSpeed")] + [ProducesResponseType(typeof(Int64), StatusCodes.Status200OK)] public async Task TestDownloadSpeed(CancellationToken cancellationToken) { var downloadPath = Settings.Get.DownloadClient.DownloadPath; @@ -121,7 +171,7 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll await aria2Downloader.Update(allDownloads); } - + if (downloadClient.BytesDone > 1024 * 1024 * 50) { await downloadClient.Cancel(); @@ -131,12 +181,22 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll } await FileHelper.Delete(testFilePath); - + // ReSharper disable once SuggestVarOrType_BuiltInTypes return Ok(downloadClient.Speed); } - + + /// + /// Tests write speed to the configured download directory + /// + /// The measured write speed in bytes per second + /// Returns the measured write speed + /// + /// Creates a 64MB test file with random data to measure disk write performance. + /// The test file is automatically deleted after the test completes. + /// [HttpGet] [Route("TestWriteSpeed")] + [ProducesResponseType(typeof(Double), StatusCodes.Status200OK)] public async Task TestWriteSpeed() { var downloadPath = Settings.Get.DownloadClient.DownloadPath; @@ -163,20 +223,35 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll 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); } + /// + /// Tests the connection to an Aria2c instance + /// + /// + /// Attempts to connect to an Aria2c RPC endpoint and retrieve its version information. + /// This verifies both connectivity and authentication with the Aria2c server. + /// + /// The connection details for the Aria2c instance + /// The version information of the Aria2c server if connection is successful + /// Returns the Aria2c version information + /// Invalid or missing connection details + /// Connection to Aria2c failed [HttpPost] [Route("TestAria2cConnection")] + [ProducesResponseType(typeof(String), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> TestAria2cConnection([FromBody] SettingsControllerTestAria2cConnectionRequest? request) { if (request == null) @@ -197,13 +272,36 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll } } +/// +/// Request model for testing path accessibility +/// public class SettingsControllerTestPathRequest { + /// + /// The directory path to test for write access + /// + /// /path/to/downloads + [Required] public String? Path { get; set; } } +/// +/// Request model for testing Aria2c connection +/// public class SettingsControllerTestAria2cConnectionRequest { + /// + /// The URL of the Aria2c RPC endpoint + /// + + /// http://localhost:6800/jsonrpc + [Required] public String? Url { get; set; } + + /// + /// The secret token for authenticating with the Aria2c server + /// + /// your-secret-token + [Required] public String? Secret { get; set; } } \ No newline at end of file