mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 02:37:05 +00:00
WIP - Register client RPC handlers on app startup
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
1ca1595490
commit
71abea728e
6 changed files with 268 additions and 269 deletions
|
@ -180,14 +180,17 @@ impl Entity for Channel {
|
|||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn init(rpc: &Arc<Client>) {
|
||||
rpc.add_entity_message_handler(Self::handle_message_sent);
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
details: ChannelDetails,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
rpc: Arc<Client>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
let _subscription =
|
||||
rpc.add_entity_message_handler(details.id, cx, Self::handle_message_sent);
|
||||
let _subscription = rpc.add_model_for_remote_entity(cx.handle(), details.id);
|
||||
|
||||
{
|
||||
let user_store = user_store.clone();
|
||||
|
|
|
@ -12,7 +12,10 @@ use async_tungstenite::tungstenite::{
|
|||
http::{Request, StatusCode},
|
||||
};
|
||||
use futures::{future::LocalBoxFuture, FutureExt, StreamExt};
|
||||
use gpui::{action, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
||||
use gpui::{
|
||||
action, AnyModelHandle, AnyWeakModelHandle, AsyncAppContext, Entity, ModelHandle,
|
||||
MutableAppContext, Task,
|
||||
};
|
||||
use http::HttpClient;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
|
@ -20,7 +23,7 @@ use postage::watch;
|
|||
use rand::prelude::*;
|
||||
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage};
|
||||
use std::{
|
||||
any::{type_name, TypeId},
|
||||
any::TypeId,
|
||||
collections::HashMap,
|
||||
convert::TryFrom,
|
||||
fmt::Write as _,
|
||||
|
@ -124,19 +127,29 @@ pub enum Status {
|
|||
ReconnectionError { next_reconnection: Instant },
|
||||
}
|
||||
|
||||
type ModelHandler = Box<
|
||||
dyn Send
|
||||
+ Sync
|
||||
+ FnMut(Box<dyn AnyTypedEnvelope>, &AsyncAppContext) -> LocalBoxFuture<'static, Result<()>>,
|
||||
>;
|
||||
|
||||
struct ClientState {
|
||||
credentials: Option<Credentials>,
|
||||
status: (watch::Sender<Status>, watch::Receiver<Status>),
|
||||
entity_id_extractors: HashMap<TypeId, Box<dyn Send + Sync + Fn(&dyn AnyTypedEnvelope) -> u64>>,
|
||||
model_handlers: HashMap<(TypeId, Option<u64>), Option<ModelHandler>>,
|
||||
_maintain_connection: Option<Task<()>>,
|
||||
heartbeat_interval: Duration,
|
||||
|
||||
pending_messages: HashMap<(TypeId, u64), Vec<Box<dyn AnyTypedEnvelope>>>,
|
||||
models_by_entity_type_and_remote_id: HashMap<(TypeId, u64), AnyWeakModelHandle>,
|
||||
models_by_message_type: HashMap<TypeId, AnyModelHandle>,
|
||||
model_types_by_message_type: HashMap<TypeId, TypeId>,
|
||||
message_handlers: HashMap<
|
||||
TypeId,
|
||||
Box<
|
||||
dyn Send
|
||||
+ Sync
|
||||
+ Fn(
|
||||
AnyModelHandle,
|
||||
Box<dyn AnyTypedEnvelope>,
|
||||
AsyncAppContext,
|
||||
) -> LocalBoxFuture<'static, Result<()>>,
|
||||
>,
|
||||
>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -151,23 +164,27 @@ impl Default for ClientState {
|
|||
credentials: None,
|
||||
status: watch::channel_with(Status::SignedOut),
|
||||
entity_id_extractors: Default::default(),
|
||||
model_handlers: Default::default(),
|
||||
_maintain_connection: None,
|
||||
heartbeat_interval: Duration::from_secs(5),
|
||||
models_by_message_type: Default::default(),
|
||||
models_by_entity_type_and_remote_id: Default::default(),
|
||||
model_types_by_message_type: Default::default(),
|
||||
pending_messages: Default::default(),
|
||||
message_handlers: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Subscription {
|
||||
client: Weak<Client>,
|
||||
id: (TypeId, Option<u64>),
|
||||
id: (TypeId, u64),
|
||||
}
|
||||
|
||||
impl Drop for Subscription {
|
||||
fn drop(&mut self) {
|
||||
if let Some(client) = self.client.upgrade() {
|
||||
let mut state = client.state.write();
|
||||
let _ = state.model_handlers.remove(&self.id).unwrap();
|
||||
let _ = state.models_by_entity_type_and_remote_id.remove(&self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -266,125 +283,108 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_message_handler<T, M, F, Fut>(
|
||||
pub fn add_model_for_remote_entity<T: Entity>(
|
||||
self: &Arc<Self>,
|
||||
cx: &mut ModelContext<M>,
|
||||
mut handler: F,
|
||||
) -> Subscription
|
||||
handle: ModelHandle<T>,
|
||||
remote_id: u64,
|
||||
) -> Subscription {
|
||||
let mut state = self.state.write();
|
||||
let id = (TypeId::of::<T>(), remote_id);
|
||||
state
|
||||
.models_by_entity_type_and_remote_id
|
||||
.insert(id, AnyModelHandle::from(handle).downgrade());
|
||||
Subscription {
|
||||
client: Arc::downgrade(self),
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_message_handler<M, E, H, F>(self: &Arc<Self>, model: ModelHandle<E>, handler: H)
|
||||
where
|
||||
T: EnvelopedMessage,
|
||||
M: Entity,
|
||||
F: 'static
|
||||
M: EnvelopedMessage,
|
||||
E: Entity,
|
||||
H: 'static
|
||||
+ Send
|
||||
+ Sync
|
||||
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
|
||||
Fut: 'static + Future<Output = Result<()>>,
|
||||
+ Fn(ModelHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
|
||||
F: 'static + Future<Output = Result<()>>,
|
||||
{
|
||||
let subscription_id = (TypeId::of::<T>(), None);
|
||||
let message_type_id = TypeId::of::<M>();
|
||||
|
||||
let client = self.clone();
|
||||
let mut state = self.state.write();
|
||||
let model = cx.weak_handle();
|
||||
let prev_handler = state.model_handlers.insert(
|
||||
subscription_id,
|
||||
Some(Box::new(move |envelope, cx| {
|
||||
if let Some(model) = model.upgrade(cx) {
|
||||
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
|
||||
handler(model, *envelope, client.clone(), cx.clone()).boxed_local()
|
||||
} else {
|
||||
async move {
|
||||
Err(anyhow!(
|
||||
"received message for {:?} but model was dropped",
|
||||
type_name::<M>()
|
||||
))
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
})),
|
||||
state
|
||||
.models_by_message_type
|
||||
.insert(message_type_id, model.into());
|
||||
|
||||
let prev_handler = state.message_handlers.insert(
|
||||
message_type_id,
|
||||
Box::new(move |handle, envelope, cx| {
|
||||
let model = handle.downcast::<E>().unwrap();
|
||||
let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap();
|
||||
handler(model, *envelope, client.clone(), cx).boxed_local()
|
||||
}),
|
||||
);
|
||||
if prev_handler.is_some() {
|
||||
panic!("registered handler for the same message twice");
|
||||
}
|
||||
|
||||
Subscription {
|
||||
client: Arc::downgrade(self),
|
||||
id: subscription_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entity_message_handler<T, M, F, Fut>(
|
||||
self: &Arc<Self>,
|
||||
remote_id: u64,
|
||||
cx: &mut ModelContext<M>,
|
||||
mut handler: F,
|
||||
) -> Subscription
|
||||
pub fn add_entity_message_handler<M, E, H, F>(self: &Arc<Self>, handler: H)
|
||||
where
|
||||
T: EntityMessage,
|
||||
M: Entity,
|
||||
F: 'static
|
||||
M: EntityMessage,
|
||||
E: Entity,
|
||||
H: 'static
|
||||
+ Send
|
||||
+ Sync
|
||||
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
|
||||
Fut: 'static + Future<Output = Result<()>>,
|
||||
+ Fn(ModelHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
|
||||
F: 'static + Future<Output = Result<()>>,
|
||||
{
|
||||
let subscription_id = (TypeId::of::<T>(), Some(remote_id));
|
||||
let model_type_id = TypeId::of::<E>();
|
||||
let message_type_id = TypeId::of::<M>();
|
||||
|
||||
let client = self.clone();
|
||||
let mut state = self.state.write();
|
||||
let model = cx.weak_handle();
|
||||
state
|
||||
.model_types_by_message_type
|
||||
.insert(message_type_id, model_type_id);
|
||||
state
|
||||
.entity_id_extractors
|
||||
.entry(subscription_id.0)
|
||||
.entry(message_type_id)
|
||||
.or_insert_with(|| {
|
||||
Box::new(|envelope| {
|
||||
let envelope = envelope
|
||||
.as_any()
|
||||
.downcast_ref::<TypedEnvelope<T>>()
|
||||
.downcast_ref::<TypedEnvelope<M>>()
|
||||
.unwrap();
|
||||
envelope.payload.remote_entity_id()
|
||||
})
|
||||
});
|
||||
let prev_handler = state.model_handlers.insert(
|
||||
subscription_id,
|
||||
Some(Box::new(move |envelope, cx| {
|
||||
if let Some(model) = model.upgrade(cx) {
|
||||
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
|
||||
handler(model, *envelope, client.clone(), cx.clone()).boxed_local()
|
||||
} else {
|
||||
async move {
|
||||
Err(anyhow!(
|
||||
"received message for {:?} but model was dropped",
|
||||
type_name::<M>()
|
||||
))
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
})),
|
||||
|
||||
let prev_handler = state.message_handlers.insert(
|
||||
message_type_id,
|
||||
Box::new(move |handle, envelope, cx| {
|
||||
let model = handle.downcast::<E>().unwrap();
|
||||
let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap();
|
||||
handler(model, *envelope, client.clone(), cx).boxed_local()
|
||||
}),
|
||||
);
|
||||
if prev_handler.is_some() {
|
||||
panic!("registered a handler for the same entity twice")
|
||||
}
|
||||
|
||||
Subscription {
|
||||
client: Arc::downgrade(self),
|
||||
id: subscription_id,
|
||||
panic!("registered handler for the same message twice");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entity_request_handler<T, M, F, Fut>(
|
||||
self: &Arc<Self>,
|
||||
remote_id: u64,
|
||||
cx: &mut ModelContext<M>,
|
||||
mut handler: F,
|
||||
) -> Subscription
|
||||
pub fn add_entity_request_handler<M, E, H, F>(self: &Arc<Self>, handler: H)
|
||||
where
|
||||
T: EntityMessage + RequestMessage,
|
||||
M: Entity,
|
||||
F: 'static
|
||||
M: EntityMessage + RequestMessage,
|
||||
E: Entity,
|
||||
H: 'static
|
||||
+ Send
|
||||
+ Sync
|
||||
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
|
||||
Fut: 'static + Future<Output = Result<T::Response>>,
|
||||
+ Fn(ModelHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
|
||||
F: 'static + Future<Output = Result<M::Response>>,
|
||||
{
|
||||
self.add_entity_message_handler(remote_id, cx, move |model, envelope, client, cx| {
|
||||
self.add_entity_message_handler(move |model, envelope, client, cx| {
|
||||
let receipt = envelope.receipt();
|
||||
let response = handler(model, envelope, client.clone(), cx);
|
||||
async move {
|
||||
|
@ -500,26 +500,37 @@ impl Client {
|
|||
while let Some(message) = incoming.next().await {
|
||||
let mut state = this.state.write();
|
||||
let payload_type_id = message.payload_type_id();
|
||||
let entity_id = if let Some(extract_entity_id) =
|
||||
state.entity_id_extractors.get(&message.payload_type_id())
|
||||
{
|
||||
Some((extract_entity_id)(message.as_ref()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let type_name = message.payload_type_name();
|
||||
|
||||
let handler_key = (payload_type_id, entity_id);
|
||||
if let Some(handler) = state.model_handlers.get_mut(&handler_key) {
|
||||
let mut handler = handler.take().unwrap();
|
||||
let model = state.models_by_message_type.get(&payload_type_id).cloned().or_else(|| {
|
||||
let extract_entity_id = state.entity_id_extractors.get(&message.payload_type_id())?;
|
||||
let entity_id = (extract_entity_id)(message.as_ref());
|
||||
let model_type_id = *state.model_types_by_message_type.get(&payload_type_id)?;
|
||||
|
||||
// TODO - if we don't have this model yet, then buffer the message
|
||||
let model = state.models_by_entity_type_and_remote_id.get(&(model_type_id, entity_id))?;
|
||||
|
||||
if let Some(model) = model.upgrade(&cx) {
|
||||
Some(model)
|
||||
} else {
|
||||
state.models_by_entity_type_and_remote_id.remove(&(model_type_id, entity_id));
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let model = if let Some(model) = model {
|
||||
model
|
||||
} else {
|
||||
log::info!("unhandled message {}", type_name);
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(handler) = state.message_handlers.remove(&payload_type_id) {
|
||||
drop(state); // Avoid deadlocks if the handler interacts with rpc::Client
|
||||
let future = (handler)(message, &cx);
|
||||
let future = handler(model, message, cx.clone());
|
||||
{
|
||||
let mut state = this.state.write();
|
||||
if state.model_handlers.contains_key(&handler_key) {
|
||||
state.model_handlers.insert(handler_key, Some(handler));
|
||||
}
|
||||
state.message_handlers.insert(payload_type_id, handler);
|
||||
}
|
||||
|
||||
let client_id = this.id;
|
||||
|
@ -915,106 +926,107 @@ mod tests {
|
|||
assert_eq!(decode_worktree_url("not://the-right-format"), None);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_subscribing_to_entity(mut cx: TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
// #[gpui::test]
|
||||
// async fn test_subscribing_to_entity(mut cx: TestAppContext) {
|
||||
// cx.foreground().forbid_parking();
|
||||
|
||||
let user_id = 5;
|
||||
let mut client = Client::new(FakeHttpClient::with_404_response());
|
||||
let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
// let user_id = 5;
|
||||
// let mut client = Client::new(FakeHttpClient::with_404_response());
|
||||
// let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
|
||||
let model = cx.add_model(|_| Model { subscription: None });
|
||||
let (mut done_tx1, mut done_rx1) = postage::oneshot::channel();
|
||||
let (mut done_tx2, mut done_rx2) = postage::oneshot::channel();
|
||||
let _subscription1 = model.update(&mut cx, |_, cx| {
|
||||
client.add_entity_message_handler(
|
||||
1,
|
||||
cx,
|
||||
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
||||
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
||||
async { Ok(()) }
|
||||
},
|
||||
)
|
||||
});
|
||||
let _subscription2 = model.update(&mut cx, |_, cx| {
|
||||
client.add_entity_message_handler(
|
||||
2,
|
||||
cx,
|
||||
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
||||
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
||||
async { Ok(()) }
|
||||
},
|
||||
)
|
||||
});
|
||||
// let model = cx.add_model(|_| Model { subscription: None });
|
||||
// let (mut done_tx1, mut done_rx1) = postage::oneshot::channel();
|
||||
// let (mut done_tx2, mut done_rx2) = postage::oneshot::channel();
|
||||
// let _subscription1 = model.update(&mut cx, |_, cx| {
|
||||
// client.add_entity_message_handler(
|
||||
// 1,
|
||||
// cx,
|
||||
// move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
||||
// postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
||||
// async { Ok(()) }
|
||||
// },
|
||||
// )
|
||||
// });
|
||||
// let _subscription2 = model.update(&mut cx, |_, cx| {
|
||||
// client.add_entity_message_handler(
|
||||
// 2,
|
||||
// cx,
|
||||
// move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
|
||||
// postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
||||
// async { Ok(()) }
|
||||
// },
|
||||
// )
|
||||
// });
|
||||
|
||||
// Ensure dropping a subscription for the same entity type still allows receiving of
|
||||
// messages for other entity IDs of the same type.
|
||||
let subscription3 = model.update(&mut cx, |_, cx| {
|
||||
client.add_entity_message_handler(
|
||||
3,
|
||||
cx,
|
||||
|_, _: TypedEnvelope<proto::UnshareProject>, _, _| async { Ok(()) },
|
||||
)
|
||||
});
|
||||
drop(subscription3);
|
||||
// // Ensure dropping a subscription for the same entity type still allows receiving of
|
||||
// // messages for other entity IDs of the same type.
|
||||
// let subscription3 = model.update(&mut cx, |_, cx| {
|
||||
// client.add_entity_message_handler(
|
||||
// 3,
|
||||
// cx,
|
||||
// |_, _: TypedEnvelope<proto::UnshareProject>, _, _| async { Ok(()) },
|
||||
// )
|
||||
// });
|
||||
// drop(subscription3);
|
||||
|
||||
server.send(proto::UnshareProject { project_id: 1 });
|
||||
server.send(proto::UnshareProject { project_id: 2 });
|
||||
done_rx1.next().await.unwrap();
|
||||
done_rx2.next().await.unwrap();
|
||||
}
|
||||
// server.send(proto::UnshareProject { project_id: 1 });
|
||||
// server.send(proto::UnshareProject { project_id: 2 });
|
||||
// done_rx1.next().await.unwrap();
|
||||
// done_rx2.next().await.unwrap();
|
||||
// }
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_subscribing_after_dropping_subscription(mut cx: TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
// #[gpui::test]
|
||||
// async fn test_subscribing_after_dropping_subscription(mut cx: TestAppContext) {
|
||||
// cx.foreground().forbid_parking();
|
||||
|
||||
let user_id = 5;
|
||||
let mut client = Client::new(FakeHttpClient::with_404_response());
|
||||
let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
// let user_id = 5;
|
||||
// let mut client = Client::new(FakeHttpClient::with_404_response());
|
||||
// let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
|
||||
let model = cx.add_model(|_| Model { subscription: None });
|
||||
let (mut done_tx1, _done_rx1) = postage::oneshot::channel();
|
||||
let (mut done_tx2, mut done_rx2) = postage::oneshot::channel();
|
||||
let subscription1 = model.update(&mut cx, |_, cx| {
|
||||
client.add_message_handler(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
||||
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
||||
async { Ok(()) }
|
||||
})
|
||||
});
|
||||
drop(subscription1);
|
||||
let _subscription2 = model.update(&mut cx, |_, cx| {
|
||||
client.add_message_handler(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
||||
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
||||
async { Ok(()) }
|
||||
})
|
||||
});
|
||||
server.send(proto::Ping {});
|
||||
done_rx2.next().await.unwrap();
|
||||
}
|
||||
// let model = cx.add_model(|_| Model { subscription: None });
|
||||
// let (mut done_tx1, _done_rx1) = postage::oneshot::channel();
|
||||
// let (mut done_tx2, mut done_rx2) = postage::oneshot::channel();
|
||||
// let subscription1 = model.update(&mut cx, |_, cx| {
|
||||
// client.add_message_handler(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
||||
// postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
|
||||
// async { Ok(()) }
|
||||
// })
|
||||
// });
|
||||
// drop(subscription1);
|
||||
// let _subscription2 = model.update(&mut cx, |_, cx| {
|
||||
// client.add_message_handler(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
|
||||
// postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
|
||||
// async { Ok(()) }
|
||||
// })
|
||||
// });
|
||||
// server.send(proto::Ping {});
|
||||
// done_rx2.next().await.unwrap();
|
||||
// }
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_dropping_subscription_in_handler(mut cx: TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
// #[gpui::test]
|
||||
// async fn test_dropping_subscription_in_handler(mut cx: TestAppContext) {
|
||||
// cx.foreground().forbid_parking();
|
||||
|
||||
let user_id = 5;
|
||||
let mut client = Client::new(FakeHttpClient::with_404_response());
|
||||
let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
// let user_id = 5;
|
||||
// let mut client = Client::new(FakeHttpClient::with_404_response());
|
||||
// let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
|
||||
let model = cx.add_model(|_| Model { subscription: None });
|
||||
let (mut done_tx, mut done_rx) = postage::oneshot::channel();
|
||||
model.update(&mut cx, |model, cx| {
|
||||
model.subscription = Some(client.add_message_handler(
|
||||
cx,
|
||||
move |model, _: TypedEnvelope<proto::Ping>, _, mut cx| {
|
||||
model.update(&mut cx, |model, _| model.subscription.take());
|
||||
postage::sink::Sink::try_send(&mut done_tx, ()).unwrap();
|
||||
async { Ok(()) }
|
||||
},
|
||||
));
|
||||
});
|
||||
server.send(proto::Ping {});
|
||||
done_rx.next().await.unwrap();
|
||||
}
|
||||
// let model = cx.add_model(|_| Model { subscription: None });
|
||||
// let (mut done_tx, mut done_rx) = postage::oneshot::channel();
|
||||
// client.add_message_handler(
|
||||
// model.clone(),
|
||||
// move |model, _: TypedEnvelope<proto::Ping>, _, mut cx| {
|
||||
// model.update(&mut cx, |model, _| model.subscription.take());
|
||||
// postage::sink::Sink::try_send(&mut done_tx, ()).unwrap();
|
||||
// async { Ok(()) }
|
||||
// },
|
||||
// );
|
||||
// model.update(&mut cx, |model, cx| {
|
||||
// model.subscription = Some();
|
||||
// });
|
||||
// server.send(proto::Ping {});
|
||||
// done_rx.next().await.unwrap();
|
||||
// }
|
||||
|
||||
struct Model {
|
||||
subscription: Option<Subscription>,
|
||||
|
|
|
@ -35,6 +35,7 @@ pub struct ProjectMetadata {
|
|||
|
||||
pub struct UserStore {
|
||||
users: HashMap<u64, Arc<User>>,
|
||||
update_contacts_tx: watch::Sender<Option<proto::UpdateContacts>>,
|
||||
current_user: watch::Receiver<Option<Arc<User>>>,
|
||||
contacts: Arc<[Contact]>,
|
||||
client: Arc<Client>,
|
||||
|
@ -56,23 +57,19 @@ impl UserStore {
|
|||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
let (mut current_user_tx, current_user_rx) = watch::channel();
|
||||
let (mut update_contacts_tx, mut update_contacts_rx) =
|
||||
let (update_contacts_tx, mut update_contacts_rx) =
|
||||
watch::channel::<Option<proto::UpdateContacts>>();
|
||||
let update_contacts_subscription = client.add_message_handler(
|
||||
cx,
|
||||
move |_: ModelHandle<Self>, msg: TypedEnvelope<proto::UpdateContacts>, _, _| {
|
||||
*update_contacts_tx.borrow_mut() = Some(msg.payload);
|
||||
async move { Ok(()) }
|
||||
},
|
||||
);
|
||||
let rpc_subscription =
|
||||
client.add_message_handler(cx.handle(), Self::handle_update_contacts);
|
||||
Self {
|
||||
users: Default::default(),
|
||||
current_user: current_user_rx,
|
||||
contacts: Arc::from([]),
|
||||
client: client.clone(),
|
||||
update_contacts_tx,
|
||||
http,
|
||||
_maintain_contacts: cx.spawn_weak(|this, mut cx| async move {
|
||||
let _subscription = update_contacts_subscription;
|
||||
let _subscription = rpc_subscription;
|
||||
while let Some(message) = update_contacts_rx.recv().await {
|
||||
if let Some((message, this)) = message.zip(this.upgrade(&cx)) {
|
||||
this.update(&mut cx, |this, cx| this.update_contacts(message, cx))
|
||||
|
@ -104,6 +101,18 @@ impl UserStore {
|
|||
}
|
||||
}
|
||||
|
||||
async fn handle_update_contacts(
|
||||
this: ModelHandle<Self>,
|
||||
msg: TypedEnvelope<proto::UpdateContacts>,
|
||||
_: Arc<Client>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
this.update(&mut cx, |this, _| {
|
||||
*this.update_contacts_tx.borrow_mut() = Some(msg.payload);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_contacts(
|
||||
&mut self,
|
||||
message: proto::UpdateContacts,
|
||||
|
|
|
@ -161,6 +161,31 @@ pub struct ProjectEntry {
|
|||
}
|
||||
|
||||
impl Project {
|
||||
pub fn init(client: &Arc<Client>) {
|
||||
client.add_entity_message_handler(Self::handle_add_collaborator);
|
||||
client.add_entity_message_handler(Self::handle_buffer_reloaded);
|
||||
client.add_entity_message_handler(Self::handle_buffer_saved);
|
||||
client.add_entity_message_handler(Self::handle_close_buffer);
|
||||
client.add_entity_message_handler(Self::handle_disk_based_diagnostics_updated);
|
||||
client.add_entity_message_handler(Self::handle_disk_based_diagnostics_updating);
|
||||
client.add_entity_message_handler(Self::handle_remove_collaborator);
|
||||
client.add_entity_message_handler(Self::handle_share_worktree);
|
||||
client.add_entity_message_handler(Self::handle_unregister_worktree);
|
||||
client.add_entity_message_handler(Self::handle_unshare_project);
|
||||
client.add_entity_message_handler(Self::handle_update_buffer_file);
|
||||
client.add_entity_message_handler(Self::handle_update_buffer);
|
||||
client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
|
||||
client.add_entity_message_handler(Self::handle_update_worktree);
|
||||
client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
|
||||
client.add_entity_request_handler(Self::handle_apply_code_action);
|
||||
client.add_entity_request_handler(Self::handle_format_buffers);
|
||||
client.add_entity_request_handler(Self::handle_get_code_actions);
|
||||
client.add_entity_request_handler(Self::handle_get_completions);
|
||||
client.add_entity_request_handler(Self::handle_get_definition);
|
||||
client.add_entity_request_handler(Self::handle_open_buffer);
|
||||
client.add_entity_request_handler(Self::handle_save_buffer);
|
||||
}
|
||||
|
||||
pub fn local(
|
||||
client: Arc<Client>,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
|
@ -287,45 +312,7 @@ impl Project {
|
|||
languages,
|
||||
user_store,
|
||||
fs,
|
||||
subscriptions: vec![
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_unshare_project),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_add_collaborator),
|
||||
client.add_entity_message_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_remove_collaborator,
|
||||
),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_share_worktree),
|
||||
client.add_entity_message_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_unregister_worktree,
|
||||
),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_update_worktree),
|
||||
client.add_entity_message_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_update_diagnostic_summary,
|
||||
),
|
||||
client.add_entity_message_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_disk_based_diagnostics_updating,
|
||||
),
|
||||
client.add_entity_message_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_disk_based_diagnostics_updated,
|
||||
),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_update_buffer),
|
||||
client.add_entity_message_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_update_buffer_file,
|
||||
),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_buffer_reloaded),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_buffer_saved),
|
||||
],
|
||||
subscriptions: vec![client.add_model_for_remote_entity(cx.handle(), remote_id)],
|
||||
client,
|
||||
client_state: ProjectClientState::Remote {
|
||||
sharing_has_stopped: false,
|
||||
|
@ -362,27 +349,10 @@ impl Project {
|
|||
|
||||
self.subscriptions.clear();
|
||||
if let Some(remote_id) = remote_id {
|
||||
let client = &self.client;
|
||||
self.subscriptions.extend([
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_open_buffer),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_close_buffer),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_add_collaborator),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_remove_collaborator),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_update_worktree),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_update_buffer),
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_save_buffer),
|
||||
client.add_entity_message_handler(remote_id, cx, Self::handle_buffer_saved),
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_format_buffers),
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_get_completions),
|
||||
client.add_entity_request_handler(
|
||||
remote_id,
|
||||
cx,
|
||||
Self::handle_apply_additional_edits_for_completion,
|
||||
),
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_get_code_actions),
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_apply_code_action),
|
||||
client.add_entity_request_handler(remote_id, cx, Self::handle_get_definition),
|
||||
]);
|
||||
self.subscriptions.push(
|
||||
self.client
|
||||
.add_model_for_remote_entity(cx.handle(), remote_id),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3794,6 +3794,9 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
Channel::init(&client);
|
||||
Project::init(&client);
|
||||
|
||||
let peer_id = PeerId(connection_id_rx.next().await.unwrap().0);
|
||||
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
|
||||
let mut authed_user =
|
||||
|
|
|
@ -53,6 +53,8 @@ fn main() {
|
|||
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
|
||||
let mut path_openers = Vec::new();
|
||||
|
||||
project::Project::init(&client);
|
||||
client::Channel::init(&client);
|
||||
client::init(client.clone(), cx);
|
||||
workspace::init(cx);
|
||||
editor::init(cx, &mut path_openers);
|
||||
|
|
Loading…
Reference in a new issue