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 let client = reqwest::Client::builder()
33 .timeout(std::time::Duration::from_secs(15))
34 .build()
35 .unwrap_or_else(|_| reqwest::Client::new());
36
37 Self {
38 gateway_url: url,
39 client,
40 }
41 }
42}
43
44#[cfg(not(target_arch = "wasm32"))]
45#[async_trait]
46impl DidResolver for GatewayResolver {
47 async fn resolve(&self, did: &str) -> crate::error::Result<Document> {
48 let parsed = did_ma::Did::try_from(did).map_err(crate::error::Error::Validation)?;
49 let url = format!("{}ipns/{}", self.gateway_url, parsed.ipns);
50
51 let response =
52 self.client
53 .get(&url)
54 .send()
55 .await
56 .map_err(|e| crate::error::Error::Resolution {
57 did: did.to_string(),
58 detail: e.to_string(),
59 })?;
60
61 if !response.status().is_success() {
62 return Err(crate::error::Error::Resolution {
63 did: did.to_string(),
64 detail: format!("gateway returned {}", response.status()),
65 });
66 }
67
68 let body = response
69 .text()
70 .await
71 .map_err(|e| crate::error::Error::Resolution {
72 did: did.to_string(),
73 detail: e.to_string(),
74 })?;
75
76 Document::unmarshal(&body).map_err(|e| crate::error::Error::Resolution {
77 did: did.to_string(),
78 detail: e.to_string(),
79 })
80 }
81}