1use std::{
3 ops::{Deref, Sub},
4 result,
5 time::{Duration, SystemTime},
6};
7
8use iroh::NodeId;
9use iroh_blobs::HashAndFormat;
10use serde::{Deserialize, Serialize};
11use serde_big_array::BigArray;
12use snafu::prelude::*;
13
14pub const ALPN: &[u8] = b"n0/tracker/1";
16pub const REQUEST_SIZE_LIMIT: usize = 1024 * 16;
18
19#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
21pub enum AnnounceKind {
22 Partial = 0,
24 Complete,
26}
27
28impl AnnounceKind {
29 pub fn from_complete(complete: bool) -> Self {
30 if complete {
31 Self::Complete
32 } else {
33 Self::Partial
34 }
35 }
36}
37
38#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
40pub struct AbsoluteTime(u64);
41
42impl AbsoluteTime {
43 pub fn now() -> Self {
44 Self::try_from(SystemTime::now()).unwrap()
45 }
46
47 pub fn from_micros(micros: u64) -> Self {
48 Self(micros)
49 }
50
51 pub fn as_micros(&self) -> u64 {
52 self.0
53 }
54}
55
56impl Sub for AbsoluteTime {
57 type Output = Duration;
58
59 fn sub(self, rhs: Self) -> Self::Output {
60 Duration::from_micros(self.0 - rhs.0)
61 }
62}
63
64impl TryFrom<SystemTime> for AbsoluteTime {
65 type Error = &'static str;
66
67 fn try_from(value: SystemTime) -> Result<Self, Self::Error> {
68 Ok(Self(
69 value
70 .duration_since(std::time::UNIX_EPOCH)
71 .map_err(|_| "SystemTime before UNIX EPOCH")?
72 .as_micros()
73 .try_into()
74 .map_err(|_| "SystemTime too large")?,
75 ))
76 }
77}
78
79impl From<AbsoluteTime> for SystemTime {
80 fn from(value: AbsoluteTime) -> Self {
81 std::time::UNIX_EPOCH + Duration::from_micros(value.0)
82 }
83}
84
85#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
90pub struct Announce {
91 pub host: NodeId,
93 pub content: HashAndFormat,
95 pub kind: AnnounceKind,
97 pub timestamp: AbsoluteTime,
99}
100
101#[derive(derive_more::Debug, Clone, Copy, Serialize, Deserialize)]
103pub struct SignedAnnounce {
104 pub announce: Announce,
106 #[serde(with = "BigArray")]
110 #[debug("{}", hex::encode(self.signature))]
111 pub signature: [u8; 64],
112}
113
114impl Deref for SignedAnnounce {
115 type Target = Announce;
116
117 fn deref(&self) -> &Self::Target {
118 &self.announce
119 }
120}
121
122#[derive(Debug, Snafu)]
123pub enum VerifyError {
124 SignatureError {
125 source: ed25519_dalek::SignatureError,
126 },
127 SerializationError {
128 source: postcard::Error,
129 },
130}
131
132impl SignedAnnounce {
133 pub fn new(
135 announce: Announce,
136 secret_key: &iroh::SecretKey,
137 ) -> result::Result<Self, postcard::Error> {
138 let announce_bytes = postcard::to_allocvec(&announce)?;
139 let signature = secret_key.sign(&announce_bytes).to_bytes();
140 Ok(Self {
141 announce,
142 signature,
143 })
144 }
145
146 pub fn verify(&self) -> result::Result<(), VerifyError> {
148 let announce_bytes = postcard::to_allocvec(&self.announce).context(SerializationSnafu)?;
149 let signature = iroh_base::Signature::from_bytes(&self.signature);
150 self.announce
151 .host
152 .verify(&announce_bytes, &signature)
153 .context(SignatureSnafu)?;
154 Ok(())
155 }
156}
157
158#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
160pub struct QueryFlags {
161 pub complete: bool,
165
166 pub verified: bool,
174}
175
176#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
178pub struct Query {
179 pub content: HashAndFormat,
183 pub flags: QueryFlags,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct QueryResponse {
190 pub hosts: Vec<SignedAnnounce>,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub enum Request {
200 Announce(SignedAnnounce),
202 Query(Query),
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub enum Response {
209 QueryResponse(QueryResponse),
211}
212
213#[cfg(test)]
214mod tests {}