community: every ledger takes its write lock, so the inbox check can no longer land on top of a friend accept

This commit is contained in:
KeelrLeek committed 2026-09-03 11:51:35 -05:00
1 parent 07227a90a7
commit 4d03cf849b
6 files changed
+89 -29

No files matched your search

+21 -6
View File
@@ -25,6 +25,7 @@ use serde::{Deserialize, Serialize};
use tauri::{Emitter, Manager};
use crate::inbox::{self, Cargo, SpaceInvite, SpaceKeyCargo};
use crate::ledger;
use crate::persona;
use crate::slsk_link;
use crate::state::AppState;
@@ -159,8 +160,11 @@ fn path(app: &tauri::AppHandle) -> Result<PathBuf, String> {
.app_data_dir()
.map_err(|e| e.to_string())?
.join("freenet")
.join("spaces.json"))
.join(LEDGER_FILE))
}
/// Both the file the ledger lives in and the key its write lock is taken on.
const LEDGER_FILE: &str = "spaces.json";
fn load(app: &tauri::AppHandle) -> Ledger {
path(app)
.ok()
@@ -363,6 +367,7 @@ pub async fn create(app: &tauri::AppHandle, name: &str, description: &str, priva
keys,
last_epoch: 1,
};
let _ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
l.spaces.insert(record_id(&rec.owner, &rec.space_id), rec.clone());
save(app, &l)?;
@@ -374,6 +379,7 @@ pub async fn open(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str) -> R
let me = my_key(app).await?;
let owner = key_of(owner_b58)?;
let space_id = id_of(space_b58)?;
let _ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
let rid = record_id(owner_b58, space_b58);
let rec = l.spaces.get(&rid).cloned().ok_or("not a Space this device knows")?;
@@ -475,6 +481,7 @@ pub async fn invite(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str, pe
})
.await?;
let rid = record_id(owner_b58, space_b58);
let ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
let rec = l.spaces.get_mut(&rid).ok_or("not a Space this device knows")?;
let mut key = None;
@@ -493,6 +500,8 @@ pub async fn invite(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str, pe
)
.await?;
log::info!("spaces: invited {persona_key} to {:?} (epoch {})", c.name, c.epoch);
// open() takes this same ledger; the write is done, so let go first.
drop(ledger);
open(app, owner_b58, space_b58).await
}
@@ -506,6 +515,7 @@ pub async fn remove_member(app: &tauri::AppHandle, owner_b58: &str, space_b58: &
}
let c = bump(app, me, owner, space_id, |c| c.members.retain(|m| m.key != gone)).await?;
let rid = record_id(owner_b58, space_b58);
let ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
let rec = l.spaces.get_mut(&rid).ok_or("not a Space this device knows")?;
rec.last_epoch = c.epoch;
@@ -523,6 +533,8 @@ pub async fn remove_member(app: &tauri::AppHandle, owner_b58: &str, space_b58: &
} else {
save(app, &l)?;
}
// open() takes this same ledger; the write is done, so let go first.
drop(ledger);
open(app, owner_b58, space_b58).await
}
@@ -538,7 +550,8 @@ pub async fn set_pinned(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str
open(app, owner_b58, space_b58).await
}
pub fn leave(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str) -> Result<(), String> {
pub async fn leave(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str) -> Result<(), String> {
let _ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
let rid = record_id(owner_b58, space_b58);
if l.spaces.get(&rid).is_some_and(|r| r.my_role == "owner") {
@@ -550,12 +563,13 @@ pub fn leave(app: &tauri::AppHandle, owner_b58: &str, space_b58: &str) -> Result
// ---------------------------------------------------------------- inbox cargo
pub(crate) fn on_inbox_invite(app: &tauri::AppHandle, sender: [u8; 32], inv: SpaceInvite) {
pub(crate) async fn on_inbox_invite(app: &tauri::AppHandle, sender: [u8; 32], inv: SpaceInvite) {
if sender != inv.owner {
log::warn!("spaces: an invitation was sealed by someone other than the Space's owner");
return;
}
let rid = record_id(&b58(&inv.owner), &b58(&inv.space_id));
let _ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
let rec = l.spaces.entry(rid).or_insert_with(|| SpaceRecord {
owner: b58(&inv.owner),
@@ -579,11 +593,12 @@ pub(crate) fn on_inbox_invite(app: &tauri::AppHandle, sender: [u8; 32], inv: Spa
}
}
pub(crate) fn on_inbox_space_key(app: &tauri::AppHandle, sender: [u8; 32], sk: SpaceKeyCargo) {
pub(crate) async fn on_inbox_space_key(app: &tauri::AppHandle, sender: [u8; 32], sk: SpaceKeyCargo) {
if sender != sk.owner {
return;
}
let rid = record_id(&b58(&sk.owner), &b58(&sk.space_id));
let _ledger = ledger::hold(LEDGER_FILE).await;
let mut l = load(app);
let Some(rec) = l.spaces.get_mut(&rid) else { return };
rec.keys.insert(sk.epoch.to_string(), b58(&sk.key));
@@ -621,8 +636,8 @@ pub async fn space_set_pinned(app: tauri::AppHandle, owner: String, space: Strin
set_pinned(&app, &owner, &space, playlist_owner, playlist_uuid).await
}
#[tauri::command]
pub fn space_leave(app: tauri::AppHandle, owner: String, space: String) -> Result<(), String> {
leave(&app, &owner, &space)
pub async fn space_leave(app: tauri::AppHandle, owner: String, space: String) -> Result<(), String> {
leave(&app, &owner, &space).await
}
#[cfg(test)]