Files
aviation/api/src/main.rs
2025-05-03 21:22:07 -04:00

145 lines
4.0 KiB
Rust

use std::env;
use std::time::Duration;
use actix_cors::Cors;
use actix_web::{App, HttpServer, middleware::Logger, web};
use dotenv::from_filename;
use reqwest::Certificate;
use crate::account::hash;
use crate::users::{User, ADMIN_ROLE};
mod account;
mod airports;
mod db;
mod error;
mod metars;
mod scheduler;
mod system;
mod users;
#[derive(Debug, Clone)]
struct AppState {
client: reqwest::Client,
}
#[actix_web::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
initialize_environment()?;
db::initialize().await?;
// scheduler::update_airports();
// Initialize admin user
let admin_email = env::var("ADMIN_EMAIL");
let admin_password = env::var("ADMIN_PASSWORD");
if admin_email.is_ok() && admin_password.is_ok() {
let email = admin_email.unwrap();
if User::select(&email).await.is_none() {
log::debug!("Creating default administrator");
let password = admin_password.unwrap();
let password_hash = hash(&password)?;
if email == "admin@example.com" || password == "CHANGEME" {
log::warn!(
"Default admin credentials are in use, update the ADMIN_EMAIL and ADMIN_PASSWORD."
);
}
let admin_user = User {
email,
email_verified: true,
password_hash,
role: ADMIN_ROLE.to_string(),
first_name: "Admin".to_string(),
last_name: "".to_string(),
avatar: None,
updated_at: Default::default(),
created_at: Default::default(),
};
match admin_user.insert().await {
Ok(_) => log::debug!("Default administrator was successfully created"),
Err(err) => {
log::warn!("{}", err);
}
};
}
}
let mut client_builder = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.tls_built_in_root_certs(true);
if let Ok(val) = env::var("NGINX_SSL_ENABLED") {
if val == "true" {
let certificate_path = env::var("SSL_CA_PATH")?;
let certificate_data = std::fs::read(certificate_path)?;
let certificate = Certificate::from_pem(&certificate_data)?;
client_builder = client_builder.add_root_certificate(certificate);
}
}
let client = client_builder
.build()
.expect("Failed to create reqwest client");
let state = AppState { client };
let host = "0.0.0.0";
let port = env::var("API_PORT").unwrap_or("5000".to_string());
let server = match HttpServer::new(move || {
let cors = Cors::default()
.allow_any_origin()
.allow_any_method()
.allow_any_header()
.supports_credentials()
.max_age(3600);
App::new()
.wrap(cors)
.wrap(Logger::default())
.app_data(web::Data::new(state.clone()))
.service(
web::scope("api")
.configure(airports::init_routes)
.configure(metars::init_routes)
.configure(account::init_routes)
.configure(users::init_routes)
.configure(system::init_routes),
)
})
.bind(format!("{}:{}", host, port))
{
Ok(b) => {
log::info!("Server bound to {}:{}", host, port);
b
}
Err(err) => {
log::error!("Could not bind server: {}", err);
return Err(err.into());
}
};
if let Err(err) = server.run().await {
return Err(err.into());
}
Ok(())
}
fn initialize_environment() -> std::io::Result<()> {
// Iterate over files in the current directory
for entry in std::fs::read_dir(".")? {
let entry = entry?;
let path = entry.path();
// Check if the file name starts with ".env" and is a file
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
if file_name.starts_with(".env") && path.is_file() {
// Try to load the file
if let Err(err) = from_filename(&file_name) {
eprintln!("Failed to load {}: {}", file_name, err);
} else {
println!("Loaded: {}", file_name);
}
}
}
}
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,api=info"));
Ok(())
}