Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
75
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 147 lines 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}