use std::fmt::Debug;
use redis::{Client, ConnectionAddr, ConnectionInfo, ProtocolVersion, RedisConnectionInfo};
#[allow(unused_imports)]
use super::result::{RedsumerError, RedsumerResult};
pub type CommunicationProtocol = ProtocolVersion;
#[derive(Clone)]
pub struct ClientCredentials {
user: String,
password: String,
}
impl ClientCredentials {
fn get_user(&self) -> &str {
&self.user
}
fn get_password(&self) -> &str {
&self.password
}
pub fn new(user: &str, password: &str) -> ClientCredentials {
ClientCredentials {
user: user.to_owned(),
password: password.to_owned(),
}
}
}
impl Debug for ClientCredentials {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClientCredentials")
.field("user", &self.user)
.field("password", &"****")
.finish()
}
}
#[derive(Debug, Clone)]
pub struct ClientArgs {
credentials: Option<ClientCredentials>,
host: String,
port: u16,
db: i64,
protocol: CommunicationProtocol,
}
impl ClientArgs {
pub fn get_credentials(&self) -> &Option<ClientCredentials> {
&self.credentials
}
pub fn get_host(&self) -> &str {
&self.host
}
pub fn get_port(&self) -> u16 {
self.port
}
pub fn get_db(&self) -> i64 {
self.db
}
pub fn get_protocol(&self) -> CommunicationProtocol {
self.protocol
}
pub fn new(
credentials: Option<ClientCredentials>,
host: &str,
port: u16,
db: i64,
protocol: CommunicationProtocol,
) -> ClientArgs {
ClientArgs {
credentials,
host: host.to_owned(),
port,
db,
protocol,
}
}
}
pub trait RedisClientBuilder {
fn build(&self) -> RedsumerResult<Client>;
}
impl RedisClientBuilder for ClientArgs {
fn build(&self) -> RedsumerResult<Client> {
let addr: ConnectionAddr =
ConnectionAddr::Tcp(String::from(self.get_host()), self.get_port());
let username: Option<String> = self
.get_credentials()
.to_owned()
.map(|c| c.get_user().to_string());
let password: Option<String> = self
.get_credentials()
.to_owned()
.map(|c| c.get_password().to_string());
let redis: RedisConnectionInfo = RedisConnectionInfo {
db: self.get_db(),
username,
password,
protocol: self.get_protocol(),
};
Client::open(ConnectionInfo { addr, redis })
}
}
#[cfg(test)]
mod test_client_credentials {
use super::*;
#[test]
fn test_client_credentials_builder_ok() {
let user: &str = "user";
let password: &str = "password";
let credentials: ClientCredentials = ClientCredentials::new(user, password);
assert_eq!(credentials.get_user(), user);
assert_eq!(credentials.get_password(), password);
}
#[test]
fn test_client_credentials_debug() {
let user: &str = "user";
let password: &str = "password";
let credentials: ClientCredentials = ClientCredentials::new(user, password);
assert_eq!(
format!("{:?}", credentials),
"ClientCredentials { user: \"user\", password: \"****\" }"
);
}
#[test]
fn test_client_credentials_clone() {
let user: &str = "user";
let password: &str = "password";
let credentials: ClientCredentials = ClientCredentials::new(user, password);
let cloned_credentials: ClientCredentials = credentials.clone();
assert_eq!(credentials.get_user(), cloned_credentials.get_user());
assert_eq!(
credentials.get_password(),
cloned_credentials.get_password()
);
}
}
#[cfg(test)]
mod test_client_args {
use super::*;
#[test]
fn test_client_args_builder_ok() {
let user: &str = "user";
let password: &str = "password";
let credentials: ClientCredentials = ClientCredentials::new(user, password);
let host: &str = "localhost";
let port: u16 = 6379;
let db: i64 = 1;
let protocol_version: CommunicationProtocol = CommunicationProtocol::RESP2;
let args: ClientArgs = ClientArgs::new(Some(credentials), host, port, db, protocol_version);
assert!(args.get_credentials().is_some());
assert_eq!(args.get_credentials().to_owned().unwrap().get_user(), user);
assert_eq!(
args.get_credentials().to_owned().unwrap().get_password(),
password
);
assert_eq!(args.get_host(), host);
assert_eq!(args.get_port(), port);
assert_eq!(args.get_db(), db);
}
#[test]
fn test_client_args_debug() {
let user: &str = "user";
let password: &str = "password";
let credentials: ClientCredentials = ClientCredentials::new(user, password);
let host: &str = "localhost";
let port: u16 = 6379;
let db: i64 = 1;
let protocol_version: CommunicationProtocol = CommunicationProtocol::RESP2;
let args: ClientArgs = ClientArgs::new(Some(credentials), host, port, db, protocol_version);
assert_eq!(format!("{:?}", args), "ClientArgs { credentials: Some(ClientCredentials { user: \"user\", password: \"****\" }), host: \"localhost\", port: 6379, db: 1, protocol: RESP2 }");
}
#[test]
fn test_client_args_clone() {
let user: &str = "user";
let password: &str = "password";
let credentials: ClientCredentials = ClientCredentials::new(user, password);
let host: &str = "localhost";
let port: u16 = 6379;
let db: i64 = 1;
let protocol_version: CommunicationProtocol = CommunicationProtocol::RESP2;
let args: ClientArgs = ClientArgs::new(Some(credentials), host, port, db, protocol_version);
let cloned_args: ClientArgs = args.clone();
assert_eq!(
args.get_credentials().to_owned().unwrap().get_user(),
cloned_args.get_credentials().to_owned().unwrap().get_user()
);
assert_eq!(
args.get_credentials().to_owned().unwrap().get_password(),
cloned_args
.get_credentials()
.to_owned()
.unwrap()
.get_password()
);
assert_eq!(args.get_host(), cloned_args.get_host());
assert_eq!(args.get_port(), cloned_args.get_port());
assert_eq!(args.get_db(), cloned_args.get_db());
assert_eq!(args.get_protocol(), cloned_args.get_protocol());
}
}
#[cfg(test)]
mod test_redis_client_builder {
use super::*;
#[test]
fn test_redis_client_builder_ok_with_null_credentials() {
let args: ClientArgs =
ClientArgs::new(None, "mylocalhost", 6377, 16, CommunicationProtocol::RESP2);
let client_result: RedsumerResult<Client> = args.build();
assert!(client_result.is_ok());
}
#[test]
fn test_redis_client_builder_ok_with_credentials() {
let args: ClientArgs = ClientArgs::new(
Some(ClientCredentials::new("user", "password")),
"mylocalhost",
6377,
16,
CommunicationProtocol::RESP2,
);
let client_result: RedsumerResult<Client> = args.build();
assert!(client_result.is_ok());
}
}