planetwars.dev/planetwars-server/src/lib.rs

119 lines
3.4 KiB
Rust
Raw Normal View History

2021-12-14 20:23:07 +01:00
#[macro_use]
extern crate diesel;
2021-12-19 00:16:46 +01:00
pub mod db;
2022-01-03 23:33:00 +01:00
pub mod db_types;
2021-12-19 00:16:46 +01:00
pub mod routes;
pub mod schema;
2021-12-14 20:23:07 +01:00
2021-12-29 16:11:27 +01:00
use std::ops::Deref;
use axum;
use bb8::PooledConnection;
use bb8_diesel::{self, DieselConnectionManager};
use diesel::PgConnection;
2022-02-20 23:06:05 +01:00
use serde::Deserialize;
2021-12-14 20:23:07 +01:00
2021-12-29 16:11:27 +01:00
use axum::{
async_trait,
extract::{Extension, FromRequest, RequestParts},
http::StatusCode,
routing::{get, post},
AddExtensionLayer, Router,
};
2022-01-01 16:32:55 +01:00
// TODO: make these configurable
const BOTS_DIR: &str = "./data/bots";
const MATCHES_DIR: &str = "./data/matches";
const MAPS_DIR: &str = "./data/maps";
2021-12-29 16:11:27 +01:00
type ConnectionPool = bb8::Pool<DieselConnectionManager<PgConnection>>;
2022-02-20 23:06:05 +01:00
pub async fn api(configuration: Configuration) -> Router {
let manager = DieselConnectionManager::<PgConnection>::new(configuration.database_url);
2021-12-29 16:11:27 +01:00
let pool = bb8::Pool::builder().build(manager).await.unwrap();
2021-12-30 16:38:02 +01:00
let api = Router::new()
.route("/register", post(routes::users::register))
.route("/login", post(routes::users::login))
2021-12-29 16:11:27 +01:00
.route("/users/me", get(routes::users::current_user))
2022-01-01 11:26:49 +01:00
.route(
"/bots",
get(routes::bots::list_bots).post(routes::bots::create_bot),
)
2021-12-30 23:40:37 +01:00
.route("/bots/my_bots", get(routes::bots::get_my_bots))
2021-12-29 16:11:27 +01:00
.route("/bots/:bot_id", get(routes::bots::get_bot))
2021-12-30 23:41:47 +01:00
.route(
"/bots/:bot_id/upload",
post(routes::bots::upload_code_multipart),
)
2022-01-02 16:14:03 +01:00
.route(
"/matches",
get(routes::matches::list_matches).post(routes::matches::play_match),
)
.route("/matches/:match_id", get(routes::matches::get_match_data))
.route(
"/matches/:match_id/log",
get(routes::matches::get_match_log),
)
.route("/submit_bot", post(routes::demo::submit_bot))
2021-12-29 16:11:27 +01:00
.layer(AddExtensionLayer::new(pool));
2021-12-30 16:38:02 +01:00
api
}
pub async fn app() -> Router {
2022-02-20 23:06:05 +01:00
let configuration = config::Config::builder()
.add_source(config::File::with_name("configuration.toml"))
.add_source(config::Environment::with_prefix("PLANETWARS"))
.build()
.unwrap()
.try_deserialize()
.unwrap();
let api = api(configuration).await;
2021-12-30 16:38:02 +01:00
Router::new().nest("/api", api)
2021-12-29 16:11:27 +01:00
}
2022-02-20 23:06:05 +01:00
#[derive(Deserialize)]
pub struct Configuration {
pub database_url: String,
}
2021-12-29 16:11:27 +01:00
// we can also write a custom extractor that grabs a connection from the pool
// which setup is appropriate depends on your application
pub struct DatabaseConnection(PooledConnection<'static, DieselConnectionManager<PgConnection>>);
impl Deref for DatabaseConnection {
type Target = PooledConnection<'static, DieselConnectionManager<PgConnection>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[async_trait]
impl<B> FromRequest<B> for DatabaseConnection
where
B: Send,
{
type Rejection = (StatusCode, String);
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let Extension(pool) = Extension::<ConnectionPool>::from_request(req)
.await
.map_err(internal_error)?;
let conn = pool.get_owned().await.map_err(internal_error)?;
Ok(Self(conn))
}
}
/// Utility function for mapping any error into a `500 Internal Server Error`
/// response.
fn internal_error<E>(err: E) -> (StatusCode, String)
where
E: std::error::Error,
{
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
2021-12-14 20:23:07 +01:00
}