An ATProtocol powered blogging engine.
1use atproto_identity::model::Document;
2use atproto_identity::resolve::IdentityResolver;
3use chrono::Utc;
4use std::sync::Arc;
5
6use crate::errors::Result;
7use crate::storage::{Identity, IdentityStorage};
8
9/// A caching identity resolver that uses an underlying `IdentityStorage` implementation
10/// to cache resolved identity documents before falling back to the underlying `IdentityResolver`.
11pub struct CachingIdentityResolver<T: IdentityStorage + ?Sized> {
12 /// The underlying identity resolver to use when cache misses occur
13 resolver: IdentityResolver,
14 /// The storage implementation to use for caching
15 storage: Arc<T>,
16}
17
18impl<T: IdentityStorage + ?Sized> CachingIdentityResolver<T> {
19 /// Create a new caching identity resolver with the given resolver and storage.
20 pub fn new(resolver: IdentityResolver, storage: Arc<T>) -> Self {
21 Self { resolver, storage }
22 }
23
24 /// Resolve a DID to a Document, using the cache when possible.
25 pub async fn resolve(&self, did: &str) -> Result<Document> {
26 // First, try to get the identity from storage
27 if let Some(identity) = self.storage.get_identity_by_did(did).await? {
28 // Parse the stored record back to a Document
29 let document: Document = serde_json::from_value(identity.record)?;
30 return Ok(document);
31 }
32
33 // If not in storage, resolve using the underlying resolver
34 let document = self.resolver.resolve(did).await?;
35
36 // Store the resolved identity for future lookups
37 self.store_resolved_identity(&document).await?;
38
39 Ok(document)
40 }
41
42 /// Store a resolved identity document in the storage.
43 async fn store_resolved_identity(&self, doc: &Document) -> Result<()> {
44 let handle = doc
45 .also_known_as
46 .first()
47 .and_then(|aka| aka.strip_prefix("at://"))
48 .unwrap_or("unknown.handle")
49 .to_string();
50
51 // Create a JSON representation of the document
52 let record = serde_json::json!(doc);
53
54 let identity = Identity {
55 did: doc.id.clone(),
56 handle,
57 record,
58 created_at: Utc::now(),
59 updated_at: Utc::now(),
60 };
61
62 self.storage.upsert_identity(&identity).await?;
63 Ok(())
64 }
65}