1use crate::web5::identity::{Web5Error, Web5Result};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10pub trait ProtocolHandler: Send + Sync {
15 fn protocol_id(&self) -> &str;
17
18 fn handle_message(&self, message: &[u8]) -> Web5Result<Vec<u8>>;
20
21 fn get_definition(&self) -> ProtocolDefinition;
23}
24
25#[derive(Clone, Serialize, Deserialize)]
29pub struct ProtocolDefinition {
30 pub protocol: String,
32 pub version: String,
34 pub types: HashMap<String, TypeDefinition>,
36 pub actions: Vec<ActionDefinition>,
38}
39
40#[derive(Clone, Serialize, Deserialize)]
44pub struct TypeDefinition {
45 pub schema: String,
47 pub description: String,
49}
50
51#[derive(Clone, Serialize, Deserialize)]
55pub struct ActionDefinition {
56 pub name: String,
58 pub description: String,
60 pub input: Option<String>,
62 pub output: Option<String>,
64}
65
66pub struct ProtocolManager {
70 protocols: HashMap<String, ProtocolDefinition>,
72 handlers: HashMap<String, Box<dyn ProtocolHandler>>,
74}
75
76impl Default for ProtocolManager {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82impl ProtocolManager {
83 pub fn new() -> Self {
85 Self {
86 protocols: HashMap::new(),
87 handlers: HashMap::new(),
88 }
89 }
90
91 pub fn register_protocol(&mut self, handler: Box<dyn ProtocolHandler>) -> Web5Result<()> {
93 let protocol_id = handler.protocol_id().to_string();
94 let definition = handler.get_definition();
95
96 self.protocols.insert(protocol_id.clone(), definition);
97 self.handlers.insert(protocol_id, handler);
98
99 Ok(())
100 }
101
102 pub fn get_protocol(&self, protocol_id: &str) -> Web5Result<&ProtocolDefinition> {
104 self.protocols
105 .get(protocol_id)
106 .ok_or_else(|| Web5Error::Protocol(format!("Protocol not found: {protocol_id}")))
107 }
108
109 pub fn handle_message(&self, protocol_id: &str, message: &[u8]) -> Web5Result<Vec<u8>> {
111 let handler = self.handlers.get(protocol_id).ok_or_else(|| {
112 Web5Error::Protocol(format!("No handler found for protocol: {protocol_id}"))
113 })?;
114
115 handler.handle_message(message)
116 }
117
118 pub fn has_protocol(&self, protocol_id: &str) -> bool {
120 self.protocols.contains_key(protocol_id)
121 }
122
123 pub fn get_all_protocols(&self) -> Vec<&ProtocolDefinition> {
125 self.protocols.values().collect()
126 }
127}
128
129pub struct ProfileProtocolHandler;
133
134impl Default for ProfileProtocolHandler {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140impl ProfileProtocolHandler {
141 pub fn new() -> Self {
143 Self {}
144 }
145}
146
147impl ProtocolHandler for ProfileProtocolHandler {
148 fn protocol_id(&self) -> &str {
149 "https://identity.foundation/schemas/profile"
150 }
151
152 fn handle_message(&self, message: &[u8]) -> Web5Result<Vec<u8>> {
153 Ok(message.to_vec())
155 }
156
157 fn get_definition(&self) -> ProtocolDefinition {
158 let mut types = HashMap::new();
159 types.insert(
160 "profile".to_string(),
161 TypeDefinition {
162 schema: r#"{
163 "type": "object",
164 "properties": {
165 "name": { "type": "string" },
166 "image": { "type": "string", "format": "uri" },
167 "description": { "type": "string" }
168 }
169 }"#
170 .to_string(),
171 description: "A user profile".to_string(),
172 },
173 );
174
175 let actions = vec![
176 ActionDefinition {
177 name: "get".to_string(),
178 description: "Get a profile".to_string(),
179 input: None,
180 output: Some("profile".to_string()),
181 },
182 ActionDefinition {
183 name: "update".to_string(),
184 description: "Update a profile".to_string(),
185 input: Some("profile".to_string()),
186 output: Some("profile".to_string()),
187 },
188 ];
189
190 ProtocolDefinition {
191 protocol: self.protocol_id().to_string(),
192 version: "1.0".to_string(),
193 types,
194 actions,
195 }
196 }
197}
198
199pub struct CredentialProtocolHandler;
203
204impl Default for CredentialProtocolHandler {
205 fn default() -> Self {
206 Self::new()
207 }
208}
209
210impl CredentialProtocolHandler {
211 pub fn new() -> Self {
213 Self {}
214 }
215}
216
217impl ProtocolHandler for CredentialProtocolHandler {
218 fn protocol_id(&self) -> &str {
219 "https://identity.foundation/schemas/credentials"
220 }
221
222 fn handle_message(&self, message: &[u8]) -> Web5Result<Vec<u8>> {
223 Ok(message.to_vec())
225 }
226
227 fn get_definition(&self) -> ProtocolDefinition {
228 let mut types = HashMap::new();
229 types.insert(
230 "credential".to_string(),
231 TypeDefinition {
232 schema: r#"{
233 "type": "object",
234 "properties": {
235 "id": { "type": "string" },
236 "type": { "type": "array", "items": { "type": "string" } },
237 "issuer": { "type": "string" },
238 "issuanceDate": { "type": "string", "format": "date-time" },
239 "credentialSubject": { "type": "object" }
240 }
241 }"#
242 .to_string(),
243 description: "A verifiable credential".to_string(),
244 },
245 );
246
247 let actions = vec![
248 ActionDefinition {
249 name: "issue".to_string(),
250 description: "Issue a credential".to_string(),
251 input: Some("credential".to_string()),
252 output: Some("credential".to_string()),
253 },
254 ActionDefinition {
255 name: "verify".to_string(),
256 description: "Verify a credential".to_string(),
257 input: Some("credential".to_string()),
258 output: None,
259 },
260 ];
261
262 ProtocolDefinition {
263 protocol: self.protocol_id().to_string(),
264 version: "1.0".to_string(),
265 types,
266 actions,
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274 use std::error::Error;
275
276 #[tokio::test]
277 async fn test_protocol_manager() -> Result<(), Box<dyn Error>> {
278 let mut manager = ProtocolManager::new();
279
280 let profile_handler = Box::new(ProfileProtocolHandler::new());
282 manager.register_protocol(profile_handler)?;
283
284 assert!(manager.has_protocol("https://identity.foundation/schemas/profile"));
286
287 let protocols = manager.get_all_protocols();
289 assert_eq!(protocols.len(), 1);
290
291 let _def = manager.get_protocol("https://identity.foundation/schemas/profile")?;
293
294 Ok(())
295 }
296
297 #[tokio::test]
298 async fn test_profile_protocol_handler() -> Result<(), Box<dyn Error>> {
299 let handler = ProfileProtocolHandler::new();
300
301 assert_eq!(
303 handler.protocol_id(),
304 "https://identity.foundation/schemas/profile"
305 );
306
307 let response = handler.handle_message(b"test")?;
309 assert_eq!(response, b"test");
310
311 Ok(())
312 }
313
314 #[tokio::test]
315 async fn test_credential_protocol_handler() -> Result<(), Box<dyn Error>> {
316 let handler = CredentialProtocolHandler::new();
317
318 assert_eq!(
320 handler.protocol_id(),
321 "https://identity.foundation/schemas/credentials"
322 );
323
324 let response = handler.handle_message(b"test")?;
326 assert_eq!(response, b"test");
327
328 Ok(())
329 }
330}