Achieve end to end channel buffer synchronization
co-authored-by: max <max@zed.dev>
This commit is contained in:
parent
95ea664725
commit
5a0315c4d5
10 changed files with 425 additions and 128 deletions
|
@ -1,7 +1,14 @@
|
|||
mod channel_store;
|
||||
|
||||
pub mod channel_buffer;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use channel_store::*;
|
||||
use client::Client;
|
||||
|
||||
#[cfg(test)]
|
||||
mod channel_store_tests;
|
||||
|
||||
pub fn init(client: &Arc<Client>) {
|
||||
channel_buffer::init(client);
|
||||
}
|
||||
|
|
|
@ -6,30 +6,34 @@ use rpc::{proto, TypedEnvelope};
|
|||
use std::sync::Arc;
|
||||
use util::ResultExt;
|
||||
|
||||
// Open the channel document
|
||||
// ChannelDocumentView { ChannelDocument, Editor } -> On clone, clones internal ChannelDocument handle, instantiates new editor
|
||||
// Produces a view which is: (ChannelDocument, Editor), ChannelDocument manages subscriptions
|
||||
// ChannelDocuments -> Buffers -> Editor with that buffer
|
||||
|
||||
// ChannelDocuments {
|
||||
// ChannleBuffers: HashMap<bufferId, ModelHandle<language::Buffer>>
|
||||
// }
|
||||
|
||||
type BufferId = u64;
|
||||
pub(crate) fn init(client: &Arc<Client>) {
|
||||
client.add_model_message_handler(ChannelBuffer::handle_update_channel_buffer);
|
||||
client.add_model_message_handler(ChannelBuffer::handle_add_channel_buffer_collaborator);
|
||||
client.add_model_message_handler(ChannelBuffer::handle_remove_channel_buffer_collaborator);
|
||||
}
|
||||
|
||||
pub struct ChannelBuffer {
|
||||
channel_id: ChannelId,
|
||||
buffer_id: BufferId,
|
||||
collaborators: Vec<proto::Collaborator>,
|
||||
buffer: ModelHandle<language::Buffer>,
|
||||
client: Arc<Client>,
|
||||
_subscription: client::Subscription,
|
||||
}
|
||||
|
||||
impl Entity for ChannelBuffer {
|
||||
type Event = ();
|
||||
|
||||
fn release(&mut self, _: &mut AppContext) {
|
||||
self.client
|
||||
.send(proto::LeaveChannelBuffer {
|
||||
channel_id: self.channel_id,
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
impl ChannelBuffer {
|
||||
pub fn for_channel(
|
||||
pub fn join_channel(
|
||||
channel_id: ChannelId,
|
||||
client: Arc<Client>,
|
||||
cx: &mut AppContext,
|
||||
|
@ -45,19 +49,24 @@ impl ChannelBuffer {
|
|||
.into_iter()
|
||||
.map(language::proto::deserialize_operation)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let buffer_id = response.buffer_id;
|
||||
|
||||
let buffer = cx.add_model(|cx| language::Buffer::new(0, base_text, cx));
|
||||
let collaborators = response.collaborators;
|
||||
|
||||
let buffer =
|
||||
cx.add_model(|cx| language::Buffer::new(response.replica_id as u16, base_text, cx));
|
||||
buffer.update(&mut cx, |buffer, cx| buffer.apply_ops(operations, cx))?;
|
||||
|
||||
let subscription = client.subscribe_to_entity(channel_id)?;
|
||||
|
||||
anyhow::Ok(cx.add_model(|cx| {
|
||||
cx.subscribe(&buffer, Self::on_buffer_update).detach();
|
||||
client.add_model_message_handler(Self::handle_update_channel_buffer);
|
||||
|
||||
Self {
|
||||
buffer_id,
|
||||
buffer,
|
||||
client,
|
||||
channel_id,
|
||||
collaborators,
|
||||
_subscription: subscription.set_model(&cx.handle(), &mut cx.to_async()),
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
@ -77,6 +86,7 @@ impl ChannelBuffer {
|
|||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
cx.notify();
|
||||
this.buffer
|
||||
.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))
|
||||
})?;
|
||||
|
@ -84,6 +94,49 @@ impl ChannelBuffer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_add_channel_buffer_collaborator(
|
||||
this: ModelHandle<Self>,
|
||||
envelope: TypedEnvelope<proto::AddChannelBufferCollaborator>,
|
||||
_: Arc<Client>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
let collaborator = envelope.payload.collaborator.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"Should have gotten a collaborator in the AddChannelBufferCollaborator message"
|
||||
)
|
||||
})?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.collaborators.push(collaborator);
|
||||
cx.notify();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_remove_channel_buffer_collaborator(
|
||||
this: ModelHandle<Self>,
|
||||
message: TypedEnvelope<proto::RemoveChannelBufferCollaborator>,
|
||||
_: Arc<Client>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.collaborators.retain(|collaborator| {
|
||||
if collaborator.peer_id == message.payload.peer_id {
|
||||
this.buffer.update(cx, |buffer, cx| {
|
||||
buffer.remove_peer(collaborator.replica_id as u16, cx)
|
||||
});
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
cx.notify();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_buffer_update(
|
||||
&mut self,
|
||||
_: ModelHandle<language::Buffer>,
|
||||
|
@ -94,7 +147,7 @@ impl ChannelBuffer {
|
|||
let operation = language::proto::serialize_operation(operation);
|
||||
self.client
|
||||
.send(proto::UpdateChannelBuffer {
|
||||
buffer_id: self.buffer_id,
|
||||
channel_id: self.channel_id,
|
||||
operations: vec![operation],
|
||||
})
|
||||
.log_err();
|
||||
|
@ -104,4 +157,8 @@ impl ChannelBuffer {
|
|||
pub fn buffer(&self) -> ModelHandle<language::Buffer> {
|
||||
self.buffer.clone()
|
||||
}
|
||||
|
||||
pub fn collaborators(&self) -> &[proto::Collaborator] {
|
||||
&self.collaborators
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue