Skip to content

Commit

Permalink
use bail for errors, fix spaces, use map for users db, fix extra serd…
Browse files Browse the repository at this point in the history
…e json, use more functions in serve flists
  • Loading branch information
rawdaGastan committed Sep 30, 2024
1 parent 2efda5e commit a82e7be
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 36 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ resolver = "2"

members = [
"rfs",
"docker2fl",
"fl-server"
"docker2fl",
"fl-server"
]

[profile.release]
Expand Down
10 changes: 5 additions & 5 deletions fl-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ pub async fn parse_config(filepath: &str) -> Result<Config> {
let c: Config = toml::from_str(&content).context("failed to convert toml config data")?;

if !hostname_validator::is_valid(&c.host) {
return Err(anyhow::Error::msg(format!("host '{}' is invalid", c.host)));
anyhow::bail!("host '{}' is invalid", c.host)
}

if c.port > 65535 {
return Err(anyhow::Error::msg(format!(
anyhow::bail!(format!(
"port '{}' is invalid, must be between [0, 65535]",
c.port
)));
))
}

rfs::store::parse_router(&c.store_url)
Expand All @@ -58,10 +58,10 @@ pub async fn parse_config(filepath: &str) -> Result<Config> {
fs::create_dir_all(&c.flist_dir).context("failed to create flists directory")?;

if c.jwt_expire_hours < 1 || c.jwt_expire_hours > 24 {
return Err(anyhow::Error::msg(format!(
anyhow::bail!(format!(
"jwt expiry interval in hours '{}' is invalid, must be between [1, 24]",
c.jwt_expire_hours
)));
))
}

Ok(c)
Expand Down
28 changes: 20 additions & 8 deletions fl-server/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{collections::HashMap, sync::Mutex};

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

Expand All @@ -8,24 +10,34 @@ pub struct User {
}

pub trait DB: Send + Sync {
fn get_user_by_username(&self, username: &str) -> Option<&User>;
fn get_user_by_username(&self, username: &str) -> Option<User>;
}

#[derive(Debug, ToSchema)]
pub struct VecDB {
users: Vec<User>,
pub struct MapDB {
users: Mutex<HashMap<String, User>>,
}

impl VecDB {
impl MapDB {
pub fn new(users: &[User]) -> Self {
Self {
users: users.to_vec(),
users: Mutex::new(
users
.to_vec()
.iter()
.map(|u| (u.username.clone(), u.to_owned()))
.collect(),
),
}
}
}

impl DB for VecDB {
fn get_user_by_username(&self, username: &str) -> Option<&User> {
self.users.iter().find(|u| u.username == username)
impl DB for MapDB {
fn get_user_by_username(&self, username: &str) -> Option<User> {
self.users
.lock()
.expect("failed to lock users map")
.get(username)
.cloned()
}
}
5 changes: 2 additions & 3 deletions fl-server/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,11 @@ pub async fn create_flist_handler(
return Err(ResponseError::Conflict("flist already exists".to_string()));
}

let created = fs::create_dir_all(&username_dir);
if created.is_err() {
if let Err(err) = fs::create_dir_all(&username_dir) {
log::error!(
"failed to create user flist directory `{:?}` with error {:?}",
&username_dir,
created.err()
err
);
return Err(ResponseError::InternalServerError);
}
Expand Down
2 changes: 1 addition & 1 deletion fl-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async fn app() -> Result<()> {
.await
.context("failed to parse config file")?;

let db = Arc::new(db::VecDB::new(&config.users));
let db = Arc::new(db::MapDB::new(&config.users.clone()));

let app_state = Arc::new(config::AppState {
jobs_state: Mutex::new(HashMap::new()),
Expand Down
8 changes: 2 additions & 6 deletions fl-server/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,15 @@ impl IntoResponse for ResponseResult {
ResponseResult::SignedIn(token) => {
(StatusCode::CREATED, Json(serde_json::json!(token))).into_response()
}
ResponseResult::FlistCreated(job) => {
(StatusCode::CREATED, Json(serde_json::json!(job))).into_response()
}
ResponseResult::FlistCreated(job) => (StatusCode::CREATED, Json(job)).into_response(),
ResponseResult::FlistState(flist_state) => (
StatusCode::OK,
Json(serde_json::json!({
"flist_state": flist_state
})),
)
.into_response(),
ResponseResult::Flists(flists) => {
(StatusCode::OK, Json(serde_json::json!(flists))).into_response()
}
ResponseResult::Flists(flists) => (StatusCode::OK, Json(flists)).into_response(),
}
}
}
33 changes: 22 additions & 11 deletions fl-server/src/serve_flists.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use askama::Template;
use axum::response::{Html, Response};
use serde::Serialize;
use std::path::PathBuf;
use std::{io::Error, path::PathBuf};
use tokio::io;
use tower::util::ServiceExt;
use tower_http::services::ServeDir;
Expand All @@ -24,22 +24,16 @@ pub async fn serve_flists(req: Request<Body>) -> impl IntoResponse {
let status = res.status();
match status {
StatusCode::NOT_FOUND => {
let path = path.trim_start_matches('/');
let path = percent_decode(path.as_ref()).decode_utf8_lossy();

let mut full_path = PathBuf::new();

// validate
for seg in path.split('/') {
if seg.starts_with("..") || seg.contains('\\') {
let full_path = match validate_path(&path) {
Ok(p) => p,
Err(_) => {
return Err(ErrorTemplate {
err: ResponseError::BadRequest("invalid path".to_string()),
cur_path: path.to_string(),
message: "invalid path".to_owned(),
});
}
full_path.push(seg);
}
};

let cur_path = std::path::Path::new(&full_path);

Expand Down Expand Up @@ -77,6 +71,23 @@ pub async fn serve_flists(req: Request<Body>) -> impl IntoResponse {
};
}

fn validate_path(path: &str) -> io::Result<PathBuf> {
let path = path.trim_start_matches('/');
let path = percent_decode(path.as_ref()).decode_utf8_lossy();

let mut full_path = PathBuf::new();

// validate
for seg in path.split('/') {
if seg.starts_with("..") || seg.contains('\\') {
return Err(Error::other("invalid path"));
}
full_path.push(seg);
}

Ok(full_path)
}

pub async fn visit_dir_one_level<P: AsRef<std::path::Path>>(path: P) -> io::Result<Vec<FileInfo>> {
let path = path.as_ref();
let mut dir = tokio::fs::read_dir(path).await?;
Expand Down

0 comments on commit a82e7be

Please sign in to comment.