1use core::ops::Add;
2
3#[cfg(feature = "std")]
4use std::time::{Duration, SystemTime};
5
6#[cfg(feature = "alloc")]
7use alloc::prelude::v1::*;
8
9use crate::base::{Base, Body, Header, PrivateOptions};
10use crate::error::Error;
11use crate::options::Options;
12use crate::page::{Page, PageInfo, PageOptions};
13use crate::service::Service;
14use crate::types::*;
15
16pub trait Publisher {
19 fn publish_primary<T: AsRef<[u8]> + AsMut<[u8]>>(
21 &mut self,
22 buff: T,
23 ) -> Result<(usize, Page), Error>;
24
25 fn publish_data<T: AsRef<[u8]> + AsMut<[u8]>>(
27 &mut self,
28 options: DataOptions,
29 buff: T,
30 ) -> Result<(usize, Page), Error>;
31
32 fn publish_secondary<T: AsRef<[u8]> + AsMut<[u8]>>(
34 &mut self,
35 id: &Id,
36 options: SecondaryOptions,
37 buff: T,
38 ) -> Result<(usize, Page), Error>;
39}
40
41#[derive(Clone)]
42pub struct SecondaryOptions {
43 pub application_id: u16,
45
46 pub page_kind: Kind,
48
49 pub version: u16,
52
53 pub body: Body,
55
56 pub issued: Option<DateTime>,
58
59 pub expiry: Option<DateTime>,
61
62 pub public_options: Vec<Options>,
64
65 pub private_options: Vec<Options>,
67}
68
69impl Default for SecondaryOptions {
70 fn default() -> Self {
71 Self {
72 application_id: 0,
73 page_kind: PageKind::Generic.into(),
74 version: 0,
75 body: Body::None,
76 issued: None,
77 expiry: None,
78 public_options: vec![],
79 private_options: vec![],
80 }
81 }
82}
83
84#[derive(Clone)]
85pub struct DataOptions {
86 pub data_kind: Kind,
88
89 pub body: Body,
91
92 pub issued: Option<DateTime>,
94
95 pub expiry: Option<DateTime>,
97
98 pub public_options: Vec<Options>,
100
101 pub private_options: Vec<Options>,
103}
104
105impl Default for DataOptions {
106 fn default() -> Self {
107 Self {
108 data_kind: DataKind::Generic.into(),
109 body: Body::None,
110 issued: None,
111 expiry: None,
112 public_options: vec![],
113 private_options: vec![],
114 }
115 }
116}
117
118impl Publisher for Service {
119 fn publish_primary<T: AsRef<[u8]> + AsMut<[u8]>>(
121 &mut self,
122 buff: T,
123 ) -> Result<(usize, Page), Error> {
124 let mut flags = Flags::default();
125 if self.encrypted {
126 flags |= Flags::ENCRYPTED;
127 }
128
129 let header = Header {
130 application_id: self.application_id,
131 kind: self.kind.into(),
132 index: self.version,
133 flags,
134 ..Default::default()
135 };
136
137 let page_options = PageOptions {
138 #[cfg(feature = "std")]
140 issued: Some(SystemTime::now().into()),
141 #[cfg(feature = "std")]
142 expiry: Some(
143 SystemTime::now()
144 .add(Duration::from_secs(24 * 60 * 60))
145 .into(),
146 ),
147 ..Default::default()
148 };
149
150 let mut p = Page::new(
152 self.id.clone(),
153 header,
154 PageInfo::primary(self.public_key.clone()),
155 self.body.clone(),
156 page_options,
157 );
158
159 self.encode(&mut p, buff).map(|n| (n, p))
160 }
161
162 fn publish_secondary<T: AsRef<[u8]> + AsMut<[u8]>>(
164 &mut self,
165 id: &Id,
166 options: SecondaryOptions,
167 buff: T,
168 ) -> Result<(usize, Page), Error> {
169 let mut flags = Flags::SECONDARY;
170 if self.encrypted {
171 flags |= Flags::ENCRYPTED;
172 }
173
174 flags |= Flags::SECONDARY;
175
176 assert!(options.page_kind.is_page());
177
178 let header = Header {
179 application_id: self.application_id,
180 kind: options.page_kind,
181 flags,
182 index: options.version,
183 ..Default::default()
184 };
185
186 let page_options = PageOptions {
187 public_options: options.public_options,
188 private_options: PrivateOptions::Cleartext(options.private_options),
189 #[cfg(feature = "std")]
191 issued: Some(SystemTime::now().into()),
192 expiry: options.expiry,
193 ..Default::default()
194 };
195
196 let mut page = Page::new(
197 id.clone(),
198 header,
199 PageInfo::secondary(self.id.clone()),
200 options.body,
201 page_options,
202 );
203
204 self.encode(&mut page, buff).map(|n| (n, page))
205 }
206
207 fn publish_data<T: AsRef<[u8]> + AsMut<[u8]>>(
208 &mut self,
209 options: DataOptions,
210 buff: T,
211 ) -> Result<(usize, Page), Error> {
212 let mut flags = Flags::default();
213 if self.encrypted {
214 flags |= Flags::ENCRYPTED;
215 }
216
217 assert!(options.data_kind.is_data());
218
219 self.data_index += 1;
220
221 let header = Header {
222 application_id: self.application_id,
223 kind: options.data_kind,
224 flags,
225 index: self.data_index,
226 ..Default::default()
227 };
228
229 let page_options = PageOptions {
230 public_options: options.public_options,
231 private_options: PrivateOptions::Cleartext(options.private_options),
232 #[cfg(feature = "std")]
233 issued: Some(SystemTime::now().into()),
234 ..Default::default()
235 };
236
237 let mut p = Page::new(
238 self.id.clone(),
239 header,
240 PageInfo::Data(()),
241 options.body,
242 page_options,
243 );
244
245 self.encode(&mut p, buff).map(|n| (n, p))
246 }
247}
248
249impl Service {
250 fn encode<T: AsRef<[u8]> + AsMut<[u8]>>(
252 &mut self,
253 page: &mut Page,
254 buff: T,
255 ) -> Result<usize, Error> {
256 let mut b = Base::from(&*page);
258
259 b.parent = self.last_sig.clone();
261
262 let n = b.encode(self.private_key.as_ref(), self.secret_key.as_ref(), buff)?;
264
265 self.last_sig = b.signature;
267
268 page.signature = self.last_sig.clone();
270
271 Ok(n)
274 }
275}