2024-11-24 12:48:12 +01:00
|
|
|
|
using System.Collections.ObjectModel;
|
2025-08-30 19:41:10 +02:00
|
|
|
|
using FluentResults;
|
2025-08-18 19:41:36 +02:00
|
|
|
|
using Npgsql;
|
2024-11-24 12:48:12 +01:00
|
|
|
|
|
|
|
|
|
|
namespace pgLabII.PgUtils.ConnectionStrings;
|
|
|
|
|
|
|
2025-08-30 19:41:10 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parser for converting a libpq style connection string into a dictionary of key value pairs
|
|
|
|
|
|
/// </summary>
|
2025-08-18 19:41:36 +02:00
|
|
|
|
public ref struct PqConnectionStringParser
|
2024-11-24 12:48:12 +01:00
|
|
|
|
{
|
|
|
|
|
|
// Note possible keywords
|
|
|
|
|
|
// host
|
|
|
|
|
|
//hostaddr
|
|
|
|
|
|
//port
|
|
|
|
|
|
//dbname
|
|
|
|
|
|
//user
|
|
|
|
|
|
//password
|
|
|
|
|
|
//passfile
|
|
|
|
|
|
//channel_binding
|
|
|
|
|
|
//connect_timeout
|
|
|
|
|
|
//client_encoding
|
|
|
|
|
|
//options
|
|
|
|
|
|
//application_name
|
|
|
|
|
|
//fallback_application_name
|
|
|
|
|
|
//keepalives
|
|
|
|
|
|
//keepalives_idle
|
|
|
|
|
|
//keepalives_interval
|
|
|
|
|
|
//keepalives_count
|
|
|
|
|
|
//tcp_user_timeout
|
|
|
|
|
|
//replication
|
|
|
|
|
|
//gssencmode
|
|
|
|
|
|
//sslmode
|
|
|
|
|
|
//requiresll
|
|
|
|
|
|
//sslcompression
|
|
|
|
|
|
//sslcert
|
|
|
|
|
|
//sslkey
|
|
|
|
|
|
//sslpassword
|
|
|
|
|
|
//sslrootcert
|
|
|
|
|
|
//sslcrl
|
|
|
|
|
|
//sslcrldir
|
|
|
|
|
|
//sslsni
|
|
|
|
|
|
//requirepeer
|
|
|
|
|
|
//ssl_min_protocol_version
|
|
|
|
|
|
//ssl_max_protocol_version
|
|
|
|
|
|
//krbsrvname
|
|
|
|
|
|
//gsslib
|
|
|
|
|
|
//service
|
|
|
|
|
|
//target_session_attrs
|
|
|
|
|
|
|
2025-08-31 13:11:59 +02:00
|
|
|
|
public static Result<IDictionary<string, string>> Parse(string input)
|
2024-11-24 12:48:12 +01:00
|
|
|
|
{
|
|
|
|
|
|
return new PqConnectionStringParser(
|
|
|
|
|
|
new PqConnectionStringTokenizer(input)
|
|
|
|
|
|
).Parse();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-30 19:41:10 +02:00
|
|
|
|
private readonly IPqConnectionStringTokenizer _tokenizer;
|
|
|
|
|
|
private readonly Dictionary<string, string> _result = new();
|
2024-11-24 12:48:12 +01:00
|
|
|
|
|
|
|
|
|
|
public PqConnectionStringParser(IPqConnectionStringTokenizer tokenizer)
|
|
|
|
|
|
{
|
2025-08-30 19:41:10 +02:00
|
|
|
|
this._tokenizer = tokenizer;
|
2024-11-24 12:48:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-31 13:11:59 +02:00
|
|
|
|
public Result<IDictionary<string, string>> Parse()
|
2024-11-24 12:48:12 +01:00
|
|
|
|
{
|
2025-08-30 19:41:10 +02:00
|
|
|
|
_result.Clear();
|
2024-11-24 12:48:12 +01:00
|
|
|
|
|
2025-08-30 19:41:10 +02:00
|
|
|
|
while (!_tokenizer.IsEof)
|
2025-08-31 13:11:59 +02:00
|
|
|
|
{
|
|
|
|
|
|
var result = ParsePair();
|
|
|
|
|
|
if (result.IsFailed)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-11-24 12:48:12 +01:00
|
|
|
|
|
2025-08-30 19:41:10 +02:00
|
|
|
|
return _result;
|
2024-11-24 12:48:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-30 19:41:10 +02:00
|
|
|
|
private Result ParsePair()
|
2024-11-24 12:48:12 +01:00
|
|
|
|
{
|
2025-08-30 19:41:10 +02:00
|
|
|
|
var kwResult = _tokenizer.GetKeyword();
|
|
|
|
|
|
if (kwResult.IsFailed)
|
|
|
|
|
|
return kwResult.ToResult();
|
|
|
|
|
|
var result = _tokenizer.ConsumeEquals();
|
|
|
|
|
|
if (result.IsFailed)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
var valResult = _tokenizer.GetValue();
|
|
|
|
|
|
if (valResult.IsFailed)
|
|
|
|
|
|
return valResult.ToResult();
|
|
|
|
|
|
|
|
|
|
|
|
_result.Add(kwResult.Value, valResult.Value);
|
|
|
|
|
|
return Result.Ok();
|
2024-11-24 12:48:12 +01:00
|
|
|
|
}
|
2025-08-18 19:41:36 +02:00
|
|
|
|
|
|
|
|
|
|
private SslMode ToSslMode(ReadOnlySpan<char> v)
|
|
|
|
|
|
=> v switch
|
|
|
|
|
|
{
|
|
|
|
|
|
"disable" => SslMode.Disable,
|
|
|
|
|
|
"allow" => SslMode.Allow,
|
|
|
|
|
|
"prefer" => SslMode.Prefer,
|
|
|
|
|
|
"require" => SslMode.Require,
|
|
|
|
|
|
"verify-ca" => SslMode.VerifyCA,
|
|
|
|
|
|
"verify-full" => SslMode.VerifyFull,
|
|
|
|
|
|
_ => throw new ArgumentException("Not a valid SSL mode"),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-24 12:48:12 +01:00
|
|
|
|
}
|