rework redis options

This commit is contained in:
Robin Appelman 2025-04-30 18:17:43 +02:00
commit 88b64b402d
5 changed files with 86 additions and 213 deletions

View file

@ -1,6 +1,7 @@
mod nc;
use form_urlencoded::Serializer;
use itertools::Either;
use miette::Diagnostic;
use std::iter::once;
use std::path::PathBuf;
@ -19,50 +20,42 @@ pub struct Config {
#[derive(Debug)]
pub enum RedisConfig {
Single(RedisConnectionInfo),
Cluster(Vec<RedisConnectionInfo>),
Cluster(RedisClusterConnectionInfo),
}
impl RedisConfig {
pub fn as_single(&self) -> Option<RedisConnectionInfo> {
match self {
RedisConfig::Single(single) => Some(single.clone()),
RedisConfig::Cluster(cluster) => cluster.iter().next(),
}
}
}
#[derive(Clone, Debug)]
pub enum RedisConnectionAddr {
Tcp {
host: String,
port: u16,
},
TcpTls {
host: String,
port: u16,
tls_params: Option<RedisTlsParams>,
},
Unix {
path: PathBuf,
},
Tcp { host: String, port: u16 },
Unix { path: PathBuf },
}
impl RedisConnectionAddr {
pub fn with_tls(self, tls_params: RedisTlsParams) -> Self {
match self {
RedisConnectionAddr::Tcp { host, port }
| RedisConnectionAddr::TcpTls { host, port, .. } => RedisConnectionAddr::TcpTls {
host,
port,
tls_params: Some(tls_params),
},
unix => unix,
}
}
#[derive(Clone, Debug)]
pub struct RedisClusterConnectionInfo {
pub addr: Vec<RedisConnectionAddr>,
pub db: i64,
pub username: Option<String>,
pub password: Option<String>,
pub tls_params: Option<RedisTlsParams>,
}
pub fn with_tls_opt(self, tls_params: Option<RedisTlsParams>) -> Self {
if let Some(params) = tls_params {
self.with_tls(params)
} else {
match self {
RedisConnectionAddr::Tcp { host, port }
| RedisConnectionAddr::TcpTls { host, port, .. } => {
RedisConnectionAddr::Tcp { host, port }
}
unix => unix,
}
}
impl RedisClusterConnectionInfo {
pub fn iter(&self) -> impl Iterator<Item = RedisConnectionInfo> + '_ {
self.addr.iter().cloned().map(|addr| RedisConnectionInfo {
addr,
db: self.db,
username: self.username.clone(),
password: self.password.clone(),
tls_params: self.tls_params.clone(),
})
}
}
@ -72,9 +65,10 @@ pub struct RedisConnectionInfo {
pub db: i64,
pub username: Option<String>,
pub password: Option<String>,
pub tls_params: Option<RedisTlsParams>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct RedisTlsParams {
pub local_cert: Option<PathBuf>,
pub local_pk: Option<PathBuf>,
@ -85,44 +79,37 @@ pub struct RedisTlsParams {
impl RedisConfig {
pub fn addr(&self) -> impl Iterator<Item = &RedisConnectionAddr> {
let boxed: Box<dyn Iterator<Item = &RedisConnectionAddr>> = match self {
RedisConfig::Single(conn) => Box::new(once(&conn.addr)),
RedisConfig::Cluster(conns) => Box::new(conns.iter().map(|conn| &conn.addr)),
};
boxed
match self {
RedisConfig::Single(conn) => Either::Left(once(&conn.addr)),
RedisConfig::Cluster(cluster) => Either::Right(cluster.addr.iter()),
}
}
pub fn db(&self) -> i64 {
match self {
RedisConfig::Single(conn) => conn.db,
RedisConfig::Cluster(conns) => conns.first().map(|conn| conn.db).unwrap_or_default(),
RedisConfig::Cluster(cluster) => cluster.db,
}
}
pub fn username(&self) -> Option<&str> {
match self {
RedisConfig::Single(conn) => conn.username.as_deref(),
RedisConfig::Cluster(conns) => conns
.first()
.map(|conn| conn.username.as_deref())
.unwrap_or_default(),
RedisConfig::Cluster(cluster) => cluster.username.as_deref(),
}
}
pub fn passwd(&self) -> Option<&str> {
match self {
RedisConfig::Single(conn) => conn.password.as_deref(),
RedisConfig::Cluster(conns) => conns
.first()
.map(|conn| conn.password.as_deref())
.unwrap_or_default(),
RedisConfig::Cluster(cluster) => cluster.password.as_deref(),
}
}
pub fn into_vec(self) -> Vec<RedisConnectionInfo> {
pub fn is_empty(&self) -> bool {
match self {
RedisConfig::Single(conn) => vec![conn],
RedisConfig::Cluster(vec) => vec,
RedisConfig::Single(_) => false,
RedisConfig::Cluster(cluster) => cluster.addr.is_empty(),
}
}
}

View file

@ -1,6 +1,6 @@
use crate::{
Config, Database, DbConnect, DbError, Error, NotAConfigError, PhpParseError,
RedisConnectionInfo, RedisTlsParams, Result, SslOptions,
RedisClusterConnectionInfo, RedisConnectionInfo, RedisTlsParams, Result, SslOptions,
};
use crate::{RedisConfig, RedisConnectionAddr};
use php_literal_parser::Value;
@ -343,8 +343,7 @@ fn parse_redis_options(parsed: &Value) -> RedisConfig {
local_cert: ssl_options["local_cert"].as_str().map(From::from),
local_pk: ssl_options["local_pk"].as_str().map(From::from),
ca_file: ssl_options["cafile"].as_str().map(From::from),
accept_invalid_hostname: ssl_options["allow_self_signed"] == true
|| ssl_options["verify_peer_name"] == false,
accept_invalid_hostname: ssl_options["verify_peer_name"] == false,
insecure: ssl_options["verify_peer "] == false,
})
} else {
@ -363,22 +362,19 @@ fn parse_redis_options(parsed: &Value) -> RedisConfig {
match address {
RedisAddress::Single(addr) => RedisConfig::Single(RedisConnectionInfo {
addr: addr.with_tls_opt(tls_params),
addr,
db,
username,
password,
tls_params,
}),
RedisAddress::Cluster(addr) => RedisConfig::Cluster(RedisClusterConnectionInfo {
addr,
db,
username,
password,
tls_params,
}),
RedisAddress::Cluster(addresses) => RedisConfig::Cluster(
addresses
.into_iter()
.map(|addr| RedisConnectionInfo {
addr: addr.with_tls_opt(tls_params.clone()),
db,
username: username.clone(),
password: password.clone(),
})
.collect(),
),
}
}