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: &mut &'a [u8]) -> tl_proto::TlResult<Self> {
245 let id = u32::read_from(&mut std::convert::identity(packet))?;
246 match id {
247 PeerValue::TL_ID => PeerValue::read_from(packet).map(Self::Peer),
248 MergedValue::TL_ID => MergedValue::read_from(packet).map(Self::Merged),
249 _ => Err(tl_proto::TlError::UnknownConstructor),
250 }
251 }
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
258pub enum ValueRef<'tl> {
259 Peer(PeerValueRef<'tl>),
261 Merged(MergedValueRef<'tl>),
263}
264
265impl ValueRef<'_> {
266 pub const fn expires_at(&self) -> u32 {
267 match self {
268 Self::Peer(value) => value.expires_at,
269 Self::Merged(value) => value.expires_at,
270 }
271 }
272}
273
274impl TlWrite for ValueRef<'_> {
275 type Repr = tl_proto::Boxed;
276
277 fn max_size_hint(&self) -> usize {
278 match self {
279 Self::Peer(value) => value.max_size_hint(),
280 Self::Merged(value) => value.max_size_hint(),
281 }
282 }
283
284 fn write_to<P>(&self, packet: &mut P)
285 where
286 P: tl_proto::TlPacket,
287 {
288 match self {
289 Self::Peer(value) => value.write_to(packet),
290 Self::Merged(value) => value.write_to(packet),
291 }
292 }
293}
294
295impl<'a> TlRead<'a> for ValueRef<'a> {
296 type Repr = tl_proto::Boxed;
297
298 fn read_from(packet: &mut &'a [u8]) -> tl_proto::TlResult<Self> {
299 let id = u32::read_from(&mut std::convert::identity(packet))?;
300 match id {
301 PeerValue::TL_ID => PeerValueRef::read_from(packet).map(Self::Peer),
302 MergedValue::TL_ID => MergedValueRef::read_from(packet).map(Self::Merged),
303 _ => Err(tl_proto::TlError::UnknownConstructor),
304 }
305 }
306}
307
308#[derive(Debug, Clone, TlRead, TlWrite)]
310#[tl(boxed, id = "dht.nodesFound", scheme = "proto.tl")]
311pub struct NodeResponse {
312 #[tl(with = "tl::VecWithMaxLen::<20>")]
314 pub nodes: Vec<Arc<PeerInfo>>,
315}
316
317#[derive(Debug, Clone, TlRead, TlWrite)]
319#[tl(boxed, scheme = "proto.tl")]
320pub enum ValueResponse {
321 #[tl(id = "dht.valueFound")]
323 Found(Box<Value>),
324 #[tl(id = "dht.valueNotFound")]
326 NotFound(#[tl(with = "tl::VecWithMaxLen::<20>")] Vec<Arc<PeerInfo>>),
327}
328
329#[derive(Debug, Clone)]
331pub enum ValueResponseRaw {
332 Found(Bytes),
333 NotFound(Vec<Arc<PeerInfo>>),
334}
335
336impl TlWrite for ValueResponseRaw {
337 type Repr = tl_proto::Boxed;
338
339 fn max_size_hint(&self) -> usize {
340 4 + match self {
341 Self::Found(value) => value.max_size_hint(),
342 Self::NotFound(nodes) => nodes.max_size_hint(),
343 }
344 }
345
346 fn write_to<P>(&self, packet: &mut P)
347 where
348 P: tl_proto::TlPacket,
349 {
350 const FOUND_TL_ID: u32 = tl_proto::id!("dht.valueFound", scheme = "proto.tl");
351 const NOT_FOUND_TL_ID: u32 = tl_proto::id!("dht.valueNotFound", scheme = "proto.tl");
352
353 match self {
354 Self::Found(value) => {
355 packet.write_u32(FOUND_TL_ID);
356 packet.write_raw_slice(value);
357 }
358 Self::NotFound(nodes) => {
359 packet.write_u32(NOT_FOUND_TL_ID);
360 nodes.write_to(packet);
361 }
362 }
363 }
364}
365
366#[derive(Debug, Clone, TlRead, TlWrite)]
368#[tl(boxed, id = "dht.nodeInfoFound", scheme = "proto.tl")]
369pub struct NodeInfoResponse {
370 pub info: PeerInfo,
372}
373
374pub mod rpc {
376 use super::*;
377
378 #[derive(Debug, Clone, TlRead, TlWrite)]
380 #[tl(boxed, id = "dht.withPeerInfo", scheme = "proto.tl")]
381 #[repr(transparent)]
382 pub struct WithPeerInfo {
383 pub peer_info: PeerInfo,
385 }
386
387 impl WithPeerInfo {
388 pub fn wrap(value: &'_ PeerInfo) -> &'_ Self {
389 unsafe { &*(value as *const PeerInfo).cast() }
391 }
392 }
393
394 #[derive(Debug, Clone, TlRead, TlWrite)]
396 #[tl(boxed, id = "dht.store", scheme = "proto.tl")]
397 #[repr(transparent)]
398 pub struct Store {
399 pub value: Value,
401 }
402
403 #[derive(Debug, Clone, TlRead, TlWrite)]
405 #[tl(boxed, id = "dht.store", scheme = "proto.tl")]
406 #[repr(transparent)]
407 pub struct StoreRef<'tl> {
408 pub value: ValueRef<'tl>,
410 }
411
412 impl<'tl> StoreRef<'tl> {
413 pub fn wrap<'a>(value: &'a ValueRef<'tl>) -> &'a Self {
414 unsafe { &*(value as *const ValueRef<'tl>).cast() }
416 }
417 }
418
419 #[derive(Debug, Clone, TlRead, TlWrite)]
423 #[tl(boxed, id = "dht.findNode", scheme = "proto.tl")]
424 pub struct FindNode {
425 pub key: [u8; 32],
427 pub k: u32,
429 }
430
431 #[derive(Debug, Clone, TlRead, TlWrite)]
435 #[tl(boxed, id = "dht.findValue", scheme = "proto.tl")]
436 pub struct FindValue {
437 pub key: [u8; 32],
439 pub k: u32,
441 }
442
443 #[derive(Debug, Clone, TlRead, TlWrite)]
447 #[tl(boxed, id = "dht.getNodeInfo", scheme = "proto.tl")]
448 pub struct GetNodeInfo;
449}