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

filter dids by `did=&did=` repeated param

atproto queries do arrays like this

Changed files
+28 -8
constellation
src
server
+3
Cargo.lock
···
"axum-core",
"bytes",
"cookie",
+
"form_urlencoded",
"futures-util",
"headers",
"http",
···
"pin-project-lite",
"rustversion",
"serde",
+
"serde_html_form",
+
"serde_path_to_error",
"tower",
"tower-layer",
"tower-service",
+1 -1
constellation/Cargo.toml
···
anyhow = "1.0.95"
askama = { version = "0.12.1", features = ["serde-json"] }
axum = "0.8.1"
-
axum-extra = { version = "0.10.0", features = ["typed-header"] }
+
axum-extra = { version = "0.10.0", features = ["query", "typed-header"] }
axum-metrics = "0.2"
bincode = "1.3.3"
clap = { version = "4.5.26", features = ["derive"] }
+24 -7
constellation/src/server/mod.rs
···
collection: String,
path: String,
cursor: Option<OpaqueApiCursor>,
+
/// Filter links only from these DIDs
+
///
+
/// include multiple times to filter by multiple source DIDs
+
#[serde(default)]
+
did: Vec<String>,
+
/// [deprecated] Filter links only from these DIDs
+
///
+
/// format: comma-separated sequence of DIDs
+
///
+
/// errors: if `did` parameter is also present
+
///
+
/// deprecated: use `did`, which can be repeated multiple times
from_dids: Option<String>, // comma separated: gross
limit: Option<u64>,
// TODO: allow reverse (er, forward) order as well
···
}
fn get_links(
accept: ExtractAccept,
-
query: Query<GetLinkItemsQuery>,
+
query: axum_extra::extract::Query<GetLinkItemsQuery>, // supports multiple param occurrences
store: impl LinkReader,
) -> Result<impl IntoResponse, http::StatusCode> {
let until = query
···
return Err(http::StatusCode::BAD_REQUEST);
}
-
let filter_dids = &query
-
.from_dids
-
.clone()
-
.map(|comma_joined| HashSet::from_iter(comma_joined.split(',').map(|d| Did(d.to_string()))))
-
.unwrap_or_default();
+
let mut filter_dids: HashSet<Did> = HashSet::from_iter(query.did.iter().map(|d| Did(d.to_string())));
+
+
if let Some(comma_joined) = &query.from_dids {
+
if !filter_dids.is_empty() {
+
return Err(http::StatusCode::BAD_REQUEST);
+
}
+
for did in comma_joined.split(',') {
+
filter_dids.insert(Did(did.to_string()));
+
}
+
}
let paged = store
.get_links(
···
&query.path,
limit,
until,
-
filter_dids,
+
&filter_dids,
)
.map_err(|_| http::StatusCode::INTERNAL_SERVER_ERROR)?;