use crate::ln::msgs;
use crate::util::ser::{LengthLimitedRead, LengthReadable, Readable, Writeable, Writer};
use std::io;
#[allow(missing_docs)]
#[derive(Debug)]
pub enum Message<T> {
Init(msgs::Init),
Error(msgs::ErrorMessage),
Warning(msgs::WarningMessage),
Ping(msgs::Ping),
Pong(msgs::Pong),
Unknown(u16),
Custom(T),
}
impl<T: core::fmt::Debug + Type + Writeable> Writeable for Message<T> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
match self {
Message::Init(msg) => msg.write(writer),
Message::Error(msg) => msg.write(writer),
Message::Warning(msg) => msg.write(writer),
Message::Ping(msg) => msg.write(writer),
Message::Pong(msg) => msg.write(writer),
Message::Unknown(_) => Ok(()),
Message::Custom(msg) => msg.write(writer),
}
}
}
impl<T: core::fmt::Debug + Type> Type for Message<T> {
fn type_id(&self) -> u16 {
match self {
Message::Init(msg) => msg.type_id(),
Message::Error(msg) => msg.type_id(),
Message::Warning(msg) => msg.type_id(),
Message::Ping(msg) => msg.type_id(),
Message::Pong(msg) => msg.type_id(),
Message::Unknown(type_id) => *type_id,
Message::Custom(msg) => msg.type_id(),
}
}
}
impl<T: core::fmt::Debug + Type> Message<T> {
pub fn is_even(&self) -> bool {
(self.type_id() & 1) == 0
}
}
pub fn read<T, R>(
buffer: &mut R,
custom_reader: impl FnOnce(u16, &mut R) -> Result<Option<T>, msgs::DecodeError>,
) -> Result<Message<T>, (msgs::DecodeError, Option<u16>)>
where
R: LengthLimitedRead,
{
let message_type = <u16 as Readable>::read(buffer).map_err(|e| (e, None))?;
do_read(buffer, message_type, custom_reader).map_err(|e| (e, Some(message_type)))
}
fn do_read<T, R>(
buffer: &mut R,
message_type: u16,
custom_reader: impl FnOnce(u16, &mut R) -> Result<Option<T>, msgs::DecodeError>,
) -> Result<Message<T>, msgs::DecodeError>
where
R: LengthLimitedRead,
{
match message_type {
msgs::Init::TYPE => {
let r = LengthReadable::read_from_fixed_length_buffer(buffer);
Ok(Message::Init(r?))
}
msgs::ErrorMessage::TYPE => Ok(Message::Error(
LengthReadable::read_from_fixed_length_buffer(buffer)?,
)),
msgs::WarningMessage::TYPE => Ok(Message::Warning(
LengthReadable::read_from_fixed_length_buffer(buffer)?,
)),
msgs::Ping::TYPE => Ok(Message::Ping(
LengthReadable::read_from_fixed_length_buffer(buffer)?,
)),
msgs::Pong::TYPE => Ok(Message::Pong(
LengthReadable::read_from_fixed_length_buffer(buffer)?,
)),
_ => {
if let Some(custom) = custom_reader(message_type, buffer)? {
Ok(Message::Custom(custom))
} else {
Ok(Message::Unknown(message_type))
}
}
}
}
pub(crate) fn write<M: Type + Writeable, W: Writer>(
message: &M,
buffer: &mut W,
) -> Result<(), io::Error> {
message.type_id().write(buffer)?;
message.write(buffer)
}
mod encode {
pub trait Encode {
const TYPE: u16;
}
}
pub(crate) use self::encode::Encode;
pub trait Type {
fn type_id(&self) -> u16;
}
impl Type for () {
fn type_id(&self) -> u16 {
unreachable!();
}
}
impl<T: Encode + core::fmt::Debug + Writeable> Type for T {
fn type_id(&self) -> u16 {
T::TYPE
}
}
impl Encode for msgs::Init {
const TYPE: u16 = 16;
}
impl Encode for msgs::ErrorMessage {
const TYPE: u16 = 17;
}
impl Encode for msgs::WarningMessage {
const TYPE: u16 = 1;
}
impl Encode for msgs::Ping {
const TYPE: u16 = 18;
}
impl Encode for msgs::Pong {
const TYPE: u16 = 19;
}