This commit is contained in:
Piotr Siuszko 2023-08-29 19:54:32 +02:00
parent 0dc478457c
commit 1918896996
7 changed files with 771 additions and 1174 deletions

21
.github/workflows/rust.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: build
on:
workflow_dispatch:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
env:
CARGO_TERM_COLOR: always
jobs:
build-unix:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: rustup toolchain install stable --profile minimal
- uses: Swatinem/rust-cache@v2
- name: Build
run: cargo build --verbose

1775
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "lwa_simple_server" name = "lwa_simple_server"
version = "0.1.0" version = "0.2.0"
authors = ["Mev Lyshkin <mev_lyshkin@protonmail.com>"] authors = ["Mev Lyshkin <mev_lyshkin@protonmail.com>"]
edition = "2018" edition = "2018"
@ -15,11 +15,11 @@ lto = true
opt-level = 2 opt-level = 2
[dependencies] [dependencies]
actix-web = { version = "~3", features = ["openssl"] } actix-web = { version = "4.4", features = ["openssl"] }
openssl = { version = "0.10" } openssl = { version = "0.10" }
actix-files = "^0.5.0" actix-files = "^0.6"
actix-cors = "^0.5.4" actix-cors = "^0.6"
env_logger = "^0.8.3" env_logger = "^0.10"
confy = "^0.4.0"
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
clap = { version = "^4.4", features = ["derive"] }

View File

@ -26,22 +26,13 @@ To start run it in folder that should be root folder of hosted site:
```bash ```bash
cd desired/folder cd desired/folder
lwa_simple_server lwa_simple_server "folder_to_host"
``` ```
After first start of the program in configs folder will be created `lwa_simple_server` directory with `lwa_simple_server.toml` in it with config values:
```toml
folder_to_host = '/example/path/TestProject'
bind_address = 'localhost:8000'
private_key_file = 'key.pem'
certificate_chain_file = 'cert.pem'
use_ssl = false
```
## SSL ## SSL
If you would like to use OpenSSL create key with command below and pass paths to generated files in config above in order to use it: If you would like to use OpenSSL create key with command below and pass paths to generated files as arguments in command in order to use it:
```bash ```bash
openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost' openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'

44
src/app.rs Normal file
View File

@ -0,0 +1,44 @@
use clap::{command, Parser};
use std::path::PathBuf;
/// Simple server made with hosting locally webgl games in mind.
#[derive(Debug, Parser, Clone)]
#[command(name = "lwa_simple_server", version = "0.1.0", author = "Mev Lyshkin")]
pub struct SimpleServer {
/// Folder to host
pub folder_to_host: String,
/// Should use SSL, false by default
#[arg(long)]
pub ssl: bool,
/// Specifies hosting address, "localhost:8080" by default
#[arg(short, long)]
pub address: Option<String>,
// Specifies folder containing "key.pem" and "cert.pem" required for ssl hosting, defaults to current folder
#[arg(short, long)]
certificates_folder: Option<PathBuf>,
}
impl SimpleServer {
pub fn get_address(&self) -> String {
if self.address.is_some() {
return self.address.clone().unwrap();
}
"localhost:8080".to_string()
}
fn get_certificates_folder(&self) -> PathBuf {
if self.certificates_folder.is_some() {
self.certificates_folder.clone().unwrap()
} else {
PathBuf::from(".")
}
}
pub fn get_private_key_path(&self) -> PathBuf {
std::fs::canonicalize(self.get_certificates_folder().join("key.pem")).unwrap()
}
pub fn get_certificate_chain_file_path(&self) -> PathBuf {
std::fs::canonicalize(self.get_certificates_folder().join("cert.pem")).unwrap()
}
}

View File

@ -1,20 +0,0 @@
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ServerConfig {
pub folder_to_host: String,
pub bind_address: String,
pub private_key_file: String,
pub certificate_chain_file: String,
pub use_ssl: bool
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
folder_to_host: String::from(std::env::current_dir().unwrap().to_str().unwrap()),
bind_address: "localhost:8000".to_string(),
private_key_file: "key.pem".to_string(),
certificate_chain_file: "cert.pem".to_string(),
use_ssl: false,
}
}
}

View File

@ -1,50 +1,68 @@
#[macro_use]
extern crate serde_derive;
extern crate confy;
use actix_cors::Cors; use actix_cors::Cors;
use actix_files as fs; use actix_files as fs;
use actix_web::{middleware, App, HttpServer}; use actix_web::{middleware, App, HttpServer};
use clap::Parser;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use std::env; use std::env;
mod config; mod app;
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
let app_args = crate::app::SimpleServer::parse();
env::set_var("RUST_LOG", "actix_web=debug,actix_server=info"); env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");
env_logger::init(); env_logger::init();
let cfg: config::ServerConfig = confy::load("lwa_simple_server").unwrap(); let path = app_args.folder_to_host.clone();
{ {
println!("The configuration is:\n{:#?}", cfg);
// `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'` // `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'`
println!( println!(
"Starting server on address: {} with hosted folder: {} wit SSL: {}", "Starting server on address: {} with hosted folder: {} wit SSL: {}",
cfg.bind_address, cfg.folder_to_host, cfg.use_ssl app_args.get_address(),
path,
app_args.ssl
); );
} }
let server = HttpServer::new(move || { let server = HttpServer::new(move || {
let cfg: config::ServerConfig = confy::load("lwa_simple_server").unwrap();
App::new() App::new()
.wrap(middleware::Compress::default())
.wrap(middleware::Logger::default()) .wrap(middleware::Logger::default())
.wrap(Cors::default()) .wrap(Cors::default())
.service(fs::Files::new("/", &cfg.folder_to_host).index_file("index.html")) .service(
fs::Files::new("/", &path)
.index_file("index.html")
.use_last_modified(true),
)
}); });
if cfg.use_ssl { if app_args.ssl {
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder
.set_private_key_file(&cfg.private_key_file, SslFiletype::PEM)
.unwrap();
builder.set_certificate_chain_file(&cfg.certificate_chain_file).unwrap();
server.bind_openssl(&cfg.bind_address, builder)? if let Err(error) =
.run() builder.set_private_key_file(&app_args.get_private_key_path(), SslFiletype::PEM)
.await {
eprintln!(
"Could not read {}: {}",
app_args.get_private_key_path().display(),
error
)
}
if let Err(error) =
builder.set_certificate_chain_file(&app_args.get_certificate_chain_file_path())
{
eprintln!(
"Could not read {}: {}",
app_args.get_certificate_chain_file_path().display(),
error
)
}
server
.bind_openssl(&app_args.get_address(), builder)?
.run()
.await
} else { } else {
server.bind(&cfg.bind_address)? server.bind(&app_args.get_address())?.run().await
.run()
.await
} }
} }