pub struct Dht(/* private fields */);
Expand description
Mainline Dht node.
Implementations§
Source§impl Dht
impl Dht
Sourcepub fn new(config: Config) -> Result<Self, Error>
pub fn new(config: Config) -> Result<Self, Error>
Create a new Dht node.
Could return an error if it failed to bind to the specified port or other io errors while binding the udp socket.
Sourcepub fn builder() -> DhtBuilder
pub fn builder() -> DhtBuilder
Returns a builder to edit settings before creating a Dht node.
Sourcepub fn server() -> Result<Self, Error>
pub fn server() -> Result<Self, Error>
Create a new DHT node that is running in Server mode as soon as possible.
You shouldn’t use this option unless you are sure your DHT node is publicly accessible (not firewalled) AND will be long running, and/or you are running your own local network for testing.
If you are not sure, use Self::client and it will switch to server mode when/if these two conditions are met.
Sourcepub fn to_bootstrap(&self) -> Vec<String>
pub fn to_bootstrap(&self) -> Vec<String>
Turn this node’s routing table to a list of bootstrapping nodes.
Sourcepub fn bootstrapped(&self) -> bool
pub fn bootstrapped(&self) -> bool
Block until the bootstrapping query is done.
Returns true if the bootstrapping was successful.
Sourcepub fn find_node(&self, target: Id) -> Box<[Node]>
pub fn find_node(&self, target: Id) -> Box<[Node]>
Returns the closest 20 secure nodes to a target Id.
Mostly useful to crawl the DHT.
The returned nodes are claims by other nodes, they may be lies, or may have churned since they were last seen, but haven’t been pinged yet.
You might need to ping them to confirm they exist, and responsive, or if you want to learn more about them like the client they are using, or if they support a given BEP.
If you are trying to find the closest nodes to a target with intent to Self::put,
a request directly to these nodes (using extra_nodes
parameter), then you should
use Self::get_closest_nodes instead.
Sourcepub fn get_peers(&self, info_hash: Id) -> GetIterator<Vec<SocketAddrV4>>
pub fn get_peers(&self, info_hash: Id) -> GetIterator<Vec<SocketAddrV4>>
Get peers for a given infohash.
Note: each node of the network will only return a random subset (usually 20) of the total peers it has for a given infohash, so if you are getting responses from 20 nodes, you can expect up to 400 peers in total, but if there are more announced peers on that infohash, you are likely to miss some, the logic here for Bittorrent is that any peer will introduce you to more peers through “peer exchange” so if you are implementing something different from Bittorrent, you might want to implement your own logic for gossipping more peers after you discover the first ones.
Sourcepub fn announce_peer(
&self,
info_hash: Id,
port: Option<u16>,
) -> Result<Id, PutQueryError>
pub fn announce_peer( &self, info_hash: Id, port: Option<u16>, ) -> Result<Id, PutQueryError>
Announce a peer for a given infohash.
The peer will be announced on this process IP. If explicit port is passed, it will be used, otherwise the port will be implicitly assumed by remote nodes to be the same ase port they received the request from.
Sourcepub fn get_immutable(&self, target: Id) -> Option<Box<[u8]>>
pub fn get_immutable(&self, target: Id) -> Option<Box<[u8]>>
Get an Immutable data by its sha1 hash.
Sourcepub fn put_immutable(&self, value: &[u8]) -> Result<Id, PutQueryError>
pub fn put_immutable(&self, value: &[u8]) -> Result<Id, PutQueryError>
Put an immutable data to the DHT.
Sourcepub fn get_mutable(
&self,
public_key: &[u8; 32],
salt: Option<&[u8]>,
more_recent_than: Option<i64>,
) -> GetIterator<MutableItem>
pub fn get_mutable( &self, public_key: &[u8; 32], salt: Option<&[u8]>, more_recent_than: Option<i64>, ) -> GetIterator<MutableItem>
Get a mutable data by its public_key
and optional salt
.
You can ask for items more_recent_than
than a certain seq
,
usually one that you already have seen before, similar to If-Modified-Since
header in HTTP.
§Order
The order of MutableItems returned by this iterator is not guaranteed to
reflect their seq
value. You should not assume that the later items are
more recent than earlier ones.
Consider using Self::get_mutable_most_recent if that is what you need.
Sourcepub fn get_mutable_most_recent(
&self,
public_key: &[u8; 32],
salt: Option<&[u8]>,
) -> Option<MutableItem>
pub fn get_mutable_most_recent( &self, public_key: &[u8; 32], salt: Option<&[u8]>, ) -> Option<MutableItem>
Get the most recent MutableItem from the network.
Sourcepub fn put_mutable(
&self,
item: MutableItem,
cas: Option<i64>,
) -> Result<Id, PutMutableError>
pub fn put_mutable( &self, item: MutableItem, cas: Option<i64>, ) -> Result<Id, PutMutableError>
Put a mutable data to the DHT.
§Lost Update Problem
As mainline DHT is a distributed system, it is vulnerable to Write–write conflict.
§Read first
To mitigate the risk of lost updates, you should call the Self::get_mutable_most_recent method then start authoring the new MutableItem based on the most recent as in the following example:
use mainline::{Dht, MutableItem, SigningKey, Testnet};
let testnet = Testnet::new(3).unwrap();
let dht = Dht::builder().bootstrap(&testnet.bootstrap).build().unwrap();
let signing_key = SigningKey::from_bytes(&[0; 32]);
let key = signing_key.verifying_key().to_bytes();
let salt = Some(b"salt".as_ref());
let (item, cas) = if let Some(most_recent) = dht .get_mutable_most_recent(&key, salt) {
// 1. Optionally Create a new value to take the most recent's value in consideration.
let mut new_value = most_recent.value().to_vec();
new_value.extend_from_slice(b" more data");
// 2. Increment the sequence number to be higher than the most recent's.
let most_recent_seq = most_recent.seq();
let new_seq = most_recent_seq + 1;
(
MutableItem::new(signing_key, &new_value, new_seq, salt),
// 3. Use the most recent [MutableItem::seq] as a `CAS`.
Some(most_recent_seq)
)
} else {
(MutableItem::new(signing_key, b"first value", 1, salt), None)
};
dht.put_mutable(item, cas).unwrap();
§Errors
In addition to the PutQueryError common with all PUT queries, PUT mutable item query has other Concurrency errors, that try to detect write conflict risks or obvious conflicts.
If you are lucky to get one of these errors (which is not guaranteed), then you should read the most recent item again, and repeat the steps in the previous example.
Sourcepub fn get_closest_nodes(&self, target: Id) -> Box<[Node]>
pub fn get_closest_nodes(&self, target: Id) -> Box<[Node]>
Get closet nodes to a specific target, that support BEP_0044.
Useful to Self::put a request to nodes further from the 20 closest nodes to the PutRequestSpecific::target. Which itself is useful to circumvent extreme vertical sybil attacks.
Sourcepub fn put(
&self,
request: PutRequestSpecific,
extra_nodes: Option<Box<[Node]>>,
) -> Result<Id, PutError>
pub fn put( &self, request: PutRequestSpecific, extra_nodes: Option<Box<[Node]>>, ) -> Result<Id, PutError>
Send a PUT request to the closest nodes, and optionally some extra nodes.
This is useful to put data to regions of the DHT other than the closest nodes to this request’s target.
You can find nodes close to other regions of the network by calling Self::get_closest_nodes with the target that you want to find the closest nodes to.
Note: extra nodes need to have Node::valid_token.