forked from
smokesignal.events/quickdid
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.
1//! Work item types for queue processing.
2//!
3//! This module defines the various work item types that can be processed
4//! through the queue system, such as handle resolution requests.
5
6use serde::{Deserialize, Serialize};
7
8/// Work item for handle resolution tasks.
9///
10/// This structure represents a request to resolve an AT Protocol handle
11/// to its corresponding DID. It's the primary work type processed by
12/// the QuickDID service's background queue workers.
13///
14/// # Examples
15///
16/// ```
17/// use quickdid::queue::HandleResolutionWork;
18///
19/// let work = HandleResolutionWork::new("alice.bsky.social".to_string());
20/// assert_eq!(work.handle, "alice.bsky.social");
21/// ```
22#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
23pub struct HandleResolutionWork {
24 /// The AT Protocol handle to resolve (e.g., "alice.bsky.social")
25 pub handle: String,
26}
27
28impl HandleResolutionWork {
29 /// Create a new handle resolution work item.
30 ///
31 /// # Arguments
32 ///
33 /// * `handle` - The AT Protocol handle to resolve
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use quickdid::queue::HandleResolutionWork;
39 ///
40 /// let work = HandleResolutionWork::new("alice.bsky.social".to_string());
41 /// ```
42 pub fn new(handle: String) -> Self {
43 Self { handle }
44 }
45}
46
47impl std::fmt::Display for HandleResolutionWork {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "HandleResolution({})", self.handle)
50 }
51}
52
53/// Trait for getting a unique deduplication key from a work item.
54/// This is used by the Redis queue adapter to prevent duplicate items.
55pub trait DedupKey {
56 /// Get a unique key for deduplication purposes.
57 /// This should return a consistent identifier for equivalent work items.
58 fn dedup_key(&self) -> String;
59}
60
61impl DedupKey for HandleResolutionWork {
62 fn dedup_key(&self) -> String {
63 // Use the handle itself as the dedup key
64 self.handle.clone()
65 }
66}
67
68// For testing purposes, implement DedupKey for String
69#[cfg(test)]
70impl DedupKey for String {
71 fn dedup_key(&self) -> String {
72 self.clone()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_handle_resolution_work_creation() {
82 let handle = "alice.example.com";
83 let work = HandleResolutionWork::new(handle.to_string());
84 assert_eq!(work.handle, handle);
85 }
86
87 #[test]
88 fn test_handle_resolution_work_serialization() {
89 let work = HandleResolutionWork::new("bob.example.com".to_string());
90
91 // Test JSON serialization (which is what we actually use in the queue adapters)
92 let json = serde_json::to_string(&work).expect("Failed to serialize to JSON");
93 let deserialized: HandleResolutionWork =
94 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
95 assert_eq!(work, deserialized);
96
97 // Verify the JSON structure
98 let json_value: serde_json::Value = serde_json::from_str(&json).unwrap();
99 assert_eq!(json_value["handle"], "bob.example.com");
100 }
101
102 #[test]
103 fn test_handle_resolution_work_display() {
104 let work = HandleResolutionWork::new("charlie.example.com".to_string());
105 let display = format!("{}", work);
106 assert_eq!(display, "HandleResolution(charlie.example.com)");
107 }
108
109 #[test]
110 fn test_handle_resolution_work_equality() {
111 let work1 = HandleResolutionWork::new("alice.example.com".to_string());
112 let work2 = HandleResolutionWork::new("alice.example.com".to_string());
113 let work3 = HandleResolutionWork::new("bob.example.com".to_string());
114
115 assert_eq!(work1, work2);
116 assert_ne!(work1, work3);
117 }
118
119 #[test]
120 fn test_handle_resolution_work_dedup_key() {
121 let work1 = HandleResolutionWork::new("alice.example.com".to_string());
122 let work2 = HandleResolutionWork::new("alice.example.com".to_string());
123 let work3 = HandleResolutionWork::new("bob.example.com".to_string());
124
125 // Same handle should have same dedup key
126 assert_eq!(work1.dedup_key(), work2.dedup_key());
127 assert_eq!(work1.dedup_key(), "alice.example.com");
128
129 // Different handle should have different dedup key
130 assert_ne!(work1.dedup_key(), work3.dedup_key());
131 assert_eq!(work3.dedup_key(), "bob.example.com");
132 }
133}