tangled
alpha
login
or
join now
nonbinary.computer
/
weaver
atproto blogging
24
fork
atom
overview
issues
2
pulls
pipelines
some cleanup
Orual
1 month ago
85733a97
8b6741eb
+12
-54
2 changed files
expand all
collapse all
unified
split
crates
weaver-app
src
lib.rs
main.rs
+12
crates/weaver-app/src/lib.rs
···
53
53
subdomain_app::{extract_subdomain, lookup_subdomain_context},
54
54
};
55
55
56
56
+
/// Reserved subdomains that should not be used for notebooks.
57
57
+
const RESERVED_SUBDOMAINS: &[&str] = &[
58
58
+
"www", "api", "admin", "app", "auth", "cdn", "alpha", "beta", "staging", "index",
59
59
+
];
60
60
+
56
61
#[derive(Debug, Clone, Routable, PartialEq)]
57
62
#[rustfmt::skip]
58
63
pub enum Route {
···
179
184
);
180
185
return None;
181
186
};
187
187
+
188
188
+
// Check if subdomain is reserved
189
189
+
if RESERVED_SUBDOMAINS.contains(&subdomain.as_str()) {
190
190
+
tracing::info!(subdomain, "Reserved subdomain, skipping notebook lookup");
191
191
+
return None;
192
192
+
}
193
193
+
182
194
// Look up notebook by global path
183
195
let result = lookup_subdomain_context(&fetcher, &subdomain).await;
184
196
if result.is_none() {
-54
crates/weaver-app/src/main.rs
···
118
118
#[cfg(not(feature = "server"))]
119
119
dioxus::launch(App);
120
120
}
121
121
-
122
122
-
/// Extract subdomain from host if it matches base domain pattern.
123
123
-
#[cfg(feature = "server")]
124
124
-
fn extract_subdomain<'a>(host: &'a str, base: &str) -> Option<&'a str> {
125
125
-
let suffix = format!(".{}", base);
126
126
-
if host.ends_with(&suffix) && host.len() > suffix.len() {
127
127
-
Some(&host[..host.len() - suffix.len()])
128
128
-
} else {
129
129
-
None
130
130
-
}
131
131
-
}
132
132
-
133
133
-
/// Look up notebook by global path.
134
134
-
///
135
135
-
/// Returns SubdomainContext if a notebook with publishGlobal=true exists for this path.
136
136
-
#[cfg(feature = "server")]
137
137
-
async fn lookup_global_notebook(
138
138
-
fetcher: &Arc<fetch::Fetcher>,
139
139
-
path: &str,
140
140
-
) -> Option<SubdomainContext> {
141
141
-
use jacquard::IntoStatic;
142
142
-
use jacquard::smol_str::SmolStr;
143
143
-
use jacquard::smol_str::ToSmolStr;
144
144
-
use jacquard::types::string::Did;
145
145
-
use jacquard::xrpc::XrpcClient;
146
146
-
use weaver_api::sh_weaver::notebook::resolve_global_notebook::ResolveGlobalNotebook;
147
147
-
148
148
-
let request = ResolveGlobalNotebook::new().path(path).build();
149
149
-
150
150
-
match fetcher.send(request).await {
151
151
-
Ok(response) => {
152
152
-
let output = response.into_output().ok()?;
153
153
-
let notebook = output.notebook;
154
154
-
155
155
-
let owner = notebook.uri.authority().clone().into_static();
156
156
-
let rkey = notebook.uri.rkey()?.0.to_smolstr();
157
157
-
let notebook_path = notebook
158
158
-
.path
159
159
-
.map(|p| SmolStr::new(p.as_ref()))
160
160
-
.unwrap_or_else(|| SmolStr::new(path));
161
161
-
162
162
-
Some(SubdomainContext {
163
163
-
owner,
164
164
-
notebook_path,
165
165
-
notebook_rkey: rkey,
166
166
-
notebook_title: notebook.title.clone().unwrap_or_default().to_smolstr(),
167
167
-
})
168
168
-
}
169
169
-
Err(e) => {
170
170
-
tracing::debug!(path = path, error = %e, "Global notebook lookup failed");
171
171
-
None
172
172
-
}
173
173
-
}
174
174
-
}