Avoid applying outdated UpdateProject messages

Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-04-04 18:34:39 -07:00
parent bcf9b2f10d
commit 1ccf174388
3 changed files with 47 additions and 11 deletions

View file

@ -10,7 +10,10 @@ use async_tungstenite::tungstenite::{
error::Error as WebsocketError, error::Error as WebsocketError,
http::{Request, StatusCode}, http::{Request, StatusCode},
}; };
use futures::{future::LocalBoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryStreamExt}; use futures::{
future::LocalBoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryFutureExt as _,
TryStreamExt,
};
use gpui::{ use gpui::{
actions, actions,
serde_json::{self, Value}, serde_json::{self, Value},
@ -1187,6 +1190,14 @@ impl Client {
&self, &self,
request: T, request: T,
) -> impl Future<Output = Result<T::Response>> { ) -> impl Future<Output = Result<T::Response>> {
self.request_envelope(request)
.map_ok(|envelope| envelope.payload)
}
pub fn request_envelope<T: RequestMessage>(
&self,
request: T,
) -> impl Future<Output = Result<TypedEnvelope<T::Response>>> {
let client_id = self.id; let client_id = self.id;
log::debug!( log::debug!(
"rpc request start. client_id:{}. name:{}", "rpc request start. client_id:{}. name:{}",
@ -1195,7 +1206,7 @@ impl Client {
); );
let response = self let response = self
.connection_id() .connection_id()
.map(|conn_id| self.peer.request(conn_id, request)); .map(|conn_id| self.peer.request_envelope(conn_id, request));
async move { async move {
let response = response?.await; let response = response?.await;
log::debug!( log::debug!(

View file

@ -100,6 +100,7 @@ pub struct Project {
next_language_server_id: usize, next_language_server_id: usize,
client: Arc<client::Client>, client: Arc<client::Client>,
next_entry_id: Arc<AtomicUsize>, next_entry_id: Arc<AtomicUsize>,
join_project_response_message_id: u32,
next_diagnostic_group_id: usize, next_diagnostic_group_id: usize,
user_store: ModelHandle<UserStore>, user_store: ModelHandle<UserStore>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
@ -425,6 +426,7 @@ impl Project {
loading_buffers_by_path: Default::default(), loading_buffers_by_path: Default::default(),
loading_local_worktrees: Default::default(), loading_local_worktrees: Default::default(),
buffer_snapshots: Default::default(), buffer_snapshots: Default::default(),
join_project_response_message_id: 0,
client_state: None, client_state: None,
opened_buffer: watch::channel(), opened_buffer: watch::channel(),
client_subscriptions: Vec::new(), client_subscriptions: Vec::new(),
@ -463,15 +465,15 @@ impl Project {
let subscription = client.subscribe_to_entity(remote_id); let subscription = client.subscribe_to_entity(remote_id);
let response = client let response = client
.request(proto::JoinProject { .request_envelope(proto::JoinProject {
project_id: remote_id, project_id: remote_id,
}) })
.await?; .await?;
let this = cx.add_model(|cx| { let this = cx.add_model(|cx| {
let replica_id = response.replica_id as ReplicaId; let replica_id = response.payload.replica_id as ReplicaId;
let mut worktrees = Vec::new(); let mut worktrees = Vec::new();
for worktree in response.worktrees { for worktree in response.payload.worktrees {
let worktree = cx.update(|cx| { let worktree = cx.update(|cx| {
Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx) Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx)
}); });
@ -487,6 +489,7 @@ impl Project {
loading_local_worktrees: Default::default(), loading_local_worktrees: Default::default(),
active_entry: None, active_entry: None,
collaborators: Default::default(), collaborators: Default::default(),
join_project_response_message_id: response.message_id,
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx), _maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
_maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx), _maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
languages, languages,
@ -505,6 +508,7 @@ impl Project {
language_servers: Default::default(), language_servers: Default::default(),
language_server_ids: Default::default(), language_server_ids: Default::default(),
language_server_statuses: response language_server_statuses: response
.payload
.language_servers .language_servers
.into_iter() .into_iter()
.map(|server| { .map(|server| {
@ -537,6 +541,7 @@ impl Project {
let subscription = subscription.set_model(&this, &mut cx); let subscription = subscription.set_model(&this, &mut cx);
let user_ids = response let user_ids = response
.payload
.collaborators .collaborators
.iter() .iter()
.map(|peer| peer.user_id) .map(|peer| peer.user_id)
@ -546,7 +551,7 @@ impl Project {
.await?; .await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.set_collaborators_from_proto(response.collaborators, cx)?; this.set_collaborators_from_proto(response.payload.collaborators, cx)?;
this.client_subscriptions.push(subscription); this.client_subscriptions.push(subscription);
anyhow::Ok(()) anyhow::Ok(())
})?; })?;
@ -4930,7 +4935,10 @@ impl Project {
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.set_worktrees_from_proto(envelope.payload.worktrees, cx)?; // Don't handle messages that were sent before the response to us joining the project
if envelope.message_id > this.join_project_response_message_id {
this.set_worktrees_from_proto(envelope.payload.worktrees, cx)?;
}
Ok(()) Ok(())
}) })
} }

View file

@ -7,7 +7,7 @@ use collections::HashMap;
use futures::{ use futures::{
channel::{mpsc, oneshot}, channel::{mpsc, oneshot},
stream::BoxStream, stream::BoxStream,
FutureExt, SinkExt, StreamExt, FutureExt, SinkExt, StreamExt, TryFutureExt,
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use serde::{ser::SerializeStruct, Serialize}; use serde::{ser::SerializeStruct, Serialize};
@ -71,6 +71,7 @@ impl<T> Clone for Receipt<T> {
impl<T> Copy for Receipt<T> {} impl<T> Copy for Receipt<T> {}
#[derive(Clone, Debug)]
pub struct TypedEnvelope<T> { pub struct TypedEnvelope<T> {
pub sender_id: ConnectionId, pub sender_id: ConnectionId,
pub original_sender_id: Option<PeerId>, pub original_sender_id: Option<PeerId>,
@ -370,6 +371,15 @@ impl Peer {
receiver_id: ConnectionId, receiver_id: ConnectionId,
request: T, request: T,
) -> impl Future<Output = Result<T::Response>> { ) -> impl Future<Output = Result<T::Response>> {
self.request_internal(None, receiver_id, request)
.map_ok(|envelope| envelope.payload)
}
pub fn request_envelope<T: RequestMessage>(
&self,
receiver_id: ConnectionId,
request: T,
) -> impl Future<Output = Result<TypedEnvelope<T::Response>>> {
self.request_internal(None, receiver_id, request) self.request_internal(None, receiver_id, request)
} }
@ -380,6 +390,7 @@ impl Peer {
request: T, request: T,
) -> impl Future<Output = Result<T::Response>> { ) -> impl Future<Output = Result<T::Response>> {
self.request_internal(Some(sender_id), receiver_id, request) self.request_internal(Some(sender_id), receiver_id, request)
.map_ok(|envelope| envelope.payload)
} }
pub fn request_internal<T: RequestMessage>( pub fn request_internal<T: RequestMessage>(
@ -387,7 +398,7 @@ impl Peer {
original_sender_id: Option<ConnectionId>, original_sender_id: Option<ConnectionId>,
receiver_id: ConnectionId, receiver_id: ConnectionId,
request: T, request: T,
) -> impl Future<Output = Result<T::Response>> { ) -> impl Future<Output = Result<TypedEnvelope<T::Response>>> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let send = self.connection_state(receiver_id).and_then(|connection| { let send = self.connection_state(receiver_id).and_then(|connection| {
let message_id = connection.next_message_id.fetch_add(1, SeqCst); let message_id = connection.next_message_id.fetch_add(1, SeqCst);
@ -410,6 +421,7 @@ impl Peer {
async move { async move {
send?; send?;
let (response, _barrier) = rx.await.map_err(|_| anyhow!("connection was closed"))?; let (response, _barrier) = rx.await.map_err(|_| anyhow!("connection was closed"))?;
if let Some(proto::envelope::Payload::Error(error)) = &response.payload { if let Some(proto::envelope::Payload::Error(error)) = &response.payload {
Err(anyhow!( Err(anyhow!(
"RPC request {} failed - {}", "RPC request {} failed - {}",
@ -417,8 +429,13 @@ impl Peer {
error.message error.message
)) ))
} else { } else {
T::Response::from_envelope(response) Ok(TypedEnvelope {
.ok_or_else(|| anyhow!("received response of the wrong type")) message_id: response.id,
sender_id: receiver_id,
original_sender_id: response.original_sender_id,
payload: T::Response::from_envelope(response)
.ok_or_else(|| anyhow!("received response of the wrong type"))?,
})
} }
} }
} }