use super::*;
impl ProtocolEngine {
pub fn hold_pending_direct_sends(&mut self, peer: PublicKey, hold: bool) {
if hold {
self.held_direct_chats.insert(peer.to_hex());
} else {
self.held_direct_chats.remove(&peer.to_hex());
}
}
pub fn retire_pending_direct_sends(
&mut self,
peer: PublicKey,
through: Option<u64>,
) -> anyhow::Result<usize> {
let chat_id = peer.to_hex();
self.with_state_checkpoint(|engine| {
let before = engine.pending_remote_sends.len()
+ engine.pending_local_sibling_sends.len()
+ engine.ready_group_publications.len()
+ engine.pending_group_fanouts.len();
let fanouts_before = engine.pending_group_fanouts.len();
engine.pending_group_fanouts.retain(|pending| {
let GroupPendingFanout::Remote {
recipient_owner,
payload,
} = pending.fanout.as_ref()
else {
return true;
};
*recipient_owner != ndr_owner(peer)
|| !serde_json::from_slice::<UnsignedEvent>(payload)
.is_ok_and(|event| event.kind.as_u16() == 21_113)
|| through.is_some_and(|cutoff| {
pending_direct_authored_at(payload, pending.created_at_secs) > cutoff
})
});
if engine.pending_group_fanouts.len() != fanouts_before {
engine.invalidate_pending_group_fanout_retry_deadline();
}
engine.ready_group_publications.retain(|_, pending| {
pending.wake_recipient != Some(ndr_owner(peer))
|| through.is_some_and(|cutoff| {
pending
.publish
.authored_at_secs
.unwrap_or(pending.publish.event.created_at.as_secs())
> cutoff
})
});
engine.pending_remote_sends.retain(|pending| {
pending.recipient_owner != ndr_owner(peer)
|| pending.chat_id != chat_id
|| through.is_some_and(|cutoff| {
pending_direct_authored_at(&pending.payload, pending.created_at_secs)
> cutoff
})
});
engine.pending_local_sibling_sends.retain(|pending| {
pending.chat_id != chat_id
|| through.is_some_and(|cutoff| {
decode_local_sibling_payload(&pending.payload).map_or(
pending.created_at_secs,
|(_, _, payload)| {
pending_direct_authored_at(&payload, pending.created_at_secs)
},
) > cutoff
})
});
let retired = before
- engine.pending_remote_sends.len()
- engine.pending_local_sibling_sends.len()
- engine.ready_group_publications.len()
- engine.pending_group_fanouts.len();
if retired > 0 {
engine.persist_now()?;
}
Ok(retired)
})
}
pub fn retire_pending_local_sibling_events(
&mut self,
matches: impl Fn(PublicKey, &UnsignedEvent) -> bool,
) -> anyhow::Result<usize> {
self.with_state_checkpoint(|engine| {
let before = engine.pending_local_sibling_sends.len();
engine.pending_local_sibling_sends.retain(|pending| {
let Some((owner, _, payload)) = decode_local_sibling_payload(&pending.payload)
else {
return true;
};
!serde_json::from_slice::<UnsignedEvent>(&payload)
.is_ok_and(|event| matches(owner, &event))
});
let retired = before - engine.pending_local_sibling_sends.len();
if retired > 0 {
engine.persist_now()?;
}
Ok(retired)
})
}
}
pub(crate) fn pending_direct_authored_at(payload: &[u8], fallback: u64) -> u64 {
serde_json::from_slice::<UnsignedEvent>(payload)
.map_or(fallback, |event| event.created_at.as_secs())
}