|
1 | | -use openmina_core::bug_condition; |
2 | | -use redux::{ActionMeta, ActionWithMeta}; |
3 | | - |
4 | | -use crate::{ |
5 | | - channels::P2pChannelsEffectfulAction, |
6 | | - connection::{outgoing::P2pConnectionOutgoingAction, P2pConnectionEffectfulAction}, |
7 | | - P2pAction, P2pStore, |
8 | | -}; |
9 | | -#[cfg(feature = "p2p-libp2p")] |
10 | 1 | use crate::{ |
11 | | - P2pNetworkKadKey, P2pNetworkKademliaAction, P2pNetworkPnetAction, P2pNetworkSelectAction, |
12 | | - PeerId, |
| 2 | + channels::P2pChannelsEffectfulAction, connection::P2pConnectionEffectfulAction, P2pAction, |
| 3 | + P2pStore, |
13 | 4 | }; |
14 | | - |
15 | | -pub fn p2p_timeout_effects<Store, S>(store: &mut Store, meta: &ActionMeta) |
16 | | -where |
17 | | - Store: P2pStore<S>, |
18 | | -{ |
19 | | - p2p_connection_timeouts(store, meta); |
20 | | - store.dispatch(P2pConnectionOutgoingAction::RandomInit); |
21 | | - |
22 | | - p2p_try_reconnect_disconnected_peers(store, meta.time()); |
23 | | - |
24 | | - #[cfg(feature = "p2p-libp2p")] |
25 | | - p2p_pnet_timeouts(store, meta); |
26 | | - |
27 | | - p2p_discovery(store, meta); |
28 | | - |
29 | | - #[cfg(feature = "p2p-libp2p")] |
30 | | - p2p_select_timeouts(store, meta); |
31 | | - #[cfg(feature = "p2p-libp2p")] |
32 | | - p2p_rpc_heartbeats(store, meta); |
33 | | - |
34 | | - let state = store.state(); |
35 | | - for (peer_id, id, is_streaming) in state.peer_rpc_timeouts(meta.time()) { |
36 | | - if !is_streaming { |
37 | | - store.dispatch(crate::channels::rpc::P2pChannelsRpcAction::Timeout { peer_id, id }); |
38 | | - } else { |
39 | | - store.dispatch( |
40 | | - crate::channels::streaming_rpc::P2pChannelsStreamingRpcAction::Timeout { |
41 | | - peer_id, |
42 | | - id, |
43 | | - }, |
44 | | - ); |
45 | | - } |
46 | | - } |
47 | | -} |
48 | | - |
49 | | -#[cfg(feature = "p2p-libp2p")] |
50 | | -fn p2p_pnet_timeouts<Store, S>(store: &mut Store, meta: &ActionMeta) |
51 | | -where |
52 | | - Store: P2pStore<S>, |
53 | | -{ |
54 | | - let now = meta.time(); |
55 | | - let timeouts = &store.state().config.timeouts; |
56 | | - let pnet_timeouts: Vec<_> = store |
57 | | - .state() |
58 | | - .network |
59 | | - .scheduler |
60 | | - .connections |
61 | | - .iter() |
62 | | - .filter_map(|(sock_addr, state)| { |
63 | | - if state.pnet.is_timed_out(now, timeouts) { |
64 | | - Some(*sock_addr) |
65 | | - } else { |
66 | | - None |
67 | | - } |
68 | | - }) |
69 | | - .collect(); |
70 | | - |
71 | | - for addr in pnet_timeouts { |
72 | | - store.dispatch(P2pNetworkPnetAction::Timeout { addr }); |
73 | | - } |
74 | | -} |
75 | | - |
76 | | -#[cfg(feature = "p2p-libp2p")] |
77 | | -fn p2p_select_timeouts<Store, S>(store: &mut Store, meta: &ActionMeta) |
78 | | -where |
79 | | - Store: P2pStore<S>, |
80 | | -{ |
81 | | - let now = meta.time(); |
82 | | - let timeouts = &store.state().config.timeouts; |
83 | | - let select_auth_timeouts: Vec<_> = store |
84 | | - .state() |
85 | | - .network |
86 | | - .scheduler |
87 | | - .connections |
88 | | - .iter() |
89 | | - .filter_map(|(sock_addr, state)| { |
90 | | - if state.select_auth.is_timed_out(now, timeouts) { |
91 | | - Some(*sock_addr) |
92 | | - } else { |
93 | | - None |
94 | | - } |
95 | | - }) |
96 | | - .collect(); |
97 | | - |
98 | | - let select_mux_timeouts: Vec<_> = store |
99 | | - .state() |
100 | | - .network |
101 | | - .scheduler |
102 | | - .connections |
103 | | - .iter() |
104 | | - .filter_map(|(sock_addr, state)| { |
105 | | - if state.select_mux.is_timed_out(now, timeouts) { |
106 | | - Some(*sock_addr) |
107 | | - } else { |
108 | | - None |
109 | | - } |
110 | | - }) |
111 | | - .collect(); |
112 | | - |
113 | | - let select_stream_timeouts: Vec<_> = store |
114 | | - .state() |
115 | | - .network |
116 | | - .scheduler |
117 | | - .connections |
118 | | - .iter() |
119 | | - .flat_map(|(sock_addr, state)| { |
120 | | - state.streams.iter().filter_map(|(stream_id, stream)| { |
121 | | - if stream.select.is_timed_out(now, timeouts) { |
122 | | - Some((*sock_addr, *stream_id)) |
123 | | - } else { |
124 | | - None |
125 | | - } |
126 | | - }) |
127 | | - }) |
128 | | - .collect(); |
129 | | - |
130 | | - for addr in select_auth_timeouts { |
131 | | - store.dispatch(P2pNetworkSelectAction::Timeout { |
132 | | - addr, |
133 | | - kind: crate::SelectKind::Authentication, |
134 | | - }); |
135 | | - } |
136 | | - |
137 | | - for addr in select_mux_timeouts { |
138 | | - store.dispatch(P2pNetworkSelectAction::Timeout { |
139 | | - addr, |
140 | | - kind: crate::SelectKind::MultiplexingNoPeerId, |
141 | | - }); |
142 | | - } |
143 | | - |
144 | | - for (addr, stream_id) in select_stream_timeouts { |
145 | | - // TODO: better solution for PeerId |
146 | | - let dummy = PeerId::from_bytes([0u8; 32]); |
147 | | - |
148 | | - store.dispatch(P2pNetworkSelectAction::Timeout { |
149 | | - addr, |
150 | | - kind: crate::SelectKind::Stream(dummy, stream_id), |
151 | | - }); |
152 | | - } |
153 | | -} |
154 | | - |
155 | | -#[cfg(feature = "p2p-libp2p")] |
156 | | -fn p2p_rpc_heartbeats<Store, S>(store: &mut Store, meta: &ActionMeta) |
157 | | -where |
158 | | - Store: P2pStore<S>, |
159 | | -{ |
160 | | - use crate::network::rpc::P2pNetworkRpcAction; |
161 | | - let scheduler = &store.state().network.scheduler; |
162 | | - |
163 | | - let send_heartbeat_actions: Vec<_> = scheduler |
164 | | - .rpc_incoming_streams |
165 | | - .iter() |
166 | | - .chain(&scheduler.rpc_outgoing_streams) |
167 | | - .flat_map(|(peer_id, state)| { |
168 | | - state |
169 | | - .iter() |
170 | | - .filter(|(_, s)| s.should_send_heartbeat(meta.time())) |
171 | | - .map(|(stream_id, state)| P2pNetworkRpcAction::HeartbeatSend { |
172 | | - addr: state.addr, |
173 | | - peer_id: *peer_id, |
174 | | - stream_id: *stream_id, |
175 | | - }) |
176 | | - }) |
177 | | - .collect(); |
178 | | - for action in send_heartbeat_actions { |
179 | | - store.dispatch(action); |
180 | | - } |
181 | | -} |
182 | | - |
183 | | -fn p2p_connection_timeouts<Store, S>(store: &mut Store, meta: &ActionMeta) |
184 | | -where |
185 | | - Store: P2pStore<S>, |
186 | | -{ |
187 | | - use crate::connection::incoming::P2pConnectionIncomingAction; |
188 | | - |
189 | | - let now = meta.time(); |
190 | | - let timeouts = &store.state().config.timeouts; |
191 | | - let p2p_connection_timeouts: Vec<_> = store |
192 | | - .state() |
193 | | - .peers |
194 | | - .iter() |
195 | | - .filter_map(|(peer_id, peer)| { |
196 | | - let s = peer.status.as_connecting()?; |
197 | | - match s.is_timed_out(now, timeouts) { |
198 | | - true => Some((*peer_id, s.as_outgoing().is_some())), |
199 | | - false => None, |
200 | | - } |
201 | | - }) |
202 | | - .collect(); |
203 | | - |
204 | | - for (peer_id, is_outgoing) in p2p_connection_timeouts { |
205 | | - match is_outgoing { |
206 | | - true => store.dispatch(P2pConnectionOutgoingAction::Timeout { peer_id }), |
207 | | - false => store.dispatch(P2pConnectionIncomingAction::Timeout { peer_id }), |
208 | | - }; |
209 | | - } |
210 | | -} |
211 | | - |
212 | | -fn p2p_try_reconnect_disconnected_peers<Store, S>(store: &mut Store, now: redux::Timestamp) |
213 | | -where |
214 | | - Store: P2pStore<S>, |
215 | | -{ |
216 | | - if store.state().already_has_min_peers() { |
217 | | - return; |
218 | | - } |
219 | | - let timeouts = &store.state().config.timeouts; |
220 | | - let reconnect_actions: Vec<_> = store |
221 | | - .state() |
222 | | - .peers |
223 | | - .iter() |
224 | | - .filter_map(|(_, p)| { |
225 | | - if p.can_reconnect(now, timeouts) { |
226 | | - p.dial_opts.clone() |
227 | | - } else { |
228 | | - None |
229 | | - } |
230 | | - }) |
231 | | - .map(|opts| P2pConnectionOutgoingAction::Reconnect { opts, rpc_id: None }) |
232 | | - .collect(); |
233 | | - for action in reconnect_actions { |
234 | | - store.dispatch(action); |
235 | | - } |
236 | | -} |
237 | | - |
238 | | -fn p2p_discovery<Store, S>(store: &mut Store, meta: &redux::ActionMeta) |
239 | | -where |
240 | | - Store: P2pStore<S>, |
241 | | -{ |
242 | | - let now = meta.time(); |
243 | | - let state = store.state(); |
244 | | - let config = &state.config; |
245 | | - if !config.peer_discovery { |
246 | | - return; |
247 | | - } |
248 | | - // ask initial peers |
249 | | - if let Some(_d) = config.timeouts.initial_peers { |
250 | | - // TODO: use RPC to ask initial peers |
251 | | - let _ = now; |
252 | | - } |
253 | | - |
254 | | - #[cfg(feature = "p2p-libp2p")] |
255 | | - if let Some(discovery_state) = state.network.scheduler.discovery_state() { |
256 | | - let my_id = state.my_id(); |
257 | | - match P2pNetworkKadKey::try_from(&my_id) { |
258 | | - Ok(key) => { |
259 | | - if discovery_state |
260 | | - .routing_table |
261 | | - .closest_peers(&key) |
262 | | - .any(|_| true) |
263 | | - && discovery_state.status.can_bootstrap(now, &config.timeouts) |
264 | | - { |
265 | | - store.dispatch(P2pNetworkKademliaAction::StartBootstrap { key: my_id }); |
266 | | - } |
267 | | - } |
268 | | - Err(e) => bug_condition!("p2p_discovery error {:?}", e), |
269 | | - } |
270 | | - } |
271 | | -} |
| 5 | +use redux::ActionWithMeta; |
272 | 6 |
|
273 | 7 | pub fn p2p_effects<Store, S>(store: &mut Store, action: ActionWithMeta<P2pAction>) |
274 | 8 | where |
|
0 commit comments