Merge branch 'main' into v0.67.x

Antonio Scandurra created

Change summary

Cargo.lock                                   |  2 
crates/call/src/participant.rs               |  1 
crates/call/src/room.rs                      | 42 +++++++++++++--------
crates/collab/Cargo.toml                     |  2 
crates/collab/src/integration_tests.rs       |  4 +-
crates/collab/src/rpc.rs                     |  6 +-
crates/collab_ui/src/collab_titlebar_item.rs | 17 +++++---
crates/collab_ui/src/collab_ui.rs            |  2 
crates/collab_ui/src/contact_list.rs         | 22 +++++------
crates/rpc/src/proto.rs                      | 18 ---------
crates/rpc/src/rpc.rs                        |  2 
crates/workspace/src/pane_group.rs           |  2 
crates/workspace/src/workspace.rs            |  4 +-
13 files changed, 59 insertions(+), 65 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1131,7 +1131,7 @@ dependencies = [
 
 [[package]]
 name = "collab"
-version = "0.4.0"
+version = "0.4.1"
 dependencies = [
  "anyhow",
  "async-tungstenite",

crates/call/src/participant.rs 🔗

@@ -39,6 +39,7 @@ pub struct LocalParticipant {
 #[derive(Clone, Debug)]
 pub struct RemoteParticipant {
     pub user: Arc<User>,
+    pub peer_id: proto::PeerId,
     pub projects: Vec<proto::ParticipantProject>,
     pub location: ParticipantLocation,
     pub tracks: HashMap<live_kit_client::Sid, Arc<RemoteVideoTrack>>,

crates/call/src/room.rs 🔗

@@ -3,7 +3,10 @@ use crate::{
     IncomingCall,
 };
 use anyhow::{anyhow, Result};
-use client::{proto, Client, TypedEnvelope, User, UserStore};
+use client::{
+    proto::{self, PeerId},
+    Client, TypedEnvelope, User, UserStore,
+};
 use collections::{BTreeMap, HashSet};
 use futures::{FutureExt, StreamExt};
 use gpui::{
@@ -41,7 +44,7 @@ pub struct Room {
     live_kit: Option<LiveKitRoom>,
     status: RoomStatus,
     local_participant: LocalParticipant,
-    remote_participants: BTreeMap<proto::PeerId, RemoteParticipant>,
+    remote_participants: BTreeMap<u64, RemoteParticipant>,
     pending_participants: Vec<Arc<User>>,
     participant_user_ids: HashSet<u64>,
     pending_call_count: usize,
@@ -349,10 +352,16 @@ impl Room {
         &self.local_participant
     }
 
-    pub fn remote_participants(&self) -> &BTreeMap<proto::PeerId, RemoteParticipant> {
+    pub fn remote_participants(&self) -> &BTreeMap<u64, RemoteParticipant> {
         &self.remote_participants
     }
 
+    pub fn remote_participant_for_peer_id(&self, peer_id: PeerId) -> Option<&RemoteParticipant> {
+        self.remote_participants
+            .values()
+            .find(|p| p.peer_id == peer_id)
+    }
+
     pub fn pending_participants(&self) -> &[Arc<User>] {
         &self.pending_participants
     }
@@ -417,15 +426,13 @@ impl Room {
                 }
 
                 if let Some(participants) = remote_participants.log_err() {
-                    let mut participant_peer_ids = HashSet::default();
                     for (participant, user) in room.participants.into_iter().zip(participants) {
                         let Some(peer_id) = participant.peer_id else { continue };
                         this.participant_user_ids.insert(participant.user_id);
-                        participant_peer_ids.insert(peer_id);
 
                         let old_projects = this
                             .remote_participants
-                            .get(&peer_id)
+                            .get(&participant.user_id)
                             .into_iter()
                             .flat_map(|existing| &existing.projects)
                             .map(|project| project.id)
@@ -454,9 +461,11 @@ impl Room {
 
                         let location = ParticipantLocation::from_proto(participant.location)
                             .unwrap_or(ParticipantLocation::External);
-                        if let Some(remote_participant) = this.remote_participants.get_mut(&peer_id)
+                        if let Some(remote_participant) =
+                            this.remote_participants.get_mut(&participant.user_id)
                         {
                             remote_participant.projects = participant.projects;
+                            remote_participant.peer_id = peer_id;
                             if location != remote_participant.location {
                                 remote_participant.location = location;
                                 cx.emit(Event::ParticipantLocationChanged {
@@ -465,9 +474,10 @@ impl Room {
                             }
                         } else {
                             this.remote_participants.insert(
-                                peer_id,
+                                participant.user_id,
                                 RemoteParticipant {
                                     user: user.clone(),
+                                    peer_id,
                                     projects: participant.projects,
                                     location,
                                     tracks: Default::default(),
@@ -488,8 +498,8 @@ impl Room {
                         }
                     }
 
-                    this.remote_participants.retain(|peer_id, participant| {
-                        if participant_peer_ids.contains(peer_id) {
+                    this.remote_participants.retain(|user_id, participant| {
+                        if this.participant_user_ids.contains(user_id) {
                             true
                         } else {
                             for project in &participant.projects {
@@ -531,11 +541,11 @@ impl Room {
     ) -> Result<()> {
         match change {
             RemoteVideoTrackUpdate::Subscribed(track) => {
-                let peer_id = track.publisher_id().parse()?;
+                let user_id = track.publisher_id().parse()?;
                 let track_id = track.sid().to_string();
                 let participant = self
                     .remote_participants
-                    .get_mut(&peer_id)
+                    .get_mut(&user_id)
                     .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?;
                 participant.tracks.insert(
                     track_id.clone(),
@@ -544,21 +554,21 @@ impl Room {
                     }),
                 );
                 cx.emit(Event::RemoteVideoTracksChanged {
-                    participant_id: peer_id,
+                    participant_id: participant.peer_id,
                 });
             }
             RemoteVideoTrackUpdate::Unsubscribed {
                 publisher_id,
                 track_id,
             } => {
-                let peer_id = publisher_id.parse()?;
+                let user_id = publisher_id.parse()?;
                 let participant = self
                     .remote_participants
-                    .get_mut(&peer_id)
+                    .get_mut(&user_id)
                     .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?;
                 participant.tracks.remove(&track_id);
                 cx.emit(Event::RemoteVideoTracksChanged {
-                    participant_id: peer_id,
+                    participant_id: participant.peer_id,
                 });
             }
         }

crates/collab/Cargo.toml 🔗

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathan@zed.dev>"]
 default-run = "collab"
 edition = "2021"
 name = "collab"
-version = "0.4.0"
+version = "0.4.1"
 
 [[bin]]
 name = "collab"

crates/collab/src/integration_tests.rs 🔗

@@ -199,7 +199,7 @@ async fn test_basic_calls(
         assert_eq!(participant_id, client_a.peer_id().unwrap());
         room_b.read_with(cx_b, |room, _| {
             assert_eq!(
-                room.remote_participants()[&client_a.peer_id().unwrap()]
+                room.remote_participants()[&client_a.user_id().unwrap()]
                     .tracks
                     .len(),
                 1
@@ -492,7 +492,7 @@ async fn test_client_disconnecting_from_room(
     // to automatically leave the room.
     server
         .test_live_kit_server
-        .disconnect_client(client_b.peer_id().unwrap().to_string())
+        .disconnect_client(client_b.user_id().unwrap().to_string())
         .await;
     deterministic.run_until_parked();
     active_call_a.update(cx_a, |call, _| assert!(call.room().is_none()));

crates/collab/src/rpc.rs 🔗

@@ -850,7 +850,7 @@ async fn create_room(
             .trace_err()
         {
             if let Some(token) = live_kit
-                .room_token(&live_kit_room, &session.connection_id.to_string())
+                .room_token(&live_kit_room, &session.user_id.to_string())
                 .trace_err()
             {
                 Some(proto::LiveKitConnectionInfo {
@@ -918,7 +918,7 @@ async fn join_room(
 
     let live_kit_connection_info = if let Some(live_kit) = session.live_kit_client.as_ref() {
         if let Some(token) = live_kit
-            .room_token(&room.live_kit_room, &session.connection_id.to_string())
+            .room_token(&room.live_kit_room, &session.user_id.to_string())
             .trace_err()
         {
             Some(proto::LiveKitConnectionInfo {
@@ -2066,7 +2066,7 @@ async fn leave_room_for_session(session: &Session) -> Result<()> {
 
     if let Some(live_kit) = session.live_kit_client.as_ref() {
         live_kit
-            .remove_participant(live_kit_room.clone(), session.connection_id.to_string())
+            .remove_participant(live_kit_room.clone(), session.user_id.to_string())
             .await
             .trace_err();
 

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -342,24 +342,27 @@ impl CollabTitlebarItem {
             let mut participants = room
                 .read(cx)
                 .remote_participants()
-                .iter()
-                .map(|(peer_id, collaborator)| (*peer_id, collaborator.clone()))
+                .values()
+                .cloned()
                 .collect::<Vec<_>>();
-            participants
-                .sort_by_key(|(peer_id, _)| Some(project.collaborators().get(peer_id)?.replica_id));
+            participants.sort_by_key(|p| Some(project.collaborators().get(&p.peer_id)?.replica_id));
             participants
                 .into_iter()
-                .filter_map(|(peer_id, participant)| {
+                .filter_map(|participant| {
                     let project = workspace.read(cx).project().read(cx);
                     let replica_id = project
                         .collaborators()
-                        .get(&peer_id)
+                        .get(&participant.peer_id)
                         .map(|collaborator| collaborator.replica_id);
                     let user = participant.user.clone();
                     Some(self.render_avatar(
                         &user,
                         replica_id,
-                        Some((peer_id, &user.github_login, participant.location)),
+                        Some((
+                            participant.peer_id,
+                            &user.github_login,
+                            participant.location,
+                        )),
                         workspace,
                         theme,
                         cx,

crates/collab_ui/src/collab_ui.rs 🔗

@@ -73,7 +73,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
                         .remote_participants()
                         .iter()
                         .find(|(_, participant)| participant.user.id == follow_user_id)
-                        .map(|(peer_id, _)| *peer_id)
+                        .map(|(_, p)| p.peer_id)
                         .or_else(|| {
                             // If we couldn't follow the given user, follow the host instead.
                             let collaborator = workspace

crates/collab_ui/src/contact_list.rs 🔗

@@ -461,15 +461,13 @@ impl ContactList {
             // Populate remote participants.
             self.match_candidates.clear();
             self.match_candidates
-                .extend(
-                    room.remote_participants()
-                        .iter()
-                        .map(|(peer_id, participant)| StringMatchCandidate {
-                            id: peer_id.as_u64() as usize,
-                            string: participant.user.github_login.clone(),
-                            char_bag: participant.user.github_login.chars().collect(),
-                        }),
-                );
+                .extend(room.remote_participants().iter().map(|(_, participant)| {
+                    StringMatchCandidate {
+                        id: participant.user.id as usize,
+                        string: participant.user.github_login.clone(),
+                        char_bag: participant.user.github_login.chars().collect(),
+                    }
+                }));
             let matches = executor.block(match_strings(
                 &self.match_candidates,
                 &query,
@@ -479,8 +477,8 @@ impl ContactList {
                 executor.clone(),
             ));
             for mat in matches {
-                let peer_id = PeerId::from_u64(mat.candidate_id as u64);
-                let participant = &room.remote_participants()[&peer_id];
+                let user_id = mat.candidate_id as u64;
+                let participant = &room.remote_participants()[&user_id];
                 participant_entries.push(ContactEntry::CallParticipant {
                     user: participant.user.clone(),
                     is_pending: false,
@@ -496,7 +494,7 @@ impl ContactList {
                 }
                 if !participant.tracks.is_empty() {
                     participant_entries.push(ContactEntry::ParticipantScreen {
-                        peer_id,
+                        peer_id: participant.peer_id,
                         is_last: true,
                     });
                 }

crates/rpc/src/proto.rs 🔗

@@ -6,7 +6,6 @@ use prost::Message as _;
 use serde::Serialize;
 use std::any::{Any, TypeId};
 use std::fmt;
-use std::str::FromStr;
 use std::{
     cmp,
     fmt::Debug,
@@ -119,23 +118,6 @@ impl fmt::Display for PeerId {
     }
 }
 
-impl FromStr for PeerId {
-    type Err = anyhow::Error;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let mut components = s.split('/');
-        let owner_id = components
-            .next()
-            .ok_or_else(|| anyhow!("invalid peer id {:?}", s))?
-            .parse()?;
-        let id = components
-            .next()
-            .ok_or_else(|| anyhow!("invalid peer id {:?}", s))?
-            .parse()?;
-        Ok(PeerId { owner_id, id })
-    }
-}
-
 messages!(
     (Ack, Foreground),
     (AddProjectCollaborator, Foreground),

crates/rpc/src/rpc.rs 🔗

@@ -6,4 +6,4 @@ pub use conn::Connection;
 pub use peer::*;
 mod macros;
 
-pub const PROTOCOL_VERSION: u32 = 42;
+pub const PROTOCOL_VERSION: u32 = 43;

crates/workspace/src/pane_group.rs 🔗

@@ -148,7 +148,7 @@ impl Member {
                     .and_then(|leader_id| {
                         let room = active_call?.read(cx).room()?.read(cx);
                         let collaborator = project.read(cx).collaborators().get(leader_id)?;
-                        let participant = room.remote_participants().get(&leader_id)?;
+                        let participant = room.remote_participant_for_peer_id(*leader_id)?;
                         Some((collaborator.replica_id, participant))
                     });
 

crates/workspace/src/workspace.rs 🔗

@@ -2141,7 +2141,7 @@ impl Workspace {
 
         let call = self.active_call()?;
         let room = call.read(cx).room()?.read(cx);
-        let participant = room.remote_participants().get(&leader_id)?;
+        let participant = room.remote_participant_for_peer_id(leader_id)?;
 
         let mut items_to_add = Vec::new();
         match participant.location {
@@ -2190,7 +2190,7 @@ impl Workspace {
     ) -> Option<ViewHandle<SharedScreen>> {
         let call = self.active_call()?;
         let room = call.read(cx).room()?.read(cx);
-        let participant = room.remote_participants().get(&peer_id)?;
+        let participant = room.remote_participant_for_peer_id(peer_id)?;
         let track = participant.tracks.values().next()?.clone();
         let user = participant.user.clone();