QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing.
···175176 result
177 }
00000000000000000000000000178}
179180/// Create a new in-memory caching handle resolver.
···175176 result
177 }
178+179+ async fn set(&self, handle: &str, did: &str) -> Result<(), HandleResolverError> {
180+ // Normalize the handle to lowercase
181+ let handle = handle.to_lowercase();
182+183+ // Update the in-memory cache
184+ {
185+ let mut cache = self.cache.write().await;
186+ let timestamp = Self::current_timestamp();
187+ cache.insert(
188+ handle.clone(),
189+ ResolveHandleResult::Found(timestamp, did.to_string()),
190+ );
191+ self.metrics.incr("resolver.memory.set").await;
192+ tracing::debug!("Set handle {} -> DID {} in memory cache", handle, did);
193+194+ // Track cache size
195+ let cache_size = cache.len() as u64;
196+ self.metrics
197+ .gauge("resolver.memory.cache_entries", cache_size)
198+ .await;
199+ }
200+201+ // Chain to inner resolver
202+ self.inner.set(&handle, did).await
203+ }
204}
205206/// Create a new in-memory caching handle resolver.
+5
src/handle_resolver/proactive_refresh.rs
···141142 Ok((did, resolve_time))
143 }
00000144}
145146/// Create a ProactiveRefreshResolver with custom threshold using trait objects
···141142 Ok((did, resolve_time))
143 }
144+145+ async fn set(&self, handle: &str, did: &str) -> Result<(), HandleResolverError> {
146+ // Simply chain to inner resolver - no proactive refresh needed for manual sets
147+ self.inner.set(handle, did).await
148+ }
149}
150151/// Create a ProactiveRefreshResolver with custom threshold using trait objects
+6
src/handle_resolver/rate_limited.rs
···187 // With permit acquired, forward to inner resolver
188 self.inner.resolve(s).await
189 }
000000190}
191192/// Create a rate-limited handle resolver.
···187 // With permit acquired, forward to inner resolver
188 self.inner.resolve(s).await
189 }
190+191+ async fn set(&self, handle: &str, did: &str) -> Result<(), HandleResolverError> {
192+ // Set operations don't need rate limiting since they're typically administrative
193+ // and don't involve network calls to external services
194+ self.inner.set(handle, did).await
195+ }
196}
197198/// Create a rate-limited handle resolver.
+64
src/handle_resolver/sqlite.rs
···255256 result
257 }
0000000000000000000000000000000000000000000000000000000000000000258}
259260/// Create a new SQLite-backed handle resolver with default 90-day TTL.
···255256 result
257 }
258+259+ async fn set(&self, handle: &str, did: &str) -> Result<(), HandleResolverError> {
260+ // Normalize the handle to lowercase
261+ let handle = handle.to_lowercase();
262+263+ // Update the SQLite cache
264+ if let Ok(mut conn) = self.pool.acquire().await {
265+ // Create a resolution result for the successful mapping
266+ let resolution_result = match HandleResolutionResult::success(did) {
267+ Ok(res) => res,
268+ Err(e) => {
269+ tracing::warn!("Failed to create resolution result for set operation: {}", e);
270+ self.metrics.incr("resolver.sqlite.set_result_create_error").await;
271+ // Still chain to inner resolver even if we can't cache
272+ return self.inner.set(&handle, did).await;
273+ }
274+ };
275+276+ // Serialize to bytes
277+ match resolution_result.to_bytes() {
278+ Ok(bytes) => {
279+ // Insert or update the cache entry
280+ let timestamp = std::time::SystemTime::now()
281+ .duration_since(std::time::UNIX_EPOCH)
282+ .unwrap_or_default()
283+ .as_secs() as i64;
284+285+ let expires_at = timestamp + self.ttl_seconds as i64;
286+287+ match sqlx::query(
288+ "INSERT OR REPLACE INTO handle_resolution_cache (handle, resolved_value, created_at, expires_at) VALUES (?, ?, ?, ?)"
289+ )
290+ .bind(&handle)
291+ .bind(&bytes)
292+ .bind(timestamp)
293+ .bind(expires_at)
294+ .execute(&mut *conn)
295+ .await
296+ {
297+ Ok(_) => {
298+ tracing::debug!("Set handle {} -> DID {} in SQLite cache", handle, did);
299+ self.metrics.incr("resolver.sqlite.set_success").await;
300+ }
301+ Err(e) => {
302+ tracing::warn!("Failed to set handle->DID mapping in SQLite: {}", e);
303+ self.metrics.incr("resolver.sqlite.set_cache_error").await;
304+ // Still chain to inner resolver even if cache update fails
305+ }
306+ }
307+ }
308+ Err(e) => {
309+ tracing::warn!("Failed to serialize resolution result for set operation: {}", e);
310+ self.metrics.incr("resolver.sqlite.set_serialize_error").await;
311+ // Still chain to inner resolver even if serialization fails
312+ }
313+ }
314+ } else {
315+ tracing::warn!("Failed to get SQLite connection for set operation");
316+ self.metrics.incr("resolver.sqlite.set_connection_error").await;
317+ }
318+319+ // Chain to inner resolver
320+ self.inner.set(&handle, did).await
321+ }
322}
323324/// Create a new SQLite-backed handle resolver with default 90-day TTL.