use std::collections::HashSet;
use std::hash::Hash;
use std::time::Duration;
use crate::adapters::IntoAdapterVec;
use crate::conn::{LdapConnAsync, LdapConnSettings};
use crate::controls_impl::IntoRawControlVec;
use crate::exop::Exop;
use crate::ldap::{Ldap, Mod};
use crate::result::{CompareResult, ExopResult, LdapResult, Result, SearchResult};
use crate::search::{ResultEntry, Scope, SearchOptions, SearchStream};
use crate::RequestId;
use tokio::runtime::{self, Runtime};
use url::Url;
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
#[derive(Debug)]
pub struct LdapConn {
rt: Runtime,
ldap: Ldap,
}
impl LdapConn {
pub fn new(url: &str) -> Result<Self> {
Self::with_settings(LdapConnSettings::new(), url)
}
pub fn with_settings(settings: LdapConnSettings, url: &str) -> Result<Self> {
let url = Url::parse(url)?;
Self::from_url_with_settings(settings, &url)
}
pub fn from_url(url: &Url) -> Result<Self> {
Self::from_url_with_settings(LdapConnSettings::new(), url)
}
pub fn from_url_with_settings(settings: LdapConnSettings, url: &Url) -> Result<Self> {
let rt = runtime::Builder::new_current_thread()
.enable_all()
.build()?;
let ldap = rt.block_on(async move {
let (conn, ldap) = match LdapConnAsync::from_url_with_settings(settings, url).await {
Ok((conn, ldap)) => (conn, ldap),
Err(e) => return Err(e),
};
super::drive!(conn);
Ok(ldap)
})?;
Ok(LdapConn { ldap, rt })
}
pub fn with_search_options(&mut self, opts: SearchOptions) -> &mut Self {
self.ldap.search_opts = Some(opts);
self
}
pub fn with_controls<V: IntoRawControlVec>(&mut self, ctrls: V) -> &mut Self {
self.ldap.controls = Some(ctrls.into());
self
}
pub fn with_timeout(&mut self, duration: Duration) -> &mut Self {
self.ldap.timeout = Some(duration);
self
}
pub fn simple_bind(&mut self, bind_dn: &str, bind_pw: &str) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.simple_bind(bind_dn, bind_pw).await })
}
pub fn sasl_external_bind(&mut self) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.sasl_external_bind().await })
}
#[cfg_attr(docsrs, doc(cfg(feature = "gssapi")))]
#[cfg(feature = "gssapi")]
pub fn sasl_gssapi_bind(&mut self, server_fqdn: &str) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.sasl_gssapi_bind(server_fqdn).await })
}
pub fn search<'a, S: AsRef<str> + Send + Sync + 'a, A: AsRef<[S]> + Send + Sync + 'a>(
&mut self,
base: &str,
scope: Scope,
filter: &str,
attrs: A,
) -> Result<SearchResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.search(base, scope, filter, attrs).await })
}
pub fn streaming_search<
'a,
'b,
S: AsRef<str> + Send + Sync + 'a,
A: AsRef<[S]> + Send + Sync + 'a,
>(
&'b mut self,
base: &str,
scope: Scope,
filter: &str,
attrs: A,
) -> Result<EntryStream<'a, 'b, S, A>> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
let stream =
rt.block_on(async move { ldap.streaming_search(base, scope, filter, attrs).await })?;
Ok(EntryStream { stream, conn: self })
}
pub fn streaming_search_with<
'a,
'b,
V: IntoAdapterVec<'a, S, A>,
S: AsRef<str> + Send + Sync + 'a,
A: AsRef<[S]> + Send + Sync + 'a,
>(
&'b mut self,
adapters: V,
base: &str,
scope: Scope,
filter: &str,
attrs: A,
) -> Result<EntryStream<'a, 'b, S, A>> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
let stream = rt.block_on(async move {
ldap.streaming_search_with(adapters.into(), base, scope, filter, attrs)
.await
})?;
Ok(EntryStream { stream, conn: self })
}
pub fn add<S: AsRef<[u8]> + Eq + Hash>(
&mut self,
dn: &str,
attrs: Vec<(S, HashSet<S>)>,
) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.add(dn, attrs).await })
}
pub fn compare<B: AsRef<[u8]>>(
&mut self,
dn: &str,
attr: &str,
val: B,
) -> Result<CompareResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.compare(dn, attr, val).await })
}
pub fn delete(&mut self, dn: &str) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.delete(dn).await })
}
pub fn modify<S: AsRef<[u8]> + Eq + Hash>(
&mut self,
dn: &str,
mods: Vec<Mod<S>>,
) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.modify(dn, mods).await })
}
pub fn modifydn(
&mut self,
dn: &str,
rdn: &str,
delete_old: bool,
new_sup: Option<&str>,
) -> Result<LdapResult> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.modifydn(dn, rdn, delete_old, new_sup).await })
}
pub fn unbind(&mut self) -> Result<()> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.unbind().await })
}
pub fn extended<E>(&mut self, exop: E) -> Result<ExopResult>
where
E: Into<Exop>,
{
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.extended(exop).await })
}
pub fn last_id(&mut self) -> RequestId {
self.ldap.last_id()
}
pub fn abandon(&mut self, msgid: RequestId) -> Result<()> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.abandon(msgid).await })
}
pub fn is_closed(&mut self) -> bool {
self.ldap.tx.is_closed()
}
pub fn get_peer_certificate(&mut self) -> Result<Option<Vec<u8>>> {
let rt = &mut self.rt;
let ldap = &mut self.ldap;
rt.block_on(async move { ldap.get_peer_certificate().await })
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
pub struct EntryStream<'a, 'b, S, A> {
stream: SearchStream<'a, S, A>,
conn: &'b mut LdapConn,
}
impl<'a, 'b, S, A> EntryStream<'a, 'b, S, A>
where
S: AsRef<str> + Send + Sync + 'a,
A: AsRef<[S]> + Send + Sync + 'a,
{
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<Option<ResultEntry>> {
let rt = &mut self.conn.rt;
let stream = &mut self.stream;
rt.block_on(async move { stream.next().await })
}
pub fn result(mut self) -> LdapResult {
let rt = &mut self.conn.rt;
let stream = &mut self.stream;
rt.block_on(async move { stream.finish().await })
}
pub fn last_id(&mut self) -> RequestId {
self.stream.ldap_handle().last_id()
}
}