mles/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 *
5 *  Copyright (C) 2023-2025  Mles developers
6 */
7
8pub(crate) mod auth;
9pub(crate) mod cache;
10pub(crate) mod compression;
11pub(crate) mod http;
12pub(crate) mod server;
13pub(crate) mod types;
14pub(crate) mod websocket;
15
16use std::io;
17use std::net::Ipv6Addr;
18use std::path::PathBuf;
19use std::sync::Arc;
20use tokio::sync::Semaphore;
21use tokio::sync::mpsc;
22use tokio_stream::wrappers::ReceiverStream;
23use warp::Filter;
24
25const TASK_BUF: usize = 16;
26const DEFAULT_CACHE_SIZE_MB: usize = 10;
27
28/// Configuration for the Mles server
29#[derive(Debug, Clone)]
30pub struct ServerConfig {
31    /// Domain(s) to serve
32    pub domains: Vec<String>,
33    /// Contact email(s) for Let's Encrypt
34    pub email: Vec<String>,
35    /// Cache directory for ACME certificates
36    pub cache: Option<PathBuf>,
37    /// History limit for message queue
38    pub limit: u32,
39    /// Open files limit
40    pub filelimit: usize,
41    /// Web root directory
42    pub wwwroot: PathBuf,
43    /// Use Let's Encrypt staging environment
44    pub staging: bool,
45    /// Server port
46    pub port: u16,
47    /// Use http redirect for port 80
48    pub redirect: bool,
49    /// Cache size for compressed files in MB
50    pub max_cache_size_mb: Option<usize>,
51}
52
53/// Run the Mles server with the given configuration
54pub async fn run(config: ServerConfig) -> io::Result<()> {
55    let limit = config.limit;
56    let www_root_dir = config.wwwroot;
57    let filelimit = config.filelimit;
58    let max_cache_size_mb = match config.max_cache_size_mb {
59        Some(size) => size,
60        None => DEFAULT_CACHE_SIZE_MB,
61    };
62    let semaphore = Arc::new(Semaphore::new(filelimit));
63
64    // Create WebSocket event channel
65    let (tx, rx) = mpsc::channel::<types::WsEvent>(TASK_BUF);
66    let rx = ReceiverStream::new(rx);
67
68    // Spawn WebSocket event loop
69    websocket::spawn_event_loop(rx, limit);
70
71    // Create TCP listener
72    let addr = format!("[{}]:{}", Ipv6Addr::UNSPECIFIED, config.port)
73        .parse()
74        .unwrap();
75    let tcp_incoming = server::create_tcp_incoming(addr)?;
76
77    // Create TLS incoming stream
78    let tls_incoming = server::create_tls_incoming(
79        config.domains.clone(),
80        config.email,
81        config.cache,
82        config.staging,
83        tcp_incoming,
84        semaphore.clone(),
85    );
86
87    // Spawn HTTP redirect server if requested
88    if config.redirect {
89        http::spawn_http_redirect_server(config.domains.clone());
90    }
91
92    // Create WebSocket handler
93    let ws = websocket::create_ws_handler(tx.clone());
94
95    let compression_cache = cache::create_cache(max_cache_size_mb);
96    // Create HTTP file serving routes with configured cache size
97    let index = http::create_http_file_routes(
98        config.domains,
99        www_root_dir,
100        semaphore.clone(),
101        compression_cache,
102    );
103
104    // Combine all routes
105    let tlsroutes = ws.or(index);
106
107    // Serve TLS connections
108    server::serve_tls(tls_incoming, tlsroutes).await;
109
110    unreachable!()
111}