citadel_sdk/prefabs/server/
client_connect_listener.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Client Connection Event Handler
//!
//! This module provides a network kernel that executes custom logic whenever a client
//! establishes a connection. It's particularly useful for implementing server-side
//! connection handling, authentication, and session initialization.
//!
//! # Features
//! - Custom connection handling
//! - Asynchronous event processing
//! - Type-safe callback execution
//! - Session security management
//! - UDP channel support
//! - Service discovery integration
//!
//! # Example:
//! ```rust
//! use citadel_sdk::prelude::*;
//! use citadel_sdk::prefabs::server::client_connect_listener::ClientConnectListenerKernel;
//!
//! # fn main() -> Result<(), NetworkError> {
//! let kernel = Box::new(ClientConnectListenerKernel::<_, _, StackedRatchet>::new(|conn| async move {
//!     println!("Client connected!");
//!     Ok(())
//! }));
//! # Ok(())
//! # }
//! ```
//!
//! # Important Notes
//! - Callbacks must be Send + Sync
//! - Futures must be Send + Sync
//! - Handles both TCP and UDP channels
//! - Automatic security settings handling
//!
//! # Related Components
//! - [`NetKernel`]: Base trait for network kernels
//! - [`ClientServerRemote`]: Client-server communication
//! - [`CitadelClientServerConnection`]: Connection event data
//! - [`NodeResult`]: Network event handling
//!
//! [`NetKernel`]: crate::prelude::NetKernel
//! [`ClientServerRemote`]: crate::prelude::ClientServerRemote
//! [`CitadelClientServerConnection`]: crate::prelude::CitadelClientServerConnection
//! [`NodeResult`]: crate::prelude::NodeResult

use crate::prefabs::ClientServerRemote;
use crate::prelude::*;
use citadel_proto::prelude::async_trait;
use futures::Future;
use std::marker::PhantomData;

/// A kernel that executes a user-provided function each time
/// a client makes a connection
pub struct ClientConnectListenerKernel<F, Fut, R: Ratchet> {
    on_channel_received: F,
    node_remote: Option<NodeRemote<R>>,
    _pd: PhantomData<Fut>,
}

impl<F, Fut, R: Ratchet> ClientConnectListenerKernel<F, Fut, R>
where
    F: Fn(CitadelClientServerConnection<R>) -> Fut + Send + Sync,
    Fut: Future<Output = Result<(), NetworkError>> + Send + Sync,
{
    pub fn new(on_channel_received: F) -> Self {
        Self {
            on_channel_received,
            node_remote: None,
            _pd: Default::default(),
        }
    }
}

#[async_trait]
impl<F, Fut, R: Ratchet> NetKernel<R> for ClientConnectListenerKernel<F, Fut, R>
where
    F: Fn(CitadelClientServerConnection<R>) -> Fut + Send + Sync,
    Fut: Future<Output = Result<(), NetworkError>> + Send + Sync,
{
    fn load_remote(&mut self, server_remote: NodeRemote<R>) -> Result<(), NetworkError> {
        self.node_remote = Some(server_remote);
        Ok(())
    }

    async fn on_start(&self) -> Result<(), NetworkError> {
        Ok(())
    }

    async fn on_node_event_received(&self, message: NodeResult<R>) -> Result<(), NetworkError> {
        match message {
            NodeResult::ConnectSuccess(ConnectSuccess {
                ticket: _,
                session_cid: cid,
                remote_addr: _,
                is_personal: _,
                v_conn_type: conn_type,
                services,
                welcome_message: _,
                channel,
                udp_rx_opt: udp_channel_rx,
                session_security_settings,
            }) => {
                let client_server_remote = ClientServerRemote::new(
                    conn_type,
                    self.node_remote.clone().unwrap(),
                    session_security_settings,
                    None,
                    None,
                );
                (self.on_channel_received)(CitadelClientServerConnection {
                    remote: client_server_remote.clone(),
                    channel: Some(channel),
                    udp_channel_rx,
                    services,
                    cid,
                    session_security_settings,
                })
                .await
            }

            other => {
                log::trace!(target: "citadel", "Unhandled server signal: {:?}", other);
                Ok(())
            }
        }
    }

    async fn on_stop(&mut self) -> Result<(), NetworkError> {
        Ok(())
    }
}