Detailed changes
@@ -1209,6 +1209,7 @@ where
id: collaborator.project_id,
host_user_id: Default::default(),
connection_ids: Default::default(),
+ host_connection_id: Default::default(),
});
let collaborator_connection_id =
@@ -1219,6 +1220,8 @@ where
if collaborator.is_host {
left_project.host_user_id = collaborator.user_id;
+ left_project.host_connection_id =
+ ConnectionId(collaborator.connection_id as u32);
}
}
}
@@ -1474,7 +1477,8 @@ where
.bind(user_id)
.bind(connection_id.0 as i32)
.fetch_one(&mut tx)
- .await?;
+ .await
+ .unwrap();
if !worktrees.is_empty() {
let mut params = "(?, ?, ?, ?, ?, ?, ?),".repeat(worktrees.len());
@@ -1505,7 +1509,7 @@ where
.bind(0)
.bind(false);
}
- query.execute(&mut tx).await?;
+ query.execute(&mut tx).await.unwrap();
}
sqlx::query(
@@ -1526,7 +1530,8 @@ where
.bind(0)
.bind(true)
.execute(&mut tx)
- .await?;
+ .await
+ .unwrap();
let room = self.commit_room_transaction(room_id, tx).await?;
Ok((project_id, room))
@@ -2086,6 +2091,64 @@ where
.await
}
+ pub async fn leave_project(
+ &self,
+ project_id: ProjectId,
+ connection_id: ConnectionId,
+ ) -> Result<LeftProject> {
+ self.transact(|mut tx| async move {
+ let result = sqlx::query(
+ "
+ DELETE FROM project_collaborators
+ WHERE project_id = $1 AND connection_id = $2
+ ",
+ )
+ .bind(project_id)
+ .bind(connection_id.0 as i32)
+ .execute(&mut tx)
+ .await?;
+
+ if result.rows_affected() != 1 {
+ Err(anyhow!("not a collaborator on this project"))?;
+ }
+
+ let connection_ids = sqlx::query_scalar::<_, i32>(
+ "
+ SELECT connection_id
+ FROM project_collaborators
+ WHERE project_id = $1
+ ",
+ )
+ .bind(project_id)
+ .fetch_all(&mut tx)
+ .await?
+ .into_iter()
+ .map(|id| ConnectionId(id as u32))
+ .collect();
+
+ let (host_user_id, host_connection_id) = sqlx::query_as::<_, (i32, i32)>(
+ "
+ SELECT host_user_id, host_connection_id
+ FROM projects
+ WHERE id = $1
+ ",
+ )
+ .bind(project_id)
+ .fetch_one(&mut tx)
+ .await?;
+
+ tx.commit().await?;
+
+ Ok(LeftProject {
+ id: project_id,
+ host_user_id: UserId(host_user_id),
+ host_connection_id: ConnectionId(host_connection_id as u32),
+ connection_ids,
+ })
+ })
+ .await
+ }
+
pub async fn project_collaborators(
&self,
project_id: ProjectId,
@@ -2645,6 +2708,7 @@ struct LanguageServer {
pub struct LeftProject {
pub id: ProjectId,
pub host_user_id: UserId,
+ pub host_connection_id: ConnectionId,
pub connection_ids: Vec<ConnectionId>,
}
@@ -1041,8 +1041,11 @@ impl Server {
let project_id = ProjectId::from_proto(request.payload.project_id);
let project;
{
- let mut store = self.store().await;
- project = store.leave_project(project_id, sender_id)?;
+ project = self
+ .app_state
+ .db
+ .leave_project(project_id, sender_id)
+ .await?;
tracing::info!(
%project_id,
host_user_id = %project.host_user_id,
@@ -1050,17 +1053,15 @@ impl Server {
"leave project"
);
- if project.remove_collaborator {
- broadcast(sender_id, project.connection_ids, |conn_id| {
- self.peer.send(
- conn_id,
- proto::RemoveProjectCollaborator {
- project_id: project_id.to_proto(),
- peer_id: sender_id.0,
- },
- )
- });
- }
+ broadcast(sender_id, project.connection_ids, |conn_id| {
+ self.peer.send(
+ conn_id,
+ proto::RemoveProjectCollaborator {
+ project_id: project_id.to_proto(),
+ peer_id: sender_id.0,
+ },
+ )
+ });
}
Ok(())
@@ -251,37 +251,6 @@ impl Store {
}
}
- pub fn leave_project(
- &mut self,
- project_id: ProjectId,
- connection_id: ConnectionId,
- ) -> Result<LeftProject> {
- let project = self
- .projects
- .get_mut(&project_id)
- .ok_or_else(|| anyhow!("no such project"))?;
-
- // If the connection leaving the project is a collaborator, remove it.
- let remove_collaborator = if let Some(guest) = project.guests.remove(&connection_id) {
- project.active_replica_ids.remove(&guest.replica_id);
- true
- } else {
- false
- };
-
- if let Some(connection) = self.connections.get_mut(&connection_id) {
- connection.projects.remove(&project_id);
- }
-
- Ok(LeftProject {
- id: project.id,
- host_connection_id: project.host_connection_id,
- host_user_id: project.host.user_id,
- connection_ids: project.connection_ids(),
- remove_collaborator,
- })
- }
-
#[cfg(test)]
pub fn check_invariants(&self) {
for (connection_id, connection) in &self.connections {
@@ -24,7 +24,7 @@ use std::{
};
use tracing::instrument;
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
+#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub struct ConnectionId(pub u32);
impl fmt::Display for ConnectionId {