use crate::cmd::{cmd, Cmd};
use crate::connection::RedisConnectionInfo;
use crate::types::{ErrorKind, RedisFuture, RedisResult, Value};
use ::tokio::io::{AsyncRead, AsyncWrite};
use async_trait::async_trait;
use futures_util::Future;
use std::net::SocketAddr;
#[cfg(unix)]
use std::path::Path;
use std::pin::Pin;
#[cfg(feature = "async-std-comp")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-std-comp")))]
pub mod async_std;
#[cfg(feature = "tls-rustls")]
use crate::tls::TlsConnParams;
#[cfg(all(feature = "tls-native-tls", not(feature = "tls-rustls")))]
use crate::connection::TlsConnParams;
#[cfg(feature = "tokio-comp")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio-comp")))]
pub mod tokio;
#[async_trait]
pub(crate) trait RedisRuntime: AsyncStream + Send + Sync + Sized + 'static {
async fn connect_tcp(socket_addr: SocketAddr) -> RedisResult<Self>;
#[cfg(any(feature = "tls-native-tls", feature = "tls-rustls"))]
async fn connect_tcp_tls(
hostname: &str,
socket_addr: SocketAddr,
insecure: bool,
tls_params: &Option<TlsConnParams>,
) -> RedisResult<Self>;
#[cfg(unix)]
async fn connect_unix(path: &Path) -> RedisResult<Self>;
fn spawn(f: impl Future<Output = ()> + Send + 'static);
fn boxed(self) -> Pin<Box<dyn AsyncStream + Send + Sync>> {
Box::pin(self)
}
}
pub trait AsyncStream: AsyncRead + AsyncWrite {}
impl<S> AsyncStream for S where S: AsyncRead + AsyncWrite {}
pub trait ConnectionLike {
fn req_packed_command<'a>(&'a mut self, cmd: &'a Cmd) -> RedisFuture<'a, Value>;
#[doc(hidden)]
fn req_packed_commands<'a>(
&'a mut self,
cmd: &'a crate::Pipeline,
offset: usize,
count: usize,
) -> RedisFuture<'a, Vec<Value>>;
fn get_db(&self) -> i64;
}
async fn setup_connection<C>(connection_info: &RedisConnectionInfo, con: &mut C) -> RedisResult<()>
where
C: ConnectionLike,
{
if let Some(password) = &connection_info.password {
let mut command = cmd("AUTH");
if let Some(username) = &connection_info.username {
command.arg(username);
}
match command.arg(password).query_async(con).await {
Ok(Value::Okay) => (),
Err(e) => {
let err_msg = e.detail().ok_or((
ErrorKind::AuthenticationFailed,
"Password authentication failed",
))?;
if !err_msg.contains("wrong number of arguments for 'auth' command") {
fail!((
ErrorKind::AuthenticationFailed,
"Password authentication failed",
));
}
let mut command = cmd("AUTH");
match command.arg(password).query_async(con).await {
Ok(Value::Okay) => (),
_ => {
fail!((
ErrorKind::AuthenticationFailed,
"Password authentication failed"
));
}
}
}
_ => {
fail!((
ErrorKind::AuthenticationFailed,
"Password authentication failed"
));
}
}
}
if connection_info.db != 0 {
match cmd("SELECT").arg(connection_info.db).query_async(con).await {
Ok(Value::Okay) => (),
_ => fail!((
ErrorKind::ResponseError,
"Redis server refused to switch database"
)),
}
}
#[cfg(not(feature = "disable-client-setinfo"))]
let _: RedisResult<()> = crate::connection::client_set_info_pipeline()
.query_async(con)
.await;
Ok(())
}
mod connection;
pub use connection::*;
mod multiplexed_connection;
pub use multiplexed_connection::*;
#[cfg(feature = "connection-manager")]
mod connection_manager;
#[cfg(feature = "connection-manager")]
#[cfg_attr(docsrs, doc(cfg(feature = "connection-manager")))]
pub use connection_manager::*;
mod runtime;
pub(super) use runtime::*;