1use super::{
2 P2pConnectionIncomingError, P2pConnectionIncomingInitOpts, P2pConnectionIncomingState,
3};
4use crate::{
5 connection::{P2pConnectionAction, P2pConnectionState},
6 webrtc, P2pAction, P2pPeerStatus, P2pState, PeerId,
7};
8use openmina_core::{requests::RpcId, ActionEvent};
9use serde::{Deserialize, Serialize};
10use std::net::SocketAddr;
11
12#[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)]
13#[action_event(fields(debug(opts), display(peer_id), display(error)))]
14pub enum P2pConnectionIncomingAction {
15 Init {
17 opts: P2pConnectionIncomingInitOpts,
18 rpc_id: Option<RpcId>,
19 },
20 #[action_event(level = trace)]
21 AnswerSdpCreatePending {
22 peer_id: PeerId,
23 },
24 AnswerSdpCreateError {
25 peer_id: PeerId,
26 error: String,
27 },
28 AnswerSdpCreateSuccess {
29 peer_id: PeerId,
30 sdp: String,
31 },
32 AnswerReady {
33 peer_id: PeerId,
34 answer: Box<webrtc::Answer>,
35 },
36 AnswerSendSuccess {
37 peer_id: PeerId,
38 },
39 #[action_event(level = trace)]
41 FinalizePending {
42 peer_id: PeerId,
43 },
44 FinalizeError {
46 peer_id: PeerId,
47 error: String,
48 },
49 FinalizeSuccess {
51 peer_id: PeerId,
52 remote_auth: webrtc::ConnectionAuthEncrypted,
53 },
54 Timeout {
56 peer_id: PeerId,
57 },
58 #[action_event(level = warn, fields(display(peer_id), display(error)))]
60 Error {
61 peer_id: PeerId,
62 error: P2pConnectionIncomingError,
63 },
64 #[action_event(level = info)]
66 Success {
67 peer_id: PeerId,
68 },
69 FinalizePendingLibp2p {
71 peer_id: PeerId,
72 addr: SocketAddr,
73 },
74 Libp2pReceived {
76 peer_id: PeerId,
77 },
78}
79
80impl P2pConnectionIncomingAction {
81 pub fn peer_id(&self) -> &PeerId {
82 match self {
83 Self::Init { opts, .. } => &opts.peer_id,
84 Self::AnswerSdpCreatePending { peer_id }
85 | Self::AnswerSdpCreateError { peer_id, .. }
86 | Self::AnswerSdpCreateSuccess { peer_id, .. }
87 | Self::AnswerReady { peer_id, .. }
88 | Self::AnswerSendSuccess { peer_id }
89 | Self::FinalizePending { peer_id }
90 | Self::FinalizeError { peer_id, .. }
91 | Self::FinalizeSuccess { peer_id, .. }
92 | Self::Timeout { peer_id }
93 | Self::Error { peer_id, .. }
94 | Self::Success { peer_id }
95 | Self::FinalizePendingLibp2p { peer_id, .. }
96 | Self::Libp2pReceived { peer_id } => peer_id,
97 }
98 }
99}
100
101impl redux::EnablingCondition<P2pState> for P2pConnectionIncomingAction {
102 fn is_enabled(&self, state: &P2pState, time: redux::Timestamp) -> bool {
103 match self {
104 P2pConnectionIncomingAction::Init { opts, .. } => {
105 state.incoming_accept(opts.peer_id, &opts.offer).is_ok()
106 }
107 P2pConnectionIncomingAction::AnswerSdpCreatePending { peer_id } => {
108 state.peers.get(peer_id).is_some_and(|peer| {
109 matches!(
110 &peer.status,
111 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
112 P2pConnectionIncomingState::Init { .. },
113 ))
114 )
115 })
116 }
117 P2pConnectionIncomingAction::AnswerSdpCreateError { peer_id, .. } => {
118 state.peers.get(peer_id).is_some_and(|peer| {
119 matches!(
120 &peer.status,
121 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
122 P2pConnectionIncomingState::AnswerSdpCreatePending { .. },
123 ))
124 )
125 })
126 }
127 P2pConnectionIncomingAction::AnswerSdpCreateSuccess { peer_id, .. } => {
128 state.peers.get(peer_id).is_some_and(|peer| {
129 matches!(
130 &peer.status,
131 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
132 P2pConnectionIncomingState::AnswerSdpCreatePending { .. },
133 ))
134 )
135 })
136 }
137 P2pConnectionIncomingAction::AnswerReady { peer_id, .. } => {
138 state.peers.get(peer_id).is_some_and(|peer| {
139 matches!(
140 &peer.status,
141 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
142 P2pConnectionIncomingState::AnswerSdpCreateSuccess { .. },
143 ))
144 )
145 })
146 }
147 P2pConnectionIncomingAction::AnswerSendSuccess { peer_id } => {
148 state.peers.get(peer_id).is_some_and(|peer| {
149 matches!(
150 &peer.status,
151 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
152 P2pConnectionIncomingState::AnswerReady { .. },
153 ))
154 )
155 })
156 }
157 P2pConnectionIncomingAction::FinalizePending { peer_id } => {
158 state.peers.get(peer_id).is_some_and(|peer| {
159 matches!(
160 &peer.status,
161 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
162 P2pConnectionIncomingState::AnswerSendSuccess { .. },
163 ))
164 )
165 })
166 }
167 P2pConnectionIncomingAction::FinalizeError { peer_id, .. } => {
168 state.peers.get(peer_id).is_some_and(|peer| {
169 matches!(
170 &peer.status,
171 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
172 P2pConnectionIncomingState::FinalizePending { .. },
173 ))
174 )
175 })
176 }
177 P2pConnectionIncomingAction::FinalizeSuccess { peer_id, .. } => {
178 state.peers.get(peer_id).is_some_and(|peer| {
179 matches!(
180 &peer.status,
181 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
182 P2pConnectionIncomingState::FinalizePending { .. },
183 ))
184 )
185 })
186 }
187 P2pConnectionIncomingAction::Timeout { peer_id } => state
188 .peers
189 .get(peer_id)
190 .and_then(|peer| peer.status.as_connecting()?.as_incoming())
191 .is_some_and(|s| s.is_timed_out(time, &state.config.timeouts)),
192 P2pConnectionIncomingAction::Error { peer_id, error } => state
193 .peers
194 .get(peer_id)
195 .is_some_and(|peer| match &peer.status {
196 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(s)) => match error {
197 P2pConnectionIncomingError::SdpCreateError(_) => {
198 matches!(s, P2pConnectionIncomingState::AnswerSdpCreatePending { .. })
199 }
200 P2pConnectionIncomingError::FinalizeError(_) => {
201 matches!(s, P2pConnectionIncomingState::FinalizePending { .. })
202 }
203 P2pConnectionIncomingError::ConnectionAuthError => {
204 matches!(s, P2pConnectionIncomingState::FinalizeSuccess { .. })
205 }
206 P2pConnectionIncomingError::Timeout => true,
207 },
208 _ => false,
209 }),
210 P2pConnectionIncomingAction::Success { peer_id } => {
211 state.peers.get(peer_id).is_some_and(|peer| {
212 matches!(
213 &peer.status,
214 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
215 P2pConnectionIncomingState::FinalizeSuccess { .. },
216 ))
217 )
218 })
219 }
220 P2pConnectionIncomingAction::FinalizePendingLibp2p { .. } => {
221 cfg!(feature = "p2p-libp2p")
222 }
223 P2pConnectionIncomingAction::Libp2pReceived { peer_id, .. } => {
224 cfg!(feature = "p2p-libp2p")
225 && state.peers.get(peer_id).is_some_and(|peer| {
226 matches!(
227 &peer.status,
228 P2pPeerStatus::Connecting(P2pConnectionState::Incoming(
229 P2pConnectionIncomingState::FinalizePendingLibp2p { .. },
230 ))
231 )
232 })
233 }
234 }
235 }
236}
237
238impl From<P2pConnectionIncomingAction> for P2pAction {
239 fn from(a: P2pConnectionIncomingAction) -> Self {
240 Self::Connection(P2pConnectionAction::Incoming(a))
241 }
242}