use bytes::Bytes;
use sia_core::encoding;
use sia_core::rhp4::HostPrices;
use sia_core::rhp4::protocol::Error as RHP4Error;
use sia_core::signing::{PrivateKey, PublicKey};
use sia_core::types::Hash256;
use sia_core::types::v2::NetAddress;
use thiserror::Error;
use crate::time::{Duration, Elapsed};
#[cfg(not(target_arch = "wasm32"))]
mod siamux;
#[cfg(target_arch = "wasm32")]
mod web_transport;
#[cfg(any(test, feature = "mock"))]
pub(crate) mod mock;
#[derive(Clone)]
pub(crate) enum Client {
#[cfg(not(target_arch = "wasm32"))]
SiaMux(siamux::Client),
#[cfg(target_arch = "wasm32")]
WebTransport(web_transport::Client),
#[cfg(any(test, feature = "mock"))]
Mock(mock::Client),
}
impl Default for Client {
fn default() -> Self {
Self::new()
}
}
impl Client {
pub(crate) fn new() -> Self {
#[cfg(not(target_arch = "wasm32"))]
{
Self::SiaMux(siamux::Client::new())
}
#[cfg(target_arch = "wasm32")]
{
Self::WebTransport(web_transport::Client::new())
}
}
#[cfg(test)]
pub(crate) fn mock() -> Self {
Self::Mock(mock::Client::new())
}
}
impl Transport for Client {
async fn host_prices(&self, host: &HostEndpoint) -> Result<(HostPrices, Duration), Error> {
match self {
#[cfg(not(target_arch = "wasm32"))]
Self::SiaMux(c) => c.host_prices(host).await,
#[cfg(target_arch = "wasm32")]
Self::WebTransport(c) => c.host_prices(host).await,
#[cfg(any(test, feature = "mock"))]
Self::Mock(c) => c.host_prices(host).await,
}
}
async fn write_sector(
&self,
host: &HostEndpoint,
prices: HostPrices,
account_key: &PrivateKey,
sector: Bytes,
) -> Result<(Hash256, Duration), Error> {
match self {
#[cfg(not(target_arch = "wasm32"))]
Self::SiaMux(c) => c.write_sector(host, prices, account_key, sector).await,
#[cfg(target_arch = "wasm32")]
Self::WebTransport(c) => c.write_sector(host, prices, account_key, sector).await,
#[cfg(any(test, feature = "mock"))]
Self::Mock(c) => c.write_sector(host, prices, account_key, sector).await,
}
}
async fn read_sector(
&self,
host: &HostEndpoint,
prices: HostPrices,
account_key: &PrivateKey,
root: Hash256,
offset: usize,
length: usize,
) -> Result<(Bytes, Duration), Error> {
match self {
#[cfg(not(target_arch = "wasm32"))]
Self::SiaMux(c) => {
c.read_sector(host, prices, account_key, root, offset, length)
.await
}
#[cfg(target_arch = "wasm32")]
Self::WebTransport(c) => {
c.read_sector(host, prices, account_key, root, offset, length)
.await
}
#[cfg(any(test, feature = "mock"))]
Self::Mock(c) => {
c.read_sector(host, prices, account_key, root, offset, length)
.await
}
}
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("i/o error: {0}")]
Io(#[from] std::io::Error),
#[error("encoding error: {0}")]
Encoding(#[from] encoding::Error),
#[error("rhp error: {0}")]
Rpc(#[from] RHP4Error),
#[error("invalid prices")]
InvalidPrices,
#[error("invalid signature")]
InvalidSignature,
#[error("timeout error: {0}")]
Timeout(#[from] Elapsed),
#[error("transport error: {0}")]
Transport(String),
}
pub(crate) struct HostEndpoint {
pub public_key: PublicKey,
pub addresses: Vec<NetAddress>,
}
pub(crate) trait Transport: Clone + Unpin + MaybeSendSync + 'static {
fn host_prices(
&self,
host: &HostEndpoint,
) -> impl Future<Output = Result<(HostPrices, Duration), Error>> + MaybeSendSync;
fn write_sector(
&self,
host: &HostEndpoint,
prices: HostPrices,
account_key: &PrivateKey,
sector: Bytes,
) -> impl Future<Output = Result<(Hash256, Duration), Error>> + MaybeSendSync;
fn read_sector(
&self,
host: &HostEndpoint,
prices: HostPrices,
account_key: &PrivateKey,
root: Hash256,
offset: usize,
length: usize,
) -> impl Future<Output = Result<(Bytes, Duration), Error>> + MaybeSendSync;
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) trait MaybeSendSync: Send + Sync {}
#[cfg(not(target_arch = "wasm32"))]
impl<T: Send + Sync> MaybeSendSync for T {}
#[cfg(target_arch = "wasm32")]
pub(crate) trait MaybeSendSync {}
#[cfg(target_arch = "wasm32")]
impl<T> MaybeSendSync for T {}