zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use lazy_static::lazy_static;

pub mod rudis_client;
pub mod settings;

pub use rudis_client::*;
pub use settings::*;

use redis::sentinel::SentinelNodeConnectionInfo;
use redis::{ProtocolVersion, RedisConnectionInfo};
use regex::Regex;
use std::sync::Arc;
use tokio::sync::Mutex;

#[rustfmt::skip]
lazy_static! {
    static ref RE_CLUSTER: Regex = Regex::new(r#"(?P<protocol>redis(?:s)?)-cluster://(?:(?P<username>\w+):(?P<password>\w+)@)?(?P<hosts>[\w.:,]+)/(?P<db>\d+)"#).unwrap();
    static ref RE_SENTINEL: Regex = Regex::new(r#"(?P<protocol>redis(?:s)?)-sentinel://(?:(?P<username>\w+):(?P<password>\w+)@)?(?P<hosts>[\w.:,]+)/(?P<db>\d+)"#).unwrap();
}

pub async fn client(cfg: &Option<Settings>) -> Option<RuidsClient> {
    if let Some(cfg) = cfg {
        if cfg.is_disable() {
            return None;
        }

        let mode = cfg.mode();

        if mode == "standalone" {
            match redis::Client::open(cfg.connection_string()) {
                Ok(client) => {
                    let c = RuidsClient {
                        standalone_client: Some(client),
                        cluster_client: None,
                        sentinel_client: None,
                    };

                    match c.ping().await {
                        Ok(pong) => {
                            log::info!(
                                "RUDISCLIENT-STANDALONE: connection_string={}, ping={}",
                                cfg,
                                pong
                            );
                        }
                        Err(e) => {
                            log::error!(
                                "RUDISCLIENT-STANDALONE: connection_string={}, error={:?}",
                                cfg,
                                e
                            );
                        }
                    }

                    return Some(c);
                }
                Err(e) => {
                    log::error!("RUDIS-STANDALONE-CLIENT: cfg={}, error={:?}", cfg, e);
                    return None;
                }
            }
        } else if mode == "cluster" {
            if let Some(captures) = RE_CLUSTER.captures(&cfg.connection_string()) {
                let protocol = captures.name("protocol").map(|m| m.as_str()).unwrap_or("");
                // let username = captures.name("username").map(|m| m.as_str()).unwrap_or("");
                // let password = captures.name("password").map(|m| m.as_str()).unwrap_or("");
                let hosts = captures.name("hosts").map(|m| m.as_str()).unwrap_or("");
                // let db = captures.name("db").map(|m| m.as_str()).unwrap_or("");
                #[rustfmt::skip]
                let servers: Vec<String> = hosts.split(',').map(|s| format!("{}://{}/", protocol, s)).collect();

                match redis::cluster::ClusterClient::new(servers) {
                    Ok(client) => {
                        let c = RuidsClient {
                            standalone_client: None,
                            cluster_client: Some(client),
                            sentinel_client: None,
                        };

                        match c.ping().await {
                            Ok(pong) => {
                                log::info!(
                                    "RUDISCLIENT-STANDALONE: connection_string={}, ping={}",
                                    cfg,
                                    pong
                                );
                            }
                            Err(e) => {
                                log::error!(
                                    "RUDISCLIENT-STANDALONE: connection_string={}, error={:?}",
                                    cfg,
                                    e
                                );
                            }
                        }

                        return Some(c);
                    }
                    Err(e) => {
                        log::error!("RUDIS-CLUSTER-CLIENT: cfg={}, error={:?}", cfg, e);
                        return None;
                    }
                }
            } else {
                log::error!(
                    "RUDIS-CLUSTER-CLIENT: error=Invalid Connection String, cfg={}",
                    cfg
                );

                return None;
            }
        } else if mode == "sentinel" {
            if let Some(captures) = RE_SENTINEL.captures(&cfg.connection_string()) {
                #[rustfmt::skip]
                let protocol = captures.name("protocol").map(|m| m.as_str()).unwrap_or("");
                #[rustfmt::skip]
                let username = captures.name("username").map(|m| Some(m.as_str().to_string())).unwrap_or(None);
                #[rustfmt::skip]
                let password = captures.name("password").map(|m| Some(m.as_str().to_string())).unwrap_or(None);

                let hosts = captures.name("hosts").map(|m| m.as_str()).unwrap_or("");
                let db = captures.name("db").map(|m| m.as_str()).unwrap_or("0");

                #[rustfmt::skip]
                let servers: Vec<String> = hosts.split(',').map(|s| format!("{}://{}/", protocol, s)).collect();

                let service_name = String::from("master1");
                let server_type = redis::sentinel::SentinelServerType::Master;

                let node_connection_info = SentinelNodeConnectionInfo {
                    tls_mode: Some(redis::TlsMode::Insecure),
                    redis_connection_info: Some(RedisConnectionInfo {
                        db: crate::commons::string_to_number(db).unwrap_or(0),
                        username,
                        password,
                        protocol: ProtocolVersion::RESP2,
                    }),
                };

                match redis::sentinel::SentinelClient::build(
                    servers,
                    service_name,
                    Some(node_connection_info),
                    server_type,
                ) {
                    Ok(client) => {
                        let c = RuidsClient {
                            standalone_client: None,
                            cluster_client: None,
                            sentinel_client: Some(Arc::new(Mutex::new(client))),
                        };

                        match c.ping().await {
                            Ok(pong) => {
                                log::info!(
                                    "RUDISCLIENT-STANDALONE: connection_string={}, ping={}",
                                    cfg,
                                    pong
                                );
                            }
                            Err(e) => {
                                log::error!(
                                    "RUDISCLIENT-STANDALONE: connection_string={}, error={:?}",
                                    cfg,
                                    e
                                );
                            }
                        }

                        return Some(c);
                    }
                    Err(e) => {
                        log::error!("RUDIS-SENTINEL-CLIENT: cfg={}, error={:?}", cfg, e);
                        return None;
                    }
                }
            } else {
                log::error!(
                    "RUDIS-SENTINEL-CLIENT: error=Invalid Connection String, cfg={}",
                    cfg
                );

                return None;
            }
        } else {
            log::error!(
                "RUDISCLIENT-{}: cfg={}, error={}",
                mode,
                cfg,
                "Not-Supported!"
            );
        }
    }

    None
}