Correctly leave projects when leaving room

This commit is contained in:
Antonio Scandurra 2022-11-16 10:36:48 +01:00
parent 3190236396
commit c151c87e12
2 changed files with 107 additions and 73 deletions

View file

@ -1171,44 +1171,68 @@ where
.fetch_all(&mut tx) .fetch_all(&mut tx)
.await?; .await?;
let mut project_collaborators = sqlx::query_as::<_, ProjectCollaborator>( let project_ids = sqlx::query_scalar::<_, ProjectId>(
" "
SELECT project_collaborators.* SELECT project_id
FROM projects, project_collaborators FROM project_collaborators
WHERE WHERE connection_id = $1
projects.room_id = $1 AND
projects.id = project_collaborators.project_id AND
project_collaborators.connection_id = $2
", ",
) )
.bind(room_id)
.bind(connection_id.0 as i32) .bind(connection_id.0 as i32)
.fetch(&mut tx); .fetch_all(&mut tx)
.await?;
// Leave projects.
let mut left_projects = HashMap::default(); let mut left_projects = HashMap::default();
while let Some(collaborator) = project_collaborators.next().await { if !project_ids.is_empty() {
let collaborator = collaborator?; let mut params = "?,".repeat(project_ids.len());
let left_project = params.pop();
left_projects let query = format!(
.entry(collaborator.project_id) "
.or_insert(LeftProject { SELECT *
id: collaborator.project_id, FROM project_collaborators
host_user_id: Default::default(), WHERE project_id IN ({params})
connection_ids: Default::default(), "
}); );
let mut query = sqlx::query_as::<_, ProjectCollaborator>(&query);
let collaborator_connection_id = for project_id in project_ids {
ConnectionId(collaborator.connection_id as u32); query = query.bind(project_id);
if collaborator_connection_id != connection_id || collaborator.is_host {
left_project.connection_ids.push(collaborator_connection_id);
} }
if collaborator.is_host { let mut project_collaborators = query.fetch(&mut tx);
left_project.host_user_id = collaborator.user_id; while let Some(collaborator) = project_collaborators.next().await {
let collaborator = collaborator?;
let left_project =
left_projects
.entry(collaborator.project_id)
.or_insert(LeftProject {
id: collaborator.project_id,
host_user_id: Default::default(),
connection_ids: Default::default(),
});
let collaborator_connection_id =
ConnectionId(collaborator.connection_id as u32);
if collaborator_connection_id != connection_id {
left_project.connection_ids.push(collaborator_connection_id);
}
if collaborator.is_host {
left_project.host_user_id = collaborator.user_id;
}
} }
} }
drop(project_collaborators); sqlx::query(
"
DELETE FROM project_collaborators
WHERE connection_id = $1
",
)
.bind(connection_id.0 as i32)
.execute(&mut tx)
.await?;
// Unshare projects.
sqlx::query( sqlx::query(
" "
DELETE FROM projects DELETE FROM projects
@ -1265,15 +1289,16 @@ where
sqlx::query( sqlx::query(
" "
UPDATE room_participants UPDATE room_participants
SET location_kind = $1 AND location_project_id = $2 SET location_kind = $1, location_project_id = $2
WHERE room_id = $3 AND answering_connection_id = $4 WHERE room_id = $3 AND answering_connection_id = $4
RETURNING 1
", ",
) )
.bind(location_kind) .bind(location_kind)
.bind(location_project_id) .bind(location_project_id)
.bind(room_id) .bind(room_id)
.bind(connection_id.0 as i32) .bind(connection_id.0 as i32)
.execute(&mut tx) .fetch_one(&mut tx)
.await?; .await?;
self.commit_room_transaction(room_id, tx).await self.commit_room_transaction(room_id, tx).await
@ -1335,21 +1360,32 @@ where
let ( let (
user_id, user_id,
answering_connection_id, answering_connection_id,
_location_kind, location_kind,
_location_project_id, location_project_id,
calling_user_id, calling_user_id,
initial_project_id, initial_project_id,
) = participant?; ) = participant?;
if let Some(answering_connection_id) = answering_connection_id { if let Some(answering_connection_id) = answering_connection_id {
let location = match (location_kind, location_project_id) {
(Some(0), Some(project_id)) => {
Some(proto::participant_location::Variant::SharedProject(
proto::participant_location::SharedProject {
id: project_id.to_proto(),
},
))
}
(Some(1), _) => Some(proto::participant_location::Variant::UnsharedProject(
Default::default(),
)),
_ => Some(proto::participant_location::Variant::External(
Default::default(),
)),
};
participants.push(proto::Participant { participants.push(proto::Participant {
user_id: user_id.to_proto(), user_id: user_id.to_proto(),
peer_id: answering_connection_id as u32, peer_id: answering_connection_id as u32,
projects: Default::default(), projects: Default::default(),
location: Some(proto::ParticipantLocation { location: Some(proto::ParticipantLocation { variant: location }),
variant: Some(proto::participant_location::Variant::External(
Default::default(),
)),
}),
}); });
} else { } else {
pending_participants.push(proto::PendingParticipant { pending_participants.push(proto::PendingParticipant {

View file

@ -624,19 +624,19 @@ impl Server {
async fn leave_room_for_connection( async fn leave_room_for_connection(
self: &Arc<Server>, self: &Arc<Server>,
connection_id: ConnectionId, leaving_connection_id: ConnectionId,
user_id: UserId, leaving_user_id: UserId,
) -> Result<()> { ) -> Result<()> {
let mut contacts_to_update = HashSet::default(); let mut contacts_to_update = HashSet::default();
let Some(left_room) = self.app_state.db.leave_room_for_connection(connection_id).await? else { let Some(left_room) = self.app_state.db.leave_room_for_connection(leaving_connection_id).await? else {
return Err(anyhow!("no room to leave"))?; return Err(anyhow!("no room to leave"))?;
}; };
contacts_to_update.insert(user_id); contacts_to_update.insert(leaving_user_id);
for project in left_room.left_projects.into_values() { for project in left_room.left_projects.into_values() {
if project.host_user_id == user_id { for connection_id in project.connection_ids {
for connection_id in project.connection_ids { if project.host_user_id == leaving_user_id {
self.peer self.peer
.send( .send(
connection_id, connection_id,
@ -645,29 +645,27 @@ impl Server {
}, },
) )
.trace_err(); .trace_err();
} } else {
} else {
for connection_id in project.connection_ids {
self.peer self.peer
.send( .send(
connection_id, connection_id,
proto::RemoveProjectCollaborator { proto::RemoveProjectCollaborator {
project_id: project.id.to_proto(), project_id: project.id.to_proto(),
peer_id: connection_id.0, peer_id: leaving_connection_id.0,
}, },
) )
.trace_err(); .trace_err();
} }
self.peer
.send(
connection_id,
proto::UnshareProject {
project_id: project.id.to_proto(),
},
)
.trace_err();
} }
self.peer
.send(
leaving_connection_id,
proto::UnshareProject {
project_id: project.id.to_proto(),
},
)
.trace_err();
} }
self.room_updated(&left_room.room); self.room_updated(&left_room.room);
@ -691,7 +689,7 @@ impl Server {
live_kit live_kit
.remove_participant( .remove_participant(
left_room.room.live_kit_room.clone(), left_room.room.live_kit_room.clone(),
connection_id.to_string(), leaving_connection_id.to_string(),
) )
.await .await
.trace_err(); .trace_err();
@ -941,6 +939,9 @@ impl Server {
let collaborators = project let collaborators = project
.collaborators .collaborators
.iter() .iter()
.filter(|collaborator| {
collaborator.connection_id != request.sender_connection_id.0 as i32
})
.map(|collaborator| proto::Collaborator { .map(|collaborator| proto::Collaborator {
peer_id: collaborator.connection_id as u32, peer_id: collaborator.connection_id as u32,
replica_id: collaborator.replica_id.0 as u32, replica_id: collaborator.replica_id.0 as u32,
@ -958,23 +959,20 @@ impl Server {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for collaborator in &project.collaborators { for collaborator in &collaborators {
let connection_id = ConnectionId(collaborator.connection_id as u32); self.peer
if connection_id != request.sender_connection_id { .send(
self.peer ConnectionId(collaborator.peer_id),
.send( proto::AddProjectCollaborator {
connection_id, project_id: project_id.to_proto(),
proto::AddProjectCollaborator { collaborator: Some(proto::Collaborator {
project_id: project_id.to_proto(), peer_id: request.sender_connection_id.0,
collaborator: Some(proto::Collaborator { replica_id: replica_id.0 as u32,
peer_id: request.sender_connection_id.0, user_id: guest_user_id.to_proto(),
replica_id: replica_id.0 as u32, }),
user_id: guest_user_id.to_proto(), },
}), )
}, .trace_err();
)
.trace_err();
}
} }
// First, we send the metadata associated with each worktree. // First, we send the metadata associated with each worktree.