use alloc::borrow::Cow;
use core::{fmt, net::IpAddr, ops, panic::UnwindSafe, pin::Pin, str, time::Duration};
pub use smoldot::libp2p::read_write;
#[cfg(feature = "std")]
pub use smoldot::libp2p::with_buffers;
pub mod address_parse;
pub mod default;
mod with_prefix;
#[cfg(feature = "std")]
pub use default::DefaultPlatform;
pub use with_prefix::WithPrefix;
pub trait PlatformRef: UnwindSafe + Clone + Send + Sync + 'static {
type Delay: Future<Output = ()> + Send + 'static;
type Instant: Clone
+ ops::Add<Duration, Output = Self::Instant>
+ ops::Sub<Self::Instant, Output = Duration>
+ PartialOrd
+ Ord
+ PartialEq
+ Eq
+ Send
+ Sync
+ 'static;
type MultiStream: Send + Sync + 'static;
type Stream: Send + 'static;
type ReadWriteAccess<'a>: ops::DerefMut<Target = read_write::ReadWrite<Self::Instant>> + 'a;
type StreamErrorRef<'a>: fmt::Display + fmt::Debug;
type StreamConnectFuture: Future<Output = Self::Stream> + Send + 'static;
type MultiStreamConnectFuture: Future<Output = MultiStreamWebRtcConnection<Self::MultiStream>>
+ Send
+ 'static;
type StreamUpdateFuture<'a>: Future<Output = ()> + Send + 'a;
type NextSubstreamFuture<'a>: Future<Output = Option<(Self::Stream, SubstreamDirection)>>
+ Send
+ 'a;
fn now_from_unix_epoch(&self) -> Duration;
fn now(&self) -> Self::Instant;
fn fill_random_bytes(&self, buffer: &mut [u8]);
fn sleep(&self, duration: Duration) -> Self::Delay;
fn sleep_until(&self, when: Self::Instant) -> Self::Delay;
fn spawn_task(&self, task_name: Cow<str>, task: impl Future<Output = ()> + Send + 'static);
fn log<'a>(
&self,
log_level: LogLevel,
log_target: &'a str,
message: &'a str,
key_values: impl Iterator<Item = (&'a str, &'a dyn fmt::Display)>,
);
fn client_name(&'_ self) -> Cow<'_, str>;
fn client_version(&'_ self) -> Cow<'_, str>;
fn supports_connection_type(&self, connection_type: ConnectionType) -> bool;
fn connect_stream(&self, address: Address) -> Self::StreamConnectFuture;
fn connect_multistream(&self, address: MultiStreamAddress) -> Self::MultiStreamConnectFuture;
fn open_out_substream(&self, connection: &mut Self::MultiStream);
fn next_substream<'a>(
&self,
connection: &'a mut Self::MultiStream,
) -> Self::NextSubstreamFuture<'a>;
fn read_write_access<'a>(
&self,
stream: Pin<&'a mut Self::Stream>,
) -> Result<Self::ReadWriteAccess<'a>, Self::StreamErrorRef<'a>>;
fn wait_read_write_again<'a>(
&self,
stream: Pin<&'a mut Self::Stream>,
) -> Self::StreamUpdateFuture<'a>;
}
#[derive(Debug)]
pub enum LogLevel {
Error = 1,
Warn = 2,
Info = 3,
Debug = 4,
Trace = 5,
}
#[derive(Debug)]
pub struct MultiStreamWebRtcConnection<TConnection> {
pub connection: TConnection,
pub local_tls_certificate_sha256: [u8; 32],
}
#[derive(Debug)]
pub enum SubstreamDirection {
Inbound,
Outbound,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ConnectionType {
TcpIpv4,
TcpIpv6,
TcpDns,
WebSocketIpv4 {
remote_is_localhost: bool,
},
WebSocketIpv6 {
remote_is_localhost: bool,
},
WebSocketDns {
secure: bool,
remote_is_localhost: bool,
},
WebRtcIpv4,
WebRtcIpv6,
}
impl<'a> From<&'a Address<'a>> for ConnectionType {
fn from(address: &'a Address<'a>) -> ConnectionType {
match address {
Address::TcpIp {
ip: IpAddr::V4(_), ..
} => ConnectionType::TcpIpv4,
Address::TcpIp {
ip: IpAddr::V6(_), ..
} => ConnectionType::TcpIpv6,
Address::TcpDns { .. } => ConnectionType::TcpDns,
Address::WebSocketIp {
ip: IpAddr::V4(ip), ..
} => ConnectionType::WebSocketIpv4 {
remote_is_localhost: ip.is_loopback(),
},
Address::WebSocketIp {
ip: IpAddr::V6(ip), ..
} => ConnectionType::WebSocketIpv6 {
remote_is_localhost: ip.is_loopback(),
},
Address::WebSocketDns {
hostname, secure, ..
} => ConnectionType::WebSocketDns {
secure: *secure,
remote_is_localhost: hostname.eq_ignore_ascii_case("localhost"),
},
}
}
}
impl<'a> From<&'a MultiStreamAddress<'a>> for ConnectionType {
fn from(address: &'a MultiStreamAddress) -> ConnectionType {
match address {
MultiStreamAddress::WebRtc {
ip: IpAddr::V4(_), ..
} => ConnectionType::WebRtcIpv4,
MultiStreamAddress::WebRtc {
ip: IpAddr::V6(_), ..
} => ConnectionType::WebRtcIpv6,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Address<'a> {
TcpDns {
hostname: &'a str,
port: u16,
},
TcpIp {
ip: IpAddr,
port: u16,
},
WebSocketIp {
ip: IpAddr,
port: u16,
},
WebSocketDns {
hostname: &'a str,
port: u16,
secure: bool,
},
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MultiStreamAddress<'a> {
WebRtc {
ip: IpAddr,
port: u16,
remote_certificate_sha256: &'a [u8; 32],
},
}
#[macro_export]
macro_rules! log_inner {
() => {
core::iter::empty()
};
(,) => {
core::iter::empty()
};
($key:ident = $value:expr) => {
$crate::log_inner!($key = $value,)
};
($key:ident = ?$value:expr) => {
$crate::log_inner!($key = ?$value,)
};
($key:ident) => {
$crate::log_inner!($key = $key,)
};
(?$key:ident) => {
$crate::log_inner!($key = ?$key,)
};
($key:ident = $value:expr, $($rest:tt)*) => {
core::iter::once((stringify!($key), &$value as &dyn core::fmt::Display)).chain($crate::log_inner!($($rest)*))
};
($key:ident = ?$value:expr, $($rest:tt)*) => {
core::iter::once((stringify!($key), &format_args!("{:?}", $value) as &dyn core::fmt::Display)).chain($crate::log_inner!($($rest)*))
};
($key:ident, $($rest:tt)*) => {
$crate::log_inner!($key = $key, $($rest)*)
};
(?$key:ident, $($rest:tt)*) => {
$crate::log_inner!($key = ?$key, $($rest)*)
};
}
#[macro_export]
macro_rules! log {
($plat:expr, $level:ident, $target:expr, $message:expr) => {
log!($plat, $level, $target, $message,)
};
($plat:expr, $level:ident, $target:expr, $message:expr, $($params:tt)*) => {
$crate::platform::PlatformRef::log(
$plat,
$crate::platform::LogLevel::$level,
$target,
AsRef::<str>::as_ref(&$message),
$crate::log_inner!($($params)*)
)
};
}