2021-12-14 20:23:07 +01:00
|
|
|
#![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate diesel;
|
|
|
|
|
2021-12-19 00:16:46 +01:00
|
|
|
pub mod db;
|
|
|
|
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;
|
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>>;
|
|
|
|
|
2021-12-30 16:38:02 +01:00
|
|
|
pub async fn api() -> Router {
|
2021-12-29 16:11:27 +01:00
|
|
|
let database_url = "postgresql://planetwars:planetwars@localhost/planetwars";
|
|
|
|
let manager = DieselConnectionManager::<PgConnection>::new(database_url);
|
|
|
|
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),
|
|
|
|
)
|
2022-01-02 17:56:52 +01:00
|
|
|
.route("/matches/:match_id", get(routes::matches::get_match_log))
|
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 {
|
|
|
|
let api = api().await;
|
|
|
|
Router::new().nest("/api", api)
|
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
|
|
|
}
|