1use malloc_size_of_derive::MallocSizeOf;
2use redux::{Callback, Timestamp};
3use serde::{Deserialize, Serialize};
4
5use openmina_core::requests::RpcId;
6
7use crate::{connection::RejectionReason, webrtc, P2pTimeouts, PeerId};
8
9use super::P2pConnectionOutgoingInitOpts;
10
11#[derive(Serialize, Deserialize, Debug, Clone, MallocSizeOf)]
12pub enum P2pConnectionOutgoingState {
13 Init {
14 #[ignore_malloc_size_of = "doesn't allocate"]
15 time: Timestamp,
16 opts: P2pConnectionOutgoingInitOpts,
17 rpc_id: Option<RpcId>,
18 #[ignore_malloc_size_of = "negligible"]
19 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
20 },
21 OfferSdpCreatePending {
22 #[ignore_malloc_size_of = "doesn't allocate"]
23 time: Timestamp,
24 opts: P2pConnectionOutgoingInitOpts,
25 rpc_id: Option<RpcId>,
26 #[ignore_malloc_size_of = "negligible"]
27 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
28 },
29 OfferSdpCreateSuccess {
30 #[ignore_malloc_size_of = "doesn't allocate"]
31 time: Timestamp,
32 opts: P2pConnectionOutgoingInitOpts,
33 sdp: String,
34 rpc_id: Option<RpcId>,
35 #[ignore_malloc_size_of = "negligible"]
36 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
37 },
38 OfferReady {
39 #[ignore_malloc_size_of = "doesn't allocate"]
40 time: Timestamp,
41 opts: P2pConnectionOutgoingInitOpts,
42 offer: Box<webrtc::Offer>,
43 rpc_id: Option<RpcId>,
44 #[ignore_malloc_size_of = "negligible"]
45 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
46 },
47 OfferSendSuccess {
48 #[ignore_malloc_size_of = "doesn't allocate"]
49 time: Timestamp,
50 opts: P2pConnectionOutgoingInitOpts,
51 offer: Box<webrtc::Offer>,
52 rpc_id: Option<RpcId>,
53 #[ignore_malloc_size_of = "negligible"]
54 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
55 },
56 AnswerRecvPending {
57 #[ignore_malloc_size_of = "doesn't allocate"]
58 time: Timestamp,
59 opts: P2pConnectionOutgoingInitOpts,
60 offer: Box<webrtc::Offer>,
61 rpc_id: Option<RpcId>,
62 #[ignore_malloc_size_of = "negligible"]
63 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
64 },
65 AnswerRecvSuccess {
66 #[ignore_malloc_size_of = "doesn't allocate"]
67 time: Timestamp,
68 opts: P2pConnectionOutgoingInitOpts,
69 offer: Box<webrtc::Offer>,
70 answer: Box<webrtc::Answer>,
71 rpc_id: Option<RpcId>,
72 #[ignore_malloc_size_of = "negligible"]
73 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
74 },
75 FinalizePending {
76 #[ignore_malloc_size_of = "doesn't allocate"]
77 time: Timestamp,
78 opts: P2pConnectionOutgoingInitOpts,
79 offer: Option<Box<webrtc::Offer>>,
80 answer: Option<Box<webrtc::Answer>>,
81 rpc_id: Option<RpcId>,
82 #[ignore_malloc_size_of = "negligible"]
83 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
84 },
85 FinalizeSuccess {
86 #[ignore_malloc_size_of = "doesn't allocate"]
87 time: Timestamp,
88 opts: P2pConnectionOutgoingInitOpts,
89 offer: Option<Box<webrtc::Offer>>,
90 answer: Option<Box<webrtc::Answer>>,
91 rpc_id: Option<RpcId>,
92 #[ignore_malloc_size_of = "negligible"]
93 on_success: Option<Callback<(PeerId, Option<RpcId>)>>,
94 },
95 Error {
96 #[ignore_malloc_size_of = "doesn't allocate"]
97 time: Timestamp,
98 error: P2pConnectionOutgoingError,
99 rpc_id: Option<RpcId>,
100 },
101 Success {
102 #[ignore_malloc_size_of = "doesn't allocate"]
103 time: Timestamp,
104 offer: Option<Box<webrtc::Offer>>,
105 answer: Option<Box<webrtc::Answer>>,
106 rpc_id: Option<RpcId>,
107 },
108}
109
110impl P2pConnectionOutgoingState {
111 pub fn time(&self) -> Timestamp {
112 match self {
113 Self::Init { time, .. } => *time,
114 Self::OfferSdpCreatePending { time, .. } => *time,
115 Self::OfferSdpCreateSuccess { time, .. } => *time,
116 Self::OfferReady { time, .. } => *time,
117 Self::OfferSendSuccess { time, .. } => *time,
118 Self::AnswerRecvPending { time, .. } => *time,
119 Self::AnswerRecvSuccess { time, .. } => *time,
120 Self::FinalizePending { time, .. } => *time,
121 Self::FinalizeSuccess { time, .. } => *time,
122 Self::Error { time, .. } => *time,
123 Self::Success { time, .. } => *time,
124 }
125 }
126
127 pub fn rpc_id(&self) -> Option<RpcId> {
128 match self {
129 Self::Init { rpc_id, .. } => *rpc_id,
130 Self::OfferSdpCreatePending { rpc_id, .. } => *rpc_id,
131 Self::OfferSdpCreateSuccess { rpc_id, .. } => *rpc_id,
132 Self::OfferReady { rpc_id, .. } => *rpc_id,
133 Self::OfferSendSuccess { rpc_id, .. } => *rpc_id,
134 Self::AnswerRecvPending { rpc_id, .. } => *rpc_id,
135 Self::AnswerRecvSuccess { rpc_id, .. } => *rpc_id,
136 Self::FinalizePending { rpc_id, .. } => *rpc_id,
137 Self::FinalizeSuccess { rpc_id, .. } => *rpc_id,
138 Self::Error { rpc_id, .. } => *rpc_id,
139 Self::Success { rpc_id, .. } => *rpc_id,
140 }
141 }
142
143 pub fn is_timed_out(&self, now: Timestamp, timeouts: &P2pTimeouts) -> bool {
144 !matches!(self, Self::Error { .. })
145 && now
146 .checked_sub(self.time())
147 .and_then(|dur| timeouts.outgoing_connection_timeout.map(|to| dur >= to))
148 .unwrap_or(false)
149 }
150}
151
152#[derive(Serialize, Deserialize, Debug, Clone, thiserror::Error, MallocSizeOf)]
153pub enum P2pConnectionOutgoingError {
154 #[error("error creating SDP: {0}")]
155 SdpCreateError(String),
156 #[error("rejected: {0}")]
157 Rejected(RejectionReason),
158 #[error("remote signal decryption failed")]
159 RemoteSignalDecryptionFailed,
160 #[error("remote internal error")]
161 RemoteInternalError,
162 #[error("finalization error: {0}")]
163 FinalizeError(String),
164 #[error("connection authorization error")]
165 ConnectionAuthError,
166 #[error("timeout error")]
167 Timeout,
168}