Maintain a set of peers as they join and leave the worktree

This commit is contained in:
Antonio Scandurra 2021-06-30 13:22:22 +02:00
parent ab089b6575
commit 7704291432
4 changed files with 98 additions and 13 deletions

View file

@ -16,7 +16,8 @@ message Envelope {
OpenBufferResponse open_buffer_response = 11; OpenBufferResponse open_buffer_response = 11;
CloseBuffer close_buffer = 12; CloseBuffer close_buffer = 12;
UpdateBuffer update_buffer = 13; UpdateBuffer update_buffer = 13;
RemoveGuest remove_guest = 14; AddGuest add_guest = 14;
RemoveGuest remove_guest = 15;
} }
} }
@ -45,19 +46,20 @@ message OpenWorktree {
message OpenWorktreeResponse { message OpenWorktreeResponse {
Worktree worktree = 1; Worktree worktree = 1;
optional uint32 replica_id = 2; uint32 replica_id = 2;
uint32 host_peer_id = 3;
} }
message AddGuest { message AddGuest {
uint64 worktree_id = 1; uint64 worktree_id = 1;
uint32 replica_id = 2; uint32 peer_id = 2;
User user = 3; uint32 replica_id = 3;
User user = 4;
} }
message RemoveGuest { message RemoveGuest {
uint64 worktree_id = 1; uint64 worktree_id = 1;
uint32 peer_id = 2; uint32 peer_id = 2;
uint32 replica_id = 3;
} }
message OpenBuffer { message OpenBuffer {

View file

@ -74,6 +74,7 @@ request_message!(OpenWorktree, OpenWorktreeResponse);
request_message!(OpenBuffer, OpenBufferResponse); request_message!(OpenBuffer, OpenBufferResponse);
message!(CloseBuffer); message!(CloseBuffer);
message!(UpdateBuffer); message!(UpdateBuffer);
message!(AddGuest);
message!(RemoveGuest); message!(RemoveGuest);
/// A stream of protobuf messages. /// A stream of protobuf messages.

View file

@ -1494,7 +1494,7 @@ impl Buffer {
self.operations.push(operation); self.operations.push(operation);
} }
pub fn peer_left(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) { pub fn remove_guest(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
self.selections self.selections
.retain(|set_id, _| set_id.replica_id != replica_id); .retain(|set_id, _| set_id.replica_id != replica_id);
cx.notify(); cx.notify();

View file

@ -37,6 +37,7 @@ use std::{
fmt, fs, fmt, fs,
future::Future, future::Future,
io, io,
iter::FromIterator,
ops::Deref, ops::Deref,
os::unix::fs::MetadataExt, os::unix::fs::MetadataExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -53,6 +54,7 @@ lazy_static! {
} }
pub fn init(cx: &mut MutableAppContext, rpc: rpc::Client) { pub fn init(cx: &mut MutableAppContext, rpc: rpc::Client) {
rpc.on_message(remote::add_guest, cx);
rpc.on_message(remote::remove_guest, cx); rpc.on_message(remote::remove_guest, cx);
rpc.on_message(remote::open_buffer, cx); rpc.on_message(remote::open_buffer, cx);
rpc.on_message(remote::close_buffer, cx); rpc.on_message(remote::close_buffer, cx);
@ -100,16 +102,16 @@ impl Worktree {
let worktree_message = open_worktree_response let worktree_message = open_worktree_response
.worktree .worktree
.ok_or_else(|| anyhow!("empty worktree"))?; .ok_or_else(|| anyhow!("empty worktree"))?;
let replica_id = open_worktree_response let replica_id = open_worktree_response.replica_id;
.replica_id let host_peer_id = PeerId(open_worktree_response.host_peer_id);
.ok_or_else(|| anyhow!("empty replica id"))?;
let worktree = cx.update(|cx| { let worktree = cx.update(|cx| {
cx.add_model(|cx| { cx.add_model(|cx| {
Worktree::Remote(RemoteWorktree::new( Worktree::Remote(RemoteWorktree::new(
id, id,
replica_id as ReplicaId,
host_peer_id,
worktree_message, worktree_message,
rpc.clone(), rpc.clone(),
replica_id as ReplicaId,
languages, languages,
cx, cx,
)) ))
@ -154,6 +156,17 @@ impl Worktree {
} }
} }
pub fn add_guest(
&mut self,
envelope: TypedEnvelope<proto::AddGuest>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
match self {
Worktree::Local(worktree) => worktree.add_guest(envelope, cx),
Worktree::Remote(worktree) => worktree.add_guest(envelope, cx),
}
}
pub fn remove_guest( pub fn remove_guest(
&mut self, &mut self,
envelope: TypedEnvelope<proto::RemoveGuest>, envelope: TypedEnvelope<proto::RemoveGuest>,
@ -161,7 +174,7 @@ impl Worktree {
) -> Result<()> { ) -> Result<()> {
match self { match self {
Worktree::Local(worktree) => worktree.remove_guest(envelope, cx), Worktree::Local(worktree) => worktree.remove_guest(envelope, cx),
Worktree::Remote(_) => todo!(), Worktree::Remote(worktree) => worktree.remove_guest(envelope, cx),
} }
} }
@ -261,6 +274,7 @@ pub struct LocalWorktree {
rpc: Option<(rpc::Client, u64)>, rpc: Option<(rpc::Client, u64)>,
open_buffers: HashMap<usize, WeakModelHandle<Buffer>>, open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>, shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
peers: HashMap<PeerId, ReplicaId>,
languages: Arc<LanguageRegistry>, languages: Arc<LanguageRegistry>,
} }
@ -298,6 +312,7 @@ impl LocalWorktree {
poll_scheduled: false, poll_scheduled: false,
open_buffers: Default::default(), open_buffers: Default::default(),
shared_buffers: Default::default(), shared_buffers: Default::default(),
peers: Default::default(),
rpc: None, rpc: None,
languages, languages,
}; };
@ -422,12 +437,34 @@ impl LocalWorktree {
Ok(()) Ok(())
} }
pub fn add_guest(
&mut self,
envelope: TypedEnvelope<proto::AddGuest>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
self.peers.insert(
PeerId(envelope.payload.peer_id),
envelope.payload.replica_id as ReplicaId,
);
Ok(())
}
pub fn remove_guest( pub fn remove_guest(
&mut self, &mut self,
envelope: TypedEnvelope<proto::RemoveGuest>, envelope: TypedEnvelope<proto::RemoveGuest>,
cx: &mut ModelContext<Worktree>, cx: &mut ModelContext<Worktree>,
) -> Result<()> { ) -> Result<()> {
self.shared_buffers.remove(&envelope.original_sender_id()?); let peer_id = PeerId(envelope.payload.peer_id);
let replica_id = self
.peers
.remove(&peer_id)
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?;
self.shared_buffers.remove(&peer_id);
for (_, buffer) in &self.open_buffers {
if let Some(buffer) = buffer.upgrade(&cx) {
buffer.update(cx, |buffer, cx| buffer.remove_guest(replica_id, cx));
}
}
Ok(()) Ok(())
} }
@ -715,15 +752,17 @@ pub struct RemoteWorktree {
rpc: rpc::Client, rpc: rpc::Client,
replica_id: ReplicaId, replica_id: ReplicaId,
open_buffers: HashMap<usize, WeakModelHandle<Buffer>>, open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
peers: HashMap<PeerId, ReplicaId>,
languages: Arc<LanguageRegistry>, languages: Arc<LanguageRegistry>,
} }
impl RemoteWorktree { impl RemoteWorktree {
fn new( fn new(
remote_id: u64, remote_id: u64,
replica_id: ReplicaId,
host_peer_id: PeerId,
worktree: proto::Worktree, worktree: proto::Worktree,
rpc: rpc::Client, rpc: rpc::Client,
replica_id: ReplicaId,
languages: Arc<LanguageRegistry>, languages: Arc<LanguageRegistry>,
cx: &mut ModelContext<Worktree>, cx: &mut ModelContext<Worktree>,
) -> Self { ) -> Self {
@ -779,6 +818,7 @@ impl RemoteWorktree {
rpc, rpc,
replica_id, replica_id,
open_buffers: Default::default(), open_buffers: Default::default(),
peers: HashMap::from_iter(Some((host_peer_id, 0))),
languages, languages,
} }
} }
@ -837,6 +877,36 @@ impl RemoteWorktree {
} }
}) })
} }
pub fn add_guest(
&mut self,
envelope: TypedEnvelope<proto::AddGuest>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
self.peers.insert(
PeerId(envelope.payload.peer_id),
envelope.payload.replica_id as ReplicaId,
);
Ok(())
}
pub fn remove_guest(
&mut self,
envelope: TypedEnvelope<proto::RemoveGuest>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
let peer_id = PeerId(envelope.payload.peer_id);
let replica_id = self
.peers
.remove(&peer_id)
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?;
for (_, buffer) in &self.open_buffers {
if let Some(buffer) = buffer.upgrade(&cx) {
buffer.update(cx, |buffer, cx| buffer.remove_guest(replica_id, cx));
}
}
Ok(())
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -1938,6 +2008,18 @@ impl<'a> Iterator for ChildEntriesIter<'a> {
mod remote { mod remote {
use super::*; use super::*;
pub async fn add_guest(
envelope: TypedEnvelope<proto::AddGuest>,
rpc: &rpc::Client,
cx: &mut AsyncAppContext,
) -> anyhow::Result<()> {
rpc.state
.lock()
.await
.shared_worktree(envelope.payload.worktree_id, cx)?
.update(cx, |worktree, cx| worktree.add_guest(envelope, cx))
}
pub async fn remove_guest( pub async fn remove_guest(
envelope: TypedEnvelope<proto::RemoveGuest>, envelope: TypedEnvelope<proto::RemoveGuest>,
rpc: &rpc::Client, rpc: &rpc::Client,