use crate::error::{ConnexaResult, Error};
use crate::handle::Connexa;
use crate::types::StreamCommand;
use bytes::Bytes;
use futures::channel::oneshot;
use libp2p::{PeerId, StreamProtocol};
pub struct ConnexaStream<'a, T, K> {
connexa: &'a Connexa<T, K>,
}
impl<'a, T, K> Copy for ConnexaStream<'a, T, K> {}
impl<'a, T, K> Clone for ConnexaStream<'a, T, K> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, T, K> ConnexaStream<'a, T, K>
where
T: Send + Sync + 'static,
{
pub(crate) fn new(connexa: &'a Connexa<T, K>) -> Self {
Self { connexa }
}
pub async fn new_stream(
&self,
protocol: StreamProtocol,
) -> ConnexaResult<libp2p_stream::IncomingStreams> {
let (tx, rx) = oneshot::channel();
self.connexa
.to_task
.clone()
.send(StreamCommand::NewStream { protocol, resp: tx }.into())
.await
.map_err(|_| Error::ChannelClosed)?;
rx.await.map_err(|_| Error::ChannelClosed)?
}
pub async fn control_handle(&self) -> ConnexaResult<libp2p_stream::Control> {
let (tx, rx) = oneshot::channel();
self.connexa
.to_task
.clone()
.send(StreamCommand::ControlHandle { resp: tx }.into())
.await
.map_err(|_| Error::ChannelClosed)?;
rx.await.map_err(|_| Error::ChannelClosed)?
}
pub async fn open_stream(
&self,
peer_id: PeerId,
protocol: impl IntoStreamProtocol,
) -> ConnexaResult<libp2p::Stream> {
let protocol: StreamProtocol = protocol.into_protocol()?;
let mut control = self.control_handle().await?;
let stream = control
.open_stream(peer_id, protocol)
.await
.map_err(std::io::Error::other)?;
Ok(stream)
}
}
pub trait IntoStreamProtocol {
fn into_protocol(self) -> std::io::Result<StreamProtocol>;
}
impl IntoStreamProtocol for StreamProtocol {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
Ok(self)
}
}
impl IntoStreamProtocol for String {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
StreamProtocol::try_from_owned(self).map_err(std::io::Error::other)
}
}
impl IntoStreamProtocol for &String {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
StreamProtocol::try_from_owned(self.to_owned()).map_err(std::io::Error::other)
}
}
impl IntoStreamProtocol for &'static str {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
Ok(StreamProtocol::new(self))
}
}
impl IntoStreamProtocol for Bytes {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
let protocol = String::from_utf8_lossy(&self).to_string();
protocol.into_protocol()
}
}
impl IntoStreamProtocol for &Bytes {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
let protocol = String::from_utf8_lossy(self).to_string();
protocol.into_protocol()
}
}
impl IntoStreamProtocol for Vec<u8> {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
let protocol = String::from_utf8_lossy(&self).to_string();
protocol.into_protocol()
}
}
impl IntoStreamProtocol for &[u8] {
fn into_protocol(self) -> std::io::Result<StreamProtocol> {
let protocol = String::from_utf8_lossy(self).to_string();
protocol.into_protocol()
}
}