refactor(backend): replace unwraps with typed errors
This commit is contained in:
@@ -7,11 +7,10 @@ use axum::{
|
||||
routing::get,
|
||||
};
|
||||
use sqlx::types::uuid;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
ctx::Ctx,
|
||||
error::LoftError,
|
||||
error::{LoftError, Result},
|
||||
model::{FileRecord, FileRepository},
|
||||
};
|
||||
|
||||
@@ -29,31 +28,24 @@ async fn upload_file(
|
||||
ctx: Ctx,
|
||||
mut multipart: Multipart,
|
||||
) -> Result<Json<FileRecord>, LoftError> {
|
||||
info!("handler: upload_file");
|
||||
let mut uploaded: Option<(String, String, usize)> = None;
|
||||
|
||||
let mut file_name = None;
|
||||
let mut file_storage_key = None;
|
||||
let mut file_size = None;
|
||||
|
||||
while let Some(field) = multipart.next_field().await.unwrap() {
|
||||
if field.name().unwrap() == "file" {
|
||||
let name = field.file_name().map(|s| s.to_string()).unwrap_or_default();
|
||||
let key = format!("{}-{}", name, uuid::Uuid::new_v4());
|
||||
while let Some(field) = multipart.next_field().await? {
|
||||
if field.name() == Some("file") {
|
||||
let name = field.file_name().map(str::to_string).unwrap_or_default();
|
||||
let key = format!("{name}-{}", uuid::Uuid::new_v4());
|
||||
let size = file_repository.upload_file(field, &key).await?;
|
||||
file_name = Some(name);
|
||||
file_storage_key = Some(key);
|
||||
file_size = Some(size);
|
||||
uploaded = Some((name, key, size));
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(name), Some(key), Some(size)) = (file_name, file_storage_key, file_size) {
|
||||
let file_record = file_repository
|
||||
.create_file_record(ctx.user_id(), &name, size, &key)
|
||||
.await?;
|
||||
return Ok(Json(file_record));
|
||||
}
|
||||
let (name, key, size) = uploaded.ok_or(LoftError::NoFileProvided)?;
|
||||
|
||||
Err(LoftError::UndefinedErrorType)
|
||||
let file_record = file_repository
|
||||
.create_file_record(ctx.user_id(), &name, size, &key)
|
||||
.await?;
|
||||
|
||||
Ok(Json(file_record))
|
||||
}
|
||||
|
||||
async fn get_file(
|
||||
@@ -71,7 +63,7 @@ async fn download_file(
|
||||
State(file_repository): State<FileRepository>,
|
||||
ctx: Ctx,
|
||||
Path(file_id): Path<u64>,
|
||||
) -> Result<impl IntoResponse, LoftError> {
|
||||
) -> Result<impl IntoResponse> {
|
||||
let stream = file_repository
|
||||
.download_file(file_id as i64, ctx.user_id())
|
||||
.await?;
|
||||
@@ -83,13 +75,12 @@ async fn stream_part(
|
||||
ctx: Ctx,
|
||||
headers: HeaderMap,
|
||||
Path(file_id): Path<u64>,
|
||||
) -> Result<impl IntoResponse, LoftError> {
|
||||
info!("stream_part");
|
||||
) -> Result<impl IntoResponse> {
|
||||
let file_record = file_repository
|
||||
.get_file(file_id as i64, ctx.user_id())
|
||||
.await?;
|
||||
let file_size = file_record.size as u64;
|
||||
let (start, end): (u64, u64) = parse_range(&headers, file_size);
|
||||
let (start, end): (u64, u64) = parse_range(&headers, file_size)?;
|
||||
|
||||
let stream = file_repository
|
||||
.stream_part(file_id as i64, ctx.user_id(), start, end + 1)
|
||||
@@ -105,20 +96,25 @@ async fn stream_part(
|
||||
)
|
||||
.header(header::ACCEPT_RANGES, "bytes")
|
||||
.body(Body::from_stream(stream))
|
||||
.unwrap();
|
||||
.expect("Failed to build response with valid headers");
|
||||
|
||||
Ok(respones)
|
||||
}
|
||||
|
||||
fn parse_range(headers: &HeaderMap, file_size: u64) -> (u64, u64) {
|
||||
let range = headers.get(header::RANGE);
|
||||
let str = range.unwrap().to_str().unwrap();
|
||||
let strip = str.strip_prefix("bytes=").unwrap();
|
||||
let tuple = strip.split_once("-").unwrap();
|
||||
let start = tuple.0.parse::<u64>().unwrap();
|
||||
fn parse_range(headers: &HeaderMap, file_size: u64) -> Result<(u64, u64)> {
|
||||
let range = headers.get(header::RANGE).ok_or(LoftError::InvalidRange)?;
|
||||
let str = range.to_str().map_err(|_| LoftError::InvalidRange)?;
|
||||
let tuple = str
|
||||
.strip_prefix("bytes=")
|
||||
.and_then(|s| s.split_once("-"))
|
||||
.ok_or(LoftError::InvalidRange)?;
|
||||
let start = tuple
|
||||
.0
|
||||
.parse::<u64>()
|
||||
.map_err(|_| LoftError::InvalidRange)?;
|
||||
let end = tuple.1.parse::<u64>().unwrap_or(file_size - 1);
|
||||
|
||||
(start, end)
|
||||
Ok((start, end))
|
||||
}
|
||||
|
||||
async fn delete_file(
|
||||
@@ -126,8 +122,6 @@ async fn delete_file(
|
||||
ctx: Ctx,
|
||||
Path(file_id): Path<u64>,
|
||||
) -> Result<Json<FileRecord>, LoftError> {
|
||||
info!("handler: delete_file");
|
||||
|
||||
let file = file_repository
|
||||
.delete_file(file_id as i64, ctx.user_id())
|
||||
.await?;
|
||||
@@ -138,8 +132,6 @@ async fn list_files(
|
||||
State(file_repository): State<FileRepository>,
|
||||
ctx: Ctx,
|
||||
) -> Result<Json<Vec<FileRecord>>, LoftError> {
|
||||
info!("handler: list_files");
|
||||
|
||||
let files = file_repository.list_files(ctx.user_id()).await?;
|
||||
Ok(Json(files))
|
||||
}
|
||||
@@ -178,7 +170,7 @@ mod tests {
|
||||
dotenvy::from_filename(".env.test").ok();
|
||||
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
let pool = PgPool::connect(&database_url).await.unwrap();
|
||||
let user_repository = UserRepository::new(pool).unwrap();
|
||||
let user_repository = UserRepository::new(pool);
|
||||
user_repository
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user