Subscribe to worktree messages at the entity level

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo
2021-08-18 19:06:46 -06:00
co-authored by Max Brunsfeld
parent ef421d735d
commit 37f24d10ec
7 changed files with 365 additions and 175 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ use sqlx::{
types::time::OffsetDateTime,
Executor as _, Postgres,
};
use std::{path::Path, sync::Arc, time::SystemTime};
use std::{path::Path, sync::Arc};
use zed::{
editor::Editor,
fs::{FakeFs, Fs as _},
+8 -13
View File
@@ -1,5 +1,5 @@
use crate::rpc::{self, Client};
use futures::StreamExt;
use anyhow::Result;
use gpui::{Entity, ModelContext, Task, WeakModelHandle};
use std::{
collections::{HashMap, VecDeque},
@@ -22,7 +22,7 @@ pub struct Channel {
first_message_id: Option<u64>,
messages: Option<VecDeque<ChannelMessage>>,
rpc: Arc<Client>,
_receive_messages: Task<()>,
_message_handler: Task<()>,
}
pub struct ChannelMessage {
@@ -50,28 +50,23 @@ impl Entity for Channel {
impl Channel {
pub fn new(details: ChannelDetails, rpc: Arc<Client>, cx: &mut ModelContext<Self>) -> Self {
let mut messages = rpc.subscribe();
let receive_messages = cx.spawn_weak(|this, mut cx| async move {
while let Some(message) = messages.next().await {
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| this.message_received(&message, cx));
}
}
});
let _message_handler = rpc.subscribe_from_model(details.id, cx, Self::handle_message_sent);
Self {
details,
rpc,
first_message_id: None,
messages: None,
_receive_messages: receive_messages,
_message_handler,
}
}
fn message_received(
fn handle_message_sent(
&mut self,
message: &TypedEnvelope<ChannelMessageSent>,
rpc: rpc::Client,
cx: &mut ModelContext<Self>,
) {
) -> Result<()> {
Ok(())
}
}
+29 -4
View File
@@ -2,14 +2,15 @@ use crate::{language::LanguageRegistry, worktree::Worktree};
use anyhow::{anyhow, Context, Result};
use async_tungstenite::tungstenite::http::Request;
use async_tungstenite::tungstenite::{Error as WebSocketError, Message as WebSocketMessage};
use futures::Stream;
use gpui::{AsyncAppContext, ModelHandle, Task, WeakModelHandle};
use futures::StreamExt;
use gpui::{AsyncAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle};
use lazy_static::lazy_static;
use smol::lock::RwLock;
use std::collections::HashMap;
use std::time::Duration;
use std::{convert::TryFrom, future::Future, sync::Arc};
use surf::Url;
use zrpc::proto::EntityMessage;
pub use zrpc::{proto, ConnectionId, PeerId, TypedEnvelope};
use zrpc::{
proto::{EnvelopedMessage, RequestMessage},
@@ -82,8 +83,32 @@ impl Client {
});
}
pub fn subscribe<T: EnvelopedMessage>(&self) -> impl Stream<Item = Arc<TypedEnvelope<T>>> {
self.peer.subscribe()
pub fn subscribe_from_model<T, M, F>(
&self,
remote_id: u64,
cx: &mut ModelContext<M>,
mut handler: F,
) -> Task<()>
where
T: EntityMessage,
M: Entity,
F: 'static + FnMut(&mut M, &TypedEnvelope<T>, Client, &mut ModelContext<M>) -> Result<()>,
{
let rpc = self.clone();
let mut incoming = self.peer.subscribe::<T>();
cx.spawn_weak(|model, mut cx| async move {
while let Some(envelope) = incoming.next().await {
if envelope.payload.remote_entity_id() == remote_id {
if let Some(model) = model.upgrade(&cx) {
model.update(&mut cx, |model, cx| {
if let Err(error) = handler(model, &envelope, rpc.clone(), cx) {
log::error!("error handling message: {}", error)
}
});
}
}
}
})
}
pub async fn log_in_and_connect(
+12
View File
@@ -1,3 +1,4 @@
use futures::Future;
use rand::prelude::*;
use std::cmp::Ordering;
@@ -81,6 +82,17 @@ impl<T: Rng> Iterator for RandomCharIter<T> {
}
}
pub async fn log_async_errors<F>(f: F) -> impl Future<Output = ()>
where
F: Future<Output = anyhow::Result<()>>,
{
async {
if let Err(error) = f.await {
log::error!("{}", error)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
+224 -71
View File
@@ -10,7 +10,7 @@ use crate::{
rpc::{self, proto},
sum_tree::{self, Cursor, Edit, SumTree},
time::{self, ReplicaId},
util::Bias,
util::{log_async_errors, Bias},
};
use ::ignore::gitignore::Gitignore;
use anyhow::{anyhow, Result};
@@ -76,7 +76,10 @@ impl Entity for Worktree {
fn release(&mut self, cx: &mut MutableAppContext) {
let rpc = match self {
Self::Local(tree) => tree.rpc.clone(),
Self::Local(tree) => tree
.share
.as_ref()
.map(|share| (share.rpc.clone(), share.remote_id)),
Self::Remote(tree) => Some((tree.rpc.clone(), tree.remote_id)),
};
@@ -226,6 +229,14 @@ impl Worktree {
.detach();
}
let _message_handlers = vec![
rpc.subscribe_from_model(remote_id, cx, Self::handle_add_peer),
rpc.subscribe_from_model(remote_id, cx, Self::handle_remove_peer),
rpc.subscribe_from_model(remote_id, cx, Self::handle_update),
rpc.subscribe_from_model(remote_id, cx, Self::handle_update_buffer),
rpc.subscribe_from_model(remote_id, cx, Self::handle_buffer_saved),
];
Worktree::Remote(RemoteWorktree {
remote_id,
replica_id,
@@ -239,6 +250,7 @@ impl Worktree {
.map(|p| (PeerId(p.peer_id), p.replica_id as ReplicaId))
.collect(),
languages,
_message_handlers,
})
})
});
@@ -289,10 +301,11 @@ impl Worktree {
}
}
pub fn add_peer(
pub fn handle_add_peer(
&mut self,
envelope: TypedEnvelope<proto::AddPeer>,
cx: &mut ModelContext<Worktree>,
envelope: &TypedEnvelope<proto::AddPeer>,
_: rpc::Client,
cx: &mut ModelContext<Self>,
) -> Result<()> {
match self {
Worktree::Local(worktree) => worktree.add_peer(envelope, cx),
@@ -300,10 +313,11 @@ impl Worktree {
}
}
pub fn remove_peer(
pub fn handle_remove_peer(
&mut self,
envelope: TypedEnvelope<proto::RemovePeer>,
cx: &mut ModelContext<Worktree>,
envelope: &TypedEnvelope<proto::RemovePeer>,
_: rpc::Client,
cx: &mut ModelContext<Self>,
) -> Result<()> {
match self {
Worktree::Local(worktree) => worktree.remove_peer(envelope, cx),
@@ -311,6 +325,51 @@ impl Worktree {
}
}
pub fn handle_update(
&mut self,
envelope: &TypedEnvelope<proto::UpdateWorktree>,
_: rpc::Client,
cx: &mut ModelContext<Self>,
) -> anyhow::Result<()> {
self.as_remote_mut()
.unwrap()
.update_from_remote(envelope, cx)
}
pub fn handle_open_buffer(
&mut self,
envelope: &TypedEnvelope<proto::OpenBuffer>,
rpc: rpc::Client,
cx: &mut ModelContext<Self>,
) -> anyhow::Result<()> {
let receipt = envelope.receipt();
let response = self
.as_local_mut()
.unwrap()
.open_remote_buffer(envelope, cx);
cx.background()
.spawn(log_async_errors(async move {
rpc.respond(receipt, response.await?).await?;
Ok(())
}))
.detach();
Ok(())
}
pub fn handle_close_buffer(
&mut self,
envelope: &TypedEnvelope<proto::CloseBuffer>,
_: rpc::Client,
cx: &mut ModelContext<Self>,
) -> anyhow::Result<()> {
self.as_local_mut()
.unwrap()
.close_remote_buffer(envelope, cx)
}
pub fn peers(&self) -> &HashMap<PeerId, ReplicaId> {
match self {
Worktree::Local(worktree) => &worktree.peers,
@@ -356,13 +415,15 @@ impl Worktree {
.is_some()
}
pub fn update_buffer(
pub fn handle_update_buffer(
&mut self,
envelope: proto::UpdateBuffer,
envelope: &TypedEnvelope<proto::UpdateBuffer>,
_: rpc::Client,
cx: &mut ModelContext<Self>,
) -> Result<()> {
let buffer_id = envelope.buffer_id as usize;
let ops = envelope
let payload = envelope.payload.clone();
let buffer_id = payload.buffer_id as usize;
let ops = payload
.operations
.into_iter()
.map(|op| op.try_into())
@@ -401,34 +462,72 @@ impl Worktree {
Ok(())
}
pub fn buffer_saved(
pub fn handle_save_buffer(
&mut self,
message: proto::BufferSaved,
envelope: &TypedEnvelope<proto::SaveBuffer>,
rpc: rpc::Client,
cx: &mut ModelContext<Self>,
) -> Result<()> {
if let Worktree::Remote(worktree) = self {
if let Some(buffer) = worktree
.open_buffers
.get(&(message.buffer_id as usize))
.and_then(|buf| buf.upgrade(cx))
{
buffer.update(cx, |buffer, cx| {
let version = message.version.try_into()?;
let mtime = message
.mtime
.ok_or_else(|| anyhow!("missing mtime"))?
.into();
buffer.did_save(version, mtime, cx);
Result::<_, anyhow::Error>::Ok(())
})?;
}
Ok(())
} else {
Err(anyhow!(
"invalid buffer {} in buffer saved message",
message.buffer_id
))
let sender_id = envelope.original_sender_id()?;
let buffer = self
.as_local()
.unwrap()
.shared_buffers
.get(&sender_id)
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
let receipt = envelope.receipt();
let worktree_id = envelope.payload.worktree_id;
let buffer_id = envelope.payload.buffer_id;
let save = buffer.update(cx, |buffer, cx| buffer.save(cx))?;
cx.background()
.spawn(log_async_errors(async move {
let (version, mtime) = save.await?;
rpc.respond(
receipt,
proto::BufferSaved {
worktree_id,
buffer_id,
version: (&version).into(),
mtime: Some(mtime.into()),
},
)
.await?;
Ok(())
}))
.detach();
Ok(())
}
pub fn handle_buffer_saved(
&mut self,
envelope: &TypedEnvelope<proto::BufferSaved>,
_: rpc::Client,
cx: &mut ModelContext<Self>,
) -> Result<()> {
let payload = envelope.payload.clone();
let worktree = self.as_remote_mut().unwrap();
if let Some(buffer) = worktree
.open_buffers
.get(&(payload.buffer_id as usize))
.and_then(|buf| buf.upgrade(cx))
{
buffer.update(cx, |buffer, cx| {
let version = payload.version.try_into()?;
let mtime = payload
.mtime
.ok_or_else(|| anyhow!("missing mtime"))?
.into();
buffer.did_save(version, mtime, cx);
Result::<_, anyhow::Error>::Ok(())
})?;
}
Ok(())
}
fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
@@ -561,11 +660,10 @@ impl Deref for Worktree {
pub struct LocalWorktree {
snapshot: Snapshot,
background_snapshot: Arc<Mutex<Snapshot>>,
snapshots_to_send_tx: Option<Sender<Snapshot>>,
last_scan_state_rx: watch::Receiver<ScanState>,
_background_scanner_task: Option<Task<()>>,
poll_task: Option<Task<()>>,
rpc: Option<(rpc::Client, u64)>,
share: Option<ShareState>,
open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
peers: HashMap<PeerId, ReplicaId>,
@@ -619,14 +717,13 @@ impl LocalWorktree {
let tree = Self {
snapshot: snapshot.clone(),
background_snapshot: Arc::new(Mutex::new(snapshot)),
snapshots_to_send_tx: None,
last_scan_state_rx,
_background_scanner_task: None,
share: None,
poll_task: None,
open_buffers: Default::default(),
shared_buffers: Default::default(),
peers: Default::default(),
rpc: None,
languages,
fs,
};
@@ -639,10 +736,8 @@ impl LocalWorktree {
this.poll_snapshot(cx);
let tree = this.as_local_mut().unwrap();
if !tree.is_scanning() {
if let Some(snapshots_to_send_tx) =
tree.snapshots_to_send_tx.clone()
{
Some((tree.snapshot(), snapshots_to_send_tx))
if let Some(share) = tree.share.as_ref() {
Some((tree.snapshot(), share.snapshots_tx.clone()))
} else {
None
}
@@ -717,7 +812,7 @@ impl LocalWorktree {
pub fn open_remote_buffer(
&mut self,
envelope: TypedEnvelope<proto::OpenBuffer>,
envelope: &TypedEnvelope<proto::OpenBuffer>,
cx: &mut ModelContext<Worktree>,
) -> Task<Result<proto::OpenBufferResponse>> {
let peer_id = envelope.original_sender_id();
@@ -744,7 +839,7 @@ impl LocalWorktree {
pub fn close_remote_buffer(
&mut self,
envelope: TypedEnvelope<proto::CloseBuffer>,
envelope: &TypedEnvelope<proto::CloseBuffer>,
_: &mut ModelContext<Worktree>,
) -> Result<()> {
if let Some(shared_buffers) = self.shared_buffers.get_mut(&envelope.original_sender_id()?) {
@@ -756,19 +851,24 @@ impl LocalWorktree {
pub fn add_peer(
&mut self,
envelope: TypedEnvelope<proto::AddPeer>,
envelope: &TypedEnvelope<proto::AddPeer>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
let peer = envelope.payload.peer.ok_or_else(|| anyhow!("empty peer"))?;
let peer = envelope
.payload
.peer
.as_ref()
.ok_or_else(|| anyhow!("empty peer"))?;
self.peers
.insert(PeerId(peer.peer_id), peer.replica_id as ReplicaId);
cx.notify();
Ok(())
}
pub fn remove_peer(
&mut self,
envelope: TypedEnvelope<proto::RemovePeer>,
envelope: &TypedEnvelope<proto::RemovePeer>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
let peer_id = PeerId(envelope.payload.peer_id);
@@ -783,6 +883,7 @@ impl LocalWorktree {
}
}
cx.notify();
Ok(())
}
@@ -892,6 +993,7 @@ impl LocalWorktree {
cx.spawn(|this, mut cx| async move {
let share_request = share_request.await;
let share_response = rpc.request(share_request).await?;
let remote_id = share_response.worktree_id;
rpc.state
.write()
@@ -906,11 +1008,10 @@ impl LocalWorktree {
cx.background()
.spawn({
let rpc = rpc.clone();
let worktree_id = share_response.worktree_id;
async move {
let mut prev_snapshot = snapshot;
while let Ok(snapshot) = snapshots_to_send_rx.recv().await {
let message = snapshot.build_update(&prev_snapshot, worktree_id);
let message = snapshot.build_update(&prev_snapshot, remote_id);
match rpc.send(message).await {
Ok(()) => prev_snapshot = snapshot,
Err(err) => log::error!("error sending snapshot diff {}", err),
@@ -920,13 +1021,26 @@ impl LocalWorktree {
})
.detach();
this.update(&mut cx, |worktree, _| {
this.update(&mut cx, |worktree, cx| {
let _message_handlers = vec![
rpc.subscribe_from_model(remote_id, cx, Worktree::handle_add_peer),
rpc.subscribe_from_model(remote_id, cx, Worktree::handle_remove_peer),
rpc.subscribe_from_model(remote_id, cx, Worktree::handle_open_buffer),
rpc.subscribe_from_model(remote_id, cx, Worktree::handle_close_buffer),
rpc.subscribe_from_model(remote_id, cx, Worktree::handle_update_buffer),
rpc.subscribe_from_model(remote_id, cx, Worktree::handle_save_buffer),
];
let worktree = worktree.as_local_mut().unwrap();
worktree.rpc = Some((rpc, share_response.worktree_id));
worktree.snapshots_to_send_tx = Some(snapshots_to_send_tx);
worktree.share = Some(ShareState {
rpc,
remote_id: share_response.worktree_id,
snapshots_tx: snapshots_to_send_tx,
_message_handlers,
});
});
Ok((share_response.worktree_id, share_response.access_token))
Ok((remote_id, share_response.access_token))
})
}
@@ -978,6 +1092,13 @@ impl fmt::Debug for LocalWorktree {
}
}
struct ShareState {
rpc: rpc::Client,
remote_id: u64,
snapshots_tx: Sender<Snapshot>,
_message_handlers: Vec<Task<()>>,
}
pub struct RemoteWorktree {
remote_id: u64,
snapshot: Snapshot,
@@ -988,6 +1109,7 @@ pub struct RemoteWorktree {
open_buffers: HashMap<usize, RemoteBuffer>,
peers: HashMap<PeerId, ReplicaId>,
languages: Arc<LanguageRegistry>,
_message_handlers: Vec<Task<()>>,
}
impl RemoteWorktree {
@@ -1055,12 +1177,32 @@ impl RemoteWorktree {
self.snapshot.clone()
}
pub fn add_peer(
fn update_from_remote(
&mut self,
envelope: TypedEnvelope<proto::AddPeer>,
envelope: &TypedEnvelope<proto::UpdateWorktree>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
let peer = envelope.payload.peer.ok_or_else(|| anyhow!("empty peer"))?;
let mut tx = self.updates_tx.clone();
let payload = envelope.payload.clone();
cx.background()
.spawn(async move {
tx.send(payload).await.expect("receiver runs to completion");
})
.detach();
Ok(())
}
pub fn add_peer(
&mut self,
envelope: &TypedEnvelope<proto::AddPeer>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
let peer = envelope
.payload
.peer
.as_ref()
.ok_or_else(|| anyhow!("empty peer"))?;
self.peers
.insert(PeerId(peer.peer_id), peer.replica_id as ReplicaId);
cx.notify();
@@ -1069,7 +1211,7 @@ impl RemoteWorktree {
pub fn remove_peer(
&mut self,
envelope: TypedEnvelope<proto::RemovePeer>,
envelope: &TypedEnvelope<proto::RemovePeer>,
cx: &mut ModelContext<Worktree>,
) -> Result<()> {
let peer_id = PeerId(envelope.payload.peer_id);
@@ -1420,7 +1562,10 @@ impl File {
pub fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext) {
self.worktree.update(cx, |worktree, cx| {
if let Some((rpc, remote_id)) = match worktree {
Worktree::Local(worktree) => worktree.rpc.clone(),
Worktree::Local(worktree) => worktree
.share
.as_ref()
.map(|share| (share.rpc.clone(), share.remote_id)),
Worktree::Remote(worktree) => Some((worktree.rpc.clone(), worktree.remote_id)),
} {
cx.spawn(|_, _| async move {
@@ -1497,9 +1642,12 @@ impl File {
) -> Task<Result<(time::Global, SystemTime)>> {
self.worktree.update(cx, |worktree, cx| match worktree {
Worktree::Local(worktree) => {
let rpc = worktree.rpc.clone();
let rpc = worktree
.share
.as_ref()
.map(|share| (share.rpc.clone(), share.remote_id));
let save = worktree.save(self.path.clone(), text, cx);
cx.spawn(|_, _| async move {
cx.background().spawn(async move {
let entry = save.await?;
if let Some((rpc, worktree_id)) = rpc {
rpc.send(proto::BufferSaved {
@@ -1516,7 +1664,7 @@ impl File {
Worktree::Remote(worktree) => {
let rpc = worktree.rpc.clone();
let worktree_id = worktree.remote_id;
cx.spawn(|_, _| async move {
cx.background().spawn(async move {
let response = rpc
.request(proto::SaveBuffer {
worktree_id,
@@ -2395,7 +2543,9 @@ mod remote {
.read()
.await
.shared_worktree(envelope.payload.worktree_id, cx)?
.update(cx, |worktree, cx| worktree.add_peer(envelope, cx))
.update(cx, |worktree, cx| {
worktree.handle_add_peer(&envelope, rpc.clone(), cx)
})
}
pub async fn remove_peer(
@@ -2407,7 +2557,9 @@ mod remote {
.read()
.await
.shared_worktree(envelope.payload.worktree_id, cx)?
.update(cx, |worktree, cx| worktree.remove_peer(envelope, cx))
.update(cx, |worktree, cx| {
worktree.handle_remove_peer(&envelope, rpc.clone(), cx)
})
}
pub async fn update_worktree(
@@ -2456,7 +2608,7 @@ mod remote {
worktree
.as_local_mut()
.unwrap()
.open_remote_buffer(envelope, cx)
.open_remote_buffer(&envelope, cx)
})
.await?;
@@ -2480,7 +2632,7 @@ mod remote {
worktree
.as_local_mut()
.unwrap()
.close_remote_buffer(envelope, cx)
.close_remote_buffer(&envelope, cx)
})
}
@@ -2489,12 +2641,13 @@ mod remote {
rpc: &rpc::Client,
cx: &mut AsyncAppContext,
) -> anyhow::Result<()> {
let message = envelope.payload;
rpc.state
.read()
.await
.shared_worktree(message.worktree_id, cx)?
.update(cx, |tree, cx| tree.update_buffer(message, cx))?;
.shared_worktree(envelope.payload.worktree_id, cx)?
.update(cx, |tree, cx| {
tree.handle_update_buffer(&envelope, rpc.clone(), cx)
})?;
Ok(())
}
@@ -2538,7 +2691,7 @@ mod remote {
.await
.shared_worktree(envelope.payload.worktree_id, cx)?
.update(cx, |worktree, cx| {
worktree.buffer_saved(envelope.payload, cx)
worktree.handle_buffer_saved(&envelope, rpc.clone(), cx)
})?;
Ok(())
}
+4 -5
View File
@@ -171,11 +171,10 @@ impl Peer {
}
} else {
router.handle(connection_id, envelope.clone()).await;
match proto::build_typed_envelope(connection_id, envelope) {
Ok(envelope) => {
broadcast_incoming_messages.send(envelope).await.ok();
}
Err(error) => log::error!("{}", error),
if let Some(envelope) = proto::build_typed_envelope(connection_id, envelope) {
broadcast_incoming_messages.send(envelope).await.ok();
} else {
log::error!("unable to construct a typed envelope");
}
}
}
+87 -81
View File
@@ -1,5 +1,5 @@
use super::{ConnectionId, PeerId, TypedEnvelope};
use anyhow::{anyhow, Result};
use anyhow::Result;
use async_tungstenite::tungstenite::{Error as WebSocketError, Message as WebSocketMessage};
use futures::{SinkExt as _, StreamExt as _};
use prost::Message;
@@ -24,127 +24,133 @@ pub trait EnvelopedMessage: Clone + Sized + Send + Sync + 'static {
fn from_envelope(envelope: Envelope) -> Option<Self>;
}
pub trait EntityMessage: EnvelopedMessage {
fn remote_entity_id(&self) -> u64;
}
pub trait RequestMessage: EnvelopedMessage {
type Response: EnvelopedMessage;
}
macro_rules! messages {
($($name:ident),*) => {
fn unicast_message_into_typed_envelope(sender_id: ConnectionId, envelope: &mut Envelope) -> Option<Arc<dyn Any + Send + Sync>> {
match &mut envelope.payload {
$(payload @ Some(envelope::Payload::$name(_)) => Some(Arc::new(TypedEnvelope {
($($name:ident),* $(,)?) => {
pub fn build_typed_envelope(sender_id: ConnectionId, envelope: Envelope) -> Option<Arc<dyn Any + Send + Sync>> {
match envelope.payload {
$(Some(envelope::Payload::$name(payload)) => Some(Arc::new(TypedEnvelope {
sender_id,
original_sender_id: envelope.original_sender_id.map(PeerId),
message_id: envelope.id,
payload: payload.take().unwrap(),
payload,
})), )*
_ => None
}
}
$(
message!($name);
impl EnvelopedMessage for $name {
const NAME: &'static str = std::stringify!($name);
fn into_envelope(
self,
id: u32,
responding_to: Option<u32>,
original_sender_id: Option<u32>,
) -> Envelope {
Envelope {
id,
responding_to,
original_sender_id,
payload: Some(envelope::Payload::$name(self)),
}
}
fn matches_envelope(envelope: &Envelope) -> bool {
matches!(&envelope.payload, Some(envelope::Payload::$name(_)))
}
fn from_envelope(envelope: Envelope) -> Option<Self> {
if let Some(envelope::Payload::$name(msg)) = envelope.payload {
Some(msg)
} else {
None
}
}
}
)*
};
}
macro_rules! request_messages {
($(($request_name:ident, $response_name:ident)),*) => {
fn request_message_into_typed_envelope(sender_id: ConnectionId, envelope: Envelope) -> Option<Arc<dyn Any + Send + Sync>> {
match envelope.payload {
$(
Some(envelope::Payload::$request_name(payload)) => Some(Arc::new(TypedEnvelope {
sender_id,
original_sender_id: envelope.original_sender_id.map(PeerId),
message_id: envelope.id,
payload,
})),
Some(envelope::Payload::$response_name(payload)) => Some(Arc::new(TypedEnvelope {
sender_id,
original_sender_id: envelope.original_sender_id.map(PeerId),
message_id: envelope.id,
payload,
})),
)*
_ => None
}
}
$(
message!($request_name);
message!($response_name);
)*
($(($request_name:ident, $response_name:ident)),* $(,)?) => {
$(impl RequestMessage for $request_name {
type Response = $response_name;
})*
};
}
macro_rules! message {
($name:ident) => {
impl EnvelopedMessage for $name {
const NAME: &'static str = std::stringify!($name);
fn into_envelope(
self,
id: u32,
responding_to: Option<u32>,
original_sender_id: Option<u32>,
) -> Envelope {
Envelope {
id,
responding_to,
original_sender_id,
payload: Some(envelope::Payload::$name(self)),
}
macro_rules! entity_messages {
($id_field:ident, $($name:ident),* $(,)?) => {
$(impl EntityMessage for $name {
fn remote_entity_id(&self) -> u64 {
self.$id_field
}
fn matches_envelope(envelope: &Envelope) -> bool {
matches!(&envelope.payload, Some(envelope::Payload::$name(_)))
}
fn from_envelope(envelope: Envelope) -> Option<Self> {
if let Some(envelope::Payload::$name(msg)) = envelope.payload {
Some(msg)
} else {
None
}
}
}
})*
};
}
messages!(
UpdateWorktree,
CloseWorktree,
CloseBuffer,
UpdateBuffer,
AddPeer,
Auth,
AuthResponse,
BufferSaved,
ChannelMessageSent,
CloseBuffer,
CloseWorktree,
GetChannels,
GetChannelsResponse,
GetUsers,
GetUsersResponse,
JoinChannel,
JoinChannelResponse,
OpenBuffer,
OpenBufferResponse,
OpenWorktree,
OpenWorktreeResponse,
RemovePeer,
SaveBuffer,
SendChannelMessage,
ChannelMessageSent
ShareWorktree,
ShareWorktreeResponse,
UpdateBuffer,
UpdateWorktree,
);
request_messages!(
(Auth, AuthResponse),
(ShareWorktree, ShareWorktreeResponse),
(OpenWorktree, OpenWorktreeResponse),
(OpenBuffer, OpenBufferResponse),
(SaveBuffer, BufferSaved),
(GetChannels, GetChannelsResponse),
(GetUsers, GetUsersResponse),
(JoinChannel, JoinChannelResponse),
(GetUsers, GetUsersResponse)
(OpenBuffer, OpenBufferResponse),
(OpenWorktree, OpenWorktreeResponse),
(SaveBuffer, BufferSaved),
(ShareWorktree, ShareWorktreeResponse),
);
pub fn build_typed_envelope(
sender_id: ConnectionId,
mut envelope: Envelope,
) -> Result<Arc<dyn Any + Send + Sync>> {
unicast_message_into_typed_envelope(sender_id, &mut envelope)
.or_else(|| request_message_into_typed_envelope(sender_id, envelope))
.ok_or_else(|| anyhow!("unrecognized payload type"))
}
entity_messages!(
worktree_id,
AddPeer,
BufferSaved,
CloseBuffer,
CloseWorktree,
OpenBuffer,
OpenWorktree,
RemovePeer,
SaveBuffer,
UpdateBuffer,
UpdateWorktree,
);
entity_messages!(channel_id, ChannelMessageSent);
/// A stream of protobuf messages.
pub struct MessageStream<S> {