forked from
microcosm.blue/microcosm-rs
Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
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}
46
47#[derive(Debug, PartialEq)]
48pub struct CollectedLink {
49 pub path: String,
50 pub target: Link,
51}
52
53// normalizing is a bit opinionated but eh
54pub fn parse_uri(s: &str) -> Option<String> {
55 Uri::parse(s).map(|u| u.normalize().into_string()).ok()
56}
57
58pub fn parse_any_link(s: &str) -> Option<Link> {
59 at_uri::parse_at_uri(s).map(Link::AtUri).or_else(|| {
60 did::parse_did(s)
61 .map(Link::Did)
62 .or_else(|| parse_uri(s).map(Link::Uri))
63 })
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_uri_parse() {
72 let s = "https://example.com";
73 let uri = parse_uri(s).unwrap();
74 assert_eq!(uri.as_str(), s);
75 }
76
77 #[test]
78 fn test_uri_normalizes() {
79 let s = "HTTPS://example.com/../";
80 let uri = parse_uri(s).unwrap();
81 assert_eq!(uri.as_str(), "https://example.com/");
82 }
83
84 #[test]
85 fn test_uri_invalid() {
86 assert!(parse_uri("https:\\bad-example.com").is_none());
87 }
88
89 #[test]
90 fn test_any_parse() {
91 assert_eq!(
92 parse_any_link("https://example.com"),
93 Some(Link::Uri("https://example.com".into()))
94 );
95
96 assert_eq!(
97 parse_any_link(
98 "at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3jwdwj2ctlk26"
99 ),
100 Some(Link::AtUri(
101 "at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3jwdwj2ctlk26".into()
102 )),
103 );
104
105 assert_eq!(
106 parse_any_link("did:plc:44ybard66vv44zksje25o7dz"),
107 Some(Link::Did("did:plc:44ybard66vv44zksje25o7dz".into()))
108 )
109 }
110
111 #[test]
112 fn test_at_uri_collection() {
113 assert_eq!(
114 parse_any_link("https://example.com")
115 .unwrap()
116 .at_uri_collection(),
117 None
118 );
119 assert_eq!(
120 parse_any_link("did:web:bad-example.com")
121 .unwrap()
122 .at_uri_collection(),
123 None
124 );
125 assert_eq!(
126 parse_any_link("at://did:web:bad-example.com/my.collection/3jwdwj2ctlk26")
127 .unwrap()
128 .at_uri_collection(),
129 Some("my.collection".into())
130 );
131 }
132}