Skip to content

Commit

Permalink
feat: Introduce IpnsError, add conversion and borrow type to function…
Browse files Browse the repository at this point in the history
… signatures (#309)
  • Loading branch information
dariusc93 authored Sep 28, 2024
1 parent 3a48b8f commit 1f618e2
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- chore: Replace tokio-stream `StreamMap` with pollable-map `StreamMap`. [PR 306](https://github.com/dariusc93/rust-ipfs/pull/306)
- chore: Provide `BitswapMessage` instead of `bitswap_pb::Message`. [PR 308](https://github.com/dariusc93/rust-ipfs/pull/308)
- refactor: bump msrv to 1.80
- refactor: Add custom error for ipns, added `Borrow<Cid>`, `Borrow<IpfsPath>` and `Into<IpfsPath>` to different function signatures. [PR 309](https://github.com/dariusc93/rust-ipfs/pull/309)

# 0.11.21
- chore: Put libp2p-webrtc-websys behind feature.
Expand Down
59 changes: 38 additions & 21 deletions src/ipns/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! IPNS functionality around [`Ipfs`].
use futures_timeout::TimeoutExt;
use std::borrow::Borrow;

use crate::error::Error;
use crate::p2p::DnsResolver;
use crate::path::{IpfsPath, PathRoot};
use crate::Ipfs;
Expand All @@ -13,7 +13,7 @@ mod dnslink;
#[derive(Clone, Debug)]
pub struct Ipns {
ipfs: Ipfs,
resolver: Option<DnsResolver>,
resolver: DnsResolver,
}

#[derive(Clone, Copy, Debug, Default)]
Expand All @@ -27,22 +27,22 @@ impl Ipns {
pub fn new(ipfs: Ipfs) -> Self {
Ipns {
ipfs,
resolver: None,
resolver: DnsResolver::default(),
}
}

/// Set dns resolver
pub fn set_resolver(&mut self, resolver: DnsResolver) {
self.resolver = Some(resolver);
self.resolver = resolver;
}

/// Resolves a ipns path to an ipld path.
// TODO: Implement ipns pubsub
// TODO: Maybe implement a check to the dht store itself too?
pub async fn resolve(&self, path: &IpfsPath) -> Result<IpfsPath, Error> {
let path = path.to_owned();
pub async fn resolve<B: Borrow<IpfsPath>>(&self, path: B) -> Result<IpfsPath, IpnsError> {
let path = path.borrow();
match path.root() {
PathRoot::Ipld(_) => Ok(path),
PathRoot::Ipld(_) => Ok(path.clone()),
PathRoot::Ipns(peer) => {
use std::str::FromStr;
use std::time::Duration;
Expand All @@ -54,13 +54,14 @@ impl Ipns {

let mut path_iter = path.iter();

let hash = Multihash::from_bytes(&peer.to_bytes())?;
let hash = Multihash::from_bytes(&peer.to_bytes()).map_err(anyhow::Error::from)?;

let cid = Cid::new_v1(0x72, hash);

let mb = format!(
"/ipns/{}",
cid.to_string_of_base(multibase::Base::Base36Lower)?
cid.to_string_of_base(multibase::Base::Base36Lower)
.map_err(anyhow::Error::from)?
);

//TODO: Determine if we want to encode the cid of the multihash in base32 or if we can just use the peer id instead
Expand Down Expand Up @@ -105,7 +106,7 @@ impl Ipns {
.unwrap_or_default();

if records.is_empty() {
anyhow::bail!("No records found")
return Err(anyhow::anyhow!("No records found").into());
}

records.sort_by_key(|record| record.sequence());
Expand All @@ -117,7 +118,7 @@ impl Ipns {
let path = String::from_utf8_lossy(data.value()).to_string();

IpfsPath::from_str(&path)
.map_err(anyhow::Error::from)
.map_err(IpnsError::from)
.and_then(|mut internal_path| {
internal_path
.path
Expand All @@ -128,36 +129,41 @@ impl Ipns {
}
PathRoot::Dns(domain) => {
let path_iter = path.iter();
Ok(dnslink::resolve(self.resolver.unwrap_or_default(), domain, path_iter).await?)
dnslink::resolve(self.resolver, domain, path_iter)
.await
.map_err(IpnsError::from)
}
}
}

pub async fn publish(
pub async fn publish<B: Borrow<IpfsPath>>(
&self,
key: Option<&str>,
path: &IpfsPath,
option: Option<IpnsOption>,
) -> Result<IpfsPath, Error> {
path: B,
option: IpnsOption,
) -> Result<IpfsPath, IpnsError> {
use ipld_core::cid::Cid;
use libp2p::kad::Quorum;
use multihash::Multihash;
use std::str::FromStr;

let path = path.borrow();

let keypair = match key {
Some(key) => self.ipfs.keystore().get_keypair(key).await?,
None => self.ipfs.keypair().clone(),
};

let peer_id = keypair.public().to_peer_id();

let hash = Multihash::from_bytes(&peer_id.to_bytes())?;
let hash = Multihash::from_bytes(&peer_id.to_bytes()).map_err(anyhow::Error::from)?;

let cid = Cid::new_v1(0x72, hash);

let mb = format!(
"/ipns/{}",
cid.to_string_of_base(multibase::Base::Base36Lower)?
cid.to_string_of_base(multibase::Base::Base36Lower)
.map_err(anyhow::Error::from)?
);

let repo = self.ipfs.repo();
Expand All @@ -178,7 +184,7 @@ impl Ipns {
let ipfs_path = IpfsPath::from_str(&String::from_utf8_lossy(data.value()))?;

if ipfs_path.eq(path) {
return IpfsPath::from_str(&mb);
return IpfsPath::from_str(&mb).map_err(IpnsError::from);
}

// inc req of the record
Expand All @@ -199,11 +205,22 @@ impl Ipns {

datastore.put(mb.as_bytes(), &bytes).await?;

match option.unwrap_or_default() {
match option {
IpnsOption::DHT => self.ipfs.dht_put(&mb, bytes, Quorum::One).await?,
IpnsOption::Local => {}
};

IpfsPath::from_str(&mb)
IpfsPath::from_str(&mb).map_err(IpnsError::from)
}
}

#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
pub enum IpnsError {
#[error(transparent)]
IpfsPath(#[from] crate::path::IpfsPathError),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Any(#[from] anyhow::Error),
}
50 changes: 29 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,15 @@ use tracing_futures::Instrument;
use unixfs::UnixfsGet;
use unixfs::{AddOpt, IpfsUnixfs, UnixfsAdd, UnixfsCat, UnixfsLs};

use self::{
dag::IpldDag,
ipns::Ipns,
p2p::{create_swarm, TSwarm},
repo::Repo,
};
use ipld_core::cid::Cid;
use ipld_core::ipld::Ipld;
use std::borrow::Borrow;
use std::{
collections::{BTreeSet, HashMap, HashSet},
fmt,
Expand All @@ -83,13 +90,6 @@ use std::{
time::Duration,
};

use self::{
dag::IpldDag,
ipns::Ipns,
p2p::{create_swarm, TSwarm},
repo::Repo,
};

pub use self::p2p::gossipsub::SubscriptionStream;

pub use self::{
Expand Down Expand Up @@ -1111,17 +1111,21 @@ impl Ipfs {

/// Retrieves a block from the local blockstore, or starts fetching from the network or join an
/// already started fetch.
pub async fn get_block(&self, cid: &Cid) -> Result<Block, Error> {
pub async fn get_block<C: Borrow<Cid>>(&self, cid: C) -> Result<Block, Error> {
self.repo
.get_block(cid, &[], false)
.instrument(self.span.clone())
.await
}

/// Remove block from the ipfs repo. A pinned block cannot be removed.
pub async fn remove_block(&self, cid: Cid, recursive: bool) -> Result<Vec<Cid>, Error> {
pub async fn remove_block<C: Borrow<Cid>>(
&self,
cid: C,
recursive: bool,
) -> Result<Vec<Cid>, Error> {
self.repo
.remove_block(&cid, recursive)
.remove_block(cid, recursive)
.instrument(self.span.clone())
.await
}
Expand Down Expand Up @@ -1152,7 +1156,7 @@ impl Ipfs {
/// If a recursive `insert_pin` operation is interrupted because of a crash or the crash
/// prevents from synchronizing the data store to disk, this will leave the system in an inconsistent
/// state. The remedy is to re-pin recursive pins.
pub fn insert_pin(&self, cid: &Cid) -> RepoInsertPin {
pub fn insert_pin<C: Borrow<Cid>>(&self, cid: C) -> RepoInsertPin {
self.repo().pin(cid).span(self.span.clone())
}

Expand All @@ -1162,7 +1166,7 @@ impl Ipfs {
///
/// Unpinning an indirectly pinned Cid is not possible other than through its recursively
/// pinned tree roots.
pub fn remove_pin(&self, cid: &Cid) -> RepoRemovePin {
pub fn remove_pin<C: Borrow<Cid>>(&self, cid: C) -> RepoRemovePin {
self.repo().remove_pin(cid).span(self.span.clone())
}

Expand All @@ -1179,8 +1183,8 @@ impl Ipfs {
/// Works correctly only under no-crash situations. Workaround for hitting a crash is to re-pin
/// any existing recursive pins.
///
pub async fn is_pinned(&self, cid: &Cid) -> Result<bool, Error> {
let span = debug_span!(parent: &self.span, "is_pinned", cid = %cid);
pub async fn is_pinned<C: Borrow<Cid>>(&self, cid: C) -> Result<bool, Error> {
let span = debug_span!(parent: &self.span, "is_pinned", cid = %cid.borrow());
self.repo.is_pinned(cid).instrument(span).await
}

Expand Down Expand Up @@ -1242,17 +1246,21 @@ impl Ipfs {
}

/// Retreive a file and saving it to a path.
pub fn get_unixfs<P: AsRef<Path>>(&self, path: IpfsPath, dest: P) -> UnixfsGet {
pub fn get_unixfs<I: Into<IpfsPath>, P: AsRef<Path>>(&self, path: I, dest: P) -> UnixfsGet {
self.unixfs().get(path, dest).span(self.span.clone())
}

/// List directory contents
pub fn ls_unixfs(&self, path: IpfsPath) -> UnixfsLs {
pub fn ls_unixfs<I: Into<IpfsPath>>(&self, path: I) -> UnixfsLs {
self.unixfs().ls(path).span(self.span.clone())
}

/// Resolves a ipns path to an ipld path; currently only supports dht and dnslink resolution.
pub async fn resolve_ipns(&self, path: &IpfsPath, recursive: bool) -> Result<IpfsPath, Error> {
pub async fn resolve_ipns<B: Borrow<IpfsPath>>(
&self,
path: B,
recursive: bool,
) -> Result<IpfsPath, Error> {
async move {
let ipns = self.ipns();
let mut resolved = ipns.resolve(path).await;
Expand All @@ -1266,17 +1274,17 @@ impl Ipfs {
resolved = ipns.resolve(res).await;
}
}
resolved
Ok(resolved?)
}
.instrument(self.span.clone())
.await
}

/// Publish ipns record to DHT
pub async fn publish_ipns(&self, path: &IpfsPath) -> Result<IpfsPath, Error> {
pub async fn publish_ipns<B: Borrow<IpfsPath>>(&self, path: B) -> Result<IpfsPath, Error> {
async move {
let ipns = self.ipns();
ipns.publish(None, path, None).await
ipns.publish(None, path, Default::default()).await.map_err(anyhow::Error::from)
}
.instrument(self.span.clone())
.await
Expand Down Expand Up @@ -2752,7 +2760,7 @@ mod tests {
let cid = ipfs.put_dag(data.clone()).pin(false).await.unwrap();

assert!(ipfs.is_pinned(&cid).await.unwrap());
ipfs.remove_pin(&cid).await.unwrap();
ipfs.remove_pin(cid).await.unwrap();
assert!(!ipfs.is_pinned(&cid).await.unwrap());
}
}
Loading

0 comments on commit 1f618e2

Please sign in to comment.