atproto blogging
1use dioxus::prelude::*;
2#[cfg(all(target_family = "wasm", target_os = "unknown"))]
3use wasm_bindgen::prelude::*;
4
5#[cfg(all(target_family = "wasm", target_os = "unknown"))]
6use wasm_bindgen_futures::JsFuture;
7#[cfg(all(target_family = "wasm", target_os = "unknown"))]
8use web_sys::{RegistrationOptions, ServiceWorkerContainer, Window};
9#[cfg(all(target_family = "wasm", target_os = "unknown"))]
10use jacquard::smol_str::format_smolstr;
11
12#[cfg(all(target_family = "wasm", target_os = "unknown"))]
13pub async fn register_service_worker() -> Result<(), JsValue> {
14 let window = web_sys::window().ok_or_else(|| JsValue::from_str("no window"))?;
15 let navigator = window.navigator();
16 let sw_container = navigator.service_worker();
17 tracing::debug!("Registering service worker");
18 let promise = sw_container.register("/sw.js");
19 JsFuture::from(promise).await?;
20 tracing::debug!("Service worker registered");
21
22 Ok(())
23}
24
25/// Register blob mappings from entry images with the service worker
26#[cfg(all(target_family = "wasm", target_os = "unknown"))]
27pub async fn register_entry_blobs(
28 ident: &jacquard::types::ident::AtIdentifier<'_>,
29 book_title: &str,
30 images: &weaver_api::sh_weaver::embed::images::Images<'_>,
31 fetcher: &crate::fetch::Fetcher,
32) -> Result<(), JsValue> {
33 use jacquard::prelude::IdentityResolver;
34 use std::collections::HashMap;
35
36 tracing::debug!("registering blobs for {}", book_title);
37 let mut blob_mappings = HashMap::new();
38
39 // Resolve DID and PDS URL
40 let (did, pds_url) = match ident {
41 jacquard::types::ident::AtIdentifier::Did(d) => {
42 let pds = fetcher.client.pds_for_did(d).await.ok();
43 (d.clone(), pds)
44 }
45 jacquard::types::ident::AtIdentifier::Handle(h) => {
46 if let Ok((did, pds)) = fetcher.client.pds_for_handle(h).await {
47 (did, Some(pds))
48 } else {
49 return Ok(());
50 }
51 }
52 };
53
54 if let Some(pds_url) = pds_url {
55 for image in &images.images {
56 let cid = image.image.blob().cid();
57
58 if let Some(name) = &image.name {
59 let blob_url = format_smolstr!(
60 "{}xrpc/com.atproto.sync.getBlob?did={}&cid={}",
61 pds_url.as_str(),
62 did.as_ref(),
63 cid.as_ref()
64 );
65 blob_mappings.insert(name.as_ref().to_string(), blob_url);
66 }
67 }
68 }
69
70 // Send mappings to service worker
71 if !blob_mappings.is_empty() {
72 send_blob_mappings(book_title, blob_mappings)?;
73 }
74 //}
75
76 Ok(())
77}
78
79/// Register blob mappings from entry images with the service worker
80#[cfg(all(target_family = "wasm", target_os = "unknown"))]
81pub async fn register_standalone_entry_blobs(
82 ident: &jacquard::types::ident::AtIdentifier<'_>,
83 rkey: &str,
84 images: &weaver_api::sh_weaver::embed::images::Images<'_>,
85 fetcher: &crate::fetch::Fetcher,
86) -> Result<(), JsValue> {
87 use jacquard::prelude::IdentityResolver;
88 use std::collections::HashMap;
89
90 tracing::debug!("registering blobs for {}", rkey);
91 let mut blob_mappings = HashMap::new();
92
93 // Resolve DID and PDS URL
94 let (did, pds_url) = match ident {
95 jacquard::types::ident::AtIdentifier::Did(d) => {
96 let pds = fetcher.client.pds_for_did(d).await.ok();
97 (d.clone(), pds)
98 }
99 jacquard::types::ident::AtIdentifier::Handle(h) => {
100 if let Ok((did, pds)) = fetcher.client.pds_for_handle(h).await {
101 (did, Some(pds))
102 } else {
103 return Ok(());
104 }
105 }
106 };
107
108 if let Some(pds_url) = pds_url {
109 for image in &images.images {
110 let cid = image.image.blob().cid();
111
112 if let Some(name) = &image.name {
113 let blob_url = format_smolstr!(
114 "{}xrpc/com.atproto.sync.getBlob?did={}&cid={}",
115 pds_url.as_str(),
116 did.as_ref(),
117 cid.as_ref()
118 );
119 blob_mappings.insert(name.as_ref().to_string(), blob_url);
120 }
121 }
122 }
123
124 // Send mappings to service worker
125 if !blob_mappings.is_empty() {
126 send_blob_rkey_mappings(rkey, ident.as_str(), blob_mappings)?;
127 }
128 //}
129
130 Ok(())
131}
132
133#[cfg(all(target_family = "wasm", target_os = "unknown"))]
134fn send_blob_mappings(
135 notebook: &str,
136 mappings: std::collections::HashMap<String, jacquard::smol_str::SmolStr>,
137) -> Result<(), JsValue> {
138 let window = web_sys::window().ok_or_else(|| JsValue::from_str("no window"))?;
139 let navigator = window.navigator();
140 let sw_container = navigator.service_worker();
141
142 tracing::debug!("sending blob mappings for {}", notebook);
143 let controller = sw_container
144 .controller()
145 .ok_or_else(|| JsValue::from_str("no service worker controller"))?;
146
147 // Build message object
148 let msg = js_sys::Object::new();
149 js_sys::Reflect::set(&msg, &"type".into(), &"register_mappings".into())?;
150 js_sys::Reflect::set(&msg, &"notebook".into(), ¬ebook.into())?;
151
152 // Convert HashMap to JS Object
153 let blobs_obj = js_sys::Object::new();
154 for (name, url) in mappings {
155 js_sys::Reflect::set(&blobs_obj, &name.into(), &url.as_str().into())?;
156 }
157 js_sys::Reflect::set(&msg, &"blobs".into(), &blobs_obj)?;
158
159 controller.post_message(&msg)?;
160 tracing::debug!("sent blob mappings for {}", notebook);
161
162 Ok(())
163}
164
165#[cfg(all(target_family = "wasm", target_os = "unknown"))]
166fn send_blob_rkey_mappings(
167 rkey: &str,
168 ident: &str,
169 mappings: std::collections::HashMap<String, jacquard::smol_str::SmolStr>,
170) -> Result<(), JsValue> {
171 let window = web_sys::window().ok_or_else(|| JsValue::from_str("no window"))?;
172 let navigator = window.navigator();
173 let sw_container = navigator.service_worker();
174
175 tracing::debug!("sending blob mappings for {}", rkey);
176 let controller = sw_container
177 .controller()
178 .ok_or_else(|| JsValue::from_str("no service worker controller"))?;
179
180 // Build message object
181 let msg = js_sys::Object::new();
182 js_sys::Reflect::set(&msg, &"type".into(), &"register_rkey_mappings".into())?;
183 js_sys::Reflect::set(&msg, &"rkey".into(), &rkey.into())?;
184 js_sys::Reflect::set(&msg, &"ident".into(), &ident.into())?;
185
186 // Convert HashMap to JS Object
187 let blobs_obj = js_sys::Object::new();
188 for (name, url) in mappings {
189 js_sys::Reflect::set(&blobs_obj, &name.into(), &url.as_str().into())?;
190 }
191 js_sys::Reflect::set(&msg, &"blobs".into(), &blobs_obj)?;
192
193 controller.post_message(&msg)?;
194 tracing::debug!("sent blob mappings for {}", rkey);
195
196 Ok(())
197}
198
199#[allow(unused)]
200#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
201pub async fn register_service_worker() -> Result<(), String> {
202 Ok(())
203}
204
205#[allow(unused)]
206#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
207pub fn send_blob_mappings(
208 _notebook: &str,
209 _mappings: std::collections::HashMap<String, jacquard::smol_str::SmolStr>,
210) -> Result<(), String> {
211 Ok(())
212}
213
214// #[used]
215// static BINDINGS_JS: Asset = asset!(
216// "/sw.js",
217// AssetOptions::js()
218// .with_hash_suffix(false)
219// .with_minify(false)
220// .with_preload(true)
221// );