starchart/src/stars.rs

125 lines
3.1 KiB
Rust

use aide::axum::{
routing::{get_with, post_with},
ApiRouter,
};
use axum::{
extract::{Path, Query},
http::StatusCode,
Json,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
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)]
pub struct Protostar {
pub id: i32,
/// hex code of the stars color
pub color: String,
}
impl Protostar {
fn seed(&self) -> u64 {
self.id.abs() as u64
}
}
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct Star {
pub size: size::Size,
pub core: Protostar,
}
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct DiscoveryLog {
pub color: String,
}
impl Into<Star> for Protostar {
fn into(self) -> Star {
let seed = self.seed();
Star {
core: self,
size: size::Size::random(seed),
}
}
}
/// 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<Protostar>> {
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)
}
#[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
.unwrap();
//.or(Err(StatusCode::NOT_FOUND))?;
let star: Star = star.into();
Ok(Json(star))
}