diff --git a/Cargo.toml b/Cargo.toml index 0fd4ed9..393700c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ dotenv = "*" env_logger = "*" futures = "0.1" diesel = "*" +serde = "*" [workspace] members = [ diff --git a/src/api.rs b/src/api.rs index c5e4527..4b234b5 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,32 +1,37 @@ use actix_web::{web, web::Json, Error, HttpResponse, Result}; use futures::Future; -use lootalot_db::{Pool}; +use lootalot_db::Pool; +use lootalot_db::{ActionResult, DbConnection, Item, Player as PlayerData, QueryResult}; -// Wrapper for database queries. -//fn db_query(q: fn(...)) -> impl Future { -// -//} +pub struct DbApi<'q>(&'q DbConnection); -mod player { - use lootalot_db::{Player as PlayerData, Item, ActionResult, QueryResult, DbConnection}; +impl<'q> DbApi<'q> { + pub fn with_conn(conn: &'q DbConnection) -> Self { + Self(conn) + } - /// A reference to a player in database - pub(super) struct Player(pub(super) i32); + pub fn fetch_players(self) -> QueryResult> { + PlayerData::fetch_list(self.0) + } - impl Player { - /// Fetch all players from db - pub(super) fn all(conn: &DbConnection) -> QueryResult> { - PlayerData::fetch_list(conn) - } - /// Fetch the content of a player's chest - pub(super) fn loot(self, conn: &DbConnection) -> QueryResult> { - PlayerData::fetch_loot(self.0, conn) - } - pub(super) fn claim(self, item: i32, conn: &DbConnection) -> ActionResult { - PlayerData::action_claim_object(self.0, item, conn) - } + pub fn as_player(self, id: i32) -> AsPlayer<'q> { + AsPlayer { id, conn: self.0 } + } +} +pub struct AsPlayer<'q> { + id: i32, + conn: &'q DbConnection, +} + +impl<'q> AsPlayer<'q> { + /// Fetch the content of a player's chest + pub fn loot(self) -> QueryResult> { + PlayerData::fetch_loot(self.id, self.conn) + } + pub fn claim(self, item: i32) -> ActionResult { + PlayerData::action_claim_object(self.id, item, self.conn) } } @@ -39,62 +44,31 @@ mod player { // .claim(item_id) -> Success status (bool) // .unclaim(item_id) -> Success status (bool) // .sell(item_id) -> Success status (bool, earned) +// .income(wealth_data) -> Success status (bool, new_wealth) +// .with_admin() +// .resolve_claims() +// // fn db_call(f: fn(DbApi) -> ApiResponse) { ... } // ApiResponse needs to be Serialize -// endpoint example -// fn endpoint_name(params...) -> impl ... { -// let param_1 = { ... }; -// db_call(move |api| api.with_player(param_1).loot()) -// } - -pub fn players_list( - pool: web::Data +pub fn db_call< + J: serde::ser::Serialize + Send + 'static, + Q: Fn(DbApi) -> QueryResult + Send + 'static, +>( + pool: web::Data, + query: Q, ) -> impl Future { + let conn = pool.get().unwrap(); web::block(move || { - let conn = pool.get().unwrap(); - player::Player::all(&conn) + let api = DbApi::with_conn(&conn); + query(api) }) .then(|res| match res { - Ok(players) => { - HttpResponse::Ok().json(players) - } - Err(_) => { + Ok(players) => HttpResponse::Ok().json(players), + Err(e) => { + dbg!(&e); HttpResponse::InternalServerError().finish() } }) } - -pub fn chest_content( - player_id: web::Path, - pool: web::Data -) -> impl Future { - web::block(move || { - let conn = pool.get().unwrap(); - player::Player(*player_id).loot(&conn) - }) - .then(|res| match res { - Ok(items) => HttpResponse::Ok().json(items), - Err(_) => HttpResponse::InternalServerError().finish(), - }) -} - -fn put_request( - params: web::Path<(i32, i32)>, - pool: web::Data -) -> impl Future { - web::block(move || { - let (player_id, item_id) = *params; - let conn = pool.get().unwrap(); - player::Player(player_id).claim(item_id, &conn) - }) - .then(|res| match res { - Ok(status) => HttpResponse::Ok().json(status), - Err(_) => HttpResponse::InternalServerError().finish(), - }) -} - -fn withdraw_request(_player_id: i32, _item_id: i32) -> Result> { - Ok(Json(false)) -} diff --git a/src/main.rs b/src/main.rs index 8f2e0c7..e4f8797 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,21 +11,32 @@ use std::env; mod api; fn main() -> std::io::Result<()> { - println!("Hello, world!"); - env::set_var("RUST_LOG", "actix_web=debug"); env_logger::init(); dotenv::dotenv().ok(); - let www_root: String = env::var("WWW_ROOT").expect("WWW_ROOT must be set"); println!("serving files from: {}", &www_root); + use lootalot_db::Pool; + type AppPool = web::Data; + let pool = lootalot_db::create_pool(); HttpServer::new(move || { App::new() .data(pool.clone()) - .route("/players", web::get().to_async(api::players_list)) - .route("/loot/{player_id}", web::get().to_async(api::chest_content)) + .route( + "/players", + web::get().to_async(move |pool: AppPool| { + api::db_call(pool, move |api| api.fetch_players()) + }), + ) + .route( + "/loot/{player_id}", + web::get().to_async(move |pool: AppPool, player_id: web::Path| { + let player_id: i32 = *player_id; + api::db_call(pool, move |api| api.as_player(player_id).loot()) + }), + ) .service(fs::Files::new("/", www_root.clone()).index_file("index.html")) }) .bind("127.0.0.1:8088")?