use crate::{
frame::{
generate::generate_cstring_tuple_vec,
parse::{self},
FrameGenerator, FrameParser,
},
types::{Address, Recipient},
Result,
};
use chrono::Utc;
use nom::IResult;
use serde::{Deserialize, Serialize};
use std::ffi::CString;
use super::Ident32;
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct LetterheadV1 {
pub from: Address,
pub to: Recipient,
pub stream_size: u64,
pub auxiliary_data: Vec<(CString, CString)>,
}
impl LetterheadV1 {
pub fn send(from: Address, to: Recipient) -> Self {
Self {
from,
to,
stream_size: 0,
auxiliary_data: vec![],
}
}
pub fn digest(&self) -> Ident32 {
let mut plen_buf = vec![];
self.stream_size.generate(&mut plen_buf).unwrap();
let pl_len: &[u8] = plen_buf.as_slice();
let inner_addr = self.to.inner_address();
let digest_input = vec![self.from.as_bytes(), inner_addr.as_bytes(), pl_len];
let mut vec = vec![];
for buf in digest_input {
buf.into_iter().for_each(|x| {
vec.push(*x);
});
}
Ident32::with_digest(&vec)
}
pub fn add_send_time(mut self) -> Self {
self.auxiliary_data.push((
CString::new("time-sent").unwrap(),
CString::new(Utc::now().to_string()).unwrap(),
));
self
}
pub fn add_aux_data(mut self, key: impl Into<Vec<u8>>, val: impl Into<Vec<u8>>) -> Self {
let key = CString::new(key).expect("invalid key data!");
let val = CString::new(val).expect("invalid value data!");
self.auxiliary_data.push((key, val));
self
}
pub fn to_many(self, additional_recipients: Vec<Recipient>) -> Vec<Self> {
let mut vec = vec![self.clone()];
additional_recipients.into_iter().for_each(|recipient| {
let mut new_lh = self.clone();
new_lh.to = recipient;
vec.push(new_lh)
});
vec
}
}
impl FrameGenerator for LetterheadV1 {
fn generate(self, buf: &mut Vec<u8>) -> Result<()> {
buf.push(1);
self.from.generate(buf)?;
Some(self.to).generate(buf)?;
self.stream_size.generate(buf)?;
generate_cstring_tuple_vec(self.auxiliary_data, buf)?;
Ok(())
}
}
impl FrameParser for LetterheadV1 {
type Output = Result<LetterheadV1>;
fn parse(input: &[u8]) -> IResult<&[u8], Self::Output> {
let (input, lh_version) = parse::take_byte(input)?;
assert!(lh_version == 1);
let (input, from) = parse::take_address(input)?;
let (input, to) = Option::<Recipient>::parse(input)?;
let (input, payload_length) = parse::take_u64(input)?;
let (input, auxiliary_data) = parse::take_cstring_tuple_vec(input)?;
trace!("Parsed: {from:?} {to:?}, {payload_length:?}");
Ok((
input,
auxiliary_data.map(|auxiliary_data| Self {
from,
to: to.unwrap(),
stream_size: payload_length,
auxiliary_data,
}),
))
}
}