chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
Spaces are listed one at a time for each account
crates/knotless-serve/src/lib.rs+12−0
| @@ -171,6 +171,11 @@ pub struct App { | ||
/// records: a space's records take no compare and swap, so two changes | ||
/// at once would each write over the other. | ||
orgs: Mutex<HashMap<String, Shared<()>>>, | ||
/// One lock per account, held while its spaces are listed | ||
/// ([`spaces::discover`]): two listings at once could each keep what | ||
/// the other's authority said after it, a removal undone by an answer | ||
/// asked before it. | ||
discovers: Mutex<HashMap<String, Shared<()>>>, | ||
} | ||
| ||
type Shared<T> = Arc<tokio::sync::Mutex<T>>; | ||
| @@ -282,6 +287,7 @@ impl App { | ||
ios_minimum: None, | ||
live: live::Live::default(), | ||
orgs: Mutex::default(), | ||
discovers: Mutex::default(), | ||
}) | ||
} | ||
| ||
| @@ -304,6 +310,12 @@ impl App { | ||
orgs.entry(org.to_string()).or_default().clone() | ||
} | ||
| ||
/// The lock held while `did`'s spaces are listed. | ||
pub(crate) fn discover_lock(&self, did: &str) -> Shared<()> { | ||
let mut discovers = self.discovers.lock().unwrap(); | ||
discovers.entry(did.to_string()).or_default().clone() | ||
} | ||
| ||
/// Whether `did`'s PDS has spaces, for private repositories: unknown | ||
/// until their spaces are first listed ([`spaces::discover`]). | ||
pub fn has_spaces(&self, did: &str) -> Option<bool> { | ||
crates/knotless-serve/src/spaces.rs+5−1
| @@ -261,7 +261,9 @@ pub const DISCOVER: Duration = Duration::from_secs(60); | ||
/// ([`Index::maybe_member`]) is asked of its authority as them, so the | ||
/// repositories shared with them are listed to them before they open one, | ||
/// and no longer once they are refused. In the background, at most once | ||
/// every [`DISCOVER`], so whoever looks never waits on it. | ||
/// every [`DISCOVER`], so whoever looks never waits on it, and one at a | ||
/// time for each account, so that an answer asked before a removal is | ||
/// never kept after one asked since. | ||
pub fn discover(app: &Arc<App>, did: &str) { | ||
let Some(index) = app.spaces.clone().filter(|_| app.discovering(did)) else { | ||
return; | ||
| @@ -276,6 +278,8 @@ pub fn discover(app: &Arc<App>, did: &str) { | ||
| ||
/// [`discover`], waited on. | ||
async fn owned(app: &App, index: &Index, did: &str) -> Result<()> { | ||
let lock = app.discover_lock(did); | ||
let _held = lock.lock().await; | ||
let ctx = crate::login::ctx_for(app, did); | ||
let me = knotless::session::me(&ctx).await?; | ||
let followed: HashSet<String> = index.spaces()?.into_iter().map(|(uri, _)| uri).collect(); | ||