Avoid infinite loop when collaborators follow each other

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
Max Brunsfeld 2022-03-21 11:47:00 -07:00
parent 13a2dacc60
commit 3e0bc979c3
4 changed files with 186 additions and 50 deletions

View file

@ -264,10 +264,10 @@ pub trait FollowableItem: Item {
&self,
event: &Self::Event,
cx: &AppContext,
) -> Option<proto::update_followers::update_view::Variant>;
) -> Option<proto::update_view::Variant>;
fn apply_update_message(
&mut self,
message: proto::update_followers::update_view::Variant,
message: proto::update_view::Variant,
cx: &mut ViewContext<Self>,
) -> Result<()>;
}
@ -279,10 +279,10 @@ pub trait FollowableItemHandle: ItemHandle {
&self,
event: &dyn Any,
cx: &AppContext,
) -> Option<proto::update_followers::update_view::Variant>;
) -> Option<proto::update_view::Variant>;
fn apply_update_message(
&self,
message: proto::update_followers::update_view::Variant,
message: proto::update_view::Variant,
cx: &mut MutableAppContext,
) -> Result<()>;
}
@ -300,13 +300,13 @@ impl<T: FollowableItem> FollowableItemHandle for ViewHandle<T> {
&self,
event: &dyn Any,
cx: &AppContext,
) -> Option<proto::update_followers::update_view::Variant> {
) -> Option<proto::update_view::Variant> {
self.read(cx).to_update_message(event.downcast_ref()?, cx)
}
fn apply_update_message(
&self,
message: proto::update_followers::update_view::Variant,
message: proto::update_view::Variant,
cx: &mut MutableAppContext,
) -> Result<()> {
self.update(cx, |this, cx| this.apply_update_message(message, cx))
@ -403,6 +403,7 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
proto::update_followers::Variant::CreateView(proto::View {
id: followed_item.id() as u64,
variant: Some(message),
leader_id: workspace.leader_for_pane(&pane).map(|id| id.0),
}),
cx,
);
@ -441,12 +442,11 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
.and_then(|i| i.to_update_message(event, cx))
{
workspace.update_followers(
proto::update_followers::Variant::UpdateView(
proto::update_followers::UpdateView {
id: item.id() as u64,
variant: Some(message),
},
),
proto::update_followers::Variant::UpdateView(proto::UpdateView {
id: item.id() as u64,
variant: Some(message),
leader_id: workspace.leader_for_pane(&pane).map(|id| id.0),
}),
cx,
);
}
@ -628,7 +628,7 @@ struct FollowerState {
#[derive(Debug)]
enum FollowerItem {
Loading(Vec<proto::update_followers::update_view::Variant>),
Loading(Vec<proto::update_view::Variant>),
Loaded(Box<dyn FollowableItemHandle>),
}
@ -1110,7 +1110,7 @@ impl Workspace {
fn activate_pane(&mut self, pane: ViewHandle<Pane>, cx: &mut ViewContext<Self>) {
if self.active_pane != pane {
self.active_pane = pane;
self.active_pane = pane.clone();
self.status_bar.update(cx, |status_bar, cx| {
status_bar.set_active_pane(&self.active_pane, cx);
});
@ -1119,11 +1119,10 @@ impl Workspace {
}
self.update_followers(
proto::update_followers::Variant::UpdateActiveView(
proto::update_followers::UpdateActiveView {
id: self.active_item(cx).map(|item| item.id() as u64),
},
),
proto::update_followers::Variant::UpdateActiveView(proto::UpdateActiveView {
id: self.active_item(cx).map(|item| item.id() as u64),
leader_id: self.leader_for_pane(&pane).map(|id| id.0),
}),
cx,
);
}
@ -1520,14 +1519,22 @@ impl Workspace {
Ok(proto::FollowResponse {
active_view_id,
views: this
.items(cx)
.filter_map(|item| {
let id = item.id() as u64;
let item = item.to_followable_item_handle(cx)?;
let variant = item.to_state_message(cx)?;
Some(proto::View {
id,
variant: Some(variant),
.panes()
.iter()
.flat_map(|pane| {
let leader_id = this.leader_for_pane(pane).map(|id| id.0);
pane.read(cx).items().filter_map({
let cx = &cx;
move |item| {
let id = item.id() as u64;
let item = item.to_followable_item_handle(cx)?;
let variant = item.to_state_message(cx)?;
Some(proto::View {
id,
leader_id,
variant: Some(variant),
})
}
})
})
.collect(),
@ -1705,6 +1712,18 @@ impl Workspace {
None
}
fn leader_for_pane(&self, pane: &ViewHandle<Pane>) -> Option<PeerId> {
self.follower_states_by_leader
.iter()
.find_map(|(leader_id, state)| {
if state.contains_key(pane) {
Some(*leader_id)
} else {
None
}
})
}
fn update_leader_state(
&mut self,
leader_id: PeerId,