139 lines
3.8 KiB
Rust
139 lines
3.8 KiB
Rust
use std::hash::Hash;
|
|
|
|
use aide::axum::{
|
|
routing::{get_with, post_with},
|
|
ApiRouter,
|
|
};
|
|
use axum::{extract::Query, http::StatusCode, Json};
|
|
use cached::proc_macro::cached;
|
|
use schemars::JsonSchema;
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::FromRow;
|
|
|
|
mod description;
|
|
mod kind;
|
|
mod names;
|
|
mod position;
|
|
mod size;
|
|
|
|
pub fn routes() -> ApiRouter {
|
|
ApiRouter::new()
|
|
.api_route(
|
|
"/discover",
|
|
post_with(discover, |docs| {
|
|
docs.response::<200, Json<Star>>()
|
|
.summary("add a new planet")
|
|
.id("discover")
|
|
.tag("stars")
|
|
}),
|
|
)
|
|
.api_route(
|
|
"/chart",
|
|
get_with(chart, |docs| {
|
|
docs.response::<200, Json<Vec<Protostar>>>()
|
|
.summary("the whole chart")
|
|
.id("chart")
|
|
.tag("stars")
|
|
}),
|
|
)
|
|
.api_route_with(
|
|
"/visit/",
|
|
get_with(visit, |docs| {
|
|
docs.response::<200, Json<Star>>()
|
|
.summary("visit a single planet")
|
|
.id("visit")
|
|
.tag("stars")
|
|
}),
|
|
|docs| docs,
|
|
)
|
|
}
|
|
|
|
/// this gets stored in the db,
|
|
/// the other stuff is generated using
|
|
/// the id as a seed
|
|
#[derive(Serialize, FromRow, Clone, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
|
|
pub struct Protostar {
|
|
pub id: i32,
|
|
/// hex code of the stars color
|
|
pub color: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, JsonSchema, Clone)]
|
|
pub struct Star {
|
|
pub core: Protostar,
|
|
pub position: position::Position,
|
|
pub kind: kind::Kind,
|
|
pub name: String,
|
|
pub description: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
|
pub struct DiscoveryLog {
|
|
pub color: String,
|
|
}
|
|
|
|
impl Into<Star> for Protostar {
|
|
fn into(self) -> Star {
|
|
star_from_seed(self.id.abs() as u64, self.clone())
|
|
}
|
|
}
|
|
|
|
#[cached]
|
|
fn star_from_seed(seed: u64, protostar: Protostar) -> Star {
|
|
let mut rng = fastrand::Rng::with_seed(seed);
|
|
let range = 0..u64::MAX;
|
|
let kind = kind::Kind::random(rng.u64(range.clone()));
|
|
Star {
|
|
core: protostar.clone(),
|
|
position: position::Position::random(rng.u64(range.clone())),
|
|
name: format!("{}-{}", names::random_name(rng.u64(range.clone())), seed,).into(),
|
|
description: protostar.generate_description(&kind, rng.u64(range.clone())),
|
|
kind,
|
|
}
|
|
}
|
|
|
|
/// discover a new star in the solar system
|
|
async fn discover(Json(log): Json<DiscoveryLog>) -> Result<Json<Star>, StatusCode> {
|
|
let query = "INSERT INTO stars (color) VALUES ($1) RETURNING id, color";
|
|
|
|
let protostar: Protostar = sqlx::query_as(query)
|
|
.bind(log.color)
|
|
.fetch_one(crate::db::pool().await)
|
|
.await
|
|
.or(Err(StatusCode::INTERNAL_SERVER_ERROR))?;
|
|
let star: Star = protostar.into();
|
|
Ok(Json(star))
|
|
}
|
|
|
|
/// show all stars
|
|
async fn chart() -> Json<Vec<Star>> {
|
|
let query = "SELECT * FROM stars ORDER BY id DESC";
|
|
let protostars: Vec<Protostar> = sqlx::query_as(query)
|
|
.fetch_all(crate::db::pool().await)
|
|
.await
|
|
.unwrap_or_default();
|
|
Json(
|
|
protostars
|
|
.iter()
|
|
.map(|proto| Into::<Star>::into(proto.clone()))
|
|
.collect::<Vec<Star>>(),
|
|
)
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
|
struct VisitorData {
|
|
/// the planet to visit
|
|
planet_id: i32,
|
|
}
|
|
|
|
async fn visit(data: Query<VisitorData>) -> Result<Json<Star>, StatusCode> {
|
|
let query = "SELECT * FROM stars WHERE id = ($1)";
|
|
let star: Protostar = sqlx::query_as(query)
|
|
.bind(data.planet_id)
|
|
.fetch_one(crate::db::pool().await)
|
|
.await
|
|
.or(Err(StatusCode::NOT_FOUND))?;
|
|
let star: Star = star.into();
|
|
Ok(Json(star))
|
|
}
|