1use std::sync::Arc;
2
3use bytes::Bytes;
4use tl_proto::{TlRead, TlWrite};
5use tycho_util::tl;
6
7use crate::types::{PeerId, PeerInfo};
8use crate::util::check_peer_signature;
9
10#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, TlRead, TlWrite)]
11#[tl(boxed, scheme = "proto.tl")]
12pub enum PeerValueKeyName {
13 #[tl(id = "dht.peerValueKeyName.nodeInfo")]
14 NodeInfo,
15}
16
17#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, TlRead, TlWrite)]
18#[tl(boxed, scheme = "proto.tl")]
19pub enum MergedValueKeyName {
20 #[tl(id = "dht.mergedValueKeyName.publicOverlayEntries")]
21 PublicOverlayEntries,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
28#[tl(boxed, id = "dht.peerValueKey", scheme = "proto.tl")]
29pub struct PeerValueKey {
30 pub name: PeerValueKeyName,
32 pub peer_id: PeerId,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
40#[tl(boxed, id = "dht.peerValueKey", scheme = "proto.tl")]
41pub struct PeerValueKeyRef<'tl> {
42 pub name: PeerValueKeyName,
44 pub peer_id: &'tl PeerId,
46}
47
48impl PeerValueKeyRef<'_> {
49 pub fn as_owned(&self) -> PeerValueKey {
50 PeerValueKey {
51 name: self.name,
52 peer_id: *self.peer_id,
53 }
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
61#[tl(boxed, id = "dht.mergedValueKey", scheme = "proto.tl")]
62pub struct MergedValueKey {
63 pub name: MergedValueKeyName,
65 pub group_id: [u8; 32],
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
73#[tl(boxed, id = "dht.mergedValueKey", scheme = "proto.tl")]
74pub struct MergedValueKeyRef<'tl> {
75 pub name: MergedValueKeyName,
77 pub group_id: &'tl [u8; 32],
79}
80
81impl MergedValueKeyRef<'_> {
82 pub fn as_owned(&self) -> MergedValueKey {
83 MergedValueKey {
84 name: self.name,
85 group_id: *self.group_id,
86 }
87 }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
94#[tl(boxed, id = "dht.peerValue", scheme = "proto.tl")]
95pub struct PeerValue {
96 pub key: PeerValueKey,
98 pub data: Box<[u8]>,
100 pub expires_at: u32,
102 #[tl(signature, with = "tl::signature_owned")]
104 pub signature: Box<[u8; 64]>,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
111#[tl(boxed, id = "dht.peerValue", scheme = "proto.tl")]
112pub struct PeerValueRef<'tl> {
113 pub key: PeerValueKeyRef<'tl>,
115 pub data: &'tl [u8],
117 pub expires_at: u32,
119 #[tl(signature, with = "tl::signature_ref")]
121 pub signature: &'tl [u8; 64],
122}
123
124impl PeerValueRef<'_> {
125 pub fn as_owned(&self) -> PeerValue {
126 PeerValue {
127 key: self.key.as_owned(),
128 data: Box::from(self.data),
129 expires_at: self.expires_at,
130 signature: Box::new(*self.signature),
131 }
132 }
133}
134
135#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
139#[tl(boxed, id = "dht.mergedValue", scheme = "proto.tl")]
140pub struct MergedValue {
141 pub key: MergedValueKey,
143 pub data: Box<[u8]>,
145 pub expires_at: u32,
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, TlRead, TlWrite)]
153#[tl(boxed, id = "dht.mergedValue", scheme = "proto.tl")]
154pub struct MergedValueRef<'tl> {
155 pub key: MergedValueKeyRef<'tl>,
157 pub data: &'tl [u8],
159 pub expires_at: u32,
161}
162
163impl MergedValueRef<'_> {
164 pub fn as_owned(&self) -> MergedValue {
165 MergedValue {
166 key: self.key.as_owned(),
167 data: Box::from(self.data),
168 expires_at: self.expires_at,
169 }
170 }
171}
172
173#[derive(Debug, Clone, PartialEq, Eq)]
177pub enum Value {
178 Peer(PeerValue),
180 Merged(MergedValue),
182}
183
184impl Value {
185 pub fn verify(&self, at: u32, key_hash: &[u8; 32]) -> bool {
189 self.verify_ext(at, key_hash, &mut false)
190 }
191
192 pub fn verify_ext(&self, at: u32, key_hash: &[u8; 32], signature_checked: &mut bool) -> bool {
196 match self {
197 Self::Peer(value) => {
198 let timings_ok = value.expires_at >= at && key_hash == &tl_proto::hash(&value.key);
199 if !timings_ok {
200 return false;
201 }
202
203 *signature_checked = true;
204 check_peer_signature(&value.key.peer_id, &value.signature, value)
205 }
206 Self::Merged(value) => {
207 value.expires_at >= at && key_hash == &tl_proto::hash(&value.key)
208 }
209 }
210 }
211
212 pub const fn expires_at(&self) -> u32 {
213 match self {
214 Self::Peer(value) => value.expires_at,
215 Self::Merged(value) => value.expires_at,
216 }
217 }
218}
219
220impl TlWrite for Value {
221 type Repr = tl_proto::Boxed;
222
223 fn max_size_hint(&self) -> usize {
224 match self {
225 Self::Peer(value) => value.max_size_hint(),
226 Self::Merged(value) => value.max_size_hint(),
227 }
228 }
229
230 fn write_to<P>(&self, packet: &mut P)
231 where
232 P: tl_proto::TlPacket,
233 {
234 match self {
235 Self::Peer(value) => value.write_to(packet),
236 Self::Merged(value) => value.write_to(packet),
237 }
238 }
239}
240
241impl<'a> TlRead<'a> for Value {
242 type Repr = tl_proto::Boxed;
243
244 fn read_from(packet: &'a [u8], offset: &mut usize) -> tl_proto::TlResult<Self> {
245 let id = u32::read_from(packet, offset)?;
246 *offset -= 4;
247 match id {
248 PeerValue::TL_ID => PeerValue::read_from(packet, offset).map(Self::Peer),
249 MergedValue::TL_ID => MergedValue::read_from(packet, offset).map(Self::Merged),
250 _ => Err(tl_proto::TlError::UnknownConstructor),
251 }
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
259pub enum ValueRef<'tl> {
260 Peer(PeerValueRef<'tl>),
262 Merged(MergedValueRef<'tl>),
264}
265
266impl ValueRef<'_> {
267 pub const fn expires_at(&self) -> u32 {
268 match self {
269 Self::Peer(value) => value.expires_at,
270 Self::Merged(value) => value.expires_at,
271 }
272 }
273}
274
275impl TlWrite for ValueRef<'_> {
276 type Repr = tl_proto::Boxed;
277
278 fn max_size_hint(&self) -> usize {
279 match self {
280 Self::Peer(value) => value.max_size_hint(),
281 Self::Merged(value) => value.max_size_hint(),
282 }
283 }
284
285 fn write_to<P>(&self, packet: &mut P)
286 where
287 P: tl_proto::TlPacket,
288 {
289 match self {
290 Self::Peer(value) => value.write_to(packet),
291 Self::Merged(value) => value.write_to(packet),
292 }
293 }
294}
295
296impl<'a> TlRead<'a> for ValueRef<'a> {
297 type Repr = tl_proto::Boxed;
298
299 fn read_from(packet: &'a [u8], offset: &mut usize) -> tl_proto::TlResult<Self> {
300 let id = u32::read_from(packet, offset)?;
301 *offset -= 4;
302 match id {
303 PeerValue::TL_ID => PeerValueRef::read_from(packet, offset).map(Self::Peer),
304 MergedValue::TL_ID => MergedValueRef::read_from(packet, offset).map(Self::Merged),
305 _ => Err(tl_proto::TlError::UnknownConstructor),
306 }
307 }
308}
309
310#[derive(Debug, Clone, TlRead, TlWrite)]
312#[tl(boxed, id = "dht.nodesFound", scheme = "proto.tl")]
313pub struct NodeResponse {
314 #[tl(with = "tl::VecWithMaxLen::<20>")]
316 pub nodes: Vec<Arc<PeerInfo>>,
317}
318
319#[derive(Debug, Clone, TlRead, TlWrite)]
321#[tl(boxed, scheme = "proto.tl")]
322pub enum ValueResponse {
323 #[tl(id = "dht.valueFound")]
325 Found(Box<Value>),
326 #[tl(id = "dht.valueNotFound")]
328 NotFound(#[tl(with = "tl::VecWithMaxLen::<20>")] Vec<Arc<PeerInfo>>),
329}
330
331#[derive(Debug, Clone)]
333pub enum ValueResponseRaw {
334 Found(Bytes),
335 NotFound(Vec<Arc<PeerInfo>>),
336}
337
338impl TlWrite for ValueResponseRaw {
339 type Repr = tl_proto::Boxed;
340
341 fn max_size_hint(&self) -> usize {
342 4 + match self {
343 Self::Found(value) => value.max_size_hint(),
344 Self::NotFound(nodes) => nodes.max_size_hint(),
345 }
346 }
347
348 fn write_to<P>(&self, packet: &mut P)
349 where
350 P: tl_proto::TlPacket,
351 {
352 const FOUND_TL_ID: u32 = tl_proto::id!("dht.valueFound", scheme = "proto.tl");
353 const NOT_FOUND_TL_ID: u32 = tl_proto::id!("dht.valueNotFound", scheme = "proto.tl");
354
355 match self {
356 Self::Found(value) => {
357 packet.write_u32(FOUND_TL_ID);
358 packet.write_raw_slice(value);
359 }
360 Self::NotFound(nodes) => {
361 packet.write_u32(NOT_FOUND_TL_ID);
362 nodes.write_to(packet);
363 }
364 }
365 }
366}
367
368#[derive(Debug, Clone, TlRead, TlWrite)]
370#[tl(boxed, id = "dht.nodeInfoFound", scheme = "proto.tl")]
371pub struct NodeInfoResponse {
372 pub info: PeerInfo,
374}
375
376pub mod rpc {
378 use super::*;
379
380 #[derive(Debug, Clone, TlRead, TlWrite)]
382 #[tl(boxed, id = "dht.withPeerInfo", scheme = "proto.tl")]
383 #[repr(transparent)]
384 pub struct WithPeerInfo {
385 pub peer_info: PeerInfo,
387 }
388
389 impl WithPeerInfo {
390 pub fn wrap(value: &'_ PeerInfo) -> &'_ Self {
391 unsafe { &*(value as *const PeerInfo).cast() }
393 }
394 }
395
396 #[derive(Debug, Clone, TlRead, TlWrite)]
398 #[tl(boxed, id = "dht.store", scheme = "proto.tl")]
399 #[repr(transparent)]
400 pub struct Store {
401 pub value: Value,
403 }
404
405 #[derive(Debug, Clone, TlRead, TlWrite)]
407 #[tl(boxed, id = "dht.store", scheme = "proto.tl")]
408 #[repr(transparent)]
409 pub struct StoreRef<'tl> {
410 pub value: ValueRef<'tl>,
412 }
413
414 impl<'tl> StoreRef<'tl> {
415 pub fn wrap<'a>(value: &'a ValueRef<'tl>) -> &'a Self {
416 unsafe { &*(value as *const ValueRef<'tl>).cast() }
418 }
419 }
420
421 #[derive(Debug, Clone, TlRead, TlWrite)]
425 #[tl(boxed, id = "dht.findNode", scheme = "proto.tl")]
426 pub struct FindNode {
427 pub key: [u8; 32],
429 pub k: u32,
431 }
432
433 #[derive(Debug, Clone, TlRead, TlWrite)]
437 #[tl(boxed, id = "dht.findValue", scheme = "proto.tl")]
438 pub struct FindValue {
439 pub key: [u8; 32],
441 pub k: u32,
443 }
444
445 #[derive(Debug, Clone, TlRead, TlWrite)]
449 #[tl(boxed, id = "dht.getNodeInfo", scheme = "proto.tl")]
450 pub struct GetNodeInfo;
451}