p2p/channels/signaling/exchange/
p2p_channels_signaling_exchange_actions.rs

1use 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::{P2pChannelsSignalingExchangeState, SignalingExchangeState};
13
14#[derive(Debug, Clone, Serialize, Deserialize, ActionEvent)]
15#[action_event(fields(display(peer_id)))]
16pub enum P2pChannelsSignalingExchangeAction {
17    /// Initialize channel.
18    Init {
19        peer_id: PeerId,
20    },
21    Pending {
22        peer_id: PeerId,
23    },
24    /// Channel is ready.
25    Ready {
26        peer_id: PeerId,
27    },
28    /// Send request to get next offer/incoming connection from peer.
29    RequestSend {
30        peer_id: PeerId,
31    },
32    OfferReceived {
33        peer_id: PeerId,
34        offerer_pub_key: PublicKey,
35        offer: EncryptedOffer,
36    },
37    OfferDecryptError {
38        peer_id: PeerId,
39    },
40    OfferDecryptSuccess {
41        peer_id: PeerId,
42        offer: Offer,
43    },
44    AnswerSend {
45        peer_id: PeerId,
46        answer: P2pConnectionResponse,
47    },
48    /// Received request to get next offer/incoming connection from peer.
49    RequestReceived {
50        peer_id: PeerId,
51    },
52    OfferSend {
53        peer_id: PeerId,
54        offerer_pub_key: PublicKey,
55        offer: EncryptedOffer,
56    },
57    AnswerReceived {
58        peer_id: PeerId,
59        answer: Option<EncryptedAnswer>,
60    },
61}
62
63impl P2pChannelsSignalingExchangeAction {
64    pub fn peer_id(&self) -> &PeerId {
65        match self {
66            Self::Init { peer_id }
67            | Self::Pending { peer_id }
68            | Self::Ready { peer_id }
69            | Self::RequestSend { peer_id }
70            | Self::OfferReceived { peer_id, .. }
71            | Self::OfferDecryptError { peer_id, .. }
72            | Self::OfferDecryptSuccess { peer_id, .. }
73            | Self::AnswerSend { peer_id, .. }
74            | Self::RequestReceived { peer_id }
75            | Self::OfferSend { peer_id, .. }
76            | Self::AnswerReceived { peer_id, .. } => peer_id,
77        }
78    }
79}
80
81impl redux::EnablingCondition<P2pState> for P2pChannelsSignalingExchangeAction {
82    fn is_enabled(&self, state: &P2pState, _time: redux::Timestamp) -> bool {
83        match self {
84            P2pChannelsSignalingExchangeAction::Init { peer_id } => {
85                state.get_ready_peer(peer_id).is_some_and(|p| {
86                    matches!(
87                        &p.channels.signaling.exchange,
88                        P2pChannelsSignalingExchangeState::Enabled
89                    )
90                })
91            }
92            P2pChannelsSignalingExchangeAction::Pending { peer_id } => {
93                state.get_ready_peer(peer_id).is_some_and(|p| {
94                    matches!(
95                        &p.channels.signaling.exchange,
96                        P2pChannelsSignalingExchangeState::Init { .. }
97                    )
98                })
99            }
100            P2pChannelsSignalingExchangeAction::Ready { peer_id } => {
101                state.get_ready_peer(peer_id).is_some_and(|p| {
102                    matches!(
103                        &p.channels.signaling.exchange,
104                        P2pChannelsSignalingExchangeState::Pending { .. }
105                    )
106                })
107            }
108            P2pChannelsSignalingExchangeAction::RequestSend { peer_id } => {
109                !state.already_has_max_peers()
110                    && state.get_ready_peer(peer_id).is_some_and(|p| {
111                        match &p.channels.signaling.exchange {
112                            P2pChannelsSignalingExchangeState::Ready { local, .. } => matches!(
113                                local,
114                                SignalingExchangeState::WaitingForRequest { .. }
115                                    | SignalingExchangeState::Answered { .. },
116                            ),
117                            _ => false,
118                        }
119                    })
120            }
121            P2pChannelsSignalingExchangeAction::OfferReceived { peer_id, .. } => state
122                .get_ready_peer(peer_id)
123                .is_some_and(|p| match &p.channels.signaling.exchange {
124                    P2pChannelsSignalingExchangeState::Ready { local, .. } => {
125                        matches!(local, SignalingExchangeState::Requested { .. })
126                    }
127                    _ => false,
128                }),
129            P2pChannelsSignalingExchangeAction::OfferDecryptError { peer_id } => state
130                .get_ready_peer(peer_id)
131                .is_some_and(|p| match &p.channels.signaling.exchange {
132                    P2pChannelsSignalingExchangeState::Ready { local, .. } => {
133                        matches!(local, SignalingExchangeState::Offered { .. })
134                    }
135                    _ => false,
136                }),
137            P2pChannelsSignalingExchangeAction::OfferDecryptSuccess { peer_id, .. } => state
138                .get_ready_peer(peer_id)
139                .is_some_and(|p| match &p.channels.signaling.exchange {
140                    P2pChannelsSignalingExchangeState::Ready { local, .. } => {
141                        matches!(local, SignalingExchangeState::Offered { .. })
142                    }
143                    _ => false,
144                }),
145            P2pChannelsSignalingExchangeAction::AnswerSend { peer_id, .. } => state
146                .get_ready_peer(peer_id)
147                .is_some_and(|p| match &p.channels.signaling.exchange {
148                    P2pChannelsSignalingExchangeState::Ready { local, .. } => {
149                        matches!(local, SignalingExchangeState::Offered { .. })
150                    }
151                    _ => false,
152                }),
153            P2pChannelsSignalingExchangeAction::RequestReceived { peer_id } => state
154                .get_ready_peer(peer_id)
155                .is_some_and(|p| match &p.channels.signaling.exchange {
156                    P2pChannelsSignalingExchangeState::Ready { remote, .. } => matches!(
157                        remote,
158                        SignalingExchangeState::WaitingForRequest { .. }
159                            | SignalingExchangeState::Answered { .. }
160                    ),
161                    _ => false,
162                }),
163            P2pChannelsSignalingExchangeAction::OfferSend { peer_id, .. } => state
164                .get_ready_peer(peer_id)
165                .is_some_and(|p| match &p.channels.signaling.exchange {
166                    P2pChannelsSignalingExchangeState::Ready { remote, .. } => {
167                        matches!(remote, SignalingExchangeState::Requested { .. })
168                    }
169                    _ => false,
170                }),
171            P2pChannelsSignalingExchangeAction::AnswerReceived { peer_id, .. } => state
172                .get_ready_peer(peer_id)
173                .is_some_and(|p| match &p.channels.signaling.exchange {
174                    P2pChannelsSignalingExchangeState::Ready { remote, .. } => {
175                        matches!(remote, SignalingExchangeState::Offered { .. })
176                    }
177                    _ => false,
178                }),
179        }
180    }
181}
182
183impl From<P2pChannelsSignalingExchangeAction> for crate::P2pAction {
184    fn from(action: P2pChannelsSignalingExchangeAction) -> Self {
185        Self::Channels(P2pChannelsAction::SignalingExchange(action))
186    }
187}