bitsock/
server.rs

1use std::{
2    fmt::{self},
3    io::{Read, Write},
4    net::{Shutdown, TcpListener, TcpStream},
5    sync::Mutex,
6};
7
8use crate::{Packet, ReadingError};
9
10/// Error type for handling physical server errors.
11///
12/// ```
13/// // Using ServerError in a custom handler
14///
15/// fn handle_server_errors(error: ServerError) {
16///     eprintln!("[SERVER][ERROR]: {}", error);
17///     
18///     // do some other logic...
19///
20/// }
21///
22/// ```
23#[derive(Clone, Debug)]
24pub struct ServerError(String);
25
26impl fmt::Display for ServerError {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        write!(f, "{}", self.0)
29    }
30}
31
32/// Logical client data structure.
33pub struct LogicalClient {
34    address: String,
35    stream: TcpStream,
36}
37
38impl LogicalClient {
39    /// Send a [Packet] to the client.
40    pub fn send(&mut self, packet: Packet) -> Result<usize, std::io::Error> {
41        let size = self.stream.write(packet.encode().as_slice())?;
42        Ok(size)
43    }
44
45    /// Listen to a [Packet] from the client.
46    pub fn read(&mut self) -> Result<Packet, ReadingError> {
47        let mut data = [0; 64];
48
49        match self.stream.read(&mut data) {
50            Ok(_) => {
51                if let Ok(packet) = Packet::decode(data.to_vec()) {
52                    Ok(packet)
53                } else {
54                    Err(ReadingError::Decode)
55                }
56            }
57            Err(_) => Err(ReadingError::Reading),
58        }
59    }
60
61    /// Get the address of the client.
62    pub fn address(&self) -> String {
63        self.address.clone()
64    }
65
66    /// Close the connection with the client.
67    pub fn disconnect(&self) -> Result<(), std::io::Error> {
68        self.stream.shutdown(Shutdown::Both)?;
69
70        Ok(())
71    }
72}
73
74/// Enum used to specify if the log is generated by a physical client or a physical server.
75pub enum LogStage {
76    SERVER,
77    CLIENT,
78}
79
80/// Enum used to specify the `level` of a log. See [Server::log] for an example.
81pub enum LogLevel {
82    INFO,
83    WARN,
84    ERROR,
85}
86
87/// Physical server data structure.
88pub struct Server<'a> {
89    pub address: &'a str,
90    pub port: u16,
91    listener: Option<TcpListener>,
92    error_handler: Option<Box<dyn Fn(ServerError) -> () + Send + Sync>>,
93    client_handler: Box<dyn Fn(LogicalClient) -> () + Send + Sync>,
94}
95
96impl<'a> Server<'a> {
97    /// Creates a new physical server object. Is recommended to use [ServerBuilder] for more customization.
98    pub fn new(address: &'a str, port: u16) -> Self {
99        Self {
100            address,
101            port,
102            listener: None,
103            error_handler: None,
104            client_handler: Box::new(|c| println!("{} connected.", c.address())),
105        }
106    }
107
108    /// Start the server execution, this will start a loop.
109    pub fn run(&mut self) {
110        self.listener =
111            if let Ok(listener) = TcpListener::bind(format!("{}:{}", self.address, self.port)) {
112                Some(listener)
113            } else {
114                self.handle_error(ServerError(format!(
115                    "failed to bind listener to address {}:{}",
116                    self.address, self.port,
117                )));
118                None
119            };
120
121        let handler = Mutex::new(&self.client_handler);
122
123        if let Err(_) = crossbeam::thread::scope(|s| {
124            s.spawn(|_| {
125                if let Some(listener) = &self.listener {
126                    for stream in listener.incoming() {
127                        match stream {
128                            Ok(stream) => {
129                                let client = LogicalClient {
130                                    address: stream.local_addr().unwrap().to_string(),
131                                    stream,
132                                };
133                                handler.lock().unwrap()(client);
134                            }
135                            Err(e) => {
136                                self.handle_error(ServerError(format!("Connection failed: {}", e)))
137                            }
138                        }
139                    }
140                }
141            });
142        }) {
143            self.handle_error(ServerError("Failed to spawn listener thread".to_string()));
144        }
145    }
146
147    /// Internal function, used to handle errors propagated by the server.
148    /// You can also use a custom handler specifing it when building the physical server (see [ServerBuilder::error_handler]).
149    fn handle_error(&self, error: ServerError) {
150        if let Some(handler) = &self.error_handler {
151            handler(error);
152        } else {
153            println!("{}", error);
154        }
155    }
156}
157
158/// Server builder object.
159/// Can be used to create [Server] objects in a convenient and flexible way.
160/// ```
161/// //e.g.
162/// fn main() {
163///     let server = ServerBuilder::new().address("192.168.1.151").port(4353).build();
164/// }
165/// ```
166pub struct ServerBuilder<'a> {
167    address: &'a str,
168    port: u16,
169    error_handler: Option<Box<dyn Fn(ServerError) -> () + Send + Sync>>,
170    client_handler: Box<dyn Fn(LogicalClient) -> () + Send + Sync>,
171}
172
173impl<'a> ServerBuilder<'a> {
174    /// Creates a new builder
175    pub fn new() -> Self {
176        Self {
177            address: "0.0.0.0",
178            port: 4444,
179            error_handler: None,
180            client_handler: Box::new(|c| println!("{} connected.", c.address())),
181        }
182    }
183
184    /// Sets the server address.
185    pub fn address(mut self, address: &'a str) -> Self {
186        Self {
187            address: address,
188            port: self.port,
189            error_handler: std::mem::replace(&mut self.error_handler, None),
190            client_handler: self.client_handler,
191        }
192    }
193
194    /// Sets the server port.
195    pub fn port(mut self, port: u16) -> Self {
196        Self {
197            address: self.address,
198            port: port,
199            error_handler: std::mem::replace(&mut self.error_handler, None),
200            client_handler: self.client_handler,
201        }
202    }
203
204    /// Sets the server `error handler`
205    pub fn error_handler(self, handler: Box<dyn Fn(ServerError) -> () + Send + Sync>) -> Self {
206        Self {
207            address: self.address,
208            port: self.port,
209            error_handler: Some(handler),
210            client_handler: self.client_handler,
211        }
212    }
213
214    /// Sets the server `client handler`
215    pub fn client_handler(
216        mut self,
217        handler: Box<dyn Fn(LogicalClient) -> () + Send + Sync>,
218    ) -> Self {
219        Self {
220            address: self.address,
221            port: self.port,
222            error_handler: std::mem::replace(&mut self.error_handler, None),
223            client_handler: handler,
224        }
225    }
226
227    /// Build the server object.
228    pub fn build(mut self) -> Server<'a> {
229        Server {
230            address: self.address,
231            port: self.port,
232            listener: None,
233            error_handler: std::mem::replace(&mut self.error_handler, None),
234            client_handler: self.client_handler,
235        }
236    }
237}