using System.Collections.ObjectModel; using FluentResults; using Npgsql; namespace pgLabII.PgUtils.ConnectionStrings; /// /// Parser for converting a libpq style connection string into a dictionary of key value pairs /// public ref struct PqConnectionStringParser { // 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 public static IDictionary Parse(string input) { return new PqConnectionStringParser( new PqConnectionStringTokenizer(input) ).Parse(); } private readonly IPqConnectionStringTokenizer _tokenizer; private readonly Dictionary _result = new(); public PqConnectionStringParser(IPqConnectionStringTokenizer tokenizer) { this._tokenizer = tokenizer; } public IDictionary Parse() { _result.Clear(); while (!_tokenizer.IsEof) ParsePair(); return _result; } private Result ParsePair() { 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(); } private SslMode ToSslMode(ReadOnlySpan 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"), }; }