pgLabII/pgLabII.PgUtils/ConnectionStrings/CodecCommon.cs

101 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Npgsql;
namespace pgLabII.PgUtils.ConnectionStrings;
/// <summary>
/// Shared helper utilities for codecs to reduce duplication (SSL mode mapping, host:port parsing/formatting,
/// URL query parsing, and .NET/libpq quoting helpers).
/// </summary>
internal static class CodecCommon
{
// SSL mapping
public static SslMode ParseSslModeLoose(string s)
=> s.Trim().ToLowerInvariant() switch
{
"disable" => SslMode.Disable,
"allow" => SslMode.Allow,
"prefer" => SslMode.Prefer,
"require" => SslMode.Require,
"verify-ca" or "verifyca" => SslMode.VerifyCA,
"verify-full" or "verifyfull" => SslMode.VerifyFull,
_ => throw new ArgumentException($"Not a valid SSL Mode: {s}")
};
public static string FormatSslModeUrlLike(SslMode mode) => mode switch
{
SslMode.Disable => "disable",
SslMode.Allow => "allow",
SslMode.Prefer => "prefer",
SslMode.Require => "require",
SslMode.VerifyCA => "verify-ca",
SslMode.VerifyFull => "verify-full",
_ => "prefer"
};
// host:port parsing for plain or [IPv6]:port
public static void ParseHostPort(string hostPart, out string host, out ushort? port)
{
host = hostPart;
port = null;
if (string.IsNullOrWhiteSpace(hostPart))
return;
if (hostPart[0] == '[')
{
int end = hostPart.IndexOf(']');
if (end > 0)
{
host = hostPart[1..end];
if (end + 1 < hostPart.Length && hostPart[end + 1] == ':')
{
string ps = hostPart[(end + 2)..];
if (ushort.TryParse(ps, NumberStyles.Integer, CultureInfo.InvariantCulture, out var p))
port = p;
}
}
return;
}
int colon = hostPart.LastIndexOf(':');
if (colon > 0 && colon < hostPart.Length - 1)
{
var ps = hostPart.Substring(colon + 1);
if (ushort.TryParse(ps, NumberStyles.Integer, CultureInfo.InvariantCulture, out var p))
{
host = hostPart.Substring(0, colon);
port = p;
}
}
}
public static string FormatHost(HostEndpoint h)
{
var host = h.Host;
if (host.Contains(':') && !host.StartsWith("["))
host = "[" + host + "]"; // IPv6
return h.Port.HasValue ? host + ":" + h.Port.Value.ToString(CultureInfo.InvariantCulture) : host;
}
public static string[] SplitHosts(string hostList)
=> hostList.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
public static Dictionary<string, string> ParseQuery(string query)
{
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrEmpty(query)) return dict;
foreach (var kv in query.Split('&', StringSplitOptions.RemoveEmptyEntries))
{
var parts = kv.Split('=', 2);
var key = Uri.UnescapeDataString(parts[0]);
var val = parts.Length > 1 ? Uri.UnescapeDataString(parts[1]) : string.Empty;
dict[key] = val;
}
return dict;
}
}