diff --git a/crates/collab/src/integration_tests.rs b/crates/collab/src/integration_tests.rs index ebdc952a0f..8753ddee35 100644 --- a/crates/collab/src/integration_tests.rs +++ b/crates/collab/src/integration_tests.rs @@ -314,11 +314,14 @@ async fn test_share_project( .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; - let project_id = project_a.read_with(cx_a, |project, _| project.remote_id().unwrap()); + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); // Join that project as client B let client_b_peer_id = client_b.peer_id; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; let replica_id_b = project_b.read_with(cx_b, |project, _| { assert_eq!( project @@ -390,17 +393,7 @@ async fn test_share_project( // Client B can join again on a different window because they are already a participant. let client_b2 = server.create_client(cx_b2, "user_b").await; - let project_b2 = Project::remote( - project_id, - client_b2.client.clone(), - client_b2.user_store.clone(), - client_b2.project_store.clone(), - client_b2.language_registry.clone(), - FakeFs::new(cx_b2.background()), - cx_b2.to_async(), - ) - .await - .unwrap(); + let project_b2 = client_b2.build_remote_project(project_id, cx_b2).await; deterministic.run_until_parked(); project_a.read_with(cx_a, |project, _| { assert_eq!(project.collaborators().len(), 2); @@ -449,8 +442,12 @@ async fn test_unshare_project( .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap()); - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared())); project_b @@ -467,7 +464,11 @@ async fn test_unshare_project( assert!(project_b.read_with(cx_b, |project, _| project.is_read_only())); // Client B can join again after client A re-shares. - let project_b2 = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b2 = client_b.build_remote_project(project_id, cx_b).await; assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared())); project_b2 .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) @@ -517,9 +518,12 @@ async fn test_host_disconnect( let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap()); - project_a.read_with(cx_a, |project, _| project.remote_id().unwrap()); + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared())); let (_, workspace_b) = @@ -574,7 +578,11 @@ async fn test_host_disconnect( }); // Ensure guests can still join. - let project_b2 = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b2 = client_b.build_remote_project(project_id, cx_b).await; assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared())); project_b2 .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) @@ -613,10 +621,14 @@ async fn test_propagate_saves_and_fs_changes( .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; let worktree_a = project_a.read_with(cx_a, |p, cx| p.worktrees(cx).next().unwrap()); + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); // Join that worktree as clients B and C. - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; - let project_c = client_c.build_remote_project(&project_a, cx_a, cx_c).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; + let project_c = client_c.build_remote_project(project_id, cx_c).await; let worktree_b = project_b.read_with(cx_b, |p, cx| p.worktrees(cx).next().unwrap()); let worktree_c = project_c.read_with(cx_c, |p, cx| p.worktrees(cx).next().unwrap()); @@ -756,7 +768,11 @@ async fn test_fs_operations( ) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap()); let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap()); @@ -1016,7 +1032,11 @@ async fn test_buffer_conflict_after_save(cx_a: &mut TestAppContext, cx_b: &mut T ) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open a buffer as client B let buffer_b = project_b @@ -1065,7 +1085,11 @@ async fn test_buffer_reloading(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont ) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open a buffer as client B let buffer_b = project_b @@ -1114,7 +1138,11 @@ async fn test_editing_while_guest_opens_buffer( .insert_tree("/dir", json!({ "a.txt": "a-contents" })) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open a buffer as client A let buffer_a = project_a @@ -1156,7 +1184,11 @@ async fn test_leaving_worktree_while_opening_buffer( .insert_tree("/dir", json!({ "a.txt": "a-contents" })) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // See that a guest has joined as client A. project_a @@ -1201,7 +1233,11 @@ async fn test_canceling_buffer_opening( ) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; let buffer_a = project_a .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) @@ -1243,7 +1279,11 @@ async fn test_leaving_project(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte ) .await; let (project_a, _) = client_a.build_local_project("/a", cx_a).await; - let _project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let _project_b = client_b.build_remote_project(project_id, cx_b).await; // Client A sees that a guest has joined. project_a @@ -1257,7 +1297,7 @@ async fn test_leaving_project(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte .await; // Rejoin the project as client B - let _project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let _project_b = client_b.build_remote_project(project_id, cx_b).await; // Client A sees that a guest has re-joined. project_a @@ -1317,7 +1357,10 @@ async fn test_collaborating_with_diagnostics( ) .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; - let project_id = project_a.update(cx_a, |p, _| p.next_remote_id()).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); // Cause the language server to start. let _buffer = cx_a @@ -1335,7 +1378,7 @@ async fn test_collaborating_with_diagnostics( .unwrap(); // Join the worktree as client B. - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Simulate a language server reporting errors for a file. let mut fake_language_server = fake_language_servers.next().await.unwrap(); @@ -1383,7 +1426,7 @@ async fn test_collaborating_with_diagnostics( }); // Join project as client C and observe the diagnostics. - let project_c = client_c.build_remote_project(&project_a, cx_a, cx_c).await; + let project_c = client_c.build_remote_project(project_id, cx_c).await; deterministic.run_until_parked(); project_c.read_with(cx_c, |project, cx| { assert_eq!( @@ -1561,7 +1604,11 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu ) .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open a file in an editor as the guest. let buffer_b = project_b @@ -1705,8 +1752,12 @@ async fn test_reloading_buffer_manually(cx_a: &mut TestAppContext, cx_b: &mut Te .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)) .await .unwrap(); + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; let buffer_b = cx_b .background() @@ -1805,7 +1856,11 @@ async fn test_formatting_buffer(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon .insert_tree(&directory, json!({ "a.rs": "let one = \"two\"" })) .await; let (project_a, worktree_id) = client_a.build_local_project(&directory, cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; let buffer_b = cx_b .background() @@ -1908,7 +1963,11 @@ async fn test_definition(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { ) .await; let (project_a, worktree_id) = client_a.build_local_project("/root/dir-1", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open the file on client B. let buffer_b = cx_b @@ -2047,7 +2106,11 @@ async fn test_references(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { ) .await; let (project_a, worktree_id) = client_a.build_local_project("/root/dir-1", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open the file on client B. let buffer_b = cx_b @@ -2142,8 +2205,12 @@ async fn test_project_search(cx_a: &mut TestAppContext, cx_b: &mut TestAppContex worktree_2 .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete()) .await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Perform a search as the guest. let results = project_b @@ -2212,7 +2279,11 @@ async fn test_document_highlights(cx_a: &mut TestAppContext, cx_b: &mut TestAppC client_a.language_registry.add(Arc::new(language)); let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open the file on client B. let buffer_b = cx_b @@ -2309,7 +2380,11 @@ async fn test_lsp_hover(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { client_a.language_registry.add(Arc::new(language)); let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Open the file as the guest let buffer_b = cx_b @@ -2414,7 +2489,11 @@ async fn test_project_symbols(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte ) .await; let (project_a, worktree_id) = client_a.build_local_project("/code/crate-1", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Cause the language server to start. let _buffer = cx_b @@ -2510,7 +2589,11 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it( ) .await; let (project_a, worktree_id) = client_a.build_local_project("/root", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; let buffer_b1 = cx_b .background() @@ -2581,9 +2664,13 @@ async fn test_collaborating_with_code_actions( ) .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); // Join the project as client B. - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(project_b.clone(), |_, _| unimplemented!(), cx)); let editor_b = workspace_b @@ -2798,7 +2885,11 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T ) .await; let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(project_b.clone(), |_, _| unimplemented!(), cx)); @@ -3006,7 +3097,11 @@ async fn test_language_server_statuses( ); }); - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; project_b.read_with(cx_b, |project, _| { let status = project.language_server_statuses().next().unwrap(); assert_eq!(status.name, "the-language-server"); @@ -3485,79 +3580,6 @@ async fn test_contacts( [("user_a".to_string(), true), ("user_b".to_string(), true)] ); - // Share a project as client A. - client_a.fs.create_dir(Path::new("/a")).await.unwrap(); - let (project_a, _) = client_a.build_local_project("/a", cx_a).await; - - deterministic.run_until_parked(); - assert_eq!( - contacts(&client_a, cx_a), - [("user_b".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_b, cx_b), - [("user_a".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_c, cx_c), - [("user_a".to_string(), true), ("user_b".to_string(), true)] - ); - - let _project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; - - deterministic.run_until_parked(); - assert_eq!( - contacts(&client_a, cx_a), - [("user_b".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_b, cx_b), - [("user_a".to_string(), true,), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_c, cx_c), - [("user_a".to_string(), true,), ("user_b".to_string(), true)] - ); - - // Add a local project as client B - client_a.fs.create_dir("/b".as_ref()).await.unwrap(); - let (_project_b, _) = client_b.build_local_project("/b", cx_b).await; - - deterministic.run_until_parked(); - assert_eq!( - contacts(&client_a, cx_a), - [("user_b".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_b, cx_b), - [("user_a".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_c, cx_c), - [("user_a".to_string(), true,), ("user_b".to_string(), true)] - ); - - project_a - .condition(cx_a, |project, _| { - project.collaborators().contains_key(&client_b.peer_id) - }) - .await; - - cx_a.update(move |_| drop(project_a)); - deterministic.run_until_parked(); - assert_eq!( - contacts(&client_a, cx_a), - [("user_b".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_b, cx_b), - [("user_a".to_string(), true), ("user_c".to_string(), true)] - ); - assert_eq!( - contacts(&client_c, cx_c), - [("user_a".to_string(), true), ("user_b".to_string(), true)] - ); - server.disconnect_client(client_c.current_user_id(cx_c)); server.forbid_connections(); deterministic.advance_clock(rpc::RECEIVE_TIMEOUT); @@ -3811,8 +3833,11 @@ async fn test_following(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { ) .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; - - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Client A opens some editors. let workspace_a = client_a.build_workspace(&project_a, cx_a); @@ -4019,9 +4044,13 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T ) .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); // Client B joins the project. - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Client A opens some editors. let workspace_a = client_a.build_workspace(&project_a, cx_a); @@ -4182,7 +4211,11 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont ) .await; let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); + let project_b = client_b.build_remote_project(project_id, cx_b).await; // Client A opens some editors. let workspace_a = client_a.build_workspace(&project_a, cx_a); @@ -4331,8 +4364,12 @@ async fn test_peers_simultaneously_following_each_other( client_a.fs.insert_tree("/a", json!({})).await; let (project_a, _) = client_a.build_local_project("/a", cx_a).await; let workspace_a = client_a.build_workspace(&project_a, cx_a); + let project_id = project_a + .update(cx_a, |project, cx| project.share(cx)) + .await + .unwrap(); - let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await; + let project_b = client_b.build_remote_project(project_id, cx_b).await; let workspace_b = client_b.build_workspace(&project_b, cx_b); deterministic.run_until_parked(); @@ -4445,9 +4482,6 @@ async fn test_random_collaboration( cx, ) }); - let host_project_id = host_project - .update(&mut host_cx, |p, _| p.next_remote_id()) - .await; let (collab_worktree, _) = host_project .update(&mut host_cx, |project, cx| { @@ -4588,7 +4622,7 @@ async fn test_random_collaboration( .await; host_language_registry.add(Arc::new(language)); - host_project + let host_project_id = host_project .update(&mut host_cx, |project, cx| project.share(cx)) .await .unwrap(); @@ -5155,40 +5189,26 @@ impl TestClient { worktree .read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete()) .await; - project - .update(cx, |project, _| project.next_remote_id()) - .await; (project, worktree.read_with(cx, |tree, _| tree.id())) } async fn build_remote_project( &self, - host_project: &ModelHandle, - host_cx: &mut TestAppContext, + host_project_id: u64, guest_cx: &mut TestAppContext, ) -> ModelHandle { - let host_project_id = host_project - .read_with(host_cx, |project, _| project.next_remote_id()) - .await; - host_project - .update(host_cx, |project, cx| project.share(cx)) - .await - .unwrap(); - let languages = host_project.read_with(host_cx, |project, _| project.languages().clone()); let project_b = guest_cx.spawn(|cx| { Project::remote( host_project_id, self.client.clone(), self.user_store.clone(), self.project_store.clone(), - languages, + self.language_registry.clone(), FakeFs::new(cx.background()), cx, ) }); - - let project = project_b.await.unwrap(); - project + project_b.await.unwrap() } fn build_workspace( diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 192adb701c..f675ff2931 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -151,11 +151,10 @@ impl Server { .add_message_handler(Server::leave_room) .add_request_handler(Server::call) .add_message_handler(Server::decline_call) - .add_request_handler(Server::register_project) - .add_request_handler(Server::unregister_project) + .add_request_handler(Server::share_project) + .add_message_handler(Server::unshare_project) .add_request_handler(Server::join_project) .add_message_handler(Server::leave_project) - .add_message_handler(Server::unshare_project) .add_message_handler(Server::update_project) .add_message_handler(Server::register_project_activity) .add_request_handler(Server::update_worktree) @@ -470,18 +469,18 @@ impl Server { async fn sign_out(self: &mut Arc, connection_id: ConnectionId) -> Result<()> { self.peer.disconnect(connection_id); - let mut projects_to_unregister = Vec::new(); + let mut projects_to_unshare = Vec::new(); let removed_user_id; { let mut store = self.store().await; let removed_connection = store.remove_connection(connection_id)?; for (project_id, project) in removed_connection.hosted_projects { - projects_to_unregister.push(project_id); + projects_to_unshare.push(project_id); broadcast(connection_id, project.guests.keys().copied(), |conn_id| { self.peer.send( conn_id, - proto::UnregisterProject { + proto::UnshareProject { project_id: project_id.to_proto(), }, ) @@ -514,7 +513,7 @@ impl Server { self.update_user_contacts(removed_user_id).await.trace_err(); - for project_id in projects_to_unregister { + for project_id in projects_to_unshare { self.app_state .db .unregister_project(project_id) @@ -687,10 +686,10 @@ impl Server { } } - async fn register_project( + async fn share_project( self: Arc, - request: TypedEnvelope, - response: Response, + request: TypedEnvelope, + response: Response, ) -> Result<()> { let user_id = self .store() @@ -699,44 +698,15 @@ impl Server { let project_id = self.app_state.db.register_project(user_id).await?; self.store() .await - .register_project(request.sender_id, project_id)?; + .share_project(request.sender_id, project_id)?; - response.send(proto::RegisterProjectResponse { + response.send(proto::ShareProjectResponse { project_id: project_id.to_proto(), })?; Ok(()) } - async fn unregister_project( - self: Arc, - request: TypedEnvelope, - response: Response, - ) -> Result<()> { - let project_id = ProjectId::from_proto(request.payload.project_id); - let project = self - .store() - .await - .unregister_project(project_id, request.sender_id)?; - self.app_state.db.unregister_project(project_id).await?; - - broadcast( - request.sender_id, - project.guests.keys().copied(), - |conn_id| { - self.peer.send( - conn_id, - proto::UnregisterProject { - project_id: project_id.to_proto(), - }, - ) - }, - ); - response.send(proto::Ack {})?; - - Ok(()) - } - async fn unshare_project( self: Arc, message: TypedEnvelope, @@ -746,9 +716,11 @@ impl Server { .store() .await .unshare_project(project_id, message.sender_id)?; - broadcast(message.sender_id, project.guest_connection_ids, |conn_id| { - self.peer.send(conn_id, message.payload.clone()) - }); + broadcast( + message.sender_id, + project.guest_connection_ids(), + |conn_id| self.peer.send(conn_id, message.payload.clone()), + ); Ok(()) } diff --git a/crates/collab/src/rpc/store.rs b/crates/collab/src/rpc/store.rs index deb2230147..e73b2130c2 100644 --- a/crates/collab/src/rpc/store.rs +++ b/crates/collab/src/rpc/store.rs @@ -96,10 +96,6 @@ pub struct LeftProject { pub remove_collaborator: bool, } -pub struct UnsharedProject { - pub guest_connection_ids: Vec, -} - #[derive(Copy, Clone)] pub struct Metrics { pub connections: usize, @@ -201,9 +197,9 @@ impl Store { self.leave_channel(connection_id, channel_id); } - // Unregister and leave all projects. + // Unshare and leave all projects. for project_id in connection_projects { - if let Ok(project) = self.unregister_project(project_id, connection_id) { + if let Ok(project) = self.unshare_project(project_id, connection_id) { result.hosted_projects.insert(project_id, project); } else if self.leave_project(connection_id, project_id).is_ok() { result.guest_project_ids.insert(project_id); @@ -566,7 +562,7 @@ impl Store { } } - pub fn register_project( + pub fn share_project( &mut self, host_connection_id: ConnectionId, project_id: ProjectId, @@ -595,6 +591,35 @@ impl Store { Ok(()) } + pub fn unshare_project( + &mut self, + project_id: ProjectId, + connection_id: ConnectionId, + ) -> Result { + match self.projects.entry(project_id) { + btree_map::Entry::Occupied(e) => { + if e.get().host_connection_id == connection_id { + let project = e.remove(); + + if let Some(host_connection) = self.connections.get_mut(&connection_id) { + host_connection.projects.remove(&project_id); + } + + for guest_connection in project.guests.keys() { + if let Some(connection) = self.connections.get_mut(guest_connection) { + connection.projects.remove(&project_id); + } + } + + Ok(project) + } else { + Err(anyhow!("no such project"))? + } + } + btree_map::Entry::Vacant(_) => Err(anyhow!("no such project"))?, + } + } + pub fn update_project( &mut self, project_id: ProjectId, @@ -628,66 +653,6 @@ impl Store { } } - pub fn unregister_project( - &mut self, - project_id: ProjectId, - connection_id: ConnectionId, - ) -> Result { - match self.projects.entry(project_id) { - btree_map::Entry::Occupied(e) => { - if e.get().host_connection_id == connection_id { - let project = e.remove(); - - if let Some(host_connection) = self.connections.get_mut(&connection_id) { - host_connection.projects.remove(&project_id); - } - - for guest_connection in project.guests.keys() { - if let Some(connection) = self.connections.get_mut(guest_connection) { - connection.projects.remove(&project_id); - } - } - - Ok(project) - } else { - Err(anyhow!("no such project"))? - } - } - btree_map::Entry::Vacant(_) => Err(anyhow!("no such project"))?, - } - } - - pub fn unshare_project( - &mut self, - project_id: ProjectId, - connection_id: ConnectionId, - ) -> Result { - let project = self - .projects - .get_mut(&project_id) - .ok_or_else(|| anyhow!("no such project"))?; - anyhow::ensure!( - project.host_connection_id == connection_id, - "no such project" - ); - - let guest_connection_ids = project.guest_connection_ids(); - project.active_replica_ids.clear(); - project.guests.clear(); - project.language_servers.clear(); - project.worktrees.clear(); - - for connection_id in &guest_connection_ids { - if let Some(connection) = self.connections.get_mut(connection_id) { - connection.projects.remove(&project_id); - } - } - - Ok(UnsharedProject { - guest_connection_ids, - }) - } - pub fn update_diagnostic_summary( &mut self, project_id: ProjectId, diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index eb1afc3810..db6d3bd3b0 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -845,14 +845,6 @@ mod tests { .detach(); }); - let request = server.receive::().await.unwrap(); - server - .respond( - request.receipt(), - proto::RegisterProjectResponse { project_id: 200 }, - ) - .await; - let get_users_request = server.receive::().await.unwrap(); server .respond( diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 903e103d41..279e2caaa3 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -35,7 +35,6 @@ use lsp::{ }; use lsp_command::*; use parking_lot::Mutex; -use postage::stream::Stream; use postage::watch; use rand::prelude::*; use search::SearchQuery; @@ -153,10 +152,8 @@ enum WorktreeHandle { enum ProjectClientState { Local { - is_shared: bool, - remote_id_tx: watch::Sender>, - remote_id_rx: watch::Receiver>, - _maintain_remote_id: Task>, + remote_id: Option, + _detect_unshare: Task>, }, Remote { sharing_has_stopped: bool, @@ -382,7 +379,6 @@ impl Project { client.add_model_message_handler(Self::handle_update_language_server); client.add_model_message_handler(Self::handle_remove_collaborator); client.add_model_message_handler(Self::handle_update_project); - client.add_model_message_handler(Self::handle_unregister_project); client.add_model_message_handler(Self::handle_unshare_project); client.add_model_message_handler(Self::handle_create_buffer_for_peer); client.add_model_message_handler(Self::handle_update_buffer_file); @@ -423,24 +419,19 @@ impl Project { cx: &mut MutableAppContext, ) -> ModelHandle { cx.add_model(|cx: &mut ModelContext| { - let (remote_id_tx, remote_id_rx) = watch::channel(); - let _maintain_remote_id = cx.spawn_weak({ - let mut status_rx = client.clone().status(); - move |this, mut cx| async move { - while let Some(status) = status_rx.recv().await { - let this = this.upgrade(&cx)?; - if status.is_connected() { - this.update(&mut cx, |this, cx| this.register(cx)) - .await - .log_err()?; - } else { - this.update(&mut cx, |this, cx| this.unregister(cx)) - .await - .log_err(); + let mut status = client.status(); + let _detect_unshare = cx.spawn_weak(move |this, mut cx| { + async move { + let is_connected = status.next().await.map_or(false, |s| s.is_connected()); + // Even if we're initially connected, any future change of the status means we momentarily disconnected. + if !is_connected || status.next().await.is_some() { + if let Some(this) = this.upgrade(&cx) { + let _ = this.update(&mut cx, |this, cx| this.unshare(cx)); } } - None + Ok(()) } + .log_err() }); let handle = cx.weak_handle(); @@ -456,10 +447,8 @@ impl Project { loading_local_worktrees: Default::default(), buffer_snapshots: Default::default(), client_state: ProjectClientState::Local { - is_shared: false, - remote_id_tx, - remote_id_rx, - _maintain_remote_id, + remote_id: None, + _detect_unshare, }, opened_buffer: watch::channel(), client_subscriptions: Vec::new(), @@ -762,113 +751,9 @@ impl Project { &self.fs } - fn unregister(&mut self, cx: &mut ModelContext) -> Task> { - self.unshare(cx).log_err(); - if let ProjectClientState::Local { remote_id_rx, .. } = &mut self.client_state { - if let Some(remote_id) = *remote_id_rx.borrow() { - let request = self.client.request(proto::UnregisterProject { - project_id: remote_id, - }); - return cx.spawn(|this, mut cx| async move { - let response = request.await; - - // Unregistering the project causes the server to send out a - // contact update removing this project from the host's list - // of online projects. Wait until this contact update has been - // processed before clearing out this project's remote id, so - // that there is no moment where this project appears in the - // contact metadata and *also* has no remote id. - this.update(&mut cx, |this, cx| { - this.user_store() - .update(cx, |store, _| store.contact_updates_done()) - }) - .await; - - this.update(&mut cx, |this, cx| { - if let ProjectClientState::Local { remote_id_tx, .. } = - &mut this.client_state - { - *remote_id_tx.borrow_mut() = None; - } - this.client_subscriptions.clear(); - this.metadata_changed(cx); - }); - response.map(drop) - }); - } - } - Task::ready(Ok(())) - } - - fn register(&mut self, cx: &mut ModelContext) -> Task> { - if let ProjectClientState::Local { remote_id_rx, .. } = &self.client_state { - if remote_id_rx.borrow().is_some() { - return Task::ready(Ok(())); - } - - let response = self.client.request(proto::RegisterProject {}); - cx.spawn(|this, mut cx| async move { - let remote_id = response.await?.project_id; - this.update(&mut cx, |this, cx| { - if let ProjectClientState::Local { remote_id_tx, .. } = &mut this.client_state { - *remote_id_tx.borrow_mut() = Some(remote_id); - } - - this.metadata_changed(cx); - cx.emit(Event::RemoteIdChanged(Some(remote_id))); - this.client_subscriptions - .push(this.client.add_model_for_remote_entity(remote_id, cx)); - Ok(()) - }) - }) - } else { - Task::ready(Err(anyhow!("can't register a remote project"))) - } - } - pub fn remote_id(&self) -> Option { match &self.client_state { - ProjectClientState::Local { remote_id_rx, .. } => *remote_id_rx.borrow(), - ProjectClientState::Remote { remote_id, .. } => Some(*remote_id), - } - } - - pub fn next_remote_id(&self) -> impl Future { - let mut id = None; - let mut watch = None; - match &self.client_state { - ProjectClientState::Local { remote_id_rx, .. } => watch = Some(remote_id_rx.clone()), - ProjectClientState::Remote { remote_id, .. } => id = Some(*remote_id), - } - - async move { - if let Some(id) = id { - return id; - } - let mut watch = watch.unwrap(); - loop { - let id = *watch.borrow(); - if let Some(id) = id { - return id; - } - watch.next().await; - } - } - } - - pub fn shared_remote_id(&self) -> Option { - match &self.client_state { - ProjectClientState::Local { - remote_id_rx, - is_shared, - .. - } => { - if *is_shared { - *remote_id_rx.borrow() - } else { - None - } - } + ProjectClientState::Local { remote_id, .. } => *remote_id, ProjectClientState::Remote { remote_id, .. } => Some(*remote_id), } } @@ -881,7 +766,7 @@ impl Project { } fn metadata_changed(&mut self, cx: &mut ModelContext) { - if let ProjectClientState::Local { remote_id_rx, .. } = &self.client_state { + if let ProjectClientState::Local { remote_id, .. } = &self.client_state { // Broadcast worktrees only if the project is online. let worktrees = self .worktrees @@ -892,7 +777,7 @@ impl Project { .map(|worktree| worktree.read(cx).as_local().unwrap().metadata_proto()) }) .collect(); - if let Some(project_id) = *remote_id_rx.borrow() { + if let Some(project_id) = *remote_id { self.client .send(proto::UpdateProject { project_id, @@ -1164,113 +1049,105 @@ impl Project { } } - pub fn share(&mut self, cx: &mut ModelContext) -> Task> { - let project_id; - if let ProjectClientState::Local { - remote_id_rx, - is_shared, - .. - } = &mut self.client_state - { - if *is_shared { - return Task::ready(Ok(())); - } - *is_shared = true; - if let Some(id) = *remote_id_rx.borrow() { - project_id = id; - } else { - return Task::ready(Err(anyhow!("project hasn't been registered"))); + pub fn share(&mut self, cx: &mut ModelContext) -> Task> { + if let ProjectClientState::Local { remote_id, .. } = &mut self.client_state { + if let Some(remote_id) = remote_id { + return Task::ready(Ok(*remote_id)); } + + let response = self.client.request(proto::ShareProject {}); + cx.spawn(|this, mut cx| async move { + let project_id = response.await?.project_id; + let mut worktree_share_tasks = Vec::new(); + this.update(&mut cx, |this, cx| { + if let ProjectClientState::Local { remote_id, .. } = &mut this.client_state { + *remote_id = Some(project_id); + } + + for open_buffer in this.opened_buffers.values_mut() { + match open_buffer { + OpenBuffer::Strong(_) => {} + OpenBuffer::Weak(buffer) => { + if let Some(buffer) = buffer.upgrade(cx) { + *open_buffer = OpenBuffer::Strong(buffer); + } + } + OpenBuffer::Operations(_) => unreachable!(), + } + } + + for worktree_handle in this.worktrees.iter_mut() { + match worktree_handle { + WorktreeHandle::Strong(_) => {} + WorktreeHandle::Weak(worktree) => { + if let Some(worktree) = worktree.upgrade(cx) { + *worktree_handle = WorktreeHandle::Strong(worktree); + } + } + } + } + + for worktree in this.worktrees(cx).collect::>() { + worktree.update(cx, |worktree, cx| { + let worktree = worktree.as_local_mut().unwrap(); + worktree_share_tasks.push(worktree.share(project_id, cx)); + }); + } + + for (server_id, status) in &this.language_server_statuses { + this.client + .send(proto::StartLanguageServer { + project_id, + server: Some(proto::LanguageServer { + id: *server_id as u64, + name: status.name.clone(), + }), + }) + .log_err(); + } + + this.client_subscriptions + .push(this.client.add_model_for_remote_entity(project_id, cx)); + this.metadata_changed(cx); + cx.emit(Event::RemoteIdChanged(Some(project_id))); + cx.notify(); + }); + + futures::future::try_join_all(worktree_share_tasks).await?; + Ok(project_id) + }) } else { - return Task::ready(Err(anyhow!("can't share a remote project"))); - }; - - for open_buffer in self.opened_buffers.values_mut() { - match open_buffer { - OpenBuffer::Strong(_) => {} - OpenBuffer::Weak(buffer) => { - if let Some(buffer) = buffer.upgrade(cx) { - *open_buffer = OpenBuffer::Strong(buffer); - } - } - OpenBuffer::Operations(_) => unreachable!(), - } + Task::ready(Err(anyhow!("can't share a remote project"))) } - - for worktree_handle in self.worktrees.iter_mut() { - match worktree_handle { - WorktreeHandle::Strong(_) => {} - WorktreeHandle::Weak(worktree) => { - if let Some(worktree) = worktree.upgrade(cx) { - *worktree_handle = WorktreeHandle::Strong(worktree); - } - } - } - } - - let mut tasks = Vec::new(); - for worktree in self.worktrees(cx).collect::>() { - worktree.update(cx, |worktree, cx| { - let worktree = worktree.as_local_mut().unwrap(); - tasks.push(worktree.share(project_id, cx)); - }); - } - - for (server_id, status) in &self.language_server_statuses { - self.client - .send(proto::StartLanguageServer { - project_id, - server: Some(proto::LanguageServer { - id: *server_id as u64, - name: status.name.clone(), - }), - }) - .log_err(); - } - - cx.spawn(|this, mut cx| async move { - for task in tasks { - task.await?; - } - this.update(&mut cx, |_, cx| cx.notify()); - Ok(()) - }) } pub fn unshare(&mut self, cx: &mut ModelContext) -> Result<()> { - if let ProjectClientState::Local { - is_shared, - remote_id_rx, - .. - } = &mut self.client_state - { - if !*is_shared { - return Ok(()); - } + if let ProjectClientState::Local { remote_id, .. } = &mut self.client_state { + if let Some(project_id) = remote_id.take() { + self.collaborators.clear(); + self.shared_buffers.clear(); + self.client_subscriptions.clear(); - *is_shared = false; - self.collaborators.clear(); - self.shared_buffers.clear(); - for worktree_handle in self.worktrees.iter_mut() { - if let WorktreeHandle::Strong(worktree) = worktree_handle { - let is_visible = worktree.update(cx, |worktree, _| { - worktree.as_local_mut().unwrap().unshare(); - worktree.is_visible() - }); - if !is_visible { - *worktree_handle = WorktreeHandle::Weak(worktree.downgrade()); + for worktree_handle in self.worktrees.iter_mut() { + if let WorktreeHandle::Strong(worktree) = worktree_handle { + let is_visible = worktree.update(cx, |worktree, _| { + worktree.as_local_mut().unwrap().unshare(); + worktree.is_visible() + }); + if !is_visible { + *worktree_handle = WorktreeHandle::Weak(worktree.downgrade()); + } } } - } - for open_buffer in self.opened_buffers.values_mut() { - if let OpenBuffer::Strong(buffer) = open_buffer { - *open_buffer = OpenBuffer::Weak(buffer.downgrade()); + for open_buffer in self.opened_buffers.values_mut() { + if let OpenBuffer::Strong(buffer) = open_buffer { + *open_buffer = OpenBuffer::Weak(buffer.downgrade()); + } } - } - cx.notify(); - if let Some(project_id) = *remote_id_rx.borrow() { + self.metadata_changed(cx); + cx.notify(); self.client.send(proto::UnshareProject { project_id })?; } @@ -1750,7 +1627,7 @@ impl Project { ) -> Option<()> { match event { BufferEvent::Operation(operation) => { - if let Some(project_id) = self.shared_remote_id() { + if let Some(project_id) = self.remote_id() { let request = self.client.request(proto::UpdateBuffer { project_id, buffer_id: buffer.read(cx).remote_id(), @@ -2155,7 +2032,7 @@ impl Project { ) .ok(); - if let Some(project_id) = this.shared_remote_id() { + if let Some(project_id) = this.remote_id() { this.client .send(proto::StartLanguageServer { project_id, @@ -2562,7 +2439,7 @@ impl Project { language_server_id: usize, event: proto::update_language_server::Variant, ) { - if let Some(project_id) = self.shared_remote_id() { + if let Some(project_id) = self.remote_id() { self.client .send(proto::UpdateLanguageServer { project_id, @@ -4273,7 +4150,7 @@ impl Project { pub fn is_shared(&self) -> bool { match &self.client_state { - ProjectClientState::Local { is_shared, .. } => *is_shared, + ProjectClientState::Local { remote_id, .. } => remote_id.is_some(), ProjectClientState::Remote { .. } => false, } } @@ -4310,7 +4187,7 @@ impl Project { let project_id = project.update(&mut cx, |project, cx| { project.add_worktree(&worktree, cx); - project.shared_remote_id() + project.remote_id() }); if let Some(project_id) = project_id { @@ -4439,7 +4316,7 @@ impl Project { renamed_buffers.push((cx.handle(), old_path)); } - if let Some(project_id) = self.shared_remote_id() { + if let Some(project_id) = self.remote_id() { self.client .send(proto::UpdateBufferFile { project_id, @@ -4552,16 +4429,6 @@ impl Project { // RPC message handlers - async fn handle_unregister_project( - this: ModelHandle, - _: TypedEnvelope, - _: Arc, - mut cx: AsyncAppContext, - ) -> Result<()> { - this.update(&mut cx, |this, cx| this.disconnected_from_host(cx)); - Ok(()) - } - async fn handle_unshare_project( this: ModelHandle, _: TypedEnvelope, @@ -5987,10 +5854,10 @@ impl Entity for Project { self.project_store.update(cx, ProjectStore::prune_projects); match &self.client_state { - ProjectClientState::Local { remote_id_rx, .. } => { - if let Some(project_id) = *remote_id_rx.borrow() { + ProjectClientState::Local { remote_id, .. } => { + if let Some(project_id) = *remote_id { self.client - .send(proto::UnregisterProject { project_id }) + .send(proto::UnshareProject { project_id }) .log_err(); } } diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 2659ddb86d..acb18878d9 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -22,15 +22,14 @@ message Envelope { DeclineCall decline_call = 13; RoomUpdated room_updated = 14; - RegisterProject register_project = 15; - RegisterProjectResponse register_project_response = 16; - UnregisterProject unregister_project = 17; + ShareProject share_project = 15; + ShareProjectResponse share_project_response = 16; + UnshareProject unshare_project = 17; JoinProject join_project = 21; JoinProjectResponse join_project_response = 22; LeaveProject leave_project = 23; AddProjectCollaborator add_project_collaborator = 24; RemoveProjectCollaborator remove_project_collaborator = 25; - UnshareProject unshare_project = 26; GetDefinition get_definition = 27; GetDefinitionResponse get_definition_response = 28; @@ -195,13 +194,13 @@ message RoomUpdated { Room room = 1; } -message RegisterProject {} +message ShareProject {} -message RegisterProjectResponse { +message ShareProjectResponse { uint64 project_id = 1; } -message UnregisterProject { +message UnshareProject { uint64 project_id = 1; } @@ -285,10 +284,6 @@ message RemoveProjectCollaborator { uint32 peer_id = 2; } -message UnshareProject { - uint64 project_id = 1; -} - message GetDefinition { uint64 project_id = 1; uint64 buffer_id = 2; diff --git a/crates/rpc/src/proto.rs b/crates/rpc/src/proto.rs index c2d2d2b321..822a50c3e4 100644 --- a/crates/rpc/src/proto.rs +++ b/crates/rpc/src/proto.rs @@ -141,10 +141,8 @@ messages!( (PrepareRename, Background), (PrepareRenameResponse, Background), (ProjectEntryResponse, Foreground), - (RegisterProjectResponse, Foreground), (RemoveContact, Foreground), (Ping, Foreground), - (RegisterProject, Foreground), (RegisterProjectActivity, Foreground), (ReloadBuffers, Foreground), (ReloadBuffersResponse, Foreground), @@ -158,11 +156,12 @@ messages!( (SearchProjectResponse, Background), (SendChannelMessage, Foreground), (SendChannelMessageResponse, Foreground), + (ShareProject, Foreground), + (ShareProjectResponse, Foreground), (ShowContacts, Foreground), (StartLanguageServer, Foreground), (Test, Foreground), (Unfollow, Foreground), - (UnregisterProject, Foreground), (UnshareProject, Foreground), (UpdateBuffer, Foreground), (UpdateBufferFile, Foreground), @@ -212,7 +211,6 @@ request_messages!( (Ping, Ack), (PerformRename, PerformRenameResponse), (PrepareRename, PrepareRenameResponse), - (RegisterProject, RegisterProjectResponse), (ReloadBuffers, ReloadBuffersResponse), (RequestContact, Ack), (RemoveContact, Ack), @@ -221,8 +219,8 @@ request_messages!( (SaveBuffer, BufferSaved), (SearchProject, SearchProjectResponse), (SendChannelMessage, SendChannelMessageResponse), + (ShareProject, ShareProjectResponse), (Test, Test), - (UnregisterProject, Ack), (UpdateBuffer, Ack), (UpdateWorktree, Ack), ); @@ -263,7 +261,6 @@ entity_messages!( SearchProject, StartLanguageServer, Unfollow, - UnregisterProject, UnshareProject, UpdateBuffer, UpdateBufferFile,