use std::ops::Add;
use std::time::{Duration, SystemTime};
use crate::base::{Base, Body, PrivateOptions};
use crate::options::Options;
use crate::page::{Page, PageBuilder, PageInfo};
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,
options: SecondaryOptions,
buff: T,
) -> Result<(usize, Page), Error>;
}
#[derive(Clone, Builder)]
pub struct SecondaryOptions {
id: Id,
#[builder(default = "0")]
application_id: u16,
#[builder(default = "Kind(0)")]
page_kind: Kind,
#[builder(default = "0")]
version: u16,
#[builder(default = "Body::None")]
body: Body,
#[builder(default = "Some(SystemTime::now().add(Duration::from_secs(24 * 60 * 60)))")]
expiry: Option<SystemTime>,
#[builder(default = "vec![]")]
public_options: Vec<Options>,
#[builder(default = "PrivateOptions::None")]
private_options: PrivateOptions,
}
#[derive(Clone, Builder)]
pub struct DataOptions {
#[builder(default = "DataKind::Generic.into()")]
data_kind: Kind,
#[builder(default = "Body::None")]
body: Body,
#[builder(default = "None")]
expiry: Option<SystemTime>,
#[builder(default = "vec![]")]
public_options: Vec<Options>,
#[builder(default = "PrivateOptions::None")]
private_options: PrivateOptions,
}
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 mut p = Page::new(
self.id.clone(),
self.application_id,
self.kind.into(),
flags,
self.version,
PageInfo::primary(self.public_key.clone()),
self.body.clone(),
SystemTime::now(),
Some(SystemTime::now().add(Duration::from_secs(24 * 60 * 60))),
);
self.encode(&mut p, buff).map(|n| (n, p))
}
fn publish_secondary<T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
options: SecondaryOptions,
buff: T,
) -> Result<(usize, Page), Error> {
let mut flags = Flags::SECONDARY;
if self.encrypted {
flags |= Flags::ENCRYPTED;
}
assert!(options.page_kind.is_page());
let mut b = PageBuilder::default();
b.id(options.id.clone())
.application_id(options.application_id)
.kind(options.page_kind)
.flags(flags)
.version(options.version)
.info(PageInfo::secondary(self.id.clone()))
.body(options.body)
.public_options(options.public_options)
.private_options(options.private_options)
.issued(SystemTime::now().into())
.expiry(options.expiry.map(|v| v.into()));
let mut p = b.build().unwrap();
self.encode(&mut p, buff).map(|n| (n, p))
}
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 mut p = Page::new(
self.id.clone(),
self.application_id,
options.data_kind,
flags,
self.data_index,
PageInfo::Data(()),
options.body,
SystemTime::now(),
options.expiry,
);
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)
}
}