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
+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> {