use core::ops::Add;
#[cfg(feature = "std")]
use std::time::{Duration, SystemTime};
#[cfg(feature = "alloc")]
use alloc::prelude::v1::*;
use crate::base::{Base, Body, Header, PrivateOptions};
use crate::error::Error;
use crate::options::Options;
use crate::page::{Page, PageInfo, PageOptions};
use crate::service::Service;
use crate::types::*;
pub trait Publisher {
fn publish_primary<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
buff: T,
) -> Result<(usize, Page), Error>;
fn publish_data<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
options: DataOptions,
buff: T,
) -> Result<(usize, Page), Error>;
fn publish_secondary<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
id: &Id,
options: SecondaryOptions,
buff: T,
) -> Result<(usize, Page), Error>;
}
#[derive(Clone)]
pub struct SecondaryOptions {
pub application_id: u16,
pub page_kind: Kind,
pub version: u16,
pub body: Body,
pub issued: Option<DateTime>,
pub expiry: Option<DateTime>,
pub public_options: Vec<Options>,
pub private_options: Vec<Options>,
}
impl Default for SecondaryOptions {
fn default() -> Self {
Self {
application_id: 0,
page_kind: PageKind::Generic.into(),
version: 0,
body: Body::None,
issued: None,
expiry: None,
public_options: vec![],
private_options: vec![],
}
}
}
#[derive(Clone)]
pub struct DataOptions {
pub data_kind: Kind,
pub body: Body,
pub issued: Option<DateTime>,
pub expiry: Option<DateTime>,
pub public_options: Vec<Options>,
pub private_options: Vec<Options>,
}
impl Default for DataOptions {
fn default() -> Self {
Self {
data_kind: DataKind::Generic.into(),
body: Body::None,
issued: None,
expiry: None,
public_options: vec![],
private_options: vec![],
}
}
}
impl Publisher for Service {
fn publish_primary<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
buff: T,
) -> Result<(usize, Page), Error> {
let mut flags = Flags::default();
if self.encrypted {
flags |= Flags::ENCRYPTED;
}
let header = Header {
application_id: self.application_id,
kind: self.kind.into(),
index: self.version,
flags,
..Default::default()
};
let page_options = PageOptions {
#[cfg(feature = "std")]
issued: Some(SystemTime::now().into()),
#[cfg(feature = "std")]
expiry: Some(
SystemTime::now()
.add(Duration::from_secs(24 * 60 * 60))
.into(),
),
..Default::default()
};
let mut p = Page::new(
self.id.clone(),
header,
PageInfo::primary(self.public_key.clone()),
self.body.clone(),
page_options,
);
self.encode(&mut p, buff).map(|n| (n, p))
}
fn publish_secondary<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
id: &Id,
options: SecondaryOptions,
buff: T,
) -> Result<(usize, Page), Error> {
let mut flags = Flags::SECONDARY;
if self.encrypted {
flags |= Flags::ENCRYPTED;
}
flags |= Flags::SECONDARY;
assert!(options.page_kind.is_page());
let header = Header {
application_id: self.application_id,
kind: options.page_kind,
flags,
index: options.version,
..Default::default()
};
let page_options = PageOptions {
public_options: options.public_options,
private_options: PrivateOptions::Cleartext(options.private_options),
#[cfg(feature = "std")]
issued: Some(SystemTime::now().into()),
expiry: options.expiry,
..Default::default()
};
let mut page = Page::new(
id.clone(),
header,
PageInfo::secondary(self.id.clone()),
options.body,
page_options,
);
self.encode(&mut page, buff).map(|n| (n, page))
}
fn publish_data<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
options: DataOptions,
buff: T,
) -> Result<(usize, Page), Error> {
let mut flags = Flags::default();
if self.encrypted {
flags |= Flags::ENCRYPTED;
}
assert!(options.data_kind.is_data());
self.data_index += 1;
let header = Header {
application_id: self.application_id,
kind: options.data_kind,
flags,
index: self.data_index,
..Default::default()
};
let page_options = PageOptions {
public_options: options.public_options,
private_options: PrivateOptions::Cleartext(options.private_options),
#[cfg(feature = "std")]
issued: Some(SystemTime::now().into()),
..Default::default()
};
let mut p = Page::new(
self.id.clone(),
header,
PageInfo::Data(()),
options.body,
page_options,
);
self.encode(&mut p, buff).map(|n| (n, p))
}
}
impl Service {
fn encode<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
page: &mut Page,
buff: T,
) -> Result<usize, Error> {
let mut b = Base::from(&*page);
b.parent = self.last_sig.clone();
let n = b.encode(self.private_key.as_ref(), self.secret_key.as_ref(), buff)?;
self.last_sig = b.signature;
page.signature = self.last_sig.clone();
Ok(n)
}
}