use rialo_cli_representable::Representable;
use rialo_cli_representation::HumanReadable;
use rialo_types::{AuthorityKeyBytes, RexData, RexId, RexOutput};
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;
use crate::errors::RexProcessorError;
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Representable)]
#[representable(human_readable = "rex_update_human_readable")]
pub struct RexUpdate {
pub(crate) data: Vec<u8>,
#[serde(with = "BigArray")]
pub(crate) validator: AuthorityKeyBytes,
}
fn rex_update_human_readable(update: &RexUpdate) -> String {
let mut out = String::new();
let auth_key_hex = hex::encode(update.validator);
out.push_str(&format!("Validator (authority key): {}; ", auth_key_hex));
out.push_str("Data: ");
match update.try_data_as_output() {
Ok(rex_output) => {
out.push_str(&format!("{rex_output:?}"));
}
Err(_) => {
out.push_str("<Unable to decode>: \n");
}
}
out
}
impl RexUpdate {
pub fn new(data: Vec<u8>, validator: AuthorityKeyBytes) -> Self {
Self { data, validator }
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn validator(&self) -> AuthorityKeyBytes {
self.validator
}
pub fn try_data_as_output(&self) -> Result<RexOutput, RexProcessorError> {
borsh::from_slice(&self.data).map_err(|_| RexProcessorError::ReportData)
}
pub fn success_payload(&self) -> Option<RexData> {
match self.try_data_as_output() {
Ok(RexOutput::Success(response)) => Some(response.response),
_ => None,
}
}
pub fn get_rex_response_timestamp(&self) -> Option<String> {
if let Ok(RexOutput::Success(response)) = self.try_data_as_output() {
Some(response.timestamp)
} else {
None
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Representable)]
#[representable(human_readable = "rex_report_human_readable")]
pub struct RexReport {
pub rex_id: RexId, pub round: u64, pub updates: Vec<RexUpdate>, }
fn rex_report_human_readable(report: &RexReport) -> String {
let mut out = String::new();
out.push_str("REX Report\n");
out.push_str("=============\n\n");
out.push_str(&format!("REX ID: {}\n", report.rex_id));
out.push_str(&format!("Round: {}\n", report.round));
out.push_str(&format!("Number of Updates: {}\n", report.updates.len()));
if !report.updates.is_empty() {
out.push_str("\nUpdates:\n");
for (i, update) in report.updates.iter().enumerate() {
out.push_str(&format!(" Update {}:\n", i + 1));
let auth_key_hex = hex::encode(update.validator());
out.push_str(&format!(" Validator: {}\n", auth_key_hex));
out.push_str(&format!(" Data Size: {} bytes\n", update.data().len()));
if let Ok(output) = update.try_data_as_output() {
match output {
RexOutput::Success(response) => {
out.push_str(&format!(" Success: {:?}\n", response.human_readable()));
}
RexOutput::RexError(err) => {
out.push_str(&format!(" RexError: {err:?}\n"));
}
RexOutput::UnserializableResponse(err) => {
out.push_str(&format!(" UnserializableResponse: {err:?}\n"));
}
_ => {
out.push_str(&format!(" Unknown Output Type: {:?}\n", output));
}
}
} else {
out.push_str(&format!(" Output: {}\n", update.human_readable()));
}
}
}
out
}
impl RexReport {
pub fn into_updates(self) -> Vec<RexUpdate> {
self.updates
}
pub fn outputs(&self) -> impl Iterator<Item = RexOutput> + '_ {
self.updates
.iter()
.filter_map(|update| update.try_data_as_output().ok())
}
}
pub fn extract_round_raw(bincode_data: &[u8]) -> Result<u64, RexProcessorError> {
let report: RexReport =
bincode::deserialize(bincode_data).map_err(|_| RexProcessorError::ReportData)?;
Ok(report.round)
}