mod api; mod model; mod storage_manager; mod config; mod state; use std::path::PathBuf; use std::sync::Arc; use axum::{Json, Router}; use axum::extract::{Path, Query, State}; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{get, post}; use axum_macros::debug_handler; use j_db::database::Database; use serde::{Deserialize, Serialize}; use structopt::StructOpt; use log::info; use crate::config::PicOxConfig; use crate::model::album::Album; use crate::state::Context; #[derive(Debug, Clone, StructOpt)] struct Args { config: PathBuf } #[derive(Debug, Clone, Serialize, Deserialize)] struct CreateAlbum { pub album_name: String } async fn create_album(State(context): State>, Json(album): Json) -> impl IntoResponse { info!("Creating new album '{}'", album.album_name); let new_album = Album::new(&album.album_name, Vec::new(), 0); let new_album = context.db.insert(new_album).unwrap(); (StatusCode::OK, Json(new_album)) } async fn get_album(album_id: Path, State(context): State>) -> impl IntoResponse { let album = context.db.get::(*album_id).unwrap(); (StatusCode::OK, Json(album)) } #[derive(Debug, Clone, Serialize, Deserialize)] struct AlbumQuery { pub album_name: Option } async fn query_album(album_query: Query, State(context): State>) -> impl IntoResponse { let resp = if let Some(album_name) = &album_query.album_name { context.db.filter(|_, album: &Album| {album.album_name == *album_name}).unwrap().next() } else { None }; (StatusCode::OK, Json(resp)) } #[tokio::main] async fn main() { let args = Args::from_args(); let config = PicOxConfig::new(args.config); let db = Database::new(&config.db_path).unwrap(); let context = Context { db, config, }; let context = Arc::new(context); // initialize tracing tracing_subscriber::fmt::init(); // build our application with a route let app = Router::new() // `GET /` goes to `root` .route("/api/album/create", post(create_album)) .route("/api/album/:id", get(get_album)) .route("/api/album/", get(query_album)) .with_state(context.clone()); // run our app with hyper, listening globally on port 3000 let listener = tokio::net::TcpListener::bind(&context.config.host).await.unwrap(); info!("Serving at {}", context.config.host); axum::serve(listener, app).await.unwrap(); }