Skip to content

Commit

Permalink
support pagination and filters for listing flists
Browse files Browse the repository at this point in the history
  • Loading branch information
rawdaGastan committed Nov 12, 2024
1 parent 5b68426 commit fb33fed
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 8 deletions.
64 changes: 59 additions & 5 deletions fl-server/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::Error;
use axum::{
extract::{Path, State},
extract::{Path, Query, State},
response::IntoResponse,
Extension, Json,
};
Expand Down Expand Up @@ -74,6 +74,23 @@ pub struct FlistStateInfo {
progress: f32,
}

const DEFAULT_LIMIT: usize = 10;
const DEFAULT_PAGE: usize = 1;

#[derive(Deserialize)]
pub struct Pagination {
page: Option<usize>,
limit: Option<usize>,
}

#[derive(Deserialize, Clone)]
pub struct Filter {
pub max_size: Option<usize>,
pub min_size: Option<usize>,
username: Option<String>,
pub name: Option<String>,
}

#[utoipa::path(
get,
path = "/v1/api",
Expand Down Expand Up @@ -337,11 +354,27 @@ pub async fn get_flist_state_handler(
)
)]
#[debug_handler]
pub async fn list_flists_handler(State(state): State<Arc<config::AppState>>) -> impl IntoResponse {
pub async fn list_flists_handler(
State(state): State<Arc<config::AppState>>,
pagination: Query<Pagination>,
filter: Query<Filter>,
) -> impl IntoResponse {
let mut flists: HashMap<String, Vec<FileInfo>> = HashMap::new();

let pagination: Pagination = pagination.0;
let page = pagination.page.unwrap_or(DEFAULT_PAGE);
let limit = pagination.limit.unwrap_or(DEFAULT_LIMIT);

if page == 0 {
return Err(ResponseError::BadRequest(
"requested page should be nonzero positive number".to_string(),
));
}

let filter: Filter = filter.0;

let rs: Result<Vec<FileInfo>, std::io::Error> =
visit_dir_one_level(&state.config.flist_dir, &state).await;
visit_dir_one_level(&state.config.flist_dir, &state, None).await;

let files = match rs {
Ok(files) => files,
Expand All @@ -353,9 +386,30 @@ pub async fn list_flists_handler(State(state): State<Arc<config::AppState>>) ->

for file in files {
if !file.is_file {
let flists_per_username = visit_dir_one_level(&file.path_uri, &state).await;
let flists_per_username =
visit_dir_one_level(&file.path_uri, &state, Some(filter.clone())).await;

if let Some(ref filter_username) = filter.username {
if filter_username.clone() != file.name {
continue;
}
}

match flists_per_username {
Ok(files) => flists.insert(file.name, files),
Ok(files) => {
let username = file.name;
flists.insert(username.clone(), Vec::new());

let start = limit * (page - 1);
let end = limit * page;
if files.len() > start {
if files.len() >= end {
flists.insert(username, files[start..end].to_vec());
} else {
flists.insert(username, files[start..].to_vec());
}
}
}
Err(e) => {
log::error!("failed to list flists per username with error: {}", e);
return Err(ResponseError::InternalServerError);
Expand Down
2 changes: 1 addition & 1 deletion fl-server/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl IntoResponse for ResponseResult {

//////// TEMPLATES ////////

#[derive(Serialize, ToSchema)]
#[derive(Serialize, Clone, Debug, ToSchema)]
pub struct FileInfo {
pub name: String,
pub path_uri: String,
Expand Down
27 changes: 25 additions & 2 deletions fl-server/src/serve_flists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use percent_encoding::percent_decode;

use crate::{
config,
handlers::Filter,
response::{
DirListTemplate, DirLister, ErrorTemplate, FileInfo, ResponseError, ResponseResult,
TemplateErr,
Expand Down Expand Up @@ -47,7 +48,7 @@ pub async fn serve_flists(

match cur_path.is_dir() {
true => {
let rs = visit_dir_one_level(&full_path, &state).await;
let rs = visit_dir_one_level(&full_path, &state, None).await;
match rs {
Ok(files) => Ok(ResponseResult::DirTemplate(DirListTemplate {
lister: DirLister { files },
Expand Down Expand Up @@ -98,6 +99,7 @@ fn validate_path(path: &str) -> io::Result<PathBuf> {
pub async fn visit_dir_one_level<P: AsRef<std::path::Path>>(
path: P,
state: &Arc<config::AppState>,
filter: Option<Filter>,
) -> io::Result<Vec<FileInfo>> {
let path = path.as_ref();
let mut dir = tokio::fs::read_dir(path).await?;
Expand All @@ -107,6 +109,7 @@ pub async fn visit_dir_one_level<P: AsRef<std::path::Path>>(
let path_uri = child.path().to_string_lossy().to_string();
let is_file = child.file_type().await?.is_file();
let name = child.file_name().to_string_lossy().to_string();
let size = child.metadata().await?.len();

let mut progress = 0.0;
if is_file {
Expand All @@ -131,11 +134,31 @@ pub async fn visit_dir_one_level<P: AsRef<std::path::Path>>(
}
}

if let Some(ref filter_files) = filter {
if let Some(ref filter_name) = filter_files.name {
if filter_name.clone() != name {
continue;
}
}

if let Some(ref filter_max_size) = filter_files.max_size {
if filter_max_size.clone() < size as usize {
continue;
}
}

if let Some(ref filter_min_size) = filter_files.min_size {
if filter_min_size.clone() > size as usize {
continue;
}
}
}

files.push(FileInfo {
name,
path_uri,
is_file,
size: child.metadata().await?.len(),
size: size,
last_modified: child
.metadata()
.await?
Expand Down

0 comments on commit fb33fed

Please sign in to comment.