Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
at main 3.7 kB view raw
1use fluent_uri::Uri; 2 3pub mod at_uri; 4pub mod did; 5pub mod record; 6 7pub use record::collect_links; 8 9#[derive(Debug, Clone, Ord, Eq, PartialOrd, PartialEq)] 10pub enum Link { 11 AtUri(String), 12 Uri(String), 13 Did(String), 14} 15 16impl Link { 17 pub fn into_string(self) -> String { 18 match self { 19 Link::AtUri(s) => s, 20 Link::Uri(s) => s, 21 Link::Did(s) => s, 22 } 23 } 24 pub fn as_str(&self) -> &str { 25 match self { 26 Link::AtUri(s) => s, 27 Link::Uri(s) => s, 28 Link::Did(s) => s, 29 } 30 } 31 pub fn name(&self) -> &'static str { 32 match self { 33 Link::AtUri(_) => "at-uri", 34 Link::Uri(_) => "uri", 35 Link::Did(_) => "did", 36 } 37 } 38 pub fn at_uri_collection(&self) -> Option<String> { 39 if let Link::AtUri(at_uri) = self { 40 at_uri::at_uri_collection(at_uri) 41 } else { 42 None 43 } 44 } 45 pub fn did(&self) -> Option<String> { 46 let did = match self { 47 Link::AtUri(s) => { 48 let rest = s.strip_prefix("at://")?; // todo: this might be safe to unwrap? 49 if let Some((did, _)) = rest.split_once("/") { 50 did 51 } else { 52 rest 53 } 54 } 55 Link::Uri(_) => return None, 56 Link::Did(did) => did, 57 }; 58 Some(did.to_string()) 59 } 60} 61 62#[derive(Debug, PartialEq)] 63pub struct CollectedLink { 64 pub path: String, 65 pub target: Link, 66} 67 68// normalizing is a bit opinionated but eh 69pub fn parse_uri(s: &str) -> Option<String> { 70 Uri::parse(s).map(|u| u.normalize().into_string()).ok() 71} 72 73pub fn parse_any_link(s: &str) -> Option<Link> { 74 at_uri::parse_at_uri(s).map(Link::AtUri).or_else(|| { 75 did::parse_did(s) 76 .map(Link::Did) 77 .or_else(|| parse_uri(s).map(Link::Uri)) 78 }) 79} 80 81#[cfg(test)] 82mod tests { 83 use super::*; 84 85 #[test] 86 fn test_uri_parse() { 87 let s = "https://example.com"; 88 let uri = parse_uri(s).unwrap(); 89 assert_eq!(uri.as_str(), s); 90 } 91 92 #[test] 93 fn test_uri_normalizes() { 94 let s = "HTTPS://example.com/../"; 95 let uri = parse_uri(s).unwrap(); 96 assert_eq!(uri.as_str(), "https://example.com/"); 97 } 98 99 #[test] 100 fn test_uri_invalid() { 101 assert!(parse_uri("https:\\bad-example.com").is_none()); 102 } 103 104 #[test] 105 fn test_any_parse() { 106 assert_eq!( 107 parse_any_link("https://example.com"), 108 Some(Link::Uri("https://example.com".into())) 109 ); 110 111 assert_eq!( 112 parse_any_link( 113 "at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3jwdwj2ctlk26" 114 ), 115 Some(Link::AtUri( 116 "at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3jwdwj2ctlk26".into() 117 )), 118 ); 119 120 assert_eq!( 121 parse_any_link("did:plc:44ybard66vv44zksje25o7dz"), 122 Some(Link::Did("did:plc:44ybard66vv44zksje25o7dz".into())) 123 ) 124 } 125 126 #[test] 127 fn test_at_uri_collection() { 128 assert_eq!( 129 parse_any_link("https://example.com") 130 .unwrap() 131 .at_uri_collection(), 132 None 133 ); 134 assert_eq!( 135 parse_any_link("did:web:bad-example.com") 136 .unwrap() 137 .at_uri_collection(), 138 None 139 ); 140 assert_eq!( 141 parse_any_link("at://did:web:bad-example.com/my.collection/3jwdwj2ctlk26") 142 .unwrap() 143 .at_uri_collection(), 144 Some("my.collection".into()) 145 ); 146 } 147}