Something went wrong. Try again.
atproto git client
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143//! Every host atgc talks to that it did not learn from a record, and the//! environment variable that moves each one.//!//! Six hostnames are compiled in: the PLC directory, Bobbin, Tangled's//! website, a knot's and a spindle's `https://` origin, and Bluesky's public//! appview. "What does this tool contact" is answered by reading this file.//!//! Each is overridable, and each override is a whole base URL rather than a//! host, so a local instance on a port and a plain `http://` scheme both//! work. Two things want that://!//! - **Running against something local.** A knot or a Bobbin you are//! developing does not answer at its production name, and pointing atgc at//! it should not need a rebuild. `ATGC_BOBBIN` already existed for exactly//! this and is unchanged; the other four are its siblings.//! - **The integration tests.** `tests/support/` stands a mock PDS, PLC//! directory, Bobbin, appview and knot up on loopback ports and drives whole//! sequences of commands against them. Without a seam at each of these//! five names, a test can reach the acting account's PDS (that address//! comes out of the session store) and nothing else. See [`crate::docs::testing`].//!//! What is deliberately *not* here: the acting account's PDS, a repo's knot//! as named by its `sh.tangled.repo` record, and the appview URL a resolve//! produced. Those are data, not configuration — atgc reads them at runtime//! from a session, a record or a redirect, so a test that wants to move them//! moves the record.
/// The PLC directory, where a `did:plc` document is fetched from./// `ATGC_PLC` moves it.pub fn plc_directory() -> String { base("ATGC_PLC", "https://plc.directory")}
/// Bobbin, Tangled's appview API. `ATGC_BOBBIN` moves it.pub fn bobbin() -> String { base("ATGC_BOBBIN", "https://api.tangled.org")}
/// Tangled's website. `ATGC_APPVIEW` moves it.////// Not the same service as [`bobbin`], which is the API. This is the/// server-rendered site, and atgc reads exactly one thing off it that/// nothing else can answer: a pull's *number*, which exists only in an/// appview's own database — see `clients/tangled/web`. It is also the base/// of every `view:` link a command prints.pub fn appview() -> String { base("ATGC_APPVIEW", "https://tangled.org")}
/// Bluesky's public appview, read best-effort for a display name and avatar./// `ATGC_BSKY_APPVIEW` moves it.pub fn bsky_appview() -> String { base("ATGC_BSKY_APPVIEW", "https://public.api.bsky.app")}
/// Where to send an XRPC call addressed to the knot `host`.////// The odd one out: a knot's address is not a single compiled-in name but a/// hostname carried in each repo's own record, so the default is derived/// rather than constant. `ATGC_KNOT` replaces the whole base for *every*/// knot, which is what a test with one mock knot wants and what a developer/// pointing at a local one wants. It does not change the audience of the/// service-auth token, which stays `did:web:<host>`: the token names the/// knot the record claims, and only the delivery address moves.pub fn knot(host: &str) -> String { base("ATGC_KNOT", &format!("https://{host}"))}
/// Where to send an XRPC call addressed to the spindle `host`, the CI runner/// a repo's record names. `ATGC_SPINDLE` replaces the base for every spindle,/// as [`knot`]'s override does for knots.pub fn spindle(host: &str) -> String { base("ATGC_SPINDLE", &format!("https://{host}"))}
/// One override, with the empty string treated as unset.////// An empty value is what an unset variable looks like after a shell has/// interpolated it — `ATGC_KNOT="$MAYBE_KNOT"` — and reading that as "send/// every knot call to the origin of the empty URL" is a failure with no good/// message at the far end of it.fn base(var: &str, default: &str) -> String { let chosen = match std::env::var(var) { Ok(value) if !value.trim().is_empty() => value.trim().to_string(), _ => default.to_string(), }; // Trimmed whichever it came from. Every caller appends a path beginning // with `/`, and a doubled separator is a 404 at a strict router. chosen.trim_end_matches('/').to_string()}
#[cfg(test)]mod tests { /// The compiled-in defaults, pinned. These are the addresses atgc /// contacts without being told to, and a typo in one is a tool that /// silently talks to the wrong service — or, for the PLC directory, one /// that cannot resolve any account at all. /// /// Read through [`super::base`] with a variable name no environment /// sets, rather than through the public wrappers: `cargo test` runs /// these on threads of one process, and a test that read the real /// `ATGC_BOBBIN` would fail on a machine where a developer has one /// exported. What the wrappers add over `base` is the name and the /// default, and both are visible at the call site. #[test] fn the_defaults_are_the_production_services() { for (default, expected) in [ ("https://plc.directory", "https://plc.directory"), ("https://api.tangled.org", "https://api.tangled.org"), ("https://tangled.org", "https://tangled.org"), ("https://public.api.bsky.app", "https://public.api.bsky.app"), ] { assert_eq!(super::base("ATGC_NOTHING_SETS_THIS", default), expected); } }
/// A trailing slash comes off, because every caller appends a path /// beginning with one. `https://pds.example//xrpc/…` is not the same URL /// as `https://pds.example/xrpc/…` to a strict router, and the value /// arrives from a person typing it into a shell. #[test] fn a_trailing_slash_is_not_carried_into_the_path() { assert_eq!( super::base("ATGC_NOTHING_SETS_THIS", "http://127.0.0.1:8080/"), "http://127.0.0.1:8080" ); }
/// A knot's default is derived from the host in its repo record, so the /// scheme is the only part this function contributes. Asserted through /// `base` for the same reason as above — a developer with `ATGC_KNOT` /// exported must not fail this suite — which leaves the derivation /// itself as the thing under test. #[test] fn a_knot_defaults_to_https_at_the_host_the_record_names() { let derived = format!("https://{}", "knot1.tangled.sh"); assert_eq!( super::base("ATGC_NOTHING_SETS_THIS", &derived), "https://knot1.tangled.sh" ); }}