citadel_sdk/prefabs/client/
mod.rs1use crate::prefabs::client::single_connection::SingleClientServerConnectionKernel;
46use crate::prelude::*;
47use std::marker::PhantomData;
48use std::net::{SocketAddr, ToSocketAddrs};
49use uuid::Uuid;
50
51pub mod broadcast;
53pub mod peer_connection;
55pub mod single_connection;
57
58#[async_trait]
59pub trait PrefabFunctions<'a, Arg: Send + 'a, R: Ratchet>: Sized + 'a {
60 type UserLevelInputFunction: Send + 'a;
61 type SharedBundle: Send + 'a;
63
64 fn get_shared_bundle(&self) -> Self::SharedBundle;
65
66 async fn on_c2s_channel_received(
67 connect_success: CitadelClientServerConnection<R>,
68 arg: Arg,
69 fx: Self::UserLevelInputFunction,
70 shared: Self::SharedBundle,
71 ) -> Result<(), NetworkError>;
72
73 fn construct(kernel: Box<dyn NetKernel<R> + 'a>) -> Self;
74
75 fn new(
77 server_connection_settings: ServerConnectionSettings<R>,
78 arg: Arg,
79 on_channel_received: Self::UserLevelInputFunction,
80 ) -> Self {
81 let (tx, rx) = citadel_io::tokio::sync::oneshot::channel();
82 let server_conn_kernel = SingleClientServerConnectionKernel::<_, _, R>::new(
83 server_connection_settings,
84 |connect_success| {
85 on_channel_received_fn::<_, Self, R>(connect_success, rx, arg, on_channel_received)
86 },
87 );
88
89 let this = Self::construct(Box::new(server_conn_kernel));
90 assert!(tx.send(this.get_shared_bundle()).is_ok());
91 this
92 }
93}
94
95async fn on_channel_received_fn<'a, Arg: Send + 'a, T: PrefabFunctions<'a, Arg, R>, R: Ratchet>(
96 connect_success: CitadelClientServerConnection<R>,
97 rx_bundle: citadel_io::tokio::sync::oneshot::Receiver<T::SharedBundle>,
98 arg: Arg,
99 on_channel_received: T::UserLevelInputFunction,
100) -> Result<(), NetworkError> {
101 let shared = rx_bundle
102 .await
103 .map_err(|err| NetworkError::Generic(err.to_string()))?;
104 T::on_c2s_channel_received(connect_success, arg, on_channel_received, shared).await
105}
106
107pub struct ServerConnectionSettingsBuilder<R: Ratchet, T: ToSocketAddrs> {
109 password: Option<SecBuffer>,
110 username: Option<String>,
111 name: Option<String>,
112 psk: Option<PreSharedKey>,
113 address: Option<T>,
114 udp_mode: Option<UdpMode>,
115 session_security_settings: Option<SessionSecuritySettings>,
116 transient_uuid: Option<Uuid>,
117 is_connect: bool,
118 _ratchet: PhantomData<R>,
119}
120
121pub type DefaultServerConnectionSettingsBuilder<T> =
122 ServerConnectionSettingsBuilder<StackedRatchet, T>;
123
124impl<R: Ratchet, T: ToSocketAddrs> ServerConnectionSettingsBuilder<R, T> {
125 pub fn transient(addr: T) -> Self {
129 Self::transient_with_id(addr, Uuid::new_v4())
130 }
131
132 pub fn transient_with_id(addr: T, id: impl Into<Uuid>) -> Self {
134 Self {
135 password: None,
136 username: None,
137 udp_mode: None,
138 session_security_settings: None,
139 name: None,
140 psk: None,
141 transient_uuid: Some(id.into()),
142 address: Some(addr),
143 is_connect: false,
144 _ratchet: PhantomData,
145 }
146 }
147
148 pub fn credentialed_registration<U: Into<String>, N: Into<String>, P: Into<SecBuffer>>(
151 addr: T,
152 username: U,
153 alias: N,
154 password: P,
155 ) -> Self {
156 Self {
157 password: Some(password.into()),
158 username: Some(username.into()),
159 name: Some(alias.into()),
160 psk: None,
161 transient_uuid: None,
162 address: Some(addr),
163 udp_mode: None,
164 session_security_settings: None,
165 is_connect: false,
166 _ratchet: PhantomData,
167 }
168 }
169
170 pub fn credentialed_login<U: Into<String>, P: Into<SecBuffer>>(
172 addr: T,
173 username: U,
174 password: P,
175 ) -> Self {
176 Self {
177 password: Some(password.into()),
178 username: Some(username.into()),
179 name: None,
180 psk: None,
181 transient_uuid: None,
182 address: Some(addr),
183 udp_mode: None,
184 session_security_settings: None,
185 is_connect: true,
186 _ratchet: PhantomData,
187 }
188 }
189
190 pub fn with_session_password<V: Into<PreSharedKey>>(mut self, psk: V) -> Self {
192 self.psk = Some(psk.into());
193 self
194 }
195
196 pub fn with_udp_mode(mut self, mode: UdpMode) -> Self {
198 self.udp_mode = Some(mode);
199 self
200 }
201
202 pub fn disable_udp(self) -> Self {
204 self.with_udp_mode(UdpMode::Disabled)
205 }
206
207 pub fn enable_udp(self) -> Self {
208 self.with_udp_mode(UdpMode::Enabled)
209 }
210
211 pub fn with_session_security_settings<V: Into<SessionSecuritySettings>>(
213 mut self,
214 settings: V,
215 ) -> Self {
216 self.session_security_settings = Some(settings.into());
217 self
218 }
219
220 pub fn build(self) -> Result<ServerConnectionSettings<R>, NetworkError> {
222 let server_addr = if let Some(addr) = self.address {
223 let addr = addr
224 .to_socket_addrs()
225 .map_err(|err| NetworkError::Generic(err.to_string()))?
226 .next()
227 .ok_or(NetworkError::Generic("No address found".to_string()))?;
228 Some(addr)
229 } else {
230 None
231 };
232
233 if let Some(uuid) = self.transient_uuid {
234 Ok(ServerConnectionSettings::<R>::Transient {
235 server_addr: server_addr
236 .ok_or(NetworkError::Generic("No address found".to_string()))?,
237 uuid,
238 udp_mode: self.udp_mode.unwrap_or_default(),
239 session_security_settings: self.session_security_settings.unwrap_or_default(),
240 pre_shared_key: self.psk,
241 _ratchet: PhantomData,
242 })
243 } else if self.is_connect {
244 Ok(ServerConnectionSettings::<R>::CredentialedConnect {
245 username: self
246 .username
247 .ok_or(NetworkError::Generic("No username found".to_string()))?,
248 password: self
249 .password
250 .ok_or(NetworkError::Generic("No password found".to_string()))?,
251 udp_mode: self.udp_mode.unwrap_or_default(),
252 session_security_settings: self.session_security_settings.unwrap_or_default(),
253 pre_shared_key: self.psk,
254 _ratchet: PhantomData,
255 })
256 } else {
257 Ok(ServerConnectionSettings::<R>::CredentialedRegister {
258 address: server_addr
259 .ok_or(NetworkError::Generic("No address found".to_string()))?,
260 username: self
261 .username
262 .ok_or(NetworkError::Generic("No username found".to_string()))?,
263 alias: self
264 .name
265 .ok_or(NetworkError::Generic("No alias found".to_string()))?,
266 password: self
267 .password
268 .ok_or(NetworkError::Generic("No password found".to_string()))?,
269 pre_shared_key: self.psk,
270 udp_mode: self.udp_mode.unwrap_or_default(),
271 session_security_settings: self.session_security_settings.unwrap_or_default(),
272 _ratchet: PhantomData,
273 })
274 }
275 }
276}
277
278pub enum ServerConnectionSettings<R: Ratchet> {
280 Transient {
281 server_addr: SocketAddr,
282 uuid: Uuid,
283 udp_mode: UdpMode,
284 session_security_settings: SessionSecuritySettings,
285 pre_shared_key: Option<PreSharedKey>,
286 _ratchet: PhantomData<R>,
287 },
288 CredentialedConnect {
289 username: String,
290 password: SecBuffer,
291 udp_mode: UdpMode,
292 session_security_settings: SessionSecuritySettings,
293 pre_shared_key: Option<PreSharedKey>,
294 _ratchet: PhantomData<R>,
295 },
296 CredentialedRegister {
297 address: SocketAddr,
298 username: String,
299 alias: String,
300 password: SecBuffer,
301 pre_shared_key: Option<PreSharedKey>,
302 udp_mode: UdpMode,
303 session_security_settings: SessionSecuritySettings,
304 _ratchet: PhantomData<R>,
305 },
306}
307
308impl<R: Ratchet> ServerConnectionSettings<R> {
309 pub(crate) fn udp_mode(&self) -> UdpMode {
310 match self {
311 Self::Transient { udp_mode, .. } => *udp_mode,
312 Self::CredentialedRegister { udp_mode, .. } => *udp_mode,
313 Self::CredentialedConnect { udp_mode, .. } => *udp_mode,
314 }
315 }
316
317 pub(crate) fn session_security_settings(&self) -> SessionSecuritySettings {
318 match self {
319 Self::Transient {
320 session_security_settings,
321 ..
322 } => *session_security_settings,
323 Self::CredentialedRegister {
324 session_security_settings,
325 ..
326 } => *session_security_settings,
327 Self::CredentialedConnect {
328 session_security_settings,
329 ..
330 } => *session_security_settings,
331 }
332 }
333
334 pub(crate) fn pre_shared_key(&self) -> Option<&PreSharedKey> {
335 match self {
336 Self::Transient { pre_shared_key, .. } => pre_shared_key.as_ref(),
337 Self::CredentialedRegister { pre_shared_key, .. } => pre_shared_key.as_ref(),
338 Self::CredentialedConnect { pre_shared_key, .. } => pre_shared_key.as_ref(),
339 }
340 }
341}