This repository has been archived on 2025-04-28. You can view files and clone it, but cannot push or open issues or pull requests.
rust-web/src/main.rs
2024-05-14 12:07:44 -07:00

90 lines
2.8 KiB
Rust

mod answer;
mod api;
mod question;
mod store;
use axum::{
extract::{Path, Query, State},
http::{StatusCode, Uri},
response::{IntoResponse, Response},
routing::{delete, get, post, put},
Form, Json, Router,
};
use serde::{Deserialize, Serialize};
use sqlx::{
self,
postgres::{PgPool, Postgres},
Pool,
};
use std::{
collections::HashMap,
env::var,
fs::File,
io::{ErrorKind, Read, Seek, Write},
net::SocketAddr,
path::PathBuf,
sync::Arc,
};
use store::Store;
use tokio::sync::RwLock;
// generic handler for any not supported route/method combination
async fn handler_404() -> Response {
(StatusCode::NOT_FOUND, "404 Not Found").into_response()
}
// generic handler to serve static for non-api routes
async fn serve_file(uri: Uri) -> impl IntoResponse {
let mut path_buf: PathBuf =
PathBuf::from("./src/static/").join(uri.path().trim_start_matches('/'));
if path_buf.is_dir() {
path_buf.push("index.html")
}
match File::open(path_buf) {
Ok(mut file) => {
let mut contents = Vec::new();
match file.read_to_end(&mut contents) {
Ok(_) => axum::response::Response::builder()
.status(StatusCode::OK)
.body(axum::body::Body::from(contents))
.unwrap(),
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Server Error").into_response(),
}
}
Err(_) => (StatusCode::NOT_FOUND, "404 Not Found").into_response(),
}
}
async fn db_connection() -> Result<Pool<Postgres>, sqlx::Error> {
let url: String = format!(
"postgres://{}:{}@{}:5432/{}",
var("POSTGRES_USER").unwrap(),
var("POSTGRES_PASSWORD").unwrap(),
var("POSTGRES_HOST").unwrap(),
var("POSTGRES_DBNAME").unwrap()
);
PgPool::connect(&url).await
}
#[tokio::main]
async fn main() {
let store: Arc<RwLock<Store>> = Arc::new(RwLock::new(store::Store::new()));
let ip: SocketAddr = SocketAddr::new([127, 0, 0, 1].into(), 3000);
let listener: tokio::net::TcpListener = tokio::net::TcpListener::bind(ip).await.unwrap();
let apis = Router::new()
.route("/question/:id", get(api::read_question))
.route("/questions", get(api::read_questions))
.route("/question", post(api::create_question))
.route("/question", put(api::update_question))
.route("/question/:id", delete(api::delete_question))
.route("/answer", post(api::create_answer))
.with_state(store);
let app = Router::new()
.nest("/api/v1", apis)
.route("/", get(serve_file))
.route("/*path", get(serve_file))
.fallback(handler_404);
let db: Pool<Postgres> = db_connection().await.unwrap();
sqlx::migrate!().run(&db).await.unwrap();
axum::serve(listener, app).await.unwrap();
}