Skip to content

Commit

Permalink
feat: add resolve and resolve_eager
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuhvi committed Nov 25, 2023
1 parent 684db6a commit 687a37c
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 38 deletions.
49 changes: 49 additions & 0 deletions pkarr/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Examples

## Publish

```sh
cargo run --example publish
```

## Resolve Eager

```sh
cargo run --example resolve <zbase32 public key from Publish step>
```

## Resolve Most Recent

```sh
cargo run --example resolve-most-recent <zbase32 public key from Publish step>
```

## Relay

```sh
cargo run --example relay-client
```

## Async Publish

```sh
cargo run --example async-publish --features="async"
```

## Async Resolve Eager

```sh
cargo run --example async-resolve --features="async" <zbase32 public key from Publish step>
```

## Resolve Most Recent

```sh
cargo run --example async-resolve-most-recent --features="async" <zbase32 public key from Publish step>
```

## Relay

```sh
cargo run --example async-relay-client --features="relay async"
```
2 changes: 1 addition & 1 deletion pkarr/examples/async/relay-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async fn main() -> Result<()> {

// Publisher
{
println!("\nPublishing pk:{}...\n", keypair);
println!("\nPublishing pk:{} ...\n", keypair);
let mut packet = dns::Packet::new_reply(0);
packet.answers.push(dns::ResourceRecord::new(
dns::Name::new("_derp_region.iroh.").unwrap(),
Expand Down
2 changes: 1 addition & 1 deletion pkarr/examples/async/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async fn main() {

println!("\nResolving pk:{} ...", public_key);

if let Some(signed_packet) = client.resolve(public_key).await {
if let Some(signed_packet) = client.resolve_eager(public_key).await {
println!("\nResolved in {:?} {}", instant.elapsed(), signed_packet);
} else {
println!("\nFailed to resolve {}", str);
Expand Down
2 changes: 1 addition & 1 deletion pkarr/examples/relay-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn main() -> Result<()> {

// Publisher
{
println!("\nPublishing pk:{}...\n", keypair);
println!("\nPublishing pk:{} ...\n", keypair);
let mut packet = dns::Packet::new_reply(0);
packet.answers.push(dns::ResourceRecord::new(
dns::Name::new("_derp_region.iroh.").unwrap(),
Expand Down
2 changes: 1 addition & 1 deletion pkarr/examples/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn main() {

println!("\nResolving pk:{} ...", public_key);

if let Some(signed_packet) = client.resolve(public_key) {
if let Some(signed_packet) = client.resolve_eager(public_key) {
println!("\nResolved in {:?} {}", instant.elapsed(), signed_packet);
} else {
println!("\nFailed to resolve {}", str);
Expand Down
8 changes: 4 additions & 4 deletions pkarr/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Rust implementation of [Pkarr](pkarr.org).

Publish and resolve DNS packets over Mainline DHT.

## Example
**[API Docs](https://docs.rs/pkarr/latest/pkarr/)**

```bash
cargo run --example relay-client
```
## Get started

Check the [Examples](./examples).
67 changes: 37 additions & 30 deletions pkarr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#[cfg(feature = "dht")]
use mainline::{
common::{MutableItem, StoreQueryMetdata},
common::{GetMutableResponse, MutableItem, Response, StoreQueryMetdata},
Dht,
};
#[cfg(feature = "relay")]
Expand Down Expand Up @@ -36,7 +36,7 @@ pub struct PkarrClient {
http_client: reqwest::blocking::Client,
#[cfg(all(feature = "relay", feature = "async"))]
http_client: reqwest::Client,
pub dht: Dht,
dht: Dht,
}

impl PkarrClient {
Expand Down Expand Up @@ -83,7 +83,7 @@ impl PkarrClient {
}

#[cfg(all(feature = "relay", feature = "async"))]
/// Async version of [relay_get](PkarrClient::relay_get)
/// Resolves a [SignedPacket] from a [relay](https://github.com/Nuhvi/pkarr/blob/main/design/relays.md).
pub async fn relay_get(&self, url: &Url, public_key: PublicKey) -> Result<SignedPacket> {
let url = format_relay_url(url, &public_key);

Expand All @@ -101,7 +101,7 @@ impl PkarrClient {
}

#[cfg(all(feature = "relay", not(feature = "async")))]
/// Publishes a [SignedPacket](crate::SignedPacket) through a [relay](https://github.com/Nuhvi/pkarr/blob/main/design/relays.md).
/// Publishes a [SignedPacket] through a [relay](https://github.com/Nuhvi/pkarr/blob/main/design/relays.md).
pub fn relay_put(&self, url: &Url, signed_packet: SignedPacket) -> Result<()> {
let url = format_relay_url(url, signed_packet.public_key());

Expand All @@ -123,7 +123,7 @@ impl PkarrClient {
}

#[cfg(all(feature = "relay", feature = "async"))]
/// Async version of [relay_put](PkarrClient::relay_put)
/// Publishes a [SignedPacket] through a [relay](https://github.com/Nuhvi/pkarr/blob/main/design/relays.md).
pub async fn relay_put(&self, url: &Url, signed_packet: SignedPacket) -> Result<()> {
let url = format_relay_url(url, signed_packet.public_key());

Expand Down Expand Up @@ -156,15 +156,36 @@ impl PkarrClient {
}

#[cfg(all(feature = "dht", feature = "async"))]
/// Async version of [publish](PkarrClient::publish)
/// Publish a [SignedPacket] to the DHT.
///
/// It performs a thorough lookup first to find the closest nodes,
/// before storing the signed packet to them, so it may take few seconds.
pub async fn publish(&self, signed_packet: &SignedPacket) -> Result<StoreQueryMetdata> {
let item: MutableItem = signed_packet.into();
self.dht.put_mutable(item).map_err(Error::MainlineError)
}

#[cfg(all(feature = "dht", not(feature = "async")))]
/// Returns the first resolved [SignedPacket] from the DHT.
pub fn resolve(&self, public_key: PublicKey) -> Option<SignedPacket> {
/// Return `mainline's` [Response] to have the most control over the response and access its metadata.
///
/// Most likely you want to use [resolve_eager](PkarrClient::resolve_eager) or
/// [resolve_most_recent](PkarrClient::resolve_most_recent) instead.
pub fn resolve(&self, public_key: PublicKey) -> Response<GetMutableResponse> {
self.dht.get_mutable(public_key.as_bytes(), None)
}

#[cfg(all(feature = "dht", feature = "async"))]
/// Return `mainline's` [Response] to have the most control over the response and access its metadata.
///
/// Most likely you want to use [resolve_eager](PkarrClient::resolve_eager) or
/// [resolve_most_recent](PkarrClient::resolve_most_recent) instead.
pub async fn resolve(&self, public_key: PublicKey) -> Response<GetMutableResponse> {
self.dht.get_mutable(public_key.as_bytes(), None)
}

#[cfg(all(feature = "dht", not(feature = "async")))]
/// Return the first resolved [SignedPacket] from the DHT.
pub fn resolve_eager(&self, public_key: PublicKey) -> Option<SignedPacket> {
let mut response = self.dht.get_mutable(public_key.as_bytes(), None);

for res in &mut response {
Expand All @@ -178,8 +199,8 @@ impl PkarrClient {
}

#[cfg(all(feature = "dht", feature = "async"))]
/// Returns the first resolved [SignedPacket](crate::SignedPacket) from the DHT.
pub async fn resolve(&self, public_key: PublicKey) -> Option<SignedPacket> {
/// Return the first resolved [SignedPacket] from the DHT.
pub async fn resolve_eager(&self, public_key: PublicKey) -> Option<SignedPacket> {
let mut response = self.dht.get_mutable(public_key.as_bytes(), None);

for res in &mut response {
Expand All @@ -193,7 +214,7 @@ impl PkarrClient {
}

#[cfg(all(feature = "dht", not(feature = "async")))]
/// Returns the most recent [SignedPacket] from the DHT.
/// Return the most recent [SignedPacket] from the DHT.
/// In order to determine the most recent, it has to do a full lookup first, so
/// this method may take few seconds.
pub fn resolve_most_recent(&self, public_key: PublicKey) -> Option<SignedPacket> {
Expand All @@ -205,15 +226,7 @@ impl PkarrClient {
let signed_packet: Result<SignedPacket> = res.item.try_into();
if let Ok(signed_packet) = signed_packet {
if let Some(most_recent) = &most_recent {
if signed_packet.timestamp() < most_recent.timestamp() {
continue;
}

// In the rare ocasion of timestamp collission,
// we use the one with the largest value
if signed_packet.timestamp() == most_recent.timestamp()
&& signed_packet.encoded_packet() < most_recent.encoded_packet()
{
if signed_packet.more_recent_than(most_recent) {
continue;
}
}
Expand All @@ -226,7 +239,9 @@ impl PkarrClient {
}

#[cfg(all(feature = "dht", feature = "async"))]
/// Async version of [resolve_most_recent](PkarrClient::resolve_most_recent).
/// Return the most recent [SignedPacket] from the DHT.
/// In order to determine the most recent, it has to do a full lookup first, so
/// this method may take few seconds.
pub async fn resolve_most_recent(&self, public_key: PublicKey) -> Option<SignedPacket> {
let mut response = self.dht.get_mutable(public_key.as_bytes(), None);

Expand All @@ -236,17 +251,9 @@ impl PkarrClient {
let signed_packet: Result<SignedPacket> = res.item.try_into();
if let Ok(signed_packet) = signed_packet {
if let Some(most_recent) = &most_recent {
if signed_packet.timestamp() < most_recent.timestamp() {
if signed_packet.more_recent_than(most_recent) {
continue;
}

// In the rare ocasion of timestamp collission,
// we use the one with the largest value
if signed_packet.timestamp() == most_recent.timestamp() {
if signed_packet.encoded_packet() < most_recent.encoded_packet() {
continue;
}
}
}

most_recent = Some(signed_packet)
Expand Down
21 changes: 21 additions & 0 deletions pkarr/src/signed_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,27 @@ impl SignedPacket {
pub fn encoded_packet(&self) -> Bytes {
self.inner.borrow_owner().slice(104..)
}

// === Public Methods ===

/// Return whether this {SignedPacket] is more recent than the given one.
/// If the timestamps are erqual, the one with the largest value is considered more recent.
/// Usefel for determining which packet contains the latest information from the Dht.
/// Assumes that both packets have the same [PublicKey], you shouldn't compare packets from
/// different keys.
pub fn more_recent_than(&self, other: &SignedPacket) -> bool {
if self.timestamp() < other.timestamp() {
return false;
}

// In the rare ocasion of timestamp collission,
// we use the one with the largest value
if self.timestamp() == other.timestamp() && self.encoded_packet() < other.encoded_packet() {
return false;
}

true
}
}

fn signable(timestamp: u64, v: &Bytes) -> Bytes {
Expand Down

0 comments on commit 687a37c

Please sign in to comment.