1use async_trait::async_trait;
4use did_ma::Document;
5
6#[async_trait]
11pub trait DidResolver: Send + Sync {
12 async fn resolve(&self, did: &str) -> crate::error::Result<Document>;
13}
14
15#[cfg(not(target_arch = "wasm32"))]
19pub struct GatewayResolver {
20 gateway_url: String,
21 client: reqwest::Client,
22}
23
24#[cfg(not(target_arch = "wasm32"))]
25impl GatewayResolver {
26 pub fn new(gateway_url: impl Into<String>) -> Self {
27 let mut url = gateway_url.into();
28 if !url.ends_with('/') {
30 url.push('/');
31 }
32 Self {
33 gateway_url: url,
34 client: reqwest::Client::builder()
35 .timeout(std::time::Duration::from_secs(15))
36 .build()
37 .expect("failed to build HTTP client"),
38 }
39 }
40}
41
42#[cfg(not(target_arch = "wasm32"))]
43#[async_trait]
44impl DidResolver for GatewayResolver {
45 async fn resolve(&self, did: &str) -> crate::error::Result<Document> {
46 let parsed = did_ma::Did::try_from(did).map_err(crate::error::Error::Validation)?;
47 let url = format!("{}ipns/{}", self.gateway_url, parsed.ipns);
48
49 let response =
50 self.client
51 .get(&url)
52 .send()
53 .await
54 .map_err(|e| crate::error::Error::Resolution {
55 did: did.to_string(),
56 detail: e.to_string(),
57 })?;
58
59 if !response.status().is_success() {
60 return Err(crate::error::Error::Resolution {
61 did: did.to_string(),
62 detail: format!("gateway returned {}", response.status()),
63 });
64 }
65
66 let body = response
67 .text()
68 .await
69 .map_err(|e| crate::error::Error::Resolution {
70 did: did.to_string(),
71 detail: e.to_string(),
72 })?;
73
74 Document::unmarshal(&body).map_err(|e| crate::error::Error::Resolution {
75 did: did.to_string(),
76 detail: e.to_string(),
77 })
78 }
79}