use comunic_server::{cleanup_thread, server}; use comunic_server::data::config::{conf, Config}; use comunic_server::data::error::Res; use comunic_server::data::user::UserID; use comunic_server::helpers::{account_helper, database}; use comunic_server::utils::date_utils::current_year; type MainActionFunction = Res; struct Action { name: String, description: String, arguments: Vec, function: Box) -> MainActionFunction>, } fn get_actions() -> Vec { vec![ // Start server Action { name: "serve".to_string(), description: "Start the Comunic Server (default action)".to_string(), arguments: vec![], function: Box::new(serve), }, // Show help Action { name: "help".to_string(), description: "Show this help".to_string(), arguments: vec![], function: Box::new(help), }, // Reset password Action { name: "reset_password".to_string(), description: "Create a password reset URL for a user".to_string(), arguments: vec!["user_id".to_string()], function: Box::new(reset_password), } ] } #[actix_rt::main] async fn main() -> std::io::Result<()> { let args: Vec = std::env::args().collect(); let conf_file = match args.get(1) { Some(el) => el.to_string(), None => { eprintln!("Please specify configuration file as first argument!"); std::process::exit(-3); } }; // Load configuration Config::load(&conf_file).expect("Could not load configuration!"); // Connect to the database database::connect(&conf().database).expect("Could not connect to database!"); // Get selected action let action = args .get(2) .map(|a| a.as_str()) .unwrap_or("serve") .to_string(); let actions = get_actions(); let selected_action = actions .iter() .filter(|p| p.name.eq(&action)) .next(); let selected_action = match selected_action { None => { eprintln!("Action {} invalid! For more information try 'help'!", action); std::process::exit(-1); } Some(a) => a }; if !selected_action.arguments.is_empty() && selected_action.arguments.len() + 3 != args.len() { eprintln!("Invalid number of arguments!"); std::process::exit(-2); } let args = match args.len() { 0 | 1 | 2 => vec![], _ => (&args[3..]).to_vec() }; let res = (selected_action.function)(args.to_vec()); res.expect("Failed to execute action!"); Ok(()) } /// Start Comunic Server (main action) fn serve(_a: Vec) -> Res { let t = std::thread::spawn(|| { let sys = actix::System::new("sys"); let promise = async { // Start cleanup thread cleanup_thread::start().expect("Failed to start cleanup thread!"); // Start the server server::start_server(conf()).await }; tokio::runtime::Runtime::new().unwrap().block_on(promise) .expect("Failed to start server!"); let _ = sys.run(); }); t.join().unwrap(); Ok(()) } fn help(_a: Vec) -> Res { println!("Comunic API v3 Server - (c) Pierre HUBERT 2012 - {}", current_year()); println!("Usage: {} [conf-file] [action] [args...]", std::env::args().next().unwrap()); println!("Available actions:"); for action in get_actions() { println!("\t{}\t{} - {}", action.name, action.arguments.iter().map(|s| format!("[{}]", s)).collect::>().join(" "), action.description ); } Ok(()) } fn reset_password(args: Vec) -> Res { let user_id = UserID::new(args[0].parse::()?); let token = account_helper::generate_password_reset_token(&user_id)?; println!("{}", conf().password_reset_url.replace("{TOKEN}", &token)); Ok(()) }