use actix_cors::Cors; use actix_files as fs; use actix_web::{web, middleware, App, Error, HttpResponse, HttpServer, Either}; use futures::{Future, IntoFuture}; use std::env; use lootalot_db as db; use crate::api; type AppPool = web::Data; type PlayerId = web::Path; type ItemId = web::Json; #[derive(Serialize, Deserialize, Debug)] struct NewGroupLoot { source_name: String, items: Vec, } type MaybeForbidden = actix_web::Either>, HttpResponse>; /// Wraps call to the database query and convert its result as a async HttpResponse fn db_call( pool: AppPool, query: api::ApiActions, ) -> impl Future { let conn = pool.get().unwrap(); web::block(move || api::execute(&conn, query)).then(|res| match res { Ok(r) => HttpResponse::Ok().json(r), Err(e) => { dbg!(&e); HttpResponse::InternalServerError().finish() } }) } fn forbidden_to_players(id: i32, params: (AppPool, api::ApiActions)) -> MaybeForbidden { if id != 0 { Either::B(HttpResponse::Forbidden().finish()) } else { Either::A(Box::new(db_call(params.0, params.1))) } } fn configure_app(config: &mut web::ServiceConfig) { use api::ApiActions as Q; config.service( web::scope("/api") .service( web::scope("/players") .service( web::resource("/").route( web::get().to_async(|pool| db_call(pool, Q::FetchPlayers)), ), //.route(web::post().to_async(endpoints::new_player)) ) // List of players .service( web::scope("/{player_id}") .route("/", web::get().to_async(|pool, player: PlayerId| { db_call(pool, Q::FetchPlayer(*player)) })) .route("/notifications", web::get().to_async(|pool, player: PlayerId| { db_call(pool, Q::FetchNotifications(*player)) })) .service( web::resource("/claims") //.route(web::get().to_async(endpoints::player_claims)) .route(web::put().to_async( |pool, (player, data): (PlayerId, ItemId)| { db_call(pool, Q::ClaimItem(*player, *data)) }, )) .route(web::delete().to_async( |pool, (player, data): (PlayerId, ItemId)| { db_call( pool, Q::UnclaimItem(*player, *data), ) }, )), ) .service( web::resource("/wealth") //.route(web::get().to_async(...)) .route(web::put().to_async( |pool, (player, data): (PlayerId, web::Json)| { db_call( pool, Q::UpdateWealth(*player, *data), ) }, )), ) .service( web::resource("/loot") .route(web::get().to_async(|pool, player: PlayerId| { db_call(pool, Q::FetchLoot(*player)) })) .route(web::put().to_async( move |pool, (player, data): (PlayerId, web::Json)| { db_call(pool, Q::BuyItems(*player, data.into_inner())) }, )) .route(web::post().to( move |pool, (player, data): (PlayerId, web::Json)| { forbidden_to_players(*player, (pool, Q::AddLoot(data.into_inner().items))) }, )) .route(web::delete().to_async( move |pool, (player, data): (PlayerId, web::Json)| { db_call(pool, Q::SellItems(*player, data.into_inner())) }, )), ), ), ) .route("/claims", web::get().to_async(|pool| db_call(pool, Q::FetchClaims))) .route( "/items", web::get() .to_async(move |pool: AppPool| db_call(pool, Q::FetchInventory)), ), ); } pub fn serve() -> std::io::Result<()> { let www_root: String = env::var("WWW_ROOT").expect("WWW_ROOT must be set"); let pool = db::create_pool(); dbg!(&www_root); HttpServer::new(move || { App::new() .data(pool.clone()) .configure(configure_app) .wrap( Cors::new() .allowed_origin("http://localhost:8080") .allowed_methods(vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"]) .max_age(3600), ) .wrap(middleware::Logger::default()) .service(fs::Files::new("/", www_root.clone()).index_file("index.html")) }) .bind("127.0.0.1:8088")? .run() }