use crate::writers::write_to_file;
use crate::Project;
use color_eyre::eyre::Result;
use regex::Regex;
use std::io::Error;
use std::{env, fs};
pub fn write_to_main_rs(project: &Project) -> Result<(), Error> {
let contents = r#"use actix_cors::Cors;
use actix_files::Files;
use actix_identity::IdentityMiddleware;
use actix_session::storage::CookieSessionStore;
use actix_session::SessionMiddleware;
use actix_web::cookie::Key;
use actix_web::{
web::{self},
App, HttpServer,
};
use color_eyre::eyre::Result;
use rustyroad::database::Database;
use std::env;
use tera::Tera;
mod controllers;
mod models;
fn get_secret_key() -> Result<Key, Box<dyn std::error::Error>> {
let secret_key_from_env = env::var("SECRET_KEY")?;
if secret_key_from_env.len() < 32 {
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Secret key must be at least 32 characters",
)));
}
let key = Key::from(secret_key_from_env.as_bytes());
Ok(key)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
let database = web::Data::new(Database::get_database_from_rustyroad_toml().unwrap());
println!("Starting Actix web server...");
HttpServer::new(move || {
let cors = Cors::permissive();
// Load tera views from the specified directory
let tera = Tera::new("src/views/**/*").unwrap();
println!("Initializing Actix web application...");
let secret_key = get_secret_key().unwrap();
let session_mw = SessionMiddleware::builder(CookieSessionStore::default(), secret_key)
// disable secure cookie for local testing
.cookie_secure(false)
.build();
App::new()
.wrap(
actix_web::middleware::Logger::default()
.exclude("/static")
.exclude("/favicon.ico"),
)
.wrap(cors)
.wrap(IdentityMiddleware::default())
.app_data(database.clone())
.wrap(session_mw)
.app_data(web::Data::new(tera.clone())) // Updated line
.service(controllers::index::index)
.service(controllers::dashboard::dashboard_controller)
.service(controllers::login::login_controller)
.service(controllers::login::login_function)
.service(controllers::login::user_logout)
.service(Files::new("/static", "./static")) // Add this line
})
.bind(("0.0.0.0", 80))
.unwrap()
.workers(2)
.run()
.await
}
"#;
write_to_file(&project.main_rs, contents.as_bytes())?;
Ok(())
}
pub fn add_new_controller_to_main_rs(
project_name: Option<&str>,
folder_or_file_name: Option<&str>,
controller_name: &str,
) -> Result<(), Error> {
println!("CONTROLLER NAME: {}", &controller_name);
let mut current_dir = match env::current_dir() {
Ok(dir) => dir,
Err(e) => {
return Err(Error::other(format!(
"Error getting current directory: {}",
e
)))
}
};
let backup_dir = current_dir.clone();
println!("Current directory is: {}", current_dir.display());
if let Some(proj_name) = project_name {
let project_path = current_dir.join(proj_name);
if project_path.is_dir() {
println!(
"Changing into project directory: {}",
project_path.display()
);
env::set_current_dir(&project_path)?;
current_dir = env::current_dir()?;
println!("Current directory is: {}", current_dir.display());
}
}
let mut main_rs_path = current_dir.join("src");
main_rs_path.push("main.rs");
println!("main.rs path is: {}", main_rs_path.display());
if !main_rs_path.exists() || !main_rs_path.is_file() {
return Err(Error::new(
std::io::ErrorKind::NotFound,
"main.rs not found in src directory",
));
}
let controllers_folder = current_dir.join("src/controllers");
if !controllers_folder.exists() {
fs::create_dir(controllers_folder)?;
}
let controllers_mod_rs = current_dir.join("src/controllers/mod.rs");
if !controllers_mod_rs.exists() {
fs::write(controllers_mod_rs.clone(), "")?;
}
let mut contents = fs::read_to_string(&controllers_mod_rs)?;
if !contents.ends_with("\n") {
contents.push('\n');
fs::write(controllers_mod_rs, contents)?;
}
let main_rs_path = current_dir.join("src/main.rs");
let mut contents = fs::read_to_string(&main_rs_path)?;
let new_controller = format!(
"\n.service({})",
if let Some(folder_or_file_name) = folder_or_file_name {
format!("controllers::{}::{}", folder_or_file_name, controller_name)
} else {
format!("controllers::{}", controller_name)
}
);
println!("{}", new_controller);
let re = Regex::new(r".service\(controllers::\w+::\w+\)").unwrap();
let last_service_end_pos = re
.find_iter(&contents)
.last()
.ok_or(Error::new(
std::io::ErrorKind::InvalidData,
"Could not find the position to insert new controller",
))?
.end();
contents.insert_str(last_service_end_pos, &new_controller);
fs::write(main_rs_path, contents)?;
env::set_current_dir(backup_dir)?;
Ok(())
}
pub fn add_new_controller_to_existing_module_in_main_rs(
existing_controller_name: &str,
new_controller_name: &str,
) -> Result<(), Error> {
let current_dir = std::env::current_dir().unwrap();
match fs::read_to_string(current_dir.join("rustyroad.toml")) {
Ok(_) => {}
Err(_) => {
return Err(Error::new(
std::io::ErrorKind::InvalidData,
"This is not a RustyRoad project",
))
}
}
let main_rs_path = current_dir.join("src/main.rs");
let mut contents = fs::read_to_string(&main_rs_path)?;
let new_controller = format!(
".service({}::{})",
existing_controller_name, new_controller_name
);
let re = Regex::new(r"\.service\((\w+::)*\w+::\w+\)").unwrap();
let last_service_end_pos = re
.find_iter(&contents)
.last()
.ok_or(Error::new(
std::io::ErrorKind::InvalidData,
"Could not find the position to insert new controller",
))?
.end();
contents.insert_str(last_service_end_pos, &new_controller);
fs::write(main_rs_path, contents)?;
Ok(())
}