Skip to main content

did_pkarr/
io.rs

1use std::{future::Future, time::SystemTime};
2
3pub use pkarr::Client;
4use pkarr::Timestamp;
5
6use crate::{
7	doc::{ToPkarrErr, TryFromSignedPacketErr},
8	DidPkarr, DidPkarrDocument,
9};
10
11#[derive(Debug, thiserror::Error)]
12pub enum ResolveErr {
13	#[error("could not resolve with PKARR")]
14	NotFound,
15	#[error("failed to convert from pkarr into DID Document")]
16	Invalid(#[from] TryFromSignedPacketErr),
17}
18
19#[derive(Debug, thiserror::Error)]
20pub enum PublishErr {
21	#[error("failed to convert from DID Document to pkarr")]
22	ToPkarr(#[from] ToPkarrErr),
23	#[error("failed to publish with pkarr client")]
24	IoErr(#[from] pkarr::errors::PublishError),
25}
26
27#[cfg(any(feature = "dht", feature = "http"))]
28pub trait PkarrClientExt {
29	/// Like [`pkarr::Client::resolve`] but for DIDs.
30	fn resolve(
31		&self,
32		did: &DidPkarr,
33	) -> impl Future<Output = Result<DidPkarrDocument, ResolveErr>> + Send;
34
35	/// Like [`pkarr::Client::resolve_most_recent`] but for DIDs.
36	fn resolve_most_recent(
37		&self,
38		did: &DidPkarr,
39	) -> impl Future<Output = Result<DidPkarrDocument, ResolveErr>> + Send;
40
41	/// Like [`pkarr::Client::publish`] but for DIDs.
42	fn publish(
43		&self,
44		doc: &DidPkarrDocument,
45		timestamp: Option<Timestamp>,
46		signing_key: &ed25519_dalek::SigningKey,
47	) -> impl Future<Output = Result<(), PublishErr>> + Send;
48}
49
50#[cfg(any(feature = "dht", feature = "http"))]
51pub trait PkarrClientBlockingExt {
52	/// Like [`pkarr::Client::resolve`] but for DIDs.
53	fn resolve(&self, did: &DidPkarr) -> Result<DidPkarrDocument, ResolveErr>;
54
55	/// Like [`pkarr::Client::resolve_most_recent`] but for DIDs.
56	fn resolve_most_recent(
57		&self,
58		did: &DidPkarr,
59	) -> Result<DidPkarrDocument, ResolveErr>;
60
61	/// Like [`pkarr::Client::publish`] but for DIDs.
62	fn publish(
63		&self,
64		doc: &DidPkarrDocument,
65		timestamp: Option<Timestamp>,
66		signing_key: &ed25519_dalek::SigningKey,
67	) -> Result<(), PublishErr>;
68}
69
70#[cfg(any(feature = "dht", feature = "http"))]
71impl PkarrClientExt for pkarr::Client {
72	async fn resolve(&self, did: &DidPkarr) -> Result<DidPkarrDocument, ResolveErr> {
73		{
74			let public_key = pkarr::PublicKey::try_from(did.as_pubkey()).unwrap();
75			let Some(packet) = self.resolve(&public_key).await else {
76				return Err(ResolveErr::NotFound);
77			};
78
79			DidPkarrDocument::try_from(packet).map_err(ResolveErr::from)
80		}
81	}
82
83	async fn resolve_most_recent(
84		&self,
85		did: &DidPkarr,
86	) -> Result<DidPkarrDocument, ResolveErr> {
87		let public_key = pkarr::PublicKey::try_from(did.as_pubkey()).unwrap();
88		let Some(packet) = self.resolve_most_recent(&public_key).await else {
89			return Err(ResolveErr::NotFound);
90		};
91
92		DidPkarrDocument::try_from(packet).map_err(ResolveErr::from)
93	}
94
95	async fn publish(
96		&self,
97		doc: &DidPkarrDocument,
98		timestamp: Option<Timestamp>,
99		signing_key: &ed25519_dalek::SigningKey,
100	) -> Result<(), PublishErr> {
101		let timestamp = if let Some(timestamp) = timestamp {
102			timestamp
103		} else {
104			SystemTime::now().into()
105		};
106		let signed_packet = doc.to_pkarr_packet(signing_key, timestamp)?;
107
108		self.publish(&signed_packet, Some(timestamp))
109			.await
110			.map_err(PublishErr::from)
111	}
112}
113
114#[cfg(any(feature = "dht", feature = "http"))]
115impl PkarrClientBlockingExt for pkarr::ClientBlocking {
116	fn resolve(&self, did: &DidPkarr) -> Result<DidPkarrDocument, ResolveErr> {
117		{
118			let public_key = pkarr::PublicKey::try_from(did.as_pubkey()).unwrap();
119			let Some(packet) = self.resolve(&public_key) else {
120				return Err(ResolveErr::NotFound);
121			};
122
123			DidPkarrDocument::try_from(packet).map_err(ResolveErr::from)
124		}
125	}
126
127	fn resolve_most_recent(
128		&self,
129		did: &DidPkarr,
130	) -> Result<DidPkarrDocument, ResolveErr> {
131		let public_key = pkarr::PublicKey::try_from(did.as_pubkey()).unwrap();
132		let Some(packet) = self.resolve_most_recent(&public_key) else {
133			return Err(ResolveErr::NotFound);
134		};
135
136		DidPkarrDocument::try_from(packet).map_err(ResolveErr::from)
137	}
138
139	fn publish(
140		&self,
141		doc: &DidPkarrDocument,
142		timestamp: Option<Timestamp>,
143		signing_key: &ed25519_dalek::SigningKey,
144	) -> Result<(), PublishErr> {
145		let timestamp = if let Some(timestamp) = timestamp {
146			timestamp
147		} else {
148			SystemTime::now().into()
149		};
150		let signed_packet = doc.to_pkarr_packet(signing_key, timestamp)?;
151
152		self.publish(&signed_packet, Some(timestamp))
153			.map_err(PublishErr::from)
154	}
155}