HomeDisk/server/src/fs/list.rs

113 lines
3.3 KiB
Rust
Raw Normal View History

use std::{fs, io, path::PathBuf, time::SystemTime};
2022-04-24 20:07:41 +00:00
use axum::{extract::rejection::JsonRejection, Extension, Json};
use axum_auth::AuthBearer;
2022-04-29 19:33:44 +00:00
use byte_unit::Byte;
2022-05-01 18:34:28 +00:00
use homedisk_database::Database;
2022-04-24 20:07:41 +00:00
use homedisk_types::{
2022-06-08 19:16:12 +00:00
config::Config,
2022-05-01 18:34:28 +00:00
errors::{FsError, ServerError},
2022-07-02 10:36:02 +00:00
fs::list::{DirInfo, FileInfo, Request, Response},
2022-04-24 20:07:41 +00:00
};
2022-07-25 21:02:25 +00:00
use crate::middleware::{find_user, validate_json, validate_jwt, validate_path};
2022-06-16 14:58:37 +00:00
2022-06-07 20:36:26 +00:00
/// Get directory size on disk (size of all files in directory).
2022-05-03 08:42:53 +00:00
fn dir_size(path: impl Into<PathBuf>) -> io::Result<u64> {
fn dir_size(mut dir: fs::ReadDir) -> io::Result<u64> {
dir.try_fold(0, |acc, file| {
let file = file?;
let size = match file.metadata()? {
data if data.is_dir() => dir_size(fs::read_dir(file.path())?)?,
data => data.len(),
};
Ok(acc + size)
})
}
dir_size(fs::read_dir(path.into())?)
}
2022-04-24 20:07:41 +00:00
pub async fn handle(
2022-05-01 18:34:28 +00:00
Extension(db): Extension<Database>,
Extension(config): Extension<Config>,
2022-04-24 20:07:41 +00:00
AuthBearer(token): AuthBearer,
request: Result<Json<Request>, JsonRejection>,
) -> Result<Json<Response>, ServerError> {
2022-06-07 20:36:26 +00:00
// validate json request
2022-04-24 20:07:41 +00:00
let Json(request) = validate_json::<Request>(request)?;
2022-06-07 20:36:26 +00:00
// validate user token
2022-04-24 20:07:41 +00:00
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
2022-05-01 18:34:28 +00:00
// validate the `path` can be used
validate_path(&request.path)?;
2022-04-24 20:07:41 +00:00
2022-05-01 18:34:28 +00:00
// search for a user by UUID from a token
2022-06-14 20:37:42 +00:00
let user = find_user(&db, &token.claims.sub).await?;
2022-04-24 20:07:41 +00:00
2022-05-01 18:34:28 +00:00
// directory where the file will be placed
let path = format!(
"{user_dir}/{req_dir}",
user_dir = user.user_dir(&config.storage.path),
req_dir = request.path
);
2022-04-24 20:07:41 +00:00
2022-06-07 20:36:26 +00:00
// get paths from dir
2022-05-01 18:34:28 +00:00
let paths = fs::read_dir(&path)
2022-06-11 08:19:47 +00:00
.map_err(|err| ServerError::FsError(FsError::ReadDirectory(err.to_string())))?;
2022-04-24 20:07:41 +00:00
2022-05-01 18:34:28 +00:00
let mut files = vec![];
let mut dirs = vec![];
2022-04-24 20:07:41 +00:00
2022-05-01 18:34:28 +00:00
for f in paths {
2022-06-07 20:36:26 +00:00
// handle Error
2022-06-11 08:19:47 +00:00
let f = f.map_err(|err| ServerError::FsError(FsError::Other(err.to_string())))?;
2022-06-07 20:36:26 +00:00
// get path metadata
2022-05-01 18:34:28 +00:00
let metadata = f
.metadata()
2022-06-11 08:19:47 +00:00
.map_err(|err| ServerError::FsError(FsError::Other(err.to_string())))?;
2022-04-24 20:07:41 +00:00
2022-06-07 20:36:26 +00:00
// get name of the path
2022-05-01 18:34:28 +00:00
let name = f.path().display().to_string().replace(&path, "");
2022-04-24 20:07:41 +00:00
2022-06-07 20:36:26 +00:00
// if path is directory
2022-05-01 18:34:28 +00:00
if metadata.is_dir() {
2022-06-07 20:36:26 +00:00
let size = Byte::from_bytes(
dir_size(f.path().display().to_string())
2022-06-11 08:19:47 +00:00
.map_err(|err| ServerError::FsError(FsError::Other(err.to_string())))?
2022-06-07 20:36:26 +00:00
.into(),
)
.get_appropriate_unit(true)
.to_string();
2022-05-03 09:26:29 +00:00
dirs.push(DirInfo { name, size })
2022-06-07 20:36:26 +00:00
}
// if path is file
else {
// get file size in bytes
2022-05-03 09:26:29 +00:00
let size = Byte::from_bytes(metadata.len().into())
.get_appropriate_unit(true)
.to_string();
// get modification time in unix time format
let modified = metadata
.modified()
.unwrap()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
2022-05-03 09:26:29 +00:00
2022-05-01 18:34:28 +00:00
files.push(FileInfo {
name,
2022-05-03 09:26:29 +00:00
size,
modified,
2022-05-01 18:34:28 +00:00
})
}
2022-05-01 18:34:28 +00:00
}
2022-04-24 20:07:41 +00:00
2022-07-25 21:02:25 +00:00
// send response
2022-05-01 18:34:28 +00:00
Ok(Json(Response { files, dirs }))
2022-04-24 20:07:41 +00:00
}