Skip to content

Commit 4f93b49

Browse files
committed
add: ability to Invite contacts to Groups
Admins of Groups can now individually invite new members to the group, with full state synchronisation across clients.
1 parent 0af1427 commit 4f93b49

File tree

5 files changed

+599
-113
lines changed

5 files changed

+599
-113
lines changed

src-tauri/src/lib.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3438,6 +3438,39 @@ async fn add_mls_member_device(
34383438
.map_err(|e| format!("Task join error: {}", e))?
34393439
}
34403440

3441+
/// Invite a new member to an existing MLS group
3442+
/// Similar to create_group_chat, this refreshes the member's keypackages and adds them to the group
3443+
#[tauri::command]
3444+
async fn invite_member_to_group(
3445+
group_id: String,
3446+
member_npub: String,
3447+
) -> Result<(), String> {
3448+
// Refresh keypackages for the new member
3449+
let devices = refresh_keypackages_for_contact(member_npub.clone()).await.map_err(|e| {
3450+
format!("Failed to refresh device keypackage for {}: {}", member_npub, e)
3451+
})?;
3452+
3453+
// Choose the first device (same policy as group creation)
3454+
let (device_id, _kp_ref) = devices
3455+
.into_iter()
3456+
.next()
3457+
.ok_or_else(|| format!("No device keypackages found for {}", member_npub))?;
3458+
3459+
// Run non-Send MLS engine work on a blocking thread
3460+
tokio::task::spawn_blocking(move || {
3461+
let handle = TAURI_APP.get().ok_or("App handle not initialized")?.clone();
3462+
let rt = tokio::runtime::Handle::current();
3463+
rt.block_on(async move {
3464+
let mls = MlsService::new_persistent(&handle).map_err(|e| e.to_string())?;
3465+
mls.add_member_device(&group_id, &member_npub, &device_id)
3466+
.await
3467+
.map_err(|e| e.to_string())
3468+
})
3469+
})
3470+
.await
3471+
.map_err(|e| format!("Task join error: {}", e))?
3472+
}
3473+
34413474
/// Remove a member device from an MLS group
34423475
#[tauri::command]
34433476
async fn remove_mls_member_device(
@@ -3643,8 +3676,8 @@ async fn accept_mls_welcome(welcome_event_id_hex: String) -> Result<bool, String
36433676
let nostr_group_id_bytes = welcome.nostr_group_id.clone();
36443677
let group_name = welcome.group_name.clone();
36453678
let welcomer_hex = welcome.welcomer.to_hex();
3646-
let wrapper_id_hex = welcome.wrapper_event_id.to_hex();
3647-
3679+
let wrapper_event_id_hex = welcome.wrapper_event_id.to_hex();
3680+
36483681
// Accept the welcome - this updates engine state internally
36493682
engine.accept_welcome(&welcome).map_err(|e| e.to_string())?;
36503683

@@ -3689,7 +3722,7 @@ async fn accept_mls_welcome(welcome_event_id_hex: String) -> Result<bool, String
36893722
println!("[MLS] - engine_group_id: {}", engine_group_id);
36903723
println!("[MLS] - group_name: {}", group_name);
36913724

3692-
(nostr_group_id, engine_group_id, group_name, welcomer_hex, wrapper_id_hex)
3725+
(nostr_group_id, engine_group_id, group_name, welcomer_hex, wrapper_event_id_hex)
36933726
}; // engine dropped here
36943727

36953728
// Now persist the group metadata (awaitable section)
@@ -4279,6 +4312,7 @@ pub fn run() {
42794312
// MLS advanced helpers
42804313
process_mls_event,
42814314
add_mls_member_device,
4315+
invite_member_to_group,
42824316
remove_mls_member_device,
42834317
get_mls_group_members,
42844318
leave_mls_group,

0 commit comments

Comments
 (0)