use lazy_static::lazy_static;
pub mod redis_client;
pub mod redis_client_cluster;
pub mod redis_client_sentinel;
pub mod redis_client_standalone;
pub mod with_rs;
pub use redis_client::*;
pub use with_rs::*;
lazy_static! {
static ref RE: regex::Regex =
regex::Regex::new(r#"^(redis(s)?)(-[a-z]+)?://((\w+)?(:(\w+))?@)?([^?]+)(\?([\w\W]*))?"#,)
.unwrap();
}
#[derive(serde::Deserialize, Clone, Debug)]
pub struct RedisSettings {
pub enable: Option<bool>,
pub server: Option<String>,
}
#[derive(serde::Deserialize, Clone, Debug)]
pub struct Schema {
pub schema: String,
pub mode: String,
pub username: String,
pub passwd: String,
pub host: Vec<String>,
pub db: i64,
pub opt: Vec<String>,
}
impl Default for RedisSettings {
fn default() -> Self {
Self {
enable: Some(false),
server: Some("rediss://127.0.0.1:6379/0".to_string()),
}
}
}
impl RedisSettings {
pub fn is_enable(&self) -> bool {
if let Some(enable) = &self.enable {
*enable
} else {
false
}
}
pub fn server(&self) -> String {
self.server.clone().unwrap()
}
pub fn get(settings: &Option<RedisSettings>) -> Self {
let _default = Self::default();
if settings.is_some() {
let mut s = settings.clone().unwrap();
if s.enable.is_none() {
s.enable = _default.enable;
}
if s.server.is_none() {
s.server = _default.server;
}
s
} else {
_default
}
}
}
impl Schema {
pub fn is_standalone(&self) -> bool {
self.mode == "-standalone"
}
pub fn is_cluster(&self) -> bool {
self.mode == "-cluster"
}
pub fn is_sentinel(&self) -> bool {
self.mode == "-sentinel"
}
pub fn connection_string_standalone(&self) -> String {
format!("{}://{}", self.schema, self.host[0])
}
pub fn connection_servers(&self) -> Vec<String> {
self.host
.iter()
.map(|s| format!("{}://{}/", self.schema, s))
.collect()
}
pub fn username(&self) -> Option<String> {
if self.username.is_empty() {
None
} else {
Some(self.username.to_owned())
}
}
pub fn passwd(&self) -> Option<String> {
if self.passwd.is_empty() {
None
} else {
Some(self.passwd.to_owned())
}
}
pub fn master_name(&self) -> String {
let o: Vec<&String> = self
.opt
.iter()
.filter(|&s| s.starts_with("master_name="))
.collect::<Vec<_>>();
if o.is_empty() {
return "".to_string();
}
match o[0].find('=') {
Some(i) => o[0][i + 1..].to_string(),
None => "".to_string(),
}
}
pub fn parse_schema(connection_string: &str) -> Schema {
let captures = RE.captures(connection_string).unwrap();
let schema = captures.get(1).map_or("", |m| m.as_str());
let mode = captures.get(3).map_or("-standalone", |m| m.as_str());
let username = captures.get(5).map_or("", |m| m.as_str());
let passwd = captures.get(7).map_or("", |m| m.as_str());
let host = captures.get(8).map_or("127.0.0.1", |m| m.as_str());
let opt = captures.get(10).map_or("", |m| m.as_str());
let (host, db) = match host.find('/') {
None => (host, "0"),
Some(i) => (&host[..i], &host[i + 1..]),
};
let db = match db.parse::<i64>() {
Ok(db) => db,
Err(e) => {
log::error!("db={}, connection_string={}", db, connection_string);
panic!("parse_schema: error={:?}", e);
}
};
let host: Vec<String> = host
.split(',')
.collect::<Vec<&str>>()
.iter()
.map(|&s| String::from(s.trim()))
.collect();
let opt: Vec<String> = opt
.split('&')
.collect::<Vec<&str>>()
.iter()
.filter(|s| !s.trim().is_empty())
.map(|&s| String::from(s.trim()))
.collect();
Schema {
schema: schema.to_owned(),
mode: mode.to_owned(),
username: username.to_owned(),
passwd: passwd.to_owned(),
host,
db,
opt,
}
}
}
impl std::fmt::Display for Schema {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}://", self.schema)?;
if !self.username.is_empty() {
f.write_str(&self.username)?;
}
if !self.passwd.is_empty() {
write!(f, ":******@")?;
}
f.write_str(&self.host.join(","))?;
write!(f, "/{}", self.db)?;
if !self.opt.is_empty() {
write!(f, "?{}", &self.opt.join("&"))?;
}
Ok(())
}
}