litep2p/protocol/libp2p/kademlia/record.rs
1// Copyright 2019 Parity Technologies (UK) Ltd.
2// Copyright 2023 litep2p developers
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22use crate::{
23 protocol::libp2p::kademlia::types::{Distance, Key as KademliaKey},
24 Multiaddr, PeerId,
25};
26
27use bytes::Bytes;
28use multihash::Multihash;
29
30use std::{borrow::Borrow, time::Instant};
31
32/// The (opaque) key of a record.
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35pub struct Key(Bytes);
36
37impl Key {
38 /// Creates a new key from the bytes of the input.
39 pub fn new<K: AsRef<[u8]>>(key: &K) -> Self {
40 Key(Bytes::copy_from_slice(key.as_ref()))
41 }
42
43 /// Copies the bytes of the key into a new vector.
44 pub fn to_vec(&self) -> Vec<u8> {
45 Vec::from(&self.0[..])
46 }
47}
48
49impl From<Key> for Vec<u8> {
50 fn from(k: Key) -> Vec<u8> {
51 Vec::from(&k.0[..])
52 }
53}
54
55impl Borrow<[u8]> for Key {
56 fn borrow(&self) -> &[u8] {
57 &self.0[..]
58 }
59}
60
61impl AsRef<[u8]> for Key {
62 fn as_ref(&self) -> &[u8] {
63 &self.0[..]
64 }
65}
66
67impl From<Vec<u8>> for Key {
68 fn from(v: Vec<u8>) -> Key {
69 Key(Bytes::from(v))
70 }
71}
72
73impl From<Multihash> for Key {
74 fn from(m: Multihash) -> Key {
75 Key::from(m.to_bytes())
76 }
77}
78
79/// A record stored in the DHT.
80#[derive(Clone, Debug, Eq, PartialEq, Hash)]
81pub struct Record {
82 /// Key of the record.
83 pub key: Key,
84
85 /// Value of the record.
86 pub value: Vec<u8>,
87
88 /// The (original) publisher of the record.
89 pub publisher: Option<PeerId>,
90
91 /// The expiration time as measured by a local, monotonic clock.
92 pub expires: Option<Instant>,
93}
94
95impl Record {
96 /// Creates a new record for insertion into the DHT.
97 pub fn new<K>(key: K, value: Vec<u8>) -> Self
98 where
99 K: Into<Key>,
100 {
101 Record {
102 key: key.into(),
103 value,
104 publisher: None,
105 expires: None,
106 }
107 }
108
109 /// Checks whether the record is expired w.r.t. the given `Instant`.
110 pub fn is_expired(&self, now: Instant) -> bool {
111 self.expires.map_or(false, |t| now >= t)
112 }
113}
114
115/// A record received by the given peer.
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct PeerRecord {
118 /// The peer from whom the record was received
119 pub peer: PeerId,
120
121 /// The provided record.
122 pub record: Record,
123}
124
125/// A record keeping information about a content provider.
126#[derive(Clone, Debug, Eq, PartialEq, Hash)]
127pub struct ProviderRecord {
128 /// Key of the record.
129 pub key: Key,
130
131 /// Key of the provider, based on its peer ID.
132 pub provider: PeerId,
133
134 /// Cached addresses of the provider.
135 pub addresses: Vec<Multiaddr>,
136
137 /// The expiration time of the record. The provider records must always have the expiration
138 /// time.
139 pub expires: Instant,
140}
141
142impl ProviderRecord {
143 /// The distance from the provider's peer ID to the provided key.
144 pub fn distance(&self) -> Distance {
145 // Note that the record key is raw (opaque bytes). In order to calculate the distance from
146 // the provider's peer ID to this key we must first hash both.
147 KademliaKey::from(self.provider).distance(&KademliaKey::new(self.key.clone()))
148 }
149
150 /// Checks whether the record is expired w.r.t. the given `Instant`.
151 pub fn is_expired(&self, now: Instant) -> bool {
152 now >= self.expires
153 }
154}