use std::fmt::{self, Debug, Display, Formatter};
use serde::Serialize;
use tracing::error;
use casper_types::Transaction;
use super::{FetchItem, FetchResponder, FetchResponse};
use crate::{
effect::{announcements::TransactionAcceptorAnnouncement, requests::FetcherRequest},
types::NodeId,
utils::Source,
};
#[derive(Debug, Serialize)]
pub(crate) enum Event<T: FetchItem> {
Fetch(FetcherRequest<T>),
GetLocallyResult {
id: T::Id,
peer: NodeId,
validation_metadata: Box<T::ValidationMetadata>,
maybe_item: Option<Box<T>>,
responder: FetchResponder<T>,
},
GotRemotely { item: Box<T>, source: Source },
PutToStorage { item: Box<T>, peer: NodeId },
GotInvalidRemotely { id: T::Id, source: Source },
AbsentRemotely { id: T::Id, peer: NodeId },
RejectedRemotely { id: T::Id, peer: NodeId },
TimeoutPeer { id: T::Id, peer: NodeId },
}
impl<T: FetchItem> Event<T> {
pub(crate) fn from_get_response_serialized_item(
peer: NodeId,
serialized_item: &[u8],
) -> Option<Self> {
match bincode::deserialize::<FetchResponse<T, T::Id>>(serialized_item) {
Ok(FetchResponse::Fetched(item)) => Some(Event::GotRemotely {
item: Box::new(item),
source: Source::Peer(peer),
}),
Ok(FetchResponse::NotFound(id)) => Some(Event::AbsentRemotely { id, peer }),
Ok(FetchResponse::NotProvided(id)) => Some(Event::RejectedRemotely { id, peer }),
Err(error) => {
error!("failed to decode {:?} from {}: {:?}", T::TAG, peer, error);
None
}
}
}
}
impl<T: FetchItem> From<FetcherRequest<T>> for Event<T> {
fn from(fetcher_request: FetcherRequest<T>) -> Self {
Event::Fetch(fetcher_request)
}
}
impl From<TransactionAcceptorAnnouncement> for Event<Transaction> {
fn from(announcement: TransactionAcceptorAnnouncement) -> Self {
match announcement {
TransactionAcceptorAnnouncement::AcceptedNewTransaction {
transaction,
source,
} => Event::GotRemotely {
item: Box::new((*transaction).clone()),
source,
},
TransactionAcceptorAnnouncement::InvalidTransaction {
transaction,
source,
} => Event::GotInvalidRemotely {
id: transaction.fetch_id(),
source,
},
}
}
}
impl<T: FetchItem> Display for Event<T> {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Event::Fetch(FetcherRequest { id, .. }) => {
write!(formatter, "request to fetch item at hash {}", id)
}
Event::GetLocallyResult { id, maybe_item, .. } => {
if maybe_item.is_some() {
write!(formatter, "got {} from storage", id)
} else {
write!(formatter, "failed to fetch {} from storage", id)
}
}
Event::GotRemotely { item, source } => {
write!(formatter, "got {} from {}", item.fetch_id(), source)
}
Event::GotInvalidRemotely { id, source } => {
write!(formatter, "invalid item {} from {}", id, source)
}
Event::TimeoutPeer { id, peer } => write!(
formatter,
"check get from peer timeout for {} with {}",
id, peer
),
Event::AbsentRemotely { id, peer } => {
write!(formatter, "item {} was not available on {}", id, peer)
}
Event::RejectedRemotely { id, peer } => {
write!(
formatter,
"request to fetch item {} was rejected by {}",
id, peer
)
}
Event::PutToStorage { item, .. } => {
write!(formatter, "item {} was put to storage", item.fetch_id())
}
}
}
}