use std::sync::RwLock;
use tokio::runtime::Handle;
use vibe_ready::VibeLogListener;
use crate::inner::inner_net::InnerNet;
use crate::net_error::NetError;
use crate::network_status::NetworkStatus;
pub type NetworkStatusListener = Box<dyn Fn(NetworkStatus) + Send + Sync + 'static>;
pub type LogListener = VibeLogListener;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NetworkStatusListenerHandle(u64);
impl NetworkStatusListenerHandle {
pub(crate) fn from_raw(id: u64) -> Self {
Self(id)
}
}
pub struct Net {
inner: RwLock<Option<InnerNet>>,
}
impl Default for Net {
fn default() -> Self {
Self::new()
}
}
impl Net {
pub fn new() -> Net {
Net {
inner: RwLock::new(None),
}
}
pub async fn start(&self) -> Result<(), NetError> {
self.start_inner(InnerNet::new).await
}
pub async fn start_with_tokio_rt(&self, runtime_handle: Handle) -> Result<(), NetError> {
self.start_inner(move || InnerNet::new_with_tokio_rt(runtime_handle))
.await
}
async fn start_inner<F>(&self, factory: F) -> Result<(), NetError>
where
F: FnOnce() -> Result<InnerNet, NetError>,
{
let initial_state = {
let mut guard = self.inner.write().map_err(NetError::from_poison)?;
if guard.is_none() {
let candidate = factory()?;
*guard = Some(candidate);
}
match guard.as_ref() {
Some(inner) => Some(inner.begin()?),
None => None,
}
};
if let Some(initial_state) = initial_state {
InnerNet::wait_for_initial_state(initial_state).await;
}
Ok(())
}
pub fn shutdown(&self) -> Result<(), NetError> {
let inner = self.inner.write().map_err(NetError::from_poison)?.take();
if let Some(inner) = inner {
inner.shutdown()?;
}
Ok(())
}
pub fn local_network_reachability(&self) -> Result<NetworkStatus, NetError> {
match self.inner.read().map_err(NetError::from_poison)?.as_ref() {
Some(inner) => inner.local_network_reachability(),
None => Ok(NetworkStatus::default()),
}
}
pub fn register(
&self,
listener: NetworkStatusListener,
) -> Result<Option<NetworkStatusListenerHandle>, NetError> {
match self.inner.read().map_err(NetError::from_poison)?.as_ref() {
Some(inner) => inner.register(listener).map(Some),
None => Ok(None),
}
}
pub fn unregister(&self, handle: NetworkStatusListenerHandle) -> Result<bool, NetError> {
match self.inner.read().map_err(NetError::from_poison)?.as_ref() {
Some(inner) => inner.unregister(handle),
None => Ok(false),
}
}
pub fn clear_all_listener(&self) -> Result<(), NetError> {
match self.inner.read().map_err(NetError::from_poison)?.as_ref() {
Some(inner) => inner.clear_all_listener(),
None => Err(NetError::NotStarted),
}
}
pub fn is_started(&self) -> bool {
match self.inner.read() {
Ok(guard) => guard.is_some(),
Err(_) => false,
}
}
pub fn is_shutdown(&self) -> bool {
!self.is_started()
}
pub fn get_current_network_name(&self) -> Result<Option<String>, NetError> {
match self.inner.read().map_err(NetError::from_poison)?.as_ref() {
Some(inner) => inner.get_current_network_name(),
None => Ok(None),
}
}
pub fn set_log_listener(&self, listener: Option<LogListener>) -> Result<(), NetError> {
match self.inner.read().map_err(NetError::from_poison)?.as_ref() {
Some(inner) => {
inner.set_log_listener(listener);
Ok(())
}
None => Err(NetError::NotStarted),
}
}
}