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