mod app_state; mod auth; mod handlers; mod lookup; mod s3_utils; mod thumbnail; use actix_cors::Cors; use actix_web::{ http::header::{self, HeaderName}, middleware::Logger, web, App, HttpServer, }; use app_state::AppState; use handlers::{ get_current_user_handler, get_quota_handler, increase_quota_handler, proxy_handler, set_quota_handler, upload_handler, }; use log::warn; use std::env; use tokio::task::spawn_blocking; #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); warn!("Started"); let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string()); let addr = format!("0.0.0.0:{}", port); let app_state = AppState::new().await; let app_state_clone = app_state.clone(); // Используем spawn_blocking для работы, которая не совместима с Send spawn_blocking(move || { let rt = tokio::runtime::Handle::current(); rt.block_on(async move { app_state_clone.cache_filelist().await; }); }); HttpServer::new(move || { // Настройка CORS middleware let cors = Cors::default() .allow_any_origin() // TODO: ограничить конкретными доменами в продакшене .allowed_methods(vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"]) .allowed_headers(vec![ header::DNT, header::USER_AGENT, HeaderName::from_static("x-requested-with"), header::IF_MODIFIED_SINCE, header::CACHE_CONTROL, header::CONTENT_TYPE, header::RANGE, header::AUTHORIZATION, ]) .expose_headers(vec![header::CONTENT_LENGTH, header::CONTENT_RANGE]) .supports_credentials() .max_age(1728000); // 20 дней App::new() .app_data(web::Data::new(app_state.clone())) .wrap(cors) .wrap(Logger::default()) .route("/", web::get().to(get_current_user_handler)) .route("/", web::post().to(upload_handler)) .route("/quota", web::get().to(get_quota_handler)) .route("/quota/increase", web::post().to(increase_quota_handler)) .route("/quota/set", web::post().to(set_quota_handler)) .route("/{path:.*}", web::get().to(proxy_handler)) }) .bind(addr)? .run() .await }