use actix_cors::Cors; use actix_web::{http::header, middleware, web, App, HttpRequest, HttpResponse, HttpServer}; use anyhow::Result; use diesel::prelude::*; use std::fs; use std::thread; use std::time::Duration; #[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; use uuidv7::Uuid; use juniper_actix::graphql_handler; use fiddle::{api, db, init, prune_job, prune_many, CONFIG}; #[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; fn tamper_prune() -> Result<()> { let db_conn = &mut db::POOL.get()?; let entries = fs::read_dir(&CONFIG.data_dir)?; let allowed: Vec = db::schema::directories::table .select(db::schema::directories::id) .load::(db_conn)? .iter() .map(|id| id.to_string()) .collect(); let mut prunes: Vec = vec![]; for p in entries { let path = match p { Ok(x) => x.path(), Err(e) => { log::error!("{:?}", e); continue; } }; let relative = match path.strip_prefix(&CONFIG.data_dir) { Ok(x) => x.to_string_lossy().to_string(), Err(e) => { log::error!("{:?}", e); continue; } }; if path.is_file() || (path.is_dir() && !allowed.contains(&relative)) { log::warn!("Invalid entry found: {}", relative); prunes.push(relative); } } prune_many(&prunes)?; Ok(()) } async fn not_found() -> &'static str { "Not found!" } async fn graphql_route( req: HttpRequest, payload: web::Payload, schema: web::Data, ) -> Result { let context = api::Context { db_pool: db::POOL.clone(), loaders: api::context::Loaders::default(), }; graphql_handler(&schema, &context, req, payload).await } #[tokio::main] async fn main() -> Result<()> { env_logger::init(); init(); thread::spawn(move || { let sleep_dur = Duration::from_secs(CONFIG.auto_prune_sleep); loop { prune_job(); thread::sleep(sleep_dur); } }); thread::spawn(move || { let sleep_dur = Duration::from_secs(CONFIG.tamper_sleep); loop { if let Err(e) = tamper_prune() { log::error!("{:?}", e); } thread::sleep(sleep_dur); } }); HttpServer::new(move || { App::new() .app_data(web::Data::new(api::schema())) .wrap(middleware::Logger::default()) .wrap(middleware::Compress::default()) .wrap( Cors::default() .allow_any_origin() .allowed_methods(["POST", "GET"]) .allowed_headers([header::ACCEPT]) .allowed_header(header::CONTENT_TYPE) .supports_credentials() .max_age(3600), ) .service( web::resource("/graphql") .route(web::post().to(graphql_route)) .route(web::get().to(graphql_route)), ) .default_service(web::to(not_found)) }) .bind(("0.0.0.0", 80))? .run() .await?; Ok(()) }