use crate::store_remove;
use crate::store_update_metadata;
use anyhow::Result;
use bp7::{Bundle, EndpointID};
use log::warn;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Copy)]
pub enum Constraint {
DispatchPending,
ForwardPending,
ReassemblyPending,
Contraindicated,
LocalEndpoint,
Deleted,
}
impl fmt::Display for Constraint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BundlePack {
pub source: EndpointID,
pub destination: EndpointID,
pub received_time: u64,
pub creation_time: u64,
pub lifetime: u64,
pub id: String,
pub administrative: bool,
pub size: usize,
pub constraints: HashSet<Constraint>,
}
impl fmt::Display for BundlePack {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {:?}", self.id(), self.constraints)
}
}
impl From<Bundle> for BundlePack {
fn from(mut bundle: Bundle) -> Self {
let bid = bundle.id();
let size = bundle.to_cbor().len();
let source = bundle.primary.source.clone();
let destination = bundle.primary.destination.clone();
let lifetime = bundle.primary.lifetime.as_millis() as u64;
BundlePack {
source,
destination,
received_time: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as u64,
creation_time: bundle.primary.creation_timestamp.dtntime(),
lifetime,
id: bid,
administrative: bundle.is_administrative_record(),
size,
constraints: HashSet::new(),
}
}
}
impl From<&Bundle> for BundlePack {
fn from(bundle: &Bundle) -> Self {
let bid = bundle.id();
let size = bundle.clone().to_cbor().len();
let source = bundle.primary.source.clone();
let destination = bundle.primary.destination.clone();
let lifetime = bundle.primary.lifetime.as_millis() as u64;
BundlePack {
source,
destination,
received_time: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as u64,
creation_time: bundle.primary.creation_timestamp.dtntime(),
lifetime,
id: bid,
administrative: bundle.is_administrative_record(),
size,
constraints: HashSet::new(),
}
}
}
impl BundlePack {
pub fn id(&self) -> &str {
&self.id
}
pub fn sync(&self) -> Result<()> {
if !self.has_constraints() {
warn!("not constraints, removing bundle from store {}", self.id());
store_remove(self.id())?;
} else {
store_update_metadata(self)?;
}
Ok(())
}
pub fn has_expired(&self) -> bool {
if self.lifetime == 0 {
return false;
}
let now = bp7::CreationTimestamp::now().dtntime();
(self.creation_time + self.lifetime) < now
}
pub fn has_receiver(&self) -> bool {
self.destination != EndpointID::none()
}
pub fn has_constraint(&self, constraint: Constraint) -> bool {
self.constraints.contains(&constraint)
}
pub fn has_constraints(&self) -> bool {
!self.constraints.is_empty()
}
pub fn add_constraint(&mut self, constraint: Constraint) {
self.constraints.insert(constraint);
}
pub fn remove_constraint(&mut self, constraint: Constraint) {
self.constraints.remove(&constraint);
}
pub fn clear_constraints(&mut self) {
let local_set = self.has_constraint(Constraint::LocalEndpoint);
self.constraints.clear();
if local_set {
self.add_constraint(Constraint::LocalEndpoint);
}
}
pub fn set_constraints(&mut self, constraints: HashSet<Constraint>) {
self.constraints = constraints;
}
pub fn to_cbor(&self) -> bp7::ByteBuffer {
serde_cbor::to_vec(self).expect("unexpected error converting BundlePack to cbor buffer")
}
}
impl From<&[u8]> for BundlePack {
fn from(buf: &[u8]) -> Self {
serde_cbor::from_slice(buf).expect("unexpected error converting cbor buffer to BundlePack")
}
}