using System.Collections.ObjectModel; using System.Diagnostics; using System.Net; using System.Runtime.CompilerServices; using Flurl; using Flurl.Http; using Microsoft.Extensions.Logging; namespace Piwigo.Client; public class PiwigoClient : IPiwigoClient { private CookieJar _cookies = new(); private string _piwigoBaseUri = null!; public bool IsLoggedIn { get; private set; } public int ChunkSize { get; set; } = 512; private IFlurlRequest Request => _piwigoBaseUri.WithCookies(_cookies).ConfigureRequest(r => r.AfterCallAsync = LogResponse); private readonly ILogger _logger; public PiwigoClient(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task LoginAsync(Uri uri, string username, string password) { if (uri == null) { throw new ArgumentNullException(nameof(uri)); } if (string.IsNullOrWhiteSpace(username)) { throw new ArgumentException("Value cannot be null or whitespace.", nameof(username)); } if (string.IsNullOrWhiteSpace(password)) { throw new ArgumentException("Value cannot be null or whitespace.", nameof(password)); } if (IsLoggedIn) { throw new PiwigoException("The client is already logged in. Create a new instance or log out first!"); } _piwigoBaseUri = uri.AppendPathSegment("ws.php").SetQueryParam("format", "json"); _logger.LogInformation("Logging into {PiwigoBaseUri} using username {Username}", _piwigoBaseUri, username); var response = await _piwigoBaseUri.WithCookies(out var cookieJar).PostMultipartAsync(c => c.PiwigoLogin(username, password)); if (response.StatusCode != (int)HttpStatusCode.OK) { _logger.LogError("Failed to log in {StatusCode}", response.StatusCode); throw new PiwigoException($"Could not log in to {_piwigoBaseUri} using username {username}"); } _logger.LogInformation("Logging in succeeded"); _cookies = cookieJar; IsLoggedIn = true; } public async Task LogoutAsync() { EnsureLoggedIn(); _logger.LogInformation("Logging out from {Uri}", _piwigoBaseUri); await Request.PostMultipartAsync(c => c.PiwigoLogout()); IsLoggedIn = false; _cookies.Clear(); } public async Task GetStatusAsync() { EnsureLoggedIn(); _logger.LogInformation("Getting status"); var response = await Request.PostMultipartAsync(c => c.PiwigoGetStatus()); var typedResponse = await response.GetJsonAsync>(); return typedResponse.Result; } public async Task> GetAllCategoriesAsync() { EnsureLoggedIn(); _logger.LogInformation("Getting all existing categories from server"); var response = await Request.PostMultipartAsync(c => c.PiwigoGetAllCategories()); var typedResponse = await response.GetJsonAsync>(); return new ReadOnlyCollection(typedResponse.Result.Categories); } private void EnsureLoggedIn([CallerMemberName] string? callerName = null) { if (!IsLoggedIn) { throw new InvalidOperationException($"Could not execute {callerName} as the client is not logged in."); } } private async Task LogResponse(FlurlCall call) { var responseString = await call.Response.GetStringAsync(); _logger.LogDebug("PiwigoResponse: {Response}", responseString); } }