Restructure RPC state to also keep track of remote worktrees on guests

This commit is contained in:
Antonio Scandurra
2021-06-28 15:35:36 +02:00
parent e72b4ae03d
commit 65aa9733d7
6 changed files with 133 additions and 40 deletions
+98 -35
View File
@@ -47,6 +47,7 @@ pub fn init(cx: &mut MutableAppContext, rpc: rpc::Client) {
rpc.on_message(remote::open_buffer, cx);
rpc.on_message(remote::close_buffer, cx);
rpc.on_message(remote::update_buffer, cx);
rpc.on_message(remote::remove_guest, cx);
}
#[derive(Clone, Debug)]
@@ -88,17 +89,23 @@ impl Worktree {
let replica_id = open_worktree_response
.replica_id
.ok_or_else(|| anyhow!("empty replica id"))?;
Ok(cx.update(|cx| {
let worktree = cx.update(|cx| {
cx.add_model(|cx| {
Worktree::Remote(RemoteWorktree::new(
id,
worktree_message,
rpc,
rpc.clone(),
replica_id as ReplicaId,
cx,
))
})
}))
});
rpc.state
.lock()
.await
.remote_worktrees
.insert(id, worktree.downgrade());
Ok(worktree)
}
pub fn as_local(&self) -> Option<&LocalWorktree> {
@@ -165,6 +172,30 @@ impl Worktree {
.is_some()
}
pub fn buffer(&self, id: u64, cx: &AppContext) -> Option<ModelHandle<Buffer>> {
let open_buffers = match self {
Worktree::Local(worktree) => &worktree.open_buffers,
Worktree::Remote(worktree) => &worktree.open_buffers,
};
open_buffers
.get(&(id as usize))
.and_then(|buffer| buffer.upgrade(cx))
}
pub fn buffers<'a>(
&'a self,
cx: &'a AppContext,
) -> impl 'a + Iterator<Item = ModelHandle<Buffer>> {
let open_buffers = match self {
Worktree::Local(worktree) => &worktree.open_buffers,
Worktree::Remote(worktree) => &worktree.open_buffers,
};
open_buffers
.values()
.filter_map(move |buffer| buffer.upgrade(cx))
}
pub fn save(
&self,
path: &Path,
@@ -520,8 +551,8 @@ impl LocalWorktree {
rpc.state
.lock()
.await
.shared_worktrees
.insert(share_response.worktree_id, handle);
.remote_worktrees
.insert(share_response.worktree_id, handle.downgrade());
log::info!("sharing worktree {:?}", share_response);
@@ -1784,10 +1815,9 @@ impl<'a> Iterator for ChildEntriesIter<'a> {
}
mod remote {
use std::convert::TryInto;
use super::*;
use crate::rpc::TypedEnvelope;
use std::convert::TryInto;
pub async fn open_buffer(
envelope: TypedEnvelope<proto::OpenBuffer>,
@@ -1801,8 +1831,9 @@ mod remote {
let mut state = rpc.state.lock().await;
let worktree = state
.shared_worktrees
.remote_worktrees
.get(&message.worktree_id)
.and_then(|worktree| cx.read(|cx| worktree.upgrade(cx)))
.ok_or_else(|| anyhow!("worktree {} not found", message.worktree_id))?
.clone();
@@ -1853,36 +1884,68 @@ mod remote {
rpc: &rpc::Client,
cx: &mut AsyncAppContext,
) -> anyhow::Result<()> {
let peer_id = envelope
.original_sender_id
.ok_or_else(|| anyhow!("missing original sender id"))?;
let message = envelope.payload;
if let Some(buffer) = rpc
.state
.lock()
.await
.shared_buffers
.get(&peer_id)
.and_then(|buffers| buffers.get(&message.buffer_id))
.cloned()
{
if let Err(error) = buffer.update(cx, |buffer, cx| {
let ops = message
.operations
.into_iter()
.map(|op| op.try_into())
.collect::<anyhow::Result<Vec<_>>>()?;
buffer.apply_ops(ops, cx)?;
Ok::<(), anyhow::Error>(())
}) {
log::error!("error applying buffer operations {}", error);
let mut state = rpc.state.lock().await;
match state.remote_worktree(message.worktree_id, cx) {
Ok(worktree) => {
if let Some(buffer) =
worktree.read_with(cx, |w, cx| w.buffer(message.buffer_id, cx))
{
if let Err(error) = buffer.update(cx, |buffer, cx| {
let ops = message
.operations
.into_iter()
.map(|op| op.try_into())
.collect::<anyhow::Result<Vec<_>>>()?;
buffer.apply_ops(ops, cx)?;
Ok::<(), anyhow::Error>(())
}) {
log::error!("error applying buffer operations {}", error);
}
} else {
log::error!(
"invalid buffer {} in update buffer message",
message.buffer_id
);
}
}
} else {
log::error!(
"invalid buffer {} in update buffer message",
message.buffer_id
);
Err(error) => log::error!("{}", error),
}
Ok(())
}
pub async fn remove_guest(
envelope: TypedEnvelope<proto::RemoveGuest>,
rpc: &rpc::Client,
cx: &mut AsyncAppContext,
) -> anyhow::Result<()> {
let peer_id = envelope.original_sender_id.unwrap();
let message = envelope.payload;
let mut state = rpc.state.lock().await;
match state.remote_worktree(message.worktree_id, cx) {
Ok(worktree) => {
let mut peer_buffers = state.shared_buffers.get_mut(&peer_id);
let buffers =
worktree.read_with(cx, |worktree, cx| worktree.buffers(cx).collect::<Vec<_>>());
for buffer in buffers {
buffer.update(cx, |buffer, cx| {
buffer.peer_left(message.replica_id as ReplicaId, cx);
if let Some(peer_buffers) = &mut peer_buffers {
peer_buffers.remove(&buffer.remote_id());
}
});
}
if let Some(peer_buffers) = peer_buffers {
if peer_buffers.is_empty() {
state.shared_buffers.remove(&peer_id);
}
}
}
Err(error) => log::error!("{}", error),
}
Ok(())
}
}