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 fn resolve(
31 &self,
32 did: &DidPkarr,
33 ) -> impl Future<Output = Result<DidPkarrDocument, ResolveErr>> + Send;
34
35 fn resolve_most_recent(
37 &self,
38 did: &DidPkarr,
39 ) -> impl Future<Output = Result<DidPkarrDocument, ResolveErr>> + Send;
40
41 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 fn resolve(&self, did: &DidPkarr) -> Result<DidPkarrDocument, ResolveErr>;
54
55 fn resolve_most_recent(
57 &self,
58 did: &DidPkarr,
59 ) -> Result<DidPkarrDocument, ResolveErr>;
60
61 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}