use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use usig::{Counter, Usig};
use anyhow::Result;
use crate::{config::Config, error::InnerError, ReplicaId, RequestPayload};
use self::{req_view_change::ReqViewChange, usig_message::UsigMessage};
pub(crate) mod req_view_change;
pub(crate) mod usig_message;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub(crate) enum ValidatedPeerMessage<Att, P, Sig> {
Hello(Att),
ReqViewChange(ReqViewChange),
Usig(UsigMessage<P, Sig>),
}
impl<Att, P, Sig> ValidatedPeerMessage<Att, P, Sig> {
pub(crate) fn msg_type(&self) -> &'static str {
match self {
ValidatedPeerMessage::Hello(_) => "Hello",
ValidatedPeerMessage::ReqViewChange(_) => "ReqViewChange",
ValidatedPeerMessage::Usig(m) => m.msg_type(),
}
}
}
impl<Att, P, Sig> From<ReqViewChange> for ValidatedPeerMessage<Att, P, Sig> {
fn from(req_view_change: ReqViewChange) -> Self {
Self::ReqViewChange(req_view_change)
}
}
impl<Att, T: Into<UsigMessage<P, Sig>>, P, Sig> From<T> for ValidatedPeerMessage<Att, P, Sig> {
fn from(usig_message: T) -> Self {
Self::Usig(usig_message.into())
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[repr(transparent)]
#[serde(transparent)]
pub struct PeerMessage<Att, P, Sig> {
peer_message: ValidatedPeerMessage<Att, P, Sig>,
}
impl<Att, P, Sig> PeerMessage<Att, P, Sig> {
pub(crate) fn msg_type(&self) -> &'static str {
self.peer_message.msg_type()
}
}
impl<Att, P: RequestPayload, Sig: Serialize + Counter + Debug> PeerMessage<Att, P, Sig> {
pub(crate) fn validate(
self,
replica: ReplicaId,
config: &Config,
usig: &mut impl Usig<Signature = Sig>,
) -> Result<ValidatedPeerMessage<Att, P, Sig>, InnerError> {
match &self.peer_message {
ValidatedPeerMessage::Hello(_) => {}
ValidatedPeerMessage::Usig(usig_message) => usig_message.validate(config, usig)?,
ValidatedPeerMessage::ReqViewChange(req_view_change_msg) => {
req_view_change_msg.validate(replica, config)?
}
}
Ok(self.peer_message)
}
}
impl<Att, P, Sig, T: Into<ValidatedPeerMessage<Att, P, Sig>>> From<T> for PeerMessage<Att, P, Sig> {
fn from(peer_message: T) -> Self {
Self {
peer_message: peer_message.into(),
}
}
}