Achieve end to end channel buffer synchronization

co-authored-by: max <max@zed.dev>
This commit is contained in:
Mikayla 2023-08-22 13:25:31 -07:00
parent 95ea664725
commit 5a0315c4d5
No known key found for this signature in database
10 changed files with 425 additions and 128 deletions

View file

@ -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);
}

View file

@ -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
}
}