Ensure client always responds when receiving a request
This commit is contained in:
parent
a41eb5a663
commit
a19735c05f
4 changed files with 519 additions and 557 deletions
|
@ -398,29 +398,23 @@ impl Channel {
|
||||||
cursor
|
cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_message_sent(
|
async fn handle_message_sent(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
message: TypedEnvelope<proto::ChannelMessageSent>,
|
message: TypedEnvelope<proto::ChannelMessageSent>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let user_store = self.user_store.clone();
|
let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
|
||||||
let message = message
|
let message = message
|
||||||
.payload
|
.payload
|
||||||
.message
|
.message
|
||||||
.ok_or_else(|| anyhow!("empty message"))?;
|
.ok_or_else(|| anyhow!("empty message"))?;
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| {
|
|
||||||
async move {
|
|
||||||
let message = ChannelMessage::from_proto(message, &user_store, &mut cx).await?;
|
let message = ChannelMessage::from_proto(message, &user_store, &mut cx).await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.insert_messages(SumTree::from_item(message, &()), cx)
|
this.insert_messages(SumTree::from_item(message, &()), cx)
|
||||||
});
|
});
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
.log_err()
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ use async_tungstenite::tungstenite::{
|
||||||
error::Error as WebsocketError,
|
error::Error as WebsocketError,
|
||||||
http::{Request, StatusCode},
|
http::{Request, StatusCode},
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::{future::LocalBoxFuture, FutureExt, StreamExt};
|
||||||
use gpui::{action, AsyncAppContext, Entity, ModelContext, MutableAppContext, Task};
|
use gpui::{action, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
||||||
use http::HttpClient;
|
use http::HttpClient;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
@ -20,10 +20,11 @@ use postage::watch;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage};
|
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage};
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::{type_name, TypeId},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
fmt::Write as _,
|
fmt::Write as _,
|
||||||
|
future::Future,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicUsize, Ordering},
|
||||||
Arc, Weak,
|
Arc, Weak,
|
||||||
|
@ -123,14 +124,17 @@ pub enum Status {
|
||||||
ReconnectionError { next_reconnection: Instant },
|
ReconnectionError { next_reconnection: Instant },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ModelHandler = Box<
|
||||||
|
dyn Send
|
||||||
|
+ Sync
|
||||||
|
+ FnMut(Box<dyn AnyTypedEnvelope>, &AsyncAppContext) -> LocalBoxFuture<'static, Result<()>>,
|
||||||
|
>;
|
||||||
|
|
||||||
struct ClientState {
|
struct ClientState {
|
||||||
credentials: Option<Credentials>,
|
credentials: Option<Credentials>,
|
||||||
status: (watch::Sender<Status>, watch::Receiver<Status>),
|
status: (watch::Sender<Status>, watch::Receiver<Status>),
|
||||||
entity_id_extractors: HashMap<TypeId, Box<dyn Send + Sync + Fn(&dyn AnyTypedEnvelope) -> u64>>,
|
entity_id_extractors: HashMap<TypeId, Box<dyn Send + Sync + Fn(&dyn AnyTypedEnvelope) -> u64>>,
|
||||||
model_handlers: HashMap<
|
model_handlers: HashMap<(TypeId, Option<u64>), Option<ModelHandler>>,
|
||||||
(TypeId, Option<u64>),
|
|
||||||
Option<Box<dyn Send + Sync + FnMut(Box<dyn AnyTypedEnvelope>, &mut AsyncAppContext)>>,
|
|
||||||
>,
|
|
||||||
_maintain_connection: Option<Task<()>>,
|
_maintain_connection: Option<Task<()>>,
|
||||||
heartbeat_interval: Duration,
|
heartbeat_interval: Duration,
|
||||||
}
|
}
|
||||||
|
@ -262,7 +266,7 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe<T, M, F>(
|
pub fn subscribe<T, M, F, Fut>(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
cx: &mut ModelContext<M>,
|
cx: &mut ModelContext<M>,
|
||||||
mut handler: F,
|
mut handler: F,
|
||||||
|
@ -273,7 +277,8 @@ impl Client {
|
||||||
F: 'static
|
F: 'static
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ FnMut(&mut M, TypedEnvelope<T>, Arc<Self>, &mut ModelContext<M>) -> Result<()>,
|
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
|
||||||
|
Fut: 'static + Future<Output = Result<()>>,
|
||||||
{
|
{
|
||||||
let subscription_id = (TypeId::of::<T>(), None);
|
let subscription_id = (TypeId::of::<T>(), None);
|
||||||
let client = self.clone();
|
let client = self.clone();
|
||||||
|
@ -284,11 +289,15 @@ impl Client {
|
||||||
Some(Box::new(move |envelope, cx| {
|
Some(Box::new(move |envelope, cx| {
|
||||||
if let Some(model) = model.upgrade(cx) {
|
if let Some(model) = model.upgrade(cx) {
|
||||||
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
|
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
|
||||||
model.update(cx, |model, cx| {
|
handler(model, *envelope, client.clone(), cx.clone()).boxed_local()
|
||||||
if let Err(error) = handler(model, *envelope, client.clone(), cx) {
|
} else {
|
||||||
log::error!("error handling message: {}", error)
|
async move {
|
||||||
|
Err(anyhow!(
|
||||||
|
"received message for {:?} but model was dropped",
|
||||||
|
type_name::<M>()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
});
|
.boxed_local()
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
@ -302,7 +311,7 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_to_entity<T, M, F>(
|
pub fn subscribe_to_entity<T, M, F, Fut>(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
remote_id: u64,
|
remote_id: u64,
|
||||||
cx: &mut ModelContext<M>,
|
cx: &mut ModelContext<M>,
|
||||||
|
@ -314,7 +323,8 @@ impl Client {
|
||||||
F: 'static
|
F: 'static
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ FnMut(&mut M, TypedEnvelope<T>, Arc<Self>, &mut ModelContext<M>) -> Result<()>,
|
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
|
||||||
|
Fut: 'static + Future<Output = Result<()>>,
|
||||||
{
|
{
|
||||||
let subscription_id = (TypeId::of::<T>(), Some(remote_id));
|
let subscription_id = (TypeId::of::<T>(), Some(remote_id));
|
||||||
let client = self.clone();
|
let client = self.clone();
|
||||||
|
@ -337,11 +347,15 @@ impl Client {
|
||||||
Some(Box::new(move |envelope, cx| {
|
Some(Box::new(move |envelope, cx| {
|
||||||
if let Some(model) = model.upgrade(cx) {
|
if let Some(model) = model.upgrade(cx) {
|
||||||
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
|
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
|
||||||
model.update(cx, |model, cx| {
|
handler(model, *envelope, client.clone(), cx.clone()).boxed_local()
|
||||||
if let Err(error) = handler(model, *envelope, client.clone(), cx) {
|
} else {
|
||||||
log::error!("error handling message: {}", error)
|
async move {
|
||||||
|
Err(anyhow!(
|
||||||
|
"received message for {:?} but model was dropped",
|
||||||
|
type_name::<M>()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
});
|
.boxed_local()
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
@ -355,6 +369,44 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe_to_entity_request<T, M, F, Fut>(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
remote_id: u64,
|
||||||
|
cx: &mut ModelContext<M>,
|
||||||
|
mut handler: F,
|
||||||
|
) -> Subscription
|
||||||
|
where
|
||||||
|
T: EntityMessage + RequestMessage,
|
||||||
|
M: Entity,
|
||||||
|
F: 'static
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
|
||||||
|
Fut: 'static + Future<Output = Result<T::Response>>,
|
||||||
|
{
|
||||||
|
self.subscribe_to_entity(remote_id, cx, move |model, envelope, client, cx| {
|
||||||
|
let receipt = envelope.receipt();
|
||||||
|
let response = handler(model, envelope, client.clone(), cx);
|
||||||
|
async move {
|
||||||
|
match response.await {
|
||||||
|
Ok(response) => {
|
||||||
|
client.respond(receipt, response)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
client.respond_with_error(
|
||||||
|
receipt,
|
||||||
|
proto::Error {
|
||||||
|
message: error.to_string(),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_keychain_credentials(&self, cx: &AsyncAppContext) -> bool {
|
pub fn has_keychain_credentials(&self, cx: &AsyncAppContext) -> bool {
|
||||||
read_credentials_from_keychain(cx).is_some()
|
read_credentials_from_keychain(cx).is_some()
|
||||||
}
|
}
|
||||||
|
@ -442,7 +494,7 @@ impl Client {
|
||||||
let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn).await;
|
let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn).await;
|
||||||
cx.foreground()
|
cx.foreground()
|
||||||
.spawn({
|
.spawn({
|
||||||
let mut cx = cx.clone();
|
let cx = cx.clone();
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
async move {
|
async move {
|
||||||
while let Some(message) = incoming.next().await {
|
while let Some(message) = incoming.next().await {
|
||||||
|
@ -468,12 +520,28 @@ impl Client {
|
||||||
this.id,
|
this.id,
|
||||||
type_name
|
type_name
|
||||||
);
|
);
|
||||||
(handler)(message, &mut cx);
|
|
||||||
|
let future = (handler)(message, &cx);
|
||||||
|
let client_id = this.id;
|
||||||
|
cx.foreground()
|
||||||
|
.spawn(async move {
|
||||||
|
match future.await {
|
||||||
|
Ok(()) => {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"rpc message handled. client_id:{}, name:{}",
|
"rpc message handled. client_id:{}, name:{}",
|
||||||
this.id,
|
client_id,
|
||||||
type_name
|
type_name
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
log::error!(
|
||||||
|
"error handling rpc message. client_id:{}, name:{}, error: {}",
|
||||||
|
client_id, type_name, error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
let mut state = this.state.write();
|
let mut state = this.state.write();
|
||||||
if state.model_handlers.contains_key(&handler_key) {
|
if state.model_handlers.contains_key(&handler_key) {
|
||||||
|
@ -715,16 +783,12 @@ impl Client {
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn respond<T: RequestMessage>(
|
fn respond<T: RequestMessage>(&self, receipt: Receipt<T>, response: T::Response) -> Result<()> {
|
||||||
&self,
|
|
||||||
receipt: Receipt<T>,
|
|
||||||
response: T::Response,
|
|
||||||
) -> Result<()> {
|
|
||||||
log::debug!("rpc respond. client_id: {}. name:{}", self.id, T::NAME);
|
log::debug!("rpc respond. client_id: {}. name:{}", self.id, T::NAME);
|
||||||
self.peer.respond(receipt, response)
|
self.peer.respond(receipt, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn respond_with_error<T: RequestMessage>(
|
fn respond_with_error<T: RequestMessage>(
|
||||||
&self,
|
&self,
|
||||||
receipt: Receipt<T>,
|
receipt: Receipt<T>,
|
||||||
error: proto::Error,
|
error: proto::Error,
|
||||||
|
@ -866,7 +930,7 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
||||||
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
||||||
Ok(())
|
async { Ok(()) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -876,7 +940,7 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
||||||
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
||||||
Ok(())
|
async { Ok(()) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -887,7 +951,7 @@ mod tests {
|
||||||
client.subscribe_to_entity(
|
client.subscribe_to_entity(
|
||||||
3,
|
3,
|
||||||
cx,
|
cx,
|
||||||
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| Ok(()),
|
|_, _: TypedEnvelope<proto::UnshareProject>, _, _| async { Ok(()) },
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
drop(subscription3);
|
drop(subscription3);
|
||||||
|
@ -912,14 +976,14 @@ mod tests {
|
||||||
let subscription1 = model.update(&mut cx, |_, cx| {
|
let subscription1 = model.update(&mut cx, |_, cx| {
|
||||||
client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
||||||
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
||||||
Ok(())
|
async { Ok(()) }
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
drop(subscription1);
|
drop(subscription1);
|
||||||
let _subscription2 = model.update(&mut cx, |_, cx| {
|
let _subscription2 = model.update(&mut cx, |_, cx| {
|
||||||
client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
||||||
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
||||||
Ok(())
|
async { Ok(()) }
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
server.send(proto::Ping {});
|
server.send(proto::Ping {});
|
||||||
|
@ -939,10 +1003,10 @@ mod tests {
|
||||||
model.update(&mut cx, |model, cx| {
|
model.update(&mut cx, |model, cx| {
|
||||||
model.subscription = Some(client.subscribe(
|
model.subscription = Some(client.subscribe(
|
||||||
cx,
|
cx,
|
||||||
move |model, _: TypedEnvelope<proto::Ping>, _, _| {
|
move |model, _: TypedEnvelope<proto::Ping>, _, mut cx| {
|
||||||
model.subscription.take();
|
model.update(&mut cx, |model, _| model.subscription.take());
|
||||||
postage::sink::Sink::try_send(&mut done_tx, ()).unwrap();
|
postage::sink::Sink::try_send(&mut done_tx, ()).unwrap();
|
||||||
Ok(())
|
async { Ok(()) }
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,9 +60,9 @@ impl UserStore {
|
||||||
watch::channel::<Option<proto::UpdateContacts>>();
|
watch::channel::<Option<proto::UpdateContacts>>();
|
||||||
let update_contacts_subscription = client.subscribe(
|
let update_contacts_subscription = client.subscribe(
|
||||||
cx,
|
cx,
|
||||||
move |_: &mut Self, msg: TypedEnvelope<proto::UpdateContacts>, _, _| {
|
move |_: ModelHandle<Self>, msg: TypedEnvelope<proto::UpdateContacts>, _, _| {
|
||||||
let _ = update_contacts_tx.blocking_send(Some(msg.payload));
|
*update_contacts_tx.borrow_mut() = Some(msg.payload);
|
||||||
Ok(())
|
async move { Ok(()) }
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -340,24 +340,24 @@ impl Project {
|
||||||
if let Some(remote_id) = remote_id {
|
if let Some(remote_id) = remote_id {
|
||||||
let client = &self.client;
|
let client = &self.client;
|
||||||
self.subscriptions.extend([
|
self.subscriptions.extend([
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_open_buffer),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_open_buffer),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_close_buffer),
|
client.subscribe_to_entity(remote_id, cx, Self::handle_close_buffer),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_add_collaborator),
|
client.subscribe_to_entity(remote_id, cx, Self::handle_add_collaborator),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_remove_collaborator),
|
client.subscribe_to_entity(remote_id, cx, Self::handle_remove_collaborator),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_update_worktree),
|
client.subscribe_to_entity(remote_id, cx, Self::handle_update_worktree),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer),
|
client.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_save_buffer),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_save_buffer),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_buffer_saved),
|
client.subscribe_to_entity(remote_id, cx, Self::handle_buffer_saved),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_format_buffers),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_format_buffers),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_get_completions),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_get_completions),
|
||||||
client.subscribe_to_entity(
|
client.subscribe_to_entity_request(
|
||||||
remote_id,
|
remote_id,
|
||||||
cx,
|
cx,
|
||||||
Self::handle_apply_additional_edits_for_completion,
|
Self::handle_apply_additional_edits_for_completion,
|
||||||
),
|
),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_get_code_actions),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_get_code_actions),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_apply_code_action),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_apply_code_action),
|
||||||
client.subscribe_to_entity(remote_id, cx, Self::handle_get_definition),
|
client.subscribe_to_entity_request(remote_id, cx, Self::handle_get_definition),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1996,132 +1996,137 @@ impl Project {
|
||||||
|
|
||||||
// RPC message handlers
|
// RPC message handlers
|
||||||
|
|
||||||
fn handle_unshare_project(
|
async fn handle_unshare_project(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
_: TypedEnvelope<proto::UnshareProject>,
|
_: TypedEnvelope<proto::UnshareProject>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
if let ProjectClientState::Remote {
|
if let ProjectClientState::Remote {
|
||||||
sharing_has_stopped,
|
sharing_has_stopped,
|
||||||
..
|
..
|
||||||
} = &mut self.client_state
|
} = &mut this.client_state
|
||||||
{
|
{
|
||||||
*sharing_has_stopped = true;
|
*sharing_has_stopped = true;
|
||||||
self.collaborators.clear();
|
this.collaborators.clear();
|
||||||
cx.notify();
|
cx.notify();
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_add_collaborator(
|
async fn handle_add_collaborator(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
|
mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let user_store = self.user_store.clone();
|
let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
|
||||||
let collaborator = envelope
|
let collaborator = envelope
|
||||||
.payload
|
.payload
|
||||||
.collaborator
|
.collaborator
|
||||||
.take()
|
.take()
|
||||||
.ok_or_else(|| anyhow!("empty collaborator"))?;
|
.ok_or_else(|| anyhow!("empty collaborator"))?;
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| {
|
let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
|
||||||
async move {
|
|
||||||
let collaborator =
|
|
||||||
Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.collaborators
|
this.collaborators
|
||||||
.insert(collaborator.peer_id, collaborator);
|
.insert(collaborator.peer_id, collaborator);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
.log_err()
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_remove_collaborator(
|
async fn handle_remove_collaborator(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
|
envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let peer_id = PeerId(envelope.payload.peer_id);
|
let peer_id = PeerId(envelope.payload.peer_id);
|
||||||
let replica_id = self
|
let replica_id = this
|
||||||
.collaborators
|
.collaborators
|
||||||
.remove(&peer_id)
|
.remove(&peer_id)
|
||||||
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
|
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
|
||||||
.replica_id;
|
.replica_id;
|
||||||
self.shared_buffers.remove(&peer_id);
|
this.shared_buffers.remove(&peer_id);
|
||||||
for (_, buffer) in &self.open_buffers {
|
for (_, buffer) in &this.open_buffers {
|
||||||
if let Some(buffer) = buffer.upgrade(cx) {
|
if let Some(buffer) = buffer.upgrade(cx) {
|
||||||
buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
|
buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_share_worktree(
|
async fn handle_share_worktree(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::ShareWorktree>,
|
envelope: TypedEnvelope<proto::ShareWorktree>,
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let remote_id = self.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
|
this.update(&mut cx, |this, cx| {
|
||||||
let replica_id = self.replica_id();
|
let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
|
||||||
|
let replica_id = this.replica_id();
|
||||||
let worktree = envelope
|
let worktree = envelope
|
||||||
.payload
|
.payload
|
||||||
.worktree
|
.worktree
|
||||||
.ok_or_else(|| anyhow!("invalid worktree"))?;
|
.ok_or_else(|| anyhow!("invalid worktree"))?;
|
||||||
let (worktree, load_task) = Worktree::remote(remote_id, replica_id, worktree, client, cx);
|
let (worktree, load_task) =
|
||||||
self.add_worktree(&worktree, cx);
|
Worktree::remote(remote_id, replica_id, worktree, client, cx);
|
||||||
|
this.add_worktree(&worktree, cx);
|
||||||
load_task.detach();
|
load_task.detach();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_unregister_worktree(
|
async fn handle_unregister_worktree(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::UnregisterWorktree>,
|
envelope: TypedEnvelope<proto::UnregisterWorktree>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
||||||
self.remove_worktree(worktree_id, cx);
|
this.remove_worktree(worktree_id, cx);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_update_worktree(
|
async fn handle_update_worktree(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::UpdateWorktree>,
|
envelope: TypedEnvelope<proto::UpdateWorktree>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
||||||
if let Some(worktree) = self.worktree_for_id(worktree_id, cx) {
|
if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
|
||||||
worktree.update(cx, |worktree, cx| {
|
worktree.update(cx, |worktree, cx| {
|
||||||
let worktree = worktree.as_remote_mut().unwrap();
|
let worktree = worktree.as_remote_mut().unwrap();
|
||||||
worktree.update_from_remote(envelope, cx)
|
worktree.update_from_remote(envelope, cx)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_update_diagnostic_summary(
|
async fn handle_update_diagnostic_summary(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
|
envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
||||||
if let Some(worktree) = self.worktree_for_id(worktree_id, cx) {
|
if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
|
||||||
if let Some(summary) = envelope.payload.summary {
|
if let Some(summary) = envelope.payload.summary {
|
||||||
let project_path = ProjectPath {
|
let project_path = ProjectPath {
|
||||||
worktree_id,
|
worktree_id,
|
||||||
|
@ -2137,34 +2142,36 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_disk_based_diagnostics_updating(
|
async fn handle_disk_based_diagnostics_updating(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
_: TypedEnvelope<proto::DiskBasedDiagnosticsUpdating>,
|
_: TypedEnvelope<proto::DiskBasedDiagnosticsUpdating>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.disk_based_diagnostics_started(cx);
|
this.update(&mut cx, |this, cx| this.disk_based_diagnostics_started(cx));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_disk_based_diagnostics_updated(
|
async fn handle_disk_based_diagnostics_updated(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
_: TypedEnvelope<proto::DiskBasedDiagnosticsUpdated>,
|
_: TypedEnvelope<proto::DiskBasedDiagnosticsUpdated>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.disk_based_diagnostics_finished(cx);
|
this.update(&mut cx, |this, cx| this.disk_based_diagnostics_finished(cx));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_update_buffer(
|
async fn handle_update_buffer(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::UpdateBuffer>,
|
envelope: TypedEnvelope<proto::UpdateBuffer>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let payload = envelope.payload.clone();
|
let payload = envelope.payload.clone();
|
||||||
let buffer_id = payload.buffer_id as usize;
|
let buffer_id = payload.buffer_id as usize;
|
||||||
let ops = payload
|
let ops = payload
|
||||||
|
@ -2172,28 +2179,30 @@ impl Project {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|op| language::proto::deserialize_operation(op))
|
.map(|op| language::proto::deserialize_operation(op))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
if let Some(buffer) = self.open_buffers.get_mut(&buffer_id) {
|
if let Some(buffer) = this.open_buffers.get_mut(&buffer_id) {
|
||||||
if let Some(buffer) = buffer.upgrade(cx) {
|
if let Some(buffer) = buffer.upgrade(cx) {
|
||||||
buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
|
buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_update_buffer_file(
|
async fn handle_update_buffer_file(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::UpdateBufferFile>,
|
envelope: TypedEnvelope<proto::UpdateBufferFile>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let payload = envelope.payload.clone();
|
let payload = envelope.payload.clone();
|
||||||
let buffer_id = payload.buffer_id as usize;
|
let buffer_id = payload.buffer_id as usize;
|
||||||
let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
|
let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
|
||||||
let worktree = self
|
let worktree = this
|
||||||
.worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
|
.worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
|
||||||
.ok_or_else(|| anyhow!("no such worktree"))?;
|
.ok_or_else(|| anyhow!("no such worktree"))?;
|
||||||
let file = File::from_proto(file, worktree.clone(), cx)?;
|
let file = File::from_proto(file, worktree.clone(), cx)?;
|
||||||
let buffer = self
|
let buffer = this
|
||||||
.open_buffers
|
.open_buffers
|
||||||
.get_mut(&buffer_id)
|
.get_mut(&buffer_id)
|
||||||
.and_then(|b| b.upgrade(cx))
|
.and_then(|b| b.upgrade(cx))
|
||||||
|
@ -2201,165 +2210,109 @@ impl Project {
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.file_updated(Box::new(file), cx).detach();
|
buffer.file_updated(Box::new(file), cx).detach();
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_save_buffer(
|
async fn handle_save_buffer(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::SaveBuffer>,
|
envelope: TypedEnvelope<proto::SaveBuffer>,
|
||||||
rpc: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<proto::BufferSaved> {
|
||||||
|
let buffer_id = envelope.payload.buffer_id;
|
||||||
let sender_id = envelope.original_sender_id()?;
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let project_id = self.remote_id().ok_or_else(|| anyhow!("not connected"))?;
|
let (project_id, save) = this.update(&mut cx, |this, cx| {
|
||||||
let buffer = self
|
let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
|
||||||
|
let buffer = this
|
||||||
.shared_buffers
|
.shared_buffers
|
||||||
.get(&sender_id)
|
.get(&sender_id)
|
||||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
.and_then(|shared_buffers| shared_buffers.get(&buffer_id).cloned())
|
||||||
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
|
||||||
let receipt = envelope.receipt();
|
Ok::<_, anyhow::Error>((project_id, buffer.update(cx, |buffer, cx| buffer.save(cx))))
|
||||||
let buffer_id = envelope.payload.buffer_id;
|
})?;
|
||||||
let save = cx.spawn(|_, mut cx| async move {
|
|
||||||
buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await
|
|
||||||
});
|
|
||||||
|
|
||||||
cx.background()
|
|
||||||
.spawn(
|
|
||||||
async move {
|
|
||||||
let (version, mtime) = save.await?;
|
let (version, mtime) = save.await?;
|
||||||
|
Ok(proto::BufferSaved {
|
||||||
rpc.respond(
|
|
||||||
receipt,
|
|
||||||
proto::BufferSaved {
|
|
||||||
project_id,
|
project_id,
|
||||||
buffer_id,
|
buffer_id,
|
||||||
version: (&version).into(),
|
version: (&version).into(),
|
||||||
mtime: Some(mtime.into()),
|
mtime: Some(mtime.into()),
|
||||||
},
|
})
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
.log_err(),
|
|
||||||
)
|
|
||||||
.detach();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_format_buffers(
|
async fn handle_format_buffers(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::FormatBuffers>,
|
envelope: TypedEnvelope<proto::FormatBuffers>,
|
||||||
rpc: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<proto::FormatBuffersResponse> {
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let sender_id = envelope.original_sender_id()?;
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let shared_buffers = self
|
let format = this.update(&mut cx, |this, cx| {
|
||||||
|
let shared_buffers = this
|
||||||
.shared_buffers
|
.shared_buffers
|
||||||
.get(&sender_id)
|
.get(&sender_id)
|
||||||
.ok_or_else(|| anyhow!("peer has no buffers"))?;
|
.ok_or_else(|| anyhow!("peer has no buffers"))?;
|
||||||
let mut buffers = HashSet::default();
|
let mut buffers = HashSet::default();
|
||||||
for buffer_id in envelope.payload.buffer_ids {
|
for buffer_id in &envelope.payload.buffer_ids {
|
||||||
buffers.insert(
|
buffers.insert(
|
||||||
shared_buffers
|
shared_buffers
|
||||||
.get(&buffer_id)
|
.get(buffer_id)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
|
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cx.spawn(|this, mut cx| async move {
|
Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
|
||||||
let project_transaction = this
|
})?;
|
||||||
.update(&mut cx, |this, cx| this.format(buffers, false, cx))
|
|
||||||
.await
|
let project_transaction = format.await?;
|
||||||
.map(|project_transaction| {
|
let project_transaction = this.update(&mut cx, |this, cx| {
|
||||||
this.update(&mut cx, |this, cx| {
|
this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
|
||||||
this.serialize_project_transaction_for_peer(
|
|
||||||
project_transaction,
|
|
||||||
sender_id,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
// We spawn here in order to enqueue the sending of the response *after* transmission of
|
Ok(proto::FormatBuffersResponse {
|
||||||
// edits associated with formatting.
|
transaction: Some(project_transaction),
|
||||||
cx.spawn(|_| async move {
|
|
||||||
match project_transaction {
|
|
||||||
Ok(transaction) => rpc.respond(
|
|
||||||
receipt,
|
|
||||||
proto::FormatBuffersResponse {
|
|
||||||
transaction: Some(transaction),
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
Err(error) => rpc.respond_with_error(
|
|
||||||
receipt,
|
|
||||||
proto::Error {
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
}
|
|
||||||
Ok::<_, anyhow::Error>(())
|
|
||||||
})
|
})
|
||||||
.await
|
|
||||||
.log_err();
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_completions(
|
async fn handle_get_completions(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::GetCompletions>,
|
envelope: TypedEnvelope<proto::GetCompletions>,
|
||||||
rpc: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<proto::GetCompletionsResponse> {
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let sender_id = envelope.original_sender_id()?;
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let buffer = self
|
|
||||||
.shared_buffers
|
|
||||||
.get(&sender_id)
|
|
||||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
|
||||||
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
|
||||||
let position = envelope
|
let position = envelope
|
||||||
.payload
|
.payload
|
||||||
.position
|
.position
|
||||||
.and_then(language::proto::deserialize_anchor)
|
.and_then(language::proto::deserialize_anchor)
|
||||||
.ok_or_else(|| anyhow!("invalid position"))?;
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
||||||
cx.spawn(|this, mut cx| async move {
|
let completions = this.update(&mut cx, |this, cx| {
|
||||||
match this
|
let buffer = this
|
||||||
.update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
|
.shared_buffers
|
||||||
.await
|
.get(&sender_id)
|
||||||
{
|
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
||||||
Ok(completions) => rpc.respond(
|
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
||||||
receipt,
|
Ok::<_, anyhow::Error>(this.completions(&buffer, position, cx))
|
||||||
proto::GetCompletionsResponse {
|
})?;
|
||||||
|
|
||||||
|
Ok(proto::GetCompletionsResponse {
|
||||||
completions: completions
|
completions: completions
|
||||||
|
.await?
|
||||||
.iter()
|
.iter()
|
||||||
.map(language::proto::serialize_completion)
|
.map(language::proto::serialize_completion)
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
|
||||||
),
|
|
||||||
Err(error) => rpc.respond_with_error(
|
|
||||||
receipt,
|
|
||||||
proto::Error {
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.detach_and_log_err(cx);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_apply_additional_edits_for_completion(
|
async fn handle_apply_additional_edits_for_completion(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
|
envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
|
||||||
rpc: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let sender_id = envelope.original_sender_id()?;
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let buffer = self
|
let apply_additional_edits = this.update(&mut cx, |this, cx| {
|
||||||
|
let buffer = this
|
||||||
.shared_buffers
|
.shared_buffers
|
||||||
.get(&sender_id)
|
.get(&sender_id)
|
||||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
||||||
|
@ -2372,153 +2325,111 @@ impl Project {
|
||||||
.ok_or_else(|| anyhow!("invalid completion"))?,
|
.ok_or_else(|| anyhow!("invalid completion"))?,
|
||||||
language,
|
language,
|
||||||
)?;
|
)?;
|
||||||
cx.spawn(|this, mut cx| async move {
|
Ok::<_, anyhow::Error>(
|
||||||
match this
|
this.apply_additional_edits_for_completion(buffer, completion, false, cx),
|
||||||
.update(&mut cx, |this, cx| {
|
)
|
||||||
this.apply_additional_edits_for_completion(buffer, completion, false, cx)
|
})?;
|
||||||
})
|
|
||||||
.await
|
Ok(proto::ApplyCompletionAdditionalEditsResponse {
|
||||||
{
|
transaction: apply_additional_edits
|
||||||
Ok(transaction) => rpc.respond(
|
.await?
|
||||||
receipt,
|
|
||||||
proto::ApplyCompletionAdditionalEditsResponse {
|
|
||||||
transaction: transaction
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(language::proto::serialize_transaction),
|
.map(language::proto::serialize_transaction),
|
||||||
},
|
|
||||||
),
|
|
||||||
Err(error) => rpc.respond_with_error(
|
|
||||||
receipt,
|
|
||||||
proto::Error {
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.detach_and_log_err(cx);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_code_actions(
|
async fn handle_get_code_actions(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::GetCodeActions>,
|
envelope: TypedEnvelope<proto::GetCodeActions>,
|
||||||
rpc: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<proto::GetCodeActionsResponse> {
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let sender_id = envelope.original_sender_id()?;
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let buffer = self
|
|
||||||
.shared_buffers
|
|
||||||
.get(&sender_id)
|
|
||||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
|
||||||
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
|
||||||
let position = envelope
|
let position = envelope
|
||||||
.payload
|
.payload
|
||||||
.position
|
.position
|
||||||
.and_then(language::proto::deserialize_anchor)
|
.and_then(language::proto::deserialize_anchor)
|
||||||
.ok_or_else(|| anyhow!("invalid position"))?;
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
||||||
cx.spawn(|this, mut cx| async move {
|
let code_actions = this.update(&mut cx, |this, cx| {
|
||||||
match this
|
let buffer = this
|
||||||
.update(&mut cx, |this, cx| this.code_actions(&buffer, position, cx))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(actions) => rpc.respond(
|
|
||||||
receipt,
|
|
||||||
proto::GetCodeActionsResponse {
|
|
||||||
actions: actions
|
|
||||||
.iter()
|
|
||||||
.map(language::proto::serialize_code_action)
|
|
||||||
.collect(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Err(error) => rpc.respond_with_error(
|
|
||||||
receipt,
|
|
||||||
proto::Error {
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach_and_log_err(cx);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_apply_code_action(
|
|
||||||
&mut self,
|
|
||||||
envelope: TypedEnvelope<proto::ApplyCodeAction>,
|
|
||||||
rpc: Arc<Client>,
|
|
||||||
cx: &mut ModelContext<Self>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let sender_id = envelope.original_sender_id()?;
|
|
||||||
let buffer = self
|
|
||||||
.shared_buffers
|
.shared_buffers
|
||||||
.get(&sender_id)
|
.get(&sender_id)
|
||||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
||||||
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
||||||
|
Ok::<_, anyhow::Error>(this.code_actions(&buffer, position, cx))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(proto::GetCodeActionsResponse {
|
||||||
|
actions: code_actions
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.map(language::proto::serialize_code_action)
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_apply_code_action(
|
||||||
|
this: ModelHandle<Self>,
|
||||||
|
envelope: TypedEnvelope<proto::ApplyCodeAction>,
|
||||||
|
_: Arc<Client>,
|
||||||
|
mut cx: AsyncAppContext,
|
||||||
|
) -> Result<proto::ApplyCodeActionResponse> {
|
||||||
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let action = language::proto::deserialize_code_action(
|
let action = language::proto::deserialize_code_action(
|
||||||
envelope
|
envelope
|
||||||
.payload
|
.payload
|
||||||
.action
|
.action
|
||||||
.ok_or_else(|| anyhow!("invalid action"))?,
|
.ok_or_else(|| anyhow!("invalid action"))?,
|
||||||
)?;
|
)?;
|
||||||
let apply_code_action = self.apply_code_action(buffer, action, false, cx);
|
let apply_code_action = this.update(&mut cx, |this, cx| {
|
||||||
cx.spawn(|this, mut cx| async move {
|
let buffer = this
|
||||||
match apply_code_action.await {
|
|
||||||
Ok(project_transaction) => this.update(&mut cx, |this, cx| {
|
|
||||||
let serialized_transaction = this.serialize_project_transaction_for_peer(
|
|
||||||
project_transaction,
|
|
||||||
sender_id,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
rpc.respond(
|
|
||||||
receipt,
|
|
||||||
proto::ApplyCodeActionResponse {
|
|
||||||
transaction: Some(serialized_transaction),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Err(error) => rpc.respond_with_error(
|
|
||||||
receipt,
|
|
||||||
proto::Error {
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach_and_log_err(cx);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_get_definition(
|
|
||||||
&mut self,
|
|
||||||
envelope: TypedEnvelope<proto::GetDefinition>,
|
|
||||||
rpc: Arc<Client>,
|
|
||||||
cx: &mut ModelContext<Self>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let sender_id = envelope.original_sender_id()?;
|
|
||||||
let source_buffer = self
|
|
||||||
.shared_buffers
|
.shared_buffers
|
||||||
.get(&sender_id)
|
.get(&sender_id)
|
||||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
||||||
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
||||||
|
Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let project_transaction = apply_code_action.await?;
|
||||||
|
let project_transaction = this.update(&mut cx, |this, cx| {
|
||||||
|
this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
|
||||||
|
});
|
||||||
|
Ok(proto::ApplyCodeActionResponse {
|
||||||
|
transaction: Some(project_transaction),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_get_definition(
|
||||||
|
this: ModelHandle<Self>,
|
||||||
|
envelope: TypedEnvelope<proto::GetDefinition>,
|
||||||
|
_: Arc<Client>,
|
||||||
|
mut cx: AsyncAppContext,
|
||||||
|
) -> Result<proto::GetDefinitionResponse> {
|
||||||
|
let sender_id = envelope.original_sender_id()?;
|
||||||
let position = envelope
|
let position = envelope
|
||||||
.payload
|
.payload
|
||||||
.position
|
.position
|
||||||
.and_then(deserialize_anchor)
|
.and_then(deserialize_anchor)
|
||||||
.ok_or_else(|| anyhow!("invalid position"))?;
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
||||||
if !source_buffer.read(cx).can_resolve(&position) {
|
let definitions = this.update(&mut cx, |this, cx| {
|
||||||
return Err(anyhow!("cannot resolve position"));
|
let source_buffer = this
|
||||||
|
.shared_buffers
|
||||||
|
.get(&sender_id)
|
||||||
|
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
||||||
|
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
||||||
|
if source_buffer.read(cx).can_resolve(&position) {
|
||||||
|
Ok(this.definition(&source_buffer, position, cx))
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("cannot resolve position"))
|
||||||
}
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
let definitions = self.definition(&source_buffer, position, cx);
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
|
||||||
let definitions = definitions.await?;
|
let definitions = definitions.await?;
|
||||||
|
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
let mut response = proto::GetDefinitionResponse {
|
let mut response = proto::GetDefinitionResponse {
|
||||||
definitions: Default::default(),
|
definitions: Default::default(),
|
||||||
};
|
};
|
||||||
this.update(&mut cx, |this, cx| {
|
|
||||||
for definition in definitions {
|
for definition in definitions {
|
||||||
let buffer =
|
let buffer =
|
||||||
this.serialize_buffer_for_peer(&definition.target_buffer, sender_id, cx);
|
this.serialize_buffer_for_peer(&definition.target_buffer, sender_id, cx);
|
||||||
|
@ -2528,48 +2439,34 @@ impl Project {
|
||||||
buffer: Some(buffer),
|
buffer: Some(buffer),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
Ok(response)
|
||||||
rpc.respond(receipt, response)?;
|
|
||||||
Ok::<_, anyhow::Error>(())
|
|
||||||
})
|
})
|
||||||
.detach_and_log_err(cx);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_open_buffer(
|
async fn handle_open_buffer(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::OpenBuffer>,
|
envelope: TypedEnvelope<proto::OpenBuffer>,
|
||||||
rpc: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<proto::OpenBufferResponse> {
|
||||||
let receipt = envelope.receipt();
|
|
||||||
let peer_id = envelope.original_sender_id()?;
|
let peer_id = envelope.original_sender_id()?;
|
||||||
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
|
||||||
let open_buffer = self.open_buffer(
|
let open_buffer = this.update(&mut cx, |this, cx| {
|
||||||
|
this.open_buffer(
|
||||||
ProjectPath {
|
ProjectPath {
|
||||||
worktree_id,
|
worktree_id,
|
||||||
path: PathBuf::from(envelope.payload.path).into(),
|
path: PathBuf::from(envelope.payload.path).into(),
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
);
|
|
||||||
cx.spawn(|this, mut cx| {
|
|
||||||
async move {
|
|
||||||
let buffer = open_buffer.await?;
|
|
||||||
let buffer = this.update(&mut cx, |this, cx| {
|
|
||||||
this.serialize_buffer_for_peer(&buffer, peer_id, cx)
|
|
||||||
});
|
|
||||||
rpc.respond(
|
|
||||||
receipt,
|
|
||||||
proto::OpenBufferResponse {
|
|
||||||
buffer: Some(buffer),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
});
|
||||||
.log_err()
|
|
||||||
|
let buffer = open_buffer.await?;
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
Ok(proto::OpenBufferResponse {
|
||||||
|
buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.detach();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_project_transaction_for_peer(
|
fn serialize_project_transaction_for_peer(
|
||||||
|
@ -2685,67 +2582,74 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_close_buffer(
|
async fn handle_close_buffer(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::CloseBuffer>,
|
envelope: TypedEnvelope<proto::CloseBuffer>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if let Some(shared_buffers) = self.shared_buffers.get_mut(&envelope.original_sender_id()?) {
|
this.update(&mut cx, |this, cx| {
|
||||||
|
if let Some(shared_buffers) =
|
||||||
|
this.shared_buffers.get_mut(&envelope.original_sender_id()?)
|
||||||
|
{
|
||||||
shared_buffers.remove(&envelope.payload.buffer_id);
|
shared_buffers.remove(&envelope.payload.buffer_id);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_buffer_saved(
|
async fn handle_buffer_saved(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::BufferSaved>,
|
envelope: TypedEnvelope<proto::BufferSaved>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let payload = envelope.payload.clone();
|
let version = envelope.payload.version.try_into()?;
|
||||||
let buffer = self
|
let mtime = envelope
|
||||||
.open_buffers
|
.payload
|
||||||
.get(&(payload.buffer_id as usize))
|
|
||||||
.and_then(|buffer| buffer.upgrade(cx));
|
|
||||||
if let Some(buffer) = buffer {
|
|
||||||
buffer.update(cx, |buffer, cx| {
|
|
||||||
let version = payload.version.try_into()?;
|
|
||||||
let mtime = payload
|
|
||||||
.mtime
|
.mtime
|
||||||
.ok_or_else(|| anyhow!("missing mtime"))?
|
.ok_or_else(|| anyhow!("missing mtime"))?
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
let buffer = this
|
||||||
|
.open_buffers
|
||||||
|
.get(&(envelope.payload.buffer_id as usize))
|
||||||
|
.and_then(|buffer| buffer.upgrade(cx));
|
||||||
|
if let Some(buffer) = buffer {
|
||||||
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.did_save(version, mtime, None, cx);
|
buffer.did_save(version, mtime, None, cx);
|
||||||
Result::<_, anyhow::Error>::Ok(())
|
});
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_buffer_reloaded(
|
async fn handle_buffer_reloaded(
|
||||||
&mut self,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::BufferReloaded>,
|
envelope: TypedEnvelope<proto::BufferReloaded>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
cx: &mut ModelContext<Self>,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let payload = envelope.payload.clone();
|
let payload = envelope.payload.clone();
|
||||||
let buffer = self
|
|
||||||
.open_buffers
|
|
||||||
.get(&(payload.buffer_id as usize))
|
|
||||||
.and_then(|buffer| buffer.upgrade(cx));
|
|
||||||
if let Some(buffer) = buffer {
|
|
||||||
buffer.update(cx, |buffer, cx| {
|
|
||||||
let version = payload.version.try_into()?;
|
let version = payload.version.try_into()?;
|
||||||
let mtime = payload
|
let mtime = payload
|
||||||
.mtime
|
.mtime
|
||||||
.ok_or_else(|| anyhow!("missing mtime"))?
|
.ok_or_else(|| anyhow!("missing mtime"))?
|
||||||
.into();
|
.into();
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
let buffer = this
|
||||||
|
.open_buffers
|
||||||
|
.get(&(payload.buffer_id as usize))
|
||||||
|
.and_then(|buffer| buffer.upgrade(cx));
|
||||||
|
if let Some(buffer) = buffer {
|
||||||
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.did_reload(version, mtime, cx);
|
buffer.did_reload(version, mtime, cx);
|
||||||
Result::<_, anyhow::Error>::Ok(())
|
});
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_paths<'a>(
|
pub fn match_paths<'a>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue