From 077f10a4af27cf837b113fe074bd0d09cc280c9f Mon Sep 17 00:00:00 2001 From: Wendell Jones Date: Tue, 10 Mar 2026 12:55:49 -0400 Subject: [PATCH] Fix connection configuration - respect ConnectionString and individual options from database.xml --- .../new-dotnet-version_02bc64/scenario.json | 2 +- .../PostgresDatabaseProvider.cs | 122 +++++++++++++++--- 2 files changed, 105 insertions(+), 19 deletions(-) diff --git a/.github/upgrades/scenarios/new-dotnet-version_02bc64/scenario.json b/.github/upgrades/scenarios/new-dotnet-version_02bc64/scenario.json index e60d4734..67551120 100644 --- a/.github/upgrades/scenarios/new-dotnet-version_02bc64/scenario.json +++ b/.github/upgrades/scenarios/new-dotnet-version_02bc64/scenario.json @@ -3,7 +3,7 @@ "operationId": "02bc6448-a69d-4ff4-a0ec-0db07ec3a09a", "description": "Upgrade solution or project to new version of .NET", "startTime": "2026-03-05T22:18:32.3921759Z", - "lastUpdateTime": "2026-03-09T19:23:25.2251779Z", + "lastUpdateTime": "2026-03-10T16:51:30.5053632Z", "stage": "Execution", "properties": {}, "folderPath": "" diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Postgres/PostgresDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Postgres/PostgresDatabaseProvider.cs index 645f9f94..b53cf300 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Postgres/PostgresDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Postgres/PostgresDatabaseProvider.cs @@ -99,17 +99,17 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider // Store the configuration for later use databaseConfig = databaseConfiguration; - static T? GetOption(ICollection? options, string key, Func converter, Func? defaultValue = null) + static T? GetOption(ICollection? options, string key, Func converter, T? defaultValue = default) { if (options is null) { - return defaultValue is not null ? defaultValue() : default; + return defaultValue; } var value = options.FirstOrDefault(e => e.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); if (value is null) { - return defaultValue is not null ? defaultValue() : default; + return defaultValue; } return converter(value.Value); @@ -117,20 +117,106 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider var customOptions = databaseConfiguration.CustomProviderOptions?.Options; - var connectionBuilder = new NpgsqlConnectionStringBuilder + // Start with connection string if provided, then override with individual options + NpgsqlConnectionStringBuilder connectionBuilder; + + if (!string.IsNullOrWhiteSpace(databaseConfiguration.CustomProviderOptions?.ConnectionString)) { - Host = GetOption(customOptions, "host", e => e, () => "localhost")!, - Port = GetOption(customOptions, "port", int.Parse, () => 5432), - Database = GetOption(customOptions, "database", e => e, () => "jellyfin")!, - Username = GetOption(customOptions, "username", e => e, () => "jellyfin")!, - Password = GetOption(customOptions, "password", e => e, () => string.Empty)!, - Pooling = GetOption(customOptions, "pooling", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), () => true), - CommandTimeout = GetOption(customOptions, "command-timeout", int.Parse, () => 120), - Timeout = GetOption(customOptions, "connection-timeout", int.Parse, () => 15), - Multiplexing = GetOption(customOptions, "multiplexing", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), () => false), - MaxPoolSize = GetOption(customOptions, "max-pool-size", int.Parse, () => 100), - MinPoolSize = GetOption(customOptions, "min-pool-size", int.Parse, () => 0) - }; + // Use the provided connection string as base + connectionBuilder = new NpgsqlConnectionStringBuilder(databaseConfiguration.CustomProviderOptions.ConnectionString); + logger.LogDebug("Using ConnectionString from configuration as base"); + } + else + { + // Start with defaults + connectionBuilder = new NpgsqlConnectionStringBuilder + { + Host = "localhost", + Port = 5432, + Database = "jellyfin", + Username = "jellyfin", + Password = string.Empty, + Pooling = true, + CommandTimeout = 120, + Timeout = 15, + Multiplexing = false, + MaxPoolSize = 100, + MinPoolSize = 0 + }; + logger.LogDebug("Using default connection parameters"); + } + + // Override with individual options if provided (these take precedence over ConnectionString) + if (customOptions is not null && customOptions.Count > 0) + { + var host = GetOption(customOptions, "host", e => e, null); + if (host is not null) + { + connectionBuilder.Host = host; + } + + var port = GetOption(customOptions, "port", e => int.Parse(e), null); + if (port.HasValue) + { + connectionBuilder.Port = port.Value; + } + + var database = GetOption(customOptions, "database", e => e, null); + if (database is not null) + { + connectionBuilder.Database = database; + } + + var username = GetOption(customOptions, "username", e => e, null); + if (username is not null) + { + connectionBuilder.Username = username; + } + + var password = GetOption(customOptions, "password", e => e, null); + if (password is not null) + { + connectionBuilder.Password = password; + } + + var pooling = GetOption(customOptions, "pooling", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), null); + if (pooling.HasValue) + { + connectionBuilder.Pooling = pooling.Value; + } + + var commandTimeout = GetOption(customOptions, "command-timeout", e => int.Parse(e), null); + if (commandTimeout.HasValue) + { + connectionBuilder.CommandTimeout = commandTimeout.Value; + } + + var timeout = GetOption(customOptions, "connection-timeout", e => int.Parse(e), null); + if (timeout.HasValue) + { + connectionBuilder.Timeout = timeout.Value; + } + + var multiplexing = GetOption(customOptions, "multiplexing", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), null); + if (multiplexing.HasValue) + { + connectionBuilder.Multiplexing = multiplexing.Value; + } + + var maxPoolSize = GetOption(customOptions, "max-pool-size", e => int.Parse(e), null); + if (maxPoolSize.HasValue) + { + connectionBuilder.MaxPoolSize = maxPoolSize.Value; + } + + var minPoolSize = GetOption(customOptions, "min-pool-size", e => int.Parse(e), null); + if (minPoolSize.HasValue) + { + connectionBuilder.MinPoolSize = minPoolSize.Value; + } + + logger.LogDebug("Applied {Count} individual option overrides", customOptions.Count); + } var connectionString = connectionBuilder.ToString(); @@ -153,7 +239,7 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider if (configurationManager is not null) { // Check if backups are explicitly disabled - var disableBackups = GetOption(customOptions, "disable-backups", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), () => false); + var disableBackups = GetOption(customOptions, "disable-backups", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), null) ?? false; if (disableBackups) { @@ -195,7 +281,7 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider .ConfigureWarnings(warnings => warnings.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning)); - var enableSensitiveDataLogging = GetOption(customOptions, "EnableSensitiveDataLogging", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), () => false); + var enableSensitiveDataLogging = GetOption(customOptions, "EnableSensitiveDataLogging", e => e.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase), null) ?? false; if (enableSensitiveDataLogging) { options.EnableSensitiveDataLogging(enableSensitiveDataLogging);