Start reworking join_project to use the database

This commit is contained in:
Antonio Scandurra 2022-11-15 11:44:26 +01:00
parent 6cbf197226
commit be523617c9
3 changed files with 164 additions and 34 deletions

View File

@ -62,6 +62,9 @@ CREATE TABLE "worktrees" (
"id" INTEGER NOT NULL,
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"root_name" VARCHAR NOT NULL,
"visible" BOOL NOT NULL,
"scan_id" INTEGER NOT NULL,
"is_complete" BOOL NOT NULL,
PRIMARY KEY(project_id, id)
);
CREATE INDEX "index_worktrees_on_project_id" ON "worktrees" ("project_id");

View File

@ -1,7 +1,7 @@
use crate::{Error, Result};
use anyhow::anyhow;
use axum::http::StatusCode;
use collections::HashMap;
use collections::{BTreeMap, HashMap, HashSet};
use futures::{future::BoxFuture, FutureExt, StreamExt};
use rpc::{proto, ConnectionId};
use serde::{Deserialize, Serialize};
@ -10,7 +10,11 @@ use sqlx::{
types::Uuid,
FromRow,
};
use std::{future::Future, path::Path, time::Duration};
use std::{
future::Future,
path::{Path, PathBuf},
time::Duration,
};
use time::{OffsetDateTime, PrimitiveDateTime};
#[cfg(test)]
@ -1404,13 +1408,26 @@ where
pub async fn share_project(
&self,
room_id: RoomId,
user_id: UserId,
expected_room_id: RoomId,
connection_id: ConnectionId,
worktrees: &[proto::WorktreeMetadata],
) -> Result<(ProjectId, proto::Room)> {
self.transact(|mut tx| async move {
let project_id = sqlx::query_scalar(
let (room_id, user_id) = sqlx::query_as::<_, (RoomId, UserId)>(
"
SELECT room_id, user_id
FROM room_participants
WHERE answering_connection_id = $1
",
)
.bind(connection_id.0 as i32)
.fetch_one(&mut tx)
.await?;
if room_id != expected_room_id {
return Err(anyhow!("shared project on unexpected room"))?;
}
let project_id: ProjectId = sqlx::query_scalar(
"
INSERT INTO projects (room_id, host_user_id, host_connection_id)
VALUES ($1, $2, $3)
@ -1421,8 +1438,7 @@ where
.bind(user_id)
.bind(connection_id.0 as i32)
.fetch_one(&mut tx)
.await
.map(ProjectId)?;
.await?;
for worktree in worktrees {
sqlx::query(
@ -1536,6 +1552,111 @@ where
.await
}
pub async fn join_project(
&self,
project_id: ProjectId,
connection_id: ConnectionId,
) -> Result<(Project, i32)> {
self.transact(|mut tx| async move {
let (room_id, user_id) = sqlx::query_as::<_, (RoomId, UserId)>(
"
SELECT room_id, user_id
FROM room_participants
WHERE answering_connection_id = $1
",
)
.bind(connection_id.0 as i32)
.fetch_one(&mut tx)
.await?;
// Ensure project id was shared on this room.
sqlx::query(
"
SELECT 1
FROM projects
WHERE project_id = $1 AND room_id = $2
",
)
.bind(project_id)
.bind(room_id)
.fetch_one(&mut tx)
.await?;
let replica_ids = sqlx::query_scalar::<_, i32>(
"
SELECT replica_id
FROM project_collaborators
WHERE project_id = $1
",
)
.bind(project_id)
.fetch_all(&mut tx)
.await?;
let replica_ids = HashSet::from_iter(replica_ids);
let mut replica_id = 1;
while replica_ids.contains(&replica_id) {
replica_id += 1;
}
sqlx::query(
"
INSERT INTO project_collaborators (
project_id,
connection_id,
user_id,
replica_id,
is_host
)
VALUES ($1, $2, $3, $4, $5)
",
)
.bind(project_id)
.bind(connection_id.0 as i32)
.bind(user_id)
.bind(replica_id)
.bind(false)
.execute(&mut tx)
.await?;
tx.commit().await?;
todo!()
})
.await
// sqlx::query(
// "
// SELECT replica_id
// FROM project_collaborators
// WHERE project_id = $
// ",
// )
// .bind(project_id)
// .bind(connection_id.0 as i32)
// .bind(user_id)
// .bind(0)
// .bind(true)
// .execute(&mut tx)
// .await?;
// sqlx::query(
// "
// INSERT INTO project_collaborators (
// project_id,
// connection_id,
// user_id,
// replica_id,
// is_host
// )
// VALUES ($1, $2, $3, $4, $5)
// ",
// )
// .bind(project_id)
// .bind(connection_id.0 as i32)
// .bind(user_id)
// .bind(0)
// .bind(true)
// .execute(&mut tx)
// .await?;
}
pub async fn unshare_project(&self, project_id: ProjectId) -> Result<()> {
todo!()
// test_support!(self, {
@ -1967,11 +2088,11 @@ pub struct Room {
}
id_type!(ProjectId);
#[derive(Clone, Debug, Default, FromRow, Serialize, PartialEq)]
pub struct Project {
pub id: ProjectId,
pub host_user_id: UserId,
pub unregistered: bool,
pub collaborators: Vec<ProjectCollaborator>,
pub worktrees: BTreeMap<u64, Worktree>,
pub language_servers: Vec<proto::LanguageServer>,
}
#[derive(Clone, Debug, Default, FromRow, PartialEq)]
@ -1983,6 +2104,17 @@ pub struct ProjectCollaborator {
pub is_host: bool,
}
#[derive(Default)]
pub struct Worktree {
pub abs_path: PathBuf,
pub root_name: String,
pub visible: bool,
pub entries: BTreeMap<u64, proto::Entry>,
pub diagnostic_summaries: BTreeMap<PathBuf, proto::DiagnosticSummary>,
pub scan_id: u64,
pub is_complete: bool,
}
pub struct LeftProject {
pub id: ProjectId,
pub host_user_id: UserId,

View File

@ -862,7 +862,6 @@ impl Server {
.db
.share_project(
RoomId::from_proto(request.payload.room_id),
request.sender_user_id,
request.sender_connection_id,
&request.payload.worktrees,
)
@ -942,15 +941,21 @@ impl Server {
tracing::info!(%project_id, %host_user_id, %host_connection_id, "join project");
let mut store = self.store().await;
let (project, replica_id) = store.join_project(request.sender_connection_id, project_id)?;
let peer_count = project.guests.len();
let mut collaborators = Vec::with_capacity(peer_count);
collaborators.push(proto::Collaborator {
peer_id: project.host_connection_id.0,
replica_id: 0,
user_id: project.host.user_id.to_proto(),
});
let (project, replica_id) = self
.app_state
.db
.join_project(project_id, request.sender_connection_id)
.await?;
let collaborators = project
.collaborators
.iter()
.map(|collaborator| proto::Collaborator {
peer_id: collaborator.connection_id as u32,
replica_id: collaborator.replica_id as u32,
user_id: collaborator.user_id.to_proto(),
})
.collect::<Vec<_>>();
let worktrees = project
.worktrees
.iter()
@ -962,22 +967,12 @@ impl Server {
})
.collect::<Vec<_>>();
// Add all guests other than the requesting user's own connections as collaborators
for (guest_conn_id, guest) in &project.guests {
if request.sender_connection_id != *guest_conn_id {
collaborators.push(proto::Collaborator {
peer_id: guest_conn_id.0,
replica_id: guest.replica_id as u32,
user_id: guest.user_id.to_proto(),
});
}
}
for conn_id in project.connection_ids() {
if conn_id != request.sender_connection_id {
for collaborator in &project.collaborators {
let connection_id = ConnectionId(collaborator.connection_id as u32);
if connection_id != request.sender_connection_id {
self.peer
.send(
conn_id,
connection_id,
proto::AddProjectCollaborator {
project_id: project_id.to_proto(),
collaborator: Some(proto::Collaborator {