#![allow(clippy::needless_return)]
use std::convert::From;
use std::io::Write;
use std::sync::{Arc, Mutex};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!(
"{} V{}",
env!("CARGO_PKG_NAME").to_uppercase(),
env!("CARGO_PKG_VERSION")
);
println!();
let workspace_path =
std::path::PathBuf::from(if let Some(workspace_dir) = std::env::args().nth(1) {
if let Err(err) = std::fs::create_dir_all(workspace_dir.clone()) {
panic!(
"Error : can not create workspace {} : {}",
workspace_dir, err
);
}
workspace_dir
} else {
String::from("database")
});
let temp_logs_list = Arc::new(Mutex::new(vec![]));
let temp_logs_list_for_dispatcher = temp_logs_list.clone();
let mut temp_logger = charlie_buffalo::Logger::new(
charlie_buffalo::new_dispatcher(Box::from(move |log: charlie_buffalo::Log| {
temp_logs_list_for_dispatcher.lock().unwrap().push(log);
})),
charlie_buffalo::new_dropper(Box::from(|_: &charlie_buffalo::Logger| {})),
);
temp_logger.push(
vec![
(String::from("event"), String::from("setup")),
(String::from("level"), String::from("INFO")),
],
Some("setup of the program"),
);
let localhost = String::from("localhost");
temp_logger.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let mut settings_path = workspace_path.clone();
settings_path.push("settings.toml");
let settings =
pontus_onyx::http_server::load_or_create_settings(settings_path.clone(), &mut temp_logger);
temp_logger.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let logger =
pontus_onyx::http_server::load_or_create_logger(&settings, temp_logger, temp_logs_list);
logger
.lock()
.unwrap()
.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let users = pontus_onyx::http_server::load_or_create_users(&settings, logger.clone());
logger
.lock()
.unwrap()
.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let database = pontus_onyx::http_server::load_or_create_database(&settings, logger.clone());
logger
.lock()
.unwrap()
.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let settings = Arc::new(Mutex::new(settings));
let users = Arc::new(Mutex::new(users));
let program_state = Arc::new(Mutex::new(pontus_onyx::http_server::ProgramState::default()));
let oauth_form_tokens: Arc<Mutex<Vec<pontus_onyx::http_server::middlewares::OauthFormToken>>> =
Arc::new(Mutex::new(vec![]));
let access_tokens: Arc<Mutex<Vec<pontus_onyx::http_server::AccessBearer>>> =
Arc::new(Mutex::new(vec![]));
logger.lock().unwrap().push(
vec![
(String::from("event"), String::from("setup")),
(String::from("level"), String::from("INFO")),
],
Some("starting servers"),
);
logger
.lock()
.unwrap()
.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let workspace_path_for_event_loop = workspace_path.clone();
let (history_sender, history_receiver) =
std::sync::mpsc::channel::<pontus_onyx::http_server::DbEvent>();
std::thread::spawn(move || {
let mut event_file = std::fs::File::options()
.create(true)
.append(true)
.open(workspace_path_for_event_loop.join("events.bin"))
.unwrap();
loop {
for event in &history_receiver {
let mut row = serde_json::to_string(&event).unwrap();
row += ",\n";
event_file.write_all(row.as_bytes()).unwrap();
event_file.flush().unwrap();
}
}
});
pontus_onyx::http_server::setup_and_run_https_server(
settings.clone(),
database.clone(),
access_tokens.clone(),
oauth_form_tokens.clone(),
users.clone(),
program_state.clone(),
logger.clone(),
&workspace_path,
Some(history_sender.clone()),
);
if !program_state.lock().unwrap().https_mode {
println!();
println!("\tâš Falling back onto HTTP mode");
println!();
println!("\tâš All data to and from HTTP server can be read and compromised.");
println!("\tâš It should better serve data though HTTPS.");
println!("\tâš You should better fix previous issues and/or get an SSL certificate.");
println!("\tâš More help : https://github.com/Jimskapt/pontus_onyx/wiki/SSL-cert");
println!();
}
let http_port = settings.lock().unwrap().port;
logger.lock().unwrap().push(
vec![
(String::from("event"), String::from("setup")),
(String::from("module"), String::from("http")),
(String::from("level"), String::from("INFO")),
],
Some(&format!(
"API should now listen to http://{}:{http_port}/",
settings
.lock()
.unwrap()
.domain
.as_ref()
.unwrap_or_else(|| &localhost)
)),
);
logger
.lock()
.unwrap()
.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let handles = {
let mut handles = String::new();
let settings = settings.lock().unwrap();
let users = users.lock().unwrap();
let mut ports = vec![settings.port];
if let Some(ref https) = settings.https {
if program_state.lock().unwrap().https_mode {
ports = vec![https.port, settings.port];
}
}
let db_users: Vec<String> = users.get_usernames().into_iter().cloned().collect();
for port in ports {
for user in &db_users {
handles += &format!(
"\n\t{user}@{}:{port}",
settings.domain.as_ref().unwrap_or_else(|| &localhost)
);
}
}
handles
};
logger.lock().unwrap().push(
vec![
(String::from("event"), String::from("startup")),
(String::from("level"), String::from("INFO")),
],
Some(&format!("Available handles are : {handles}",)),
);
logger
.lock()
.unwrap()
.push(vec![], Some("*CONSOLE_WHITESPACE*"));
let enable_hsts = match &settings.lock().unwrap().https {
Some(https) => https.enable_hsts,
None => program_state.lock().unwrap().https_mode,
};
let domain = settings
.lock()
.unwrap()
.domain
.as_ref()
.unwrap_or_else(|| &localhost)
.clone();
let logger_for_server = logger.clone();
let http_binding = actix_web::HttpServer::new(move || {
actix_web::App::new()
.wrap(pontus_onyx::http_server::middlewares::Hsts {
enable: enable_hsts,
})
.wrap(pontus_onyx::http_server::middlewares::Auth {
logger: logger_for_server.clone(),
})
.wrap(pontus_onyx::http_server::middlewares::Logger {
logger: logger_for_server.clone(),
})
.configure(pontus_onyx::http_server::configure_server(
settings.clone(),
database.clone(),
access_tokens.clone(),
oauth_form_tokens.clone(),
users.clone(),
program_state.clone(),
logger_for_server.clone(),
&workspace_path,
Some(history_sender.clone()),
))
})
.bind(format!("{domain}:{http_port}"));
match http_binding {
Ok(binding) => binding.run().await,
Err(e) => {
logger.lock().unwrap().push(
vec![
(String::from("event"), String::from("setup")),
(String::from("module"), String::from("http")),
(String::from("level"), String::from("ERROR")),
],
Some(&format!("can not set up HTTP server : {}", e)),
);
Err(e)
}
}
}