simple_pub_sub/server/
mod.rs1mod client_handler;
2use crate::topics;
3use log::error;
4use log::info;
5use std::fs::File;
6use std::io::Read;
7use tokio::net::TcpListener;
8use tokio::net::UnixListener;
9use tokio_native_tls::native_tls::{Identity, TlsAcceptor};
10
11pub trait ServerTrait {
12 fn start(&self) -> impl std::future::Future<Output = Result<(), tokio::io::Error>> + Send;
13}
14pub struct Tcp {
15 pub host: String,
16 pub port: u16,
17 pub cert: Option<String>,
18 pub cert_password: Option<String>,
19}
20
21impl ServerTrait for Tcp {
22 async fn start(&self) -> Result<(), tokio::io::Error> {
23 if let Some(cert) = &self.cert {
24 start_tls_server(
25 self.host.clone(),
26 self.port,
27 cert.clone(),
28 self.cert_password.clone(),
29 )
30 .await
31 } else {
32 start_tcp_server(format!("{}:{}", self.host, self.port)).await
33 }
34 }
35}
36pub struct Unix {
37 pub path: String,
38}
39
40impl ServerTrait for Unix {
41 async fn start(&self) -> Result<(), tokio::io::Error> {
42 start_unix_server(self.path.clone()).await
43 }
44}
45impl Drop for Unix {
46 fn drop(&mut self) {
47 if std::path::Path::new(&self.path).exists() {
48 std::fs::remove_file(&self.path).unwrap();
49 }
50 }
51}
52
53pub enum ServerType {
54 Tcp(Tcp),
55 Unix(Unix),
56}
57impl ServerTrait for ServerType {
58 async fn start(&self) -> Result<(), tokio::io::Error> {
59 match self {
60 ServerType::Tcp(tcp) => tcp.start().await,
61 ServerType::Unix(unix) => unix.start().await,
62 }
63 }
64}
65
66pub struct Server {
67 pub server_type: ServerType,
68}
69
70impl Server {
71 pub async fn start(&self) -> Result<(), tokio::io::Error> {
72 self.server_type.start().await
73 }
74}
75
76async fn start_tls_server(
78 host: String,
79 port: u16,
80 cert: String,
81 cert_password: Option<String>,
82) -> Result<(), tokio::io::Error> {
83 let mut file = match File::open(&cert) {
86 Ok(file) => file,
87 Err(e) => {
88 error!("could not open identity file: {}: {}", cert, e);
89 return Err(tokio::io::Error::new(
90 tokio::io::ErrorKind::Other,
91 "could not open identity file",
92 ));
93 }
94 };
95 let mut identity_vec = vec![];
96 file.read_to_end(&mut identity_vec)?;
97
98 let identity: Identity;
99 if let Some(cert_password) = cert_password {
100 identity = match Identity::from_pkcs12(&identity_vec, cert_password.as_str()) {
101 Ok(identity) => identity,
102 Err(e) => {
103 error!("could not parse identity file: {}", e);
104 return Err(tokio::io::Error::new(tokio::io::ErrorKind::Other, e));
105 }
106 };
107 } else {
108 identity = match Identity::from_pkcs12(&identity_vec, "") {
109 Ok(identity) => identity,
110 Err(e) => {
111 error!("could not parse identity file: {}", e);
112 return Err(tokio::io::Error::new(tokio::io::ErrorKind::Other, e));
113 }
114 };
115 }
116
117 let acceptor = TlsAcceptor::builder(identity)
118 .build()
119 .expect("cannot create TLS acceptor");
120 let acceptor = tokio_native_tls::TlsAcceptor::from(acceptor);
121
122 let listener = TcpListener::bind(format!("{host}:{port}"))
124 .await
125 .expect("cannot bind to address");
126
127 info!("Server listening on port 4433");
128 let tx = topics::get_global_broadcaster();
129
130 let _topic_handler = tokio::spawn(topics::topic_manager(tx.clone()));
131
132 loop {
133 let (stream, addr) = listener.accept().await?;
134 info!("Accepted connection from {:?}", addr);
135 let acceptor = acceptor.clone();
136 let tls_stream = match acceptor.accept(stream).await {
137 Ok(stream) => stream,
138 Err(e) => {
139 error!("could not accept TLS connection: {}", e);
140 continue;
141 }
142 };
143 client_handler::handle_client(tls_stream, tx.clone()).await;
144 }
145}
146
147async fn start_tcp_server(addr: String) -> Result<(), tokio::io::Error> {
149 let listener = TcpListener::bind(&addr).await?;
150 info!("Listening on: {}", addr);
151 info!("getting global broadcaster");
152
153 let tx = topics::get_global_broadcaster();
154
155 let _topic_handler = tokio::spawn(topics::topic_manager(tx.clone()));
156
157 loop {
158 let (socket, addr) = listener.accept().await?;
159 info!("addr is: {addr}");
160 client_handler::handle_client(socket, tx.clone()).await;
161 }
162}
163
164async fn start_unix_server(path: String) -> Result<(), tokio::io::Error> {
166 if std::path::Path::new(&path).exists() {
167 std::fs::remove_file(path.clone())?;
168 }
169
170 let listener = UnixListener::bind(&path)?;
171 info!("Listening on: {}", path);
172 info!("getting global broadcaster");
173 let tx = topics::get_global_broadcaster();
174 let _topic_handler = tokio::spawn(topics::topic_manager(tx.clone()));
175 loop {
176 let (socket, addr) = listener.accept().await?;
177 info!("addr is: {:?}", addr.as_pathname());
178 client_handler::handle_client(socket, tx.clone()).await;
179 }
180}