Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
at main 5.4 kB view raw
1use tinyjson::JsonValue; 2 3use crate::{parse_any_link, CollectedLink}; 4 5pub fn walk_record(path: &str, v: &JsonValue, found: &mut Vec<CollectedLink>) { 6 match v { 7 JsonValue::Object(o) => { 8 for (key, child) in o { 9 walk_record(&format!("{path}.{key}"), child, found) 10 } 11 } 12 JsonValue::Array(a) => { 13 for child in a { 14 let child_p = match child { 15 JsonValue::Object(o) => { 16 if let Some(JsonValue::String(t)) = o.get("$type") { 17 format!("{path}[{t}]") 18 } else { 19 format!("{path}[]") 20 } 21 } 22 _ => format!("{path}[]"), 23 }; 24 walk_record(&child_p, child, found) 25 } 26 } 27 JsonValue::String(s) => { 28 if let Some(link) = parse_any_link(s) { 29 found.push(CollectedLink { 30 path: path.to_string(), 31 target: link, 32 }); 33 } 34 } 35 _ => {} 36 } 37} 38 39pub fn collect_links(v: &JsonValue) -> Vec<CollectedLink> { 40 let mut found = vec![]; 41 walk_record("", v, &mut found); 42 found 43} 44 45#[cfg(test)] 46mod tests { 47 use super::*; 48 use crate::Link; 49 50 fn l(path: &str, target: Link) -> CollectedLink { 51 CollectedLink { 52 path: path.into(), 53 target, 54 } 55 } 56 57 #[test] 58 fn test_collect_links() { 59 let rec = r#"{"a": "https://example.com", "b": "not a link"}"#; 60 let json = collect_links(&rec.parse().unwrap()); 61 assert_eq!(json, vec![l(".a", Link::Uri("https://example.com".into()))]); 62 } 63 64 #[test] 65 fn test_bsky_feed_post_record_reply() { 66 let rec = r#"{ 67 "$type": "app.bsky.feed.post", 68 "createdAt": "2025-01-08T20:52:43.041Z", 69 "langs": [ 70 "en" 71 ], 72 "reply": { 73 "parent": { 74 "cid": "bafyreifk3bwnmulk37ezrarg4ouheqnhgucypynftqafl4limssogvzk6i", 75 "uri": "at://did:plc:b3rzzkblqsxhr3dgcueymkqe/app.bsky.feed.post/3lf6yc4drhk2f" 76 }, 77 "root": { 78 "cid": "bafyreifk3bwnmulk37ezrarg4ouheqnhgucypynftqafl4limssogvzk6i", 79 "uri": "at://did:plc:b3rzzkblqsxhr3dgcueymkqe/app.bsky.feed.post/3lf6yc4drhk2f" 80 } 81 }, 82 "text": "Yup!" 83 }"#; 84 let mut json = collect_links(&rec.parse().unwrap()); 85 json.sort_by_key(|c| (c.path.clone(), c.target.clone())); 86 assert_eq!( 87 json, 88 vec![ 89 l( 90 ".reply.parent.uri", 91 Link::AtUri( 92 "at://did:plc:b3rzzkblqsxhr3dgcueymkqe/app.bsky.feed.post/3lf6yc4drhk2f" 93 .into() 94 ) 95 ), 96 l( 97 ".reply.root.uri", 98 Link::AtUri( 99 "at://did:plc:b3rzzkblqsxhr3dgcueymkqe/app.bsky.feed.post/3lf6yc4drhk2f" 100 .into() 101 ) 102 ), 103 ] 104 ) 105 } 106 107 #[test] 108 fn test_bsky_feed_post_record_embed() { 109 let rec = r#"{ 110 "$type": "app.bsky.feed.post", 111 "createdAt": "2025-01-08T20:52:39.539Z", 112 "embed": { 113 "$type": "app.bsky.embed.external", 114 "external": { 115 "description": "YouTube video by More Perfect Union", 116 "thumb": { 117 "$type": "blob", 118 "ref": { 119 "$link": "bafkreifxuvkbqksq5usi4cryex37o4absjexuouvgenlb62ojsx443b2tm" 120 }, 121 "mimeType": "image/jpeg", 122 "size": 477460 123 }, 124 "title": "Corporations & Wealthy Elites Are Coopting Our Government. Who Can Stop Them?", 125 "uri": "https://youtu.be/oKXm4szEP1Q?si=_0n_uPu4qNKokMnq" 126 } 127 }, 128 "facets": [ 129 { 130 "features": [ 131 { 132 "$type": "app.bsky.richtext.facet#link", 133 "uri": "https://youtu.be/oKXm4szEP1Q?si=_0n_uPu4qNKokMnq" 134 } 135 ], 136 "index": { 137 "byteEnd": 24, 138 "byteStart": 0 139 } 140 } 141 ], 142 "langs": [ 143 "en" 144 ], 145 "text": "youtu.be/oKXm4szEP1Q?..." 146 }"#; 147 let mut json = collect_links(&rec.parse().unwrap()); 148 json.sort_by_key(|c| (c.path.clone(), c.target.clone())); 149 assert_eq!( 150 json, 151 vec![ 152 l( 153 ".embed.external.uri", 154 Link::Uri("https://youtu.be/oKXm4szEP1Q?si=_0n_uPu4qNKokMnq".into()), 155 ), 156 l( 157 ".facets[].features[app.bsky.richtext.facet#link].uri", 158 Link::Uri("https://youtu.be/oKXm4szEP1Q?si=_0n_uPu4qNKokMnq".into()), 159 ), 160 ] 161 ) 162 } 163}