p2p/disconnection/
p2p_disconnection_actions.rs

1use std::time::Duration;
2
3use openmina_core::ActionEvent;
4use serde::{Deserialize, Serialize};
5
6use super::P2pDisconnectionReason;
7use crate::{P2pPeerStatus, P2pState, PeerId};
8
9pub type P2pDisconnectionActionWithMetaRef<'a> = redux::ActionWithMeta<&'a P2pDisconnectionAction>;
10
11const RANDOM_DISCONNECTION_TRY_FREQUENCY: Duration = Duration::from_secs(10);
12
13#[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)]
14#[action_event(level = debug)]
15pub enum P2pDisconnectionAction {
16    RandomTry,
17    /// Initialize disconnection.
18    #[action_event(fields(display(peer_id), display(reason)), level = info)]
19    Init {
20        peer_id: PeerId,
21        reason: P2pDisconnectionReason,
22    },
23    /// Peer disconnection.
24    #[action_event(fields(display(peer_id)), level = info)]
25    PeerClosed {
26        peer_id: PeerId,
27    },
28    #[action_event(fields(display(peer_id)), level = info)]
29    FailedCleanup {
30        peer_id: PeerId,
31    },
32    /// Finish disconnecting from a peer.
33    #[action_event(fields(display(peer_id)), level = debug)]
34    Finish {
35        peer_id: PeerId,
36    },
37}
38
39impl redux::EnablingCondition<P2pState> for P2pDisconnectionAction {
40    fn is_enabled(&self, state: &P2pState, time: redux::Timestamp) -> bool {
41        match self {
42            P2pDisconnectionAction::RandomTry => time
43                .checked_sub(state.last_random_disconnection_try)
44                .is_some_and(|dur| dur >= RANDOM_DISCONNECTION_TRY_FREQUENCY),
45            P2pDisconnectionAction::Init { peer_id, .. } => {
46                state.peers.get(peer_id).is_some_and(|peer| {
47                    !peer.status.is_disconnected_or_disconnecting() && !peer.status.is_error()
48                })
49            }
50            P2pDisconnectionAction::Finish { peer_id } => {
51                state.peers.get(peer_id).is_some_and(|peer| {
52                    !matches!(peer.status, P2pPeerStatus::Disconnected { .. })
53                        && !peer.status.is_error()
54                })
55            }
56            P2pDisconnectionAction::PeerClosed { peer_id, .. } => {
57                state.peers.get(peer_id).is_some_and(|peer| {
58                    !peer.status.is_disconnected_or_disconnecting() && !peer.status.is_error()
59                })
60            }
61            P2pDisconnectionAction::FailedCleanup { peer_id } => state
62                .peers
63                .get(peer_id)
64                .is_some_and(|peer| !peer.is_libp2p() && peer.status.is_error()),
65        }
66    }
67}