reorganized routes

This commit is contained in:
Jackzie 2025-04-14 17:32:08 -05:00
parent 361459d931
commit 670d6c33a6
6 changed files with 98 additions and 69 deletions

1
server/Cargo.lock generated
View file

@ -2042,6 +2042,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"dotenvy",
"int-enum",
"log",
"rocket",

View file

@ -13,4 +13,5 @@ chrono = { version = "0.4.40", features = ["serde"] }
anyhow = "1.0.98"
serde = "1.0.219"
serde_json = "1.0.140"
int-enum = "1.2.0"
int-enum = "1.2.0"
dotenvy = "0.15.7"

View file

@ -10,6 +10,7 @@ use crate::managers::libraries::LibraryManager;
use crate::managers::repos::RepoManager;
use crate::objs::library::Library;
use crate::util::{setup_logger, JsonErrorResponse, ResponseError};
use routes::api;
mod routes;
mod util;
@ -27,6 +28,7 @@ const MAX_UPLOAD_SIZE: ByteUnit = ByteUnit::Mebibyte(100_000);
#[launch]
async fn rocket() -> _ {
setup_logger();
dotenvy::dotenv().ok();
debug!("{}", std::env::var("DATABASE_URL").unwrap().as_str());
let pool = PgPoolOptions::new()
.max_connections(5)
@ -52,7 +54,9 @@ async fn rocket() -> _ {
.manage(pool)
.manage(repo_manager)
.manage(libraries_manager)
.mount("/api", routes![routes::index, routes::get_library, routes::list_library_files, routes::get_library_file, routes::upload_library_file, routes::move_library_file])
.mount("/api", routes![
api::library::move_file, api::library::upload_file, api::library::download_file, api::library::list_files, api::library::get_file, api::library::delete_file,
])
}
#[catch(404)]

View file

@ -18,70 +18,4 @@ use crate::models::user;
use crate::storage::FileEntry;
use crate::util::{JsonErrorResponse, ResponseError};
#[get("/")]
pub(crate) fn index() -> &'static str {
"Hello, world!"
}
#[get("/library/<library_id>")]
pub(crate) async fn get_library(pool: &State<DB>, library_id: &str) -> Result<Option<Json<LibraryWithRepoModel>>, ResponseError> {
let library = models::library::get_library_with_repo(pool, library_id).await
.map_err(|e| ResponseError::GenericError)?;
debug!("{:?}", library);
Ok(library.map(|lib| Json(lib)))
}
#[get("/library/<library_id>/files?<path>")]
pub(crate) async fn list_library_files(pool: &State<DB>, libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<Json<Vec<FileEntry>>, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
library.list_files(&PathBuf::from(path)).await
.map(|files| Json(files))
.map_err(|e| ResponseError::InternalServerError(JsonErrorResponse {
code: "STORAGE_ERROR".to_string(),
message: e.to_string(),
}))
}
#[get("/library/<library_id>/files/download?<path>")]
pub(crate) async fn get_library_file(pool: &State<DB>, libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<Vec<u8>, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
match library.read_file(&PathBuf::from(path)).await
.map_err(|e| ResponseError::GenericError)?
{
None => {
Err(ResponseError::NotFound(JsonErrorResponse {
code: "FILE_NOT_FOUND".to_string(),
message: "Requested file does not exist".to_string()
}))
}
Some(contents) => {
// TODO: headers?
Ok(contents)
}
}
}
#[post("/library/<library_id>/files/move?<from>&<to>")]
pub(crate) async fn move_library_file(pool: &State<DB>, libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, from: &str, to: &str) -> Result<(), ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
library.move_file(&PathBuf::from(from), &PathBuf::from(to)).await
.map_err(|e| ResponseError::GenericError)
}
#[post("/library/<library_id>/files?<path>", data = "<data>")]
pub(crate) async fn upload_library_file(pool: &State<DB>, libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str, data: Data<'_>) -> Result<status::NoContent, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
let mut stream = data.open(MAX_UPLOAD_SIZE);
// TODO: don't just copy all to memory
let mut buf = Vec::new();
stream.read_to_end(&mut buf).await.unwrap();
library.write_file(&PathBuf::from(path), &buf).await
.map_err(|e| ResponseError::GenericError)?;
Ok(status::NoContent)
}
pub mod api;

1
server/src/routes/api.rs Normal file
View file

@ -0,0 +1 @@
pub mod library;

View file

@ -0,0 +1,88 @@
use std::path::PathBuf;
use std::sync::Arc;
use log::debug;
use rocket::{delete, get, post, Data, Route, State};
use rocket::fs::TempFile;
use rocket::http::Status;
use rocket::response::status;
use rocket::serde::json::Json;
use sqlx::{query, Postgres};
use sqlx::types::{Uuid};
use tokio::io::AsyncReadExt;
use tokio::sync::Mutex;
use crate::{library, models, DB, MAX_UPLOAD_SIZE};
use crate::managers::libraries::LibraryManager;
use crate::managers::repos::RepoManager;
use crate::models::library::{LibraryModel, LibraryWithRepoModel};
use crate::models::user;
use crate::storage::FileEntry;
use crate::util::{JsonErrorResponse, ResponseError};
#[get("/<library_id>")]
pub(crate) async fn get_file(pool: &State<DB>, library_id: &str) -> Result<Option<Json<LibraryWithRepoModel>>, ResponseError> {
let library = models::library::get_library_with_repo(pool, library_id).await
.map_err(|e| ResponseError::GenericError)?;
Ok(library.map(|lib| Json(lib)))
}
#[get("/<library_id>/files?<path>")]
pub(crate) async fn list_files(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<Json<Vec<FileEntry>>, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
library.list_files(&PathBuf::from(path)).await
.map(|files| Json(files))
.map_err(|e| ResponseError::InternalServerError(JsonErrorResponse {
code: "STORAGE_ERROR".to_string(),
message: e.to_string(),
}))
}
#[get("/<library_id>/files/download?<path>")]
pub(crate) async fn download_file(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<Vec<u8>, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
match library.read_file(&PathBuf::from(path)).await
.map_err(|e| ResponseError::GenericError)?
{
None => {
Err(ResponseError::NotFound(JsonErrorResponse {
code: "FILE_NOT_FOUND".to_string(),
message: "Requested file does not exist".to_string()
}))
}
Some(contents) => {
// TODO: headers?
Ok(contents)
}
}
}
#[post("/<library_id>/files/move?<from>&<to>")]
pub(crate) async fn move_file(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, from: &str, to: &str) -> Result<(), ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
library.move_file(&PathBuf::from(from), &PathBuf::from(to)).await
.map_err(|e| ResponseError::GenericError)
}
#[post("/<library_id>/files?<path>", data = "<data>")]
pub(crate) async fn upload_file(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str, data: Data<'_>) -> Result<status::NoContent, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
let mut stream = data.open(MAX_UPLOAD_SIZE);
// TODO: don't just copy all to memory
let mut buf = Vec::new();
stream.read_to_end(&mut buf).await.unwrap();
library.write_file(&PathBuf::from(path), &buf).await
.map_err(|e| ResponseError::GenericError)?;
Ok(status::NoContent)
}
#[delete("/<library_id>/files/move?<path>")]
pub(crate) async fn delete_file(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<(), ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
library.delete_file(&PathBuf::from(path)).await
.map_err(|e| ResponseError::GenericError)
}