#![allow(missing_docs)]
pub mod db;
mod handler;
use async_trait::async_trait;
use db::pool;
use rocket::fairing::{self, AdHoc, Fairing, Info, Kind};
use rocket::http::Header;
use rocket::serde::json::{json, Value};
use rocket::tokio::runtime;
use rocket::{catch, Build, Request, Responder, Response, Rocket};
use sea_orm::DbErr;
use sea_orm_rocket::Database;
use starfish_core::{
migrator::{Migrator, MigratorTrait},
sea_orm,
};
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
let conn = &pool::Db::fetch(&rocket).unwrap().conn;
Migrator::up(conn, None).await.unwrap();
Ok(rocket)
}
pub fn rocket() -> Rocket<Build> {
use figment::{
providers::{Env, Format, Toml},
Figment,
};
let figment = Figment::new()
.merge(rocket::Config::default())
.merge(Toml::file("Rocket.toml").nested())
.merge(Env::prefixed("ROCKET_APP_").split("_"));
rocket::custom(figment)
.attach(pool::Db::init())
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
.attach(Cors)
.mount("/", handler::core::routes())
}
#[catch(404)]
#[allow(dead_code)]
fn not_found() -> Value {
json!({
"status": "error",
"reason": "Resource was not found."
})
}
#[derive(Responder)]
#[response(status = 500, content_type = "json")]
struct ErrorResponder {
message: String,
}
#[allow(clippy::from_over_into)]
impl Into<ErrorResponder> for DbErr {
fn into(self) -> ErrorResponder {
ErrorResponder {
message: self.to_string(),
}
}
}
#[allow(clippy::from_over_into)]
impl Into<ErrorResponder> for &str {
fn into(self) -> ErrorResponder {
ErrorResponder {
message: self.to_string(),
}
}
}
fn check_auth_match(auth: Option<String>) -> Result<(), ErrorResponder> {
let err = Err("Authorization failed.".into());
match (auth, std::env::var("API_AUTH_KEY").ok()) {
(Some(auth), Some(expected)) => {
if !auth.eq(&expected) {
err
} else {
Ok(())
}
}
(None, Some(_)) => err,
(_, None) => Ok(()),
}
}
#[derive(Debug)]
pub struct Cors;
#[async_trait]
impl Fairing for Cors {
fn info(&self) -> Info {
Info {
name: "Cross-Origin-Resource-Sharing Middleware",
kind: Kind::Response,
}
}
async fn on_response<'r>(&self, _: &'r Request<'_>, response: &mut Response<'r>) {
response.set_header(Header::new("access-control-allow-origin", "*"));
response.set_header(Header::new(
"access-control-allow-methods",
"GET, POST, PATCH, OPTIONS",
));
}
}
pub fn main() {
runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(rocket().launch())
.unwrap();
}