p2p/channels/signaling/discovery/
p2p_channels_signaling_discovery_actions.rs1use openmina_core::ActionEvent;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 channels::P2pChannelsAction,
6 connection::P2pConnectionResponse,
7 identity::PublicKey,
8 webrtc::{EncryptedAnswer, EncryptedOffer, Offer},
9 P2pState, PeerId,
10};
11
12use super::{P2pChannelsSignalingDiscoveryState, SignalingDiscoveryState};
13
14#[derive(Debug, Clone, Serialize, Deserialize, ActionEvent)]
15#[action_event(fields(display(peer_id)))]
16pub enum P2pChannelsSignalingDiscoveryAction {
17 Init {
19 peer_id: PeerId,
20 },
21 Pending {
22 peer_id: PeerId,
23 },
24 Ready {
26 peer_id: PeerId,
27 },
28 RequestSend {
30 peer_id: PeerId,
31 },
32 DiscoveryRequestReceived {
33 peer_id: PeerId,
34 },
35 DiscoveredSend {
36 peer_id: PeerId,
37 target_public_key: PublicKey,
38 },
39 DiscoveredRejectReceived {
40 peer_id: PeerId,
41 },
42 DiscoveredAcceptReceived {
43 peer_id: PeerId,
44 offer: EncryptedOffer,
45 },
46 AnswerSend {
47 peer_id: PeerId,
48 answer: Option<EncryptedAnswer>,
49 },
50 RequestReceived {
52 peer_id: PeerId,
53 },
54 DiscoveryRequestSend {
55 peer_id: PeerId,
56 },
57 DiscoveredReceived {
58 peer_id: PeerId,
59 target_public_key: PublicKey,
60 },
61 DiscoveredReject {
62 peer_id: PeerId,
63 },
64 DiscoveredAccept {
65 peer_id: PeerId,
66 offer: Box<Offer>,
67 },
68 AnswerReceived {
69 peer_id: PeerId,
70 answer: Option<EncryptedAnswer>,
71 },
72 AnswerDecrypted {
73 peer_id: PeerId,
74 answer: P2pConnectionResponse,
75 },
76}
77
78impl P2pChannelsSignalingDiscoveryAction {
79 pub fn peer_id(&self) -> &PeerId {
80 match self {
81 Self::Init { peer_id }
82 | Self::Pending { peer_id }
83 | Self::Ready { peer_id }
84 | Self::RequestSend { peer_id }
85 | Self::DiscoveryRequestReceived { peer_id }
86 | Self::DiscoveredSend { peer_id, .. }
87 | Self::DiscoveredRejectReceived { peer_id }
88 | Self::DiscoveredAcceptReceived { peer_id, .. }
89 | Self::AnswerSend { peer_id, .. }
90 | Self::RequestReceived { peer_id }
91 | Self::DiscoveryRequestSend { peer_id, .. }
92 | Self::DiscoveredReceived { peer_id, .. }
93 | Self::DiscoveredReject { peer_id, .. }
94 | Self::DiscoveredAccept { peer_id, .. }
95 | Self::AnswerReceived { peer_id, .. }
96 | Self::AnswerDecrypted { peer_id, .. } => peer_id,
97 }
98 }
99}
100
101impl redux::EnablingCondition<P2pState> for P2pChannelsSignalingDiscoveryAction {
102 fn is_enabled(&self, state: &P2pState, now: redux::Timestamp) -> bool {
103 match self {
104 P2pChannelsSignalingDiscoveryAction::Init { peer_id } => {
105 state.get_ready_peer(peer_id).is_some_and(|p| {
106 matches!(
107 &p.channels.signaling.discovery,
108 P2pChannelsSignalingDiscoveryState::Enabled
109 )
110 })
111 }
112 P2pChannelsSignalingDiscoveryAction::Pending { peer_id } => {
113 state.get_ready_peer(peer_id).is_some_and(|p| {
114 matches!(
115 &p.channels.signaling.discovery,
116 P2pChannelsSignalingDiscoveryState::Init { .. }
117 )
118 })
119 }
120 P2pChannelsSignalingDiscoveryAction::Ready { peer_id } => {
121 state.get_ready_peer(peer_id).is_some_and(|p| {
122 matches!(
123 &p.channels.signaling.discovery,
124 P2pChannelsSignalingDiscoveryState::Pending { .. }
125 )
126 })
127 }
128 P2pChannelsSignalingDiscoveryAction::RequestSend { peer_id } => {
129 state.get_ready_peer(peer_id).is_some_and(|p| {
130 match &p.channels.signaling.discovery {
131 P2pChannelsSignalingDiscoveryState::Ready { local, .. } => {
132 match local {
133 SignalingDiscoveryState::WaitingForRequest { .. } => true,
134 SignalingDiscoveryState::DiscoveredRejected { time, .. }
135 | SignalingDiscoveryState::Answered { time, .. } => {
136 now.checked_sub(*time)
139 .is_some_and(|dur| dur.as_secs() >= 60)
140 }
141 _ => false,
142 }
143 }
144 _ => false,
145 }
146 })
147 }
148 P2pChannelsSignalingDiscoveryAction::DiscoveryRequestReceived { peer_id, .. } => state
149 .get_ready_peer(peer_id)
150 .is_some_and(|p| match &p.channels.signaling.discovery {
151 P2pChannelsSignalingDiscoveryState::Ready { local, .. } => {
152 matches!(local, SignalingDiscoveryState::Requested { .. })
153 }
154 _ => false,
155 }),
156 P2pChannelsSignalingDiscoveryAction::DiscoveredSend {
157 peer_id,
158 target_public_key,
159 ..
160 } => {
161 let target_peer_id = target_public_key.peer_id();
162 let has_peer_requested_discovery = state.get_ready_peer(peer_id).is_some_and(|p| {
163 match &p.channels.signaling.discovery {
164 P2pChannelsSignalingDiscoveryState::Ready { local, .. } => {
165 matches!(local, SignalingDiscoveryState::DiscoveryRequested { .. })
166 }
167 _ => false,
168 }
169 });
170 let target_peer_already_discovering_them =
171 state.get_ready_peer(&target_peer_id).is_some_and(|p| {
172 p.channels.signaling.sent_discovered_peer_id() == Some(*peer_id)
173 });
174 has_peer_requested_discovery
175 && !target_peer_already_discovering_them
176 && state.ready_peers_iter().all(|(_, p)| {
177 p.channels.signaling.sent_discovered_peer_id() != Some(target_peer_id)
178 })
179 }
180 P2pChannelsSignalingDiscoveryAction::DiscoveredRejectReceived { peer_id, .. } => state
181 .get_ready_peer(peer_id)
182 .is_some_and(|p| match &p.channels.signaling.discovery {
183 P2pChannelsSignalingDiscoveryState::Ready { local, .. } => {
184 matches!(local, SignalingDiscoveryState::Discovered { .. })
185 }
186 _ => false,
187 }),
188 P2pChannelsSignalingDiscoveryAction::DiscoveredAcceptReceived { peer_id, .. } => state
189 .get_ready_peer(peer_id)
190 .is_some_and(|p| match &p.channels.signaling.discovery {
191 P2pChannelsSignalingDiscoveryState::Ready { local, .. } => {
192 matches!(local, SignalingDiscoveryState::Discovered { .. })
193 }
194 _ => false,
195 }),
196 P2pChannelsSignalingDiscoveryAction::AnswerSend { peer_id, .. } => state
197 .get_ready_peer(peer_id)
198 .is_some_and(|p| match &p.channels.signaling.discovery {
199 P2pChannelsSignalingDiscoveryState::Ready { local, .. } => {
200 matches!(local, SignalingDiscoveryState::DiscoveredAccepted { .. })
201 }
202 _ => false,
203 }),
204 P2pChannelsSignalingDiscoveryAction::RequestReceived { peer_id } => state
205 .get_ready_peer(peer_id)
206 .is_some_and(|p| match &p.channels.signaling.discovery {
207 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => matches!(
208 remote,
209 SignalingDiscoveryState::WaitingForRequest { .. }
210 | SignalingDiscoveryState::DiscoveredRejected { .. }
211 | SignalingDiscoveryState::Answered { .. }
212 ),
213 _ => false,
214 }),
215 P2pChannelsSignalingDiscoveryAction::DiscoveryRequestSend { peer_id, .. } => {
218 !state.already_has_min_peers()
219 && state.get_ready_peer(peer_id).is_some_and(|p| {
220 match &p.channels.signaling.discovery {
221 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => {
222 matches!(remote, SignalingDiscoveryState::Requested { .. })
223 }
224 _ => false,
225 }
226 })
227 }
228 P2pChannelsSignalingDiscoveryAction::DiscoveredReceived { peer_id, .. } => state
229 .get_ready_peer(peer_id)
230 .is_some_and(|p| match &p.channels.signaling.discovery {
231 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => {
232 matches!(remote, SignalingDiscoveryState::DiscoveryRequested { .. })
233 }
234 _ => false,
235 }),
236 P2pChannelsSignalingDiscoveryAction::DiscoveredReject { peer_id, .. } => state
237 .get_ready_peer(peer_id)
238 .is_some_and(|p| match &p.channels.signaling.discovery {
239 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => {
240 matches!(remote, SignalingDiscoveryState::Discovered { .. })
241 }
242 _ => false,
243 }),
244 P2pChannelsSignalingDiscoveryAction::DiscoveredAccept { peer_id, .. } => state
245 .get_ready_peer(peer_id)
246 .is_some_and(|p| match &p.channels.signaling.discovery {
247 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => {
248 matches!(remote, SignalingDiscoveryState::Discovered { .. })
249 }
250 _ => false,
251 }),
252 P2pChannelsSignalingDiscoveryAction::AnswerReceived { peer_id, .. } => state
253 .get_ready_peer(peer_id)
254 .is_some_and(|p| match &p.channels.signaling.discovery {
255 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => {
256 matches!(remote, SignalingDiscoveryState::DiscoveredAccepted { .. })
257 }
258 _ => false,
259 }),
260 P2pChannelsSignalingDiscoveryAction::AnswerDecrypted { peer_id, .. } => state
261 .get_ready_peer(peer_id)
262 .is_some_and(|p| match &p.channels.signaling.discovery {
263 P2pChannelsSignalingDiscoveryState::Ready { remote, .. } => {
264 matches!(remote, SignalingDiscoveryState::DiscoveredAccepted { .. })
265 }
266 _ => false,
267 }),
268 }
269 }
270}
271
272impl From<P2pChannelsSignalingDiscoveryAction> for crate::P2pAction {
273 fn from(action: P2pChannelsSignalingDiscoveryAction) -> Self {
274 Self::Channels(P2pChannelsAction::SignalingDiscovery(action))
275 }
276}