use std::fmt::Display;
use std::io::Cursor;
use amplify::Bipolar;
use internet2::addr::{LocalNode, NodeAddr};
use internet2::presentation::{self, Unmarshall};
use internet2::session::{BrontideSession, BrontozaurSession, LocalSession, Split};
use internet2::{session, transport, SendRecvMessage, TypedEnum};
pub trait RecvMessage {
fn recv_message<D>(&mut self, d: &D) -> Result<D::Data, presentation::Error>
where
D: Unmarshall,
<D as Unmarshall>::Data: Display,
<D as Unmarshall>::Error: Into<presentation::Error>;
}
pub trait SendMessage {
fn send_message(
&mut self,
message: impl TypedEnum + Display,
) -> Result<usize, presentation::Error>;
}
pub struct PeerConnection {
session: Box<dyn SendRecvMessage>,
}
pub struct PeerReceiver {
receiver: Box<dyn session::RecvMessage + Send>,
}
pub struct PeerSender {
sender: Box<dyn session::SendMessage + Send>,
}
impl PeerConnection {
pub fn with(session: impl SendRecvMessage + 'static) -> Self {
Self { session: Box::new(session) }
}
pub fn connect_brontide(local: LocalNode, remote: NodeAddr) -> Result<Self, transport::Error> {
BrontideSession::connect(local.private_key(), remote).map(PeerConnection::with)
}
pub fn connect_brontozaur(
local: LocalNode,
remote: NodeAddr,
) -> Result<Self, transport::Error> {
BrontozaurSession::connect(local.private_key(), remote).map(PeerConnection::with)
}
}
impl RecvMessage for PeerConnection {
fn recv_message<D>(&mut self, d: &D) -> Result<D::Data, presentation::Error>
where
D: Unmarshall,
<D as Unmarshall>::Data: Display,
<D as Unmarshall>::Error: Into<presentation::Error>,
{
debug!("Awaiting incoming messages from the remote peer");
let payload = self.session.recv_raw_message()?;
trace!("Incoming data from the remote peer: {:?}", payload);
let message: D::Data = d.unmarshall(Cursor::new(payload)).map_err(Into::into)?;
debug!("Message from the remote peer: {}", message);
Ok(message)
}
}
impl SendMessage for PeerConnection {
fn send_message(
&mut self,
message: impl TypedEnum + Display,
) -> Result<usize, presentation::Error> {
debug!("Sending LN message to the remote peer: {}", message);
let data = message.serialize();
trace!("Encoded message representation: {:?}", data);
Ok(self.session.send_raw_message(&data)?)
}
}
impl RecvMessage for PeerReceiver {
fn recv_message<D>(&mut self, d: &D) -> Result<D::Data, presentation::Error>
where
D: Unmarshall,
<D as Unmarshall>::Data: Display,
<D as Unmarshall>::Error: Into<presentation::Error>,
{
debug!("Awaiting incoming messages from the remote peer");
let payload = self.receiver.recv_raw_message()?;
trace!("Incoming data from the remote peer: {:?}", payload);
let message: D::Data = d.unmarshall(Cursor::new(payload)).map_err(Into::into)?;
debug!("Message from the remote peer: {}", message);
Ok(message)
}
}
impl SendMessage for PeerSender {
fn send_message(
&mut self,
message: impl TypedEnum + Display,
) -> Result<usize, presentation::Error> {
debug!("Sending LN message to the remote peer: {}", message);
let data = message.serialize();
trace!("Encoded message representation: {:?}", data);
Ok(self.sender.send_raw_message(&data)?)
}
}
impl Bipolar for PeerConnection {
type Left = PeerReceiver;
type Right = PeerSender;
fn join(_left: Self::Left, _right: Self::Right) -> Self {
unimplemented!()
}
fn split(self) -> (Self::Left, Self::Right) {
let session = self.session.into_any();
let (input, output) = if session.downcast_ref::<BrontozaurSession>().is_some() {
let session = session
.downcast::<BrontozaurSession>()
.expect("downcast can't process type accepted by downcast_ref");
(*session).split()
} else if session.downcast_ref::<BrontideSession>().is_some() {
let session = session
.downcast::<BrontideSession>()
.expect("downcast can't process type accepted by downcast_ref");
(*session).split()
} else if session.downcast_ref::<LocalSession>().is_some() {
let session = session
.downcast::<LocalSession>()
.expect("downcast can't process type accepted by downcast_ref");
(*session).split()
} else {
panic!("Impossible to split this type of session")
};
(PeerReceiver { receiver: input }, PeerSender { sender: output })
}
}