p2p_testing/
event.rs

1use std::net::{IpAddr, SocketAddr};
2
3use mina_p2p::{
4    channels::{rpc::P2pChannelsRpcAction, P2pChannelsAction},
5    connection::{incoming::P2pConnectionIncomingAction, outgoing::P2pConnectionOutgoingAction},
6    disconnection::P2pDisconnectionAction,
7    identify::P2pIdentifyAction,
8    network::identify::P2pNetworkIdentify,
9    peer::P2pPeerAction,
10    MioEvent, P2pAction, P2pEvent, PeerId,
11};
12
13use crate::cluster::ClusterEvent;
14
15#[derive(Debug)]
16pub enum RustNodeEvent {
17    Interface {
18        addr: IpAddr,
19    },
20    ListenerReady {
21        addr: SocketAddr,
22    },
23    ListenerError {
24        addr: SocketAddr,
25        error: String,
26    },
27    PeerConnected {
28        peer_id: PeerId,
29        incoming: bool,
30    },
31    PeerConnectionError {
32        peer_id: Option<PeerId>,
33        incoming: bool,
34        error: String,
35    },
36    PeerDisconnected {
37        peer_id: PeerId,
38        reason: String,
39    },
40    RpcChannelReady {
41        peer_id: PeerId,
42    },
43    RpcChannelRequestReceived {
44        peer_id: PeerId,
45        id: mina_p2p::channels::rpc::P2pRpcId,
46        request: mina_p2p::channels::rpc::P2pRpcRequest,
47    },
48    RpcChannelResponseReceived {
49        peer_id: PeerId,
50        id: mina_p2p::channels::rpc::P2pRpcId,
51        response: Option<mina_p2p::channels::rpc::P2pRpcResponse>,
52    },
53    Identify {
54        peer_id: PeerId,
55        info: Box<P2pNetworkIdentify>,
56    },
57    KadBootstrapFinished,
58    KadUpdateFindNodeRequest {
59        peer_id: PeerId,
60        closest_peers: Vec<mina_p2p::network::kad::P2pNetworkKadEntry>,
61    },
62    /// Other non-specific p2p event.
63    P2p {
64        event: P2pEvent,
65    },
66    /// Timeout event with no specific outcome.
67    Idle,
68}
69
70pub(super) trait RustNodeEventStore {
71    fn store_event(&mut self, event: RustNodeEvent);
72}
73
74pub fn event_mapper_effect(store: &mut super::redux::Store, action: P2pAction) {
75    let store_event = |store: &mut super::redux::Store, event| store.service().store_event(event);
76    match action {
77        P2pAction::Peer(P2pPeerAction::Ready { peer_id, incoming }) => {
78            store_event(store, RustNodeEvent::PeerConnected { peer_id, incoming })
79        }
80        P2pAction::Connection(action) => match action {
81            mina_p2p::connection::P2pConnectionAction::Outgoing(
82                P2pConnectionOutgoingAction::Error { peer_id, error },
83            ) => store_event(
84                store,
85                RustNodeEvent::PeerConnectionError {
86                    peer_id: Some(peer_id),
87                    incoming: false,
88                    error: error.to_string(),
89                },
90            ),
91            mina_p2p::connection::P2pConnectionAction::Incoming(
92                P2pConnectionIncomingAction::Error { peer_id, error },
93            ) => store_event(
94                store,
95                RustNodeEvent::PeerConnectionError {
96                    peer_id: Some(peer_id),
97                    incoming: true,
98                    error: error.to_string(),
99                },
100            ),
101            _ => {}
102        },
103
104        P2pAction::Disconnection(P2pDisconnectionAction::Init { peer_id, reason }) => store_event(
105            store,
106            RustNodeEvent::PeerDisconnected {
107                peer_id,
108                reason: reason.to_string(),
109            },
110        ),
111        P2pAction::Network(mina_p2p::P2pNetworkAction::Kad(
112            mina_p2p::P2pNetworkKadAction::System(
113                mina_p2p::P2pNetworkKademliaAction::BootstrapFinished,
114            ),
115        )) => {
116            store_event(store, RustNodeEvent::KadBootstrapFinished);
117        }
118        P2pAction::Network(mina_p2p::P2pNetworkAction::Kad(
119            mina_p2p::P2pNetworkKadAction::System(
120                mina_p2p::P2pNetworkKademliaAction::UpdateFindNodeRequest {
121                    peer_id,
122                    closest_peers,
123                    ..
124                },
125            ),
126        )) => {
127            store_event(
128                store,
129                RustNodeEvent::KadUpdateFindNodeRequest {
130                    peer_id,
131                    closest_peers,
132                },
133            );
134        }
135        P2pAction::Channels(P2pChannelsAction::Rpc(action)) => match action {
136            P2pChannelsRpcAction::Ready { peer_id } => {
137                store_event(store, RustNodeEvent::RpcChannelReady { peer_id })
138            }
139            P2pChannelsRpcAction::RequestReceived {
140                peer_id,
141                id,
142                request,
143            } => {
144                // if matches!(store.service.peek_rust_node_event(), Some(RustNodeEvent::RpcChannelReady { peer_id: pid }) if pid == &peer_id )
145                // {
146                //     store.service.rust_node_event();
147                // }
148                store_event(
149                    store,
150                    RustNodeEvent::RpcChannelRequestReceived {
151                        peer_id,
152                        id,
153                        request: *request,
154                    },
155                )
156            }
157            P2pChannelsRpcAction::ResponseReceived {
158                peer_id,
159                id,
160                response,
161            } => store_event(
162                store,
163                RustNodeEvent::RpcChannelResponseReceived {
164                    peer_id,
165                    id,
166                    response: response.map(|v| *v),
167                },
168            ),
169            _ => {}
170        },
171        P2pAction::Identify(P2pIdentifyAction::UpdatePeerInformation { peer_id, info, .. }) => {
172            store_event(store, RustNodeEvent::Identify { peer_id, info })
173        }
174
175        P2pAction::Network(mina_p2p::P2pNetworkAction::Scheduler(action)) => match action {
176            mina_p2p::P2pNetworkSchedulerAction::InterfaceDetected { ip } => {
177                store_event(store, RustNodeEvent::Interface { addr: ip })
178            }
179            mina_p2p::P2pNetworkSchedulerAction::ListenerReady { listener } => {
180                store_event(store, RustNodeEvent::ListenerReady { addr: listener })
181            }
182            mina_p2p::P2pNetworkSchedulerAction::ListenerError { listener, error } => store_event(
183                store,
184                RustNodeEvent::ListenerError {
185                    addr: listener,
186                    error,
187                },
188            ),
189            mina_p2p::P2pNetworkSchedulerAction::Error { addr, error } => {
190                if let Some(conn_state) = store.state().0.network.scheduler.connections.get(&addr) {
191                    if conn_state.peer_id().is_none() {
192                        let error = error.to_string();
193                        let incoming = conn_state.incoming;
194                        store_event(
195                            store,
196                            RustNodeEvent::PeerConnectionError {
197                                peer_id: None,
198                                incoming,
199                                error,
200                            },
201                        );
202                    }
203                }
204            }
205            _ => {}
206        },
207        _ => {}
208    }
209}
210
211pub fn is_error(event: &ClusterEvent) -> bool {
212    let ClusterEvent::Rust { event, .. } = event else {
213        return false;
214    };
215    match event {
216        RustNodeEvent::ListenerError { .. } => true,
217        RustNodeEvent::PeerConnectionError { .. } => true,
218        RustNodeEvent::PeerDisconnected { .. } => true,
219        RustNodeEvent::P2p { event } => match event {
220            P2pEvent::Connection(_event) => false, // TODO
221            P2pEvent::Channel(_event) => false,    // TODO
222            P2pEvent::MioEvent(event) => matches!(
223                event,
224                MioEvent::ListenerError { .. }
225                    | MioEvent::IncomingConnectionDidAccept(_, Err(_))
226                    | MioEvent::IncomingDataDidReceive(_, Err(_))
227                    | MioEvent::OutgoingConnectionDidConnect(_, Err(_))
228                    | MioEvent::OutgoingDataDidSend(_, Err(_))
229                    | MioEvent::ConnectionDidClose(_, Err(_))
230            ),
231        },
232        _ => false,
233    }
234}
235
236pub fn allow_disconnections(event: &ClusterEvent) -> bool {
237    let ClusterEvent::Rust { event, .. } = event else {
238        return false;
239    };
240    match event {
241        RustNodeEvent::ListenerError { .. } => true,
242        RustNodeEvent::PeerConnectionError { .. } => false,
243        RustNodeEvent::PeerDisconnected { .. } => true,
244        RustNodeEvent::P2p { event } => match event {
245            P2pEvent::Connection(_event) => false, // TODO
246            P2pEvent::Channel(_event) => false,    // TODO
247            P2pEvent::MioEvent(event) => matches!(
248                event,
249                MioEvent::ListenerError { .. } | MioEvent::IncomingConnectionDidAccept(_, Err(_)) // | MioEvent::IncomingDataDidReceive(_, Err(_))
250                                                                                                  // | MioEvent::OutgoingConnectionDidConnect(_, Err(_))
251                                                                                                  // | MioEvent::OutgoingDataDidSend(_, Err(_))
252                                                                                                  // | MioEvent::ConnectionDidClose(_, Err(_))
253            ),
254        },
255        _ => false,
256    }
257}