use crate::app_state::{AppState, RaftType};
use crate::client::DbClient;
use crate::config::RateLimitConfig;
use crate::http_client::build_http_client;
use crate::{Client, Error, tls};
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, AtomicUsize};
use tokio::sync::{RwLock, watch};
#[cfg(feature = "listen_notify")]
use crate::client::listen_notify::remote::RemoteListener;
#[cfg(feature = "sqlite")]
use crate::client::stream::ClientStreamReq;
const RATE_LIMIT_AWAIT_SIZE: usize = 64;
impl Client {
#[allow(clippy::too_many_arguments)]
pub(crate) async fn new_local(
state: Arc<AppState>,
tls_config: Option<Arc<rustls::ClientConfig>>,
#[cfg(feature = "cache")] tls_no_verify: bool,
#[cfg(feature = "sqlite")] tx_client_db: flume::Sender<ClientStreamReq>,
#[cfg(feature = "sqlite")] rx_client_db: flume::Receiver<ClientStreamReq>,
tx_shutdown: watch::Sender<bool>,
#[cfg(feature = "cache")] rate_limit_cache: Option<RateLimitConfig>,
#[cfg(feature = "sqlite")] rate_limit_db: Option<RateLimitConfig>,
) -> Self {
let leader_id = state.id;
let leader_addr = state.addr_api.clone();
let secret = state.secret_api.as_bytes().to_vec();
#[cfg(feature = "cache")]
let leader_cache = Arc::new(RwLock::new((leader_id, leader_addr.clone())));
#[cfg(feature = "sqlite")]
let leader_db = Arc::new(RwLock::new((leader_id, leader_addr)));
#[cfg(feature = "cache")]
let (tx_client_cache, rx_client_cache) = flume::bounded(1);
#[allow(unused_variables)]
let (rate_limit_cache_await, rx_cache_await) =
crossbeam::channel::bounded(RATE_LIMIT_AWAIT_SIZE);
#[allow(unused_variables)]
let (rate_limit_db_await, rx_db_await) = crossbeam::channel::bounded(RATE_LIMIT_AWAIT_SIZE);
let db_client = DbClient {
state: Some(state),
#[cfg(feature = "cache")]
leader_cache,
#[cfg(feature = "sqlite")]
leader_db,
nodes: Vec::default(),
client: None,
#[cfg(feature = "cache")]
tx_client_cache,
#[cfg(feature = "sqlite")]
tx_client_db,
tls_config,
#[cfg(feature = "cache")]
tls_no_verify,
api_secret: None,
request_id: AtomicUsize::new(0),
tx_shutdown: Some(tx_shutdown),
#[cfg(feature = "listen_notify_local")]
app_start: chrono::Utc::now().timestamp_micros(),
#[cfg(feature = "listen_notify_local")]
rx_notify: None,
#[cfg(feature = "cache")]
rate_limit_cache: rate_limit_cache.as_ref().map(|c| AtomicU32::new(c.rps)),
#[cfg(feature = "cache")]
rate_limit_cache_await,
#[cfg(feature = "sqlite")]
rate_limit_db: rate_limit_db.as_ref().map(|c| AtomicU32::new(c.rps)),
#[cfg(feature = "sqlite")]
rate_limit_db_await,
};
let slf = Self {
inner: Arc::new(db_client),
};
slf.find_set_active_leader().await;
#[cfg(feature = "cache")]
slf.open_stream(
secret.clone(),
slf.inner.leader_cache.clone(),
rx_client_cache,
RaftType::Cache,
);
#[cfg(feature = "sqlite")]
slf.open_stream(
secret,
slf.inner.leader_db.clone(),
rx_client_db,
RaftType::Sqlite,
);
#[cfg(all(feature = "cache", feature = "sqlite"))]
slf.spawn_rate_limit_ticker(rate_limit_cache, rate_limit_db, rx_cache_await, rx_db_await);
#[cfg(all(feature = "cache", not(feature = "sqlite")))]
slf.spawn_rate_limit_ticker(rate_limit_cache, None, rx_cache_await, rx_db_await);
#[cfg(all(not(feature = "cache"), feature = "sqlite"))]
slf.spawn_rate_limit_ticker(None, rate_limit_db, rx_cache_await, rx_db_await);
slf
}
#[allow(clippy::too_many_arguments)]
pub async fn remote(
nodes: Vec<String>,
tls: bool,
tls_no_verify: bool,
api_secret: String,
with_proxy: bool,
#[cfg(feature = "cache")] rate_limit_cache: Option<RateLimitConfig>,
#[cfg(feature = "sqlite")] rate_limit_db: Option<RateLimitConfig>,
) -> Result<Self, Error> {
if nodes.is_empty() {
return Err(Error::Config(
"You must provide at least 1 node to connect to".into(),
));
}
let tls_config = if tls {
Some(tls::build_tls_config(tls_no_verify))
} else {
None
};
let node_id = 0;
let node_addr = nodes[0].clone();
#[cfg(feature = "cache")]
let leader_cache = Arc::new(RwLock::new((node_id, node_addr.clone())));
#[cfg(feature = "sqlite")]
let leader_db = Arc::new(RwLock::new((node_id, node_addr)));
#[cfg(feature = "sqlite")]
let (tx_client_db, rx_client_db) = flume::bounded(1);
#[cfg(feature = "cache")]
let (tx_client_cache, rx_client_cache) = flume::bounded(1);
#[cfg(feature = "listen_notify")]
let rx_notify = Some(RemoteListener::spawn(
leader_cache.clone(),
tls,
api_secret.clone(),
));
#[cfg(all(feature = "listen_notify_local", not(feature = "listen_notify")))]
let rx_notify = None;
#[allow(unused_variables)]
let (rate_limit_cache_await, rx_cache_await) =
crossbeam::channel::bounded(RATE_LIMIT_AWAIT_SIZE);
#[allow(unused_variables)]
let (rate_limit_db_await, rx_db_await) = crossbeam::channel::bounded(RATE_LIMIT_AWAIT_SIZE);
let api_secret_bytes = api_secret.as_bytes().to_vec();
let db_client = DbClient {
state: None,
#[cfg(feature = "sqlite")]
leader_db,
#[cfg(feature = "cache")]
leader_cache,
nodes,
client: Some(build_http_client(tls_no_verify)),
#[cfg(feature = "cache")]
tx_client_cache,
#[cfg(feature = "sqlite")]
tx_client_db,
tls_config,
#[cfg(feature = "cache")]
tls_no_verify,
api_secret: Some(api_secret),
request_id: AtomicUsize::new(0),
tx_shutdown: None,
#[cfg(feature = "listen_notify_local")]
app_start: chrono::Utc::now().timestamp_micros(),
#[cfg(feature = "listen_notify_local")]
rx_notify,
#[cfg(feature = "cache")]
rate_limit_cache: rate_limit_cache.as_ref().map(|c| AtomicU32::new(c.rps)),
#[cfg(feature = "cache")]
rate_limit_cache_await,
#[cfg(feature = "sqlite")]
rate_limit_db: rate_limit_db.as_ref().map(|c| AtomicU32::new(c.rps)),
#[cfg(feature = "sqlite")]
rate_limit_db_await,
};
let slf = Self {
inner: Arc::new(db_client),
};
if !with_proxy {
slf.find_set_active_leader().await;
}
#[cfg(feature = "cache")]
slf.open_stream(
api_secret_bytes.clone(),
slf.inner.leader_cache.clone(),
rx_client_cache,
RaftType::Cache,
);
#[cfg(feature = "sqlite")]
slf.open_stream(
api_secret_bytes,
slf.inner.leader_db.clone(),
rx_client_db,
RaftType::Sqlite,
);
#[cfg(all(feature = "cache", feature = "sqlite"))]
slf.spawn_rate_limit_ticker(rate_limit_cache, rate_limit_db, rx_cache_await, rx_db_await);
#[cfg(all(feature = "cache", not(feature = "sqlite")))]
slf.spawn_rate_limit_ticker(rate_limit_cache, None, rx_cache_await, rx_db_await);
#[cfg(all(not(feature = "cache"), feature = "sqlite"))]
slf.spawn_rate_limit_ticker(None, rate_limit_db, rx_cache_await, rx_db_await);
Ok(slf)
}
}