update code
This commit is contained in:
parent
18b6cb21b1
commit
ece96bb3af
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
# database
|
# database
|
||||||
*.db
|
*.db
|
||||||
|
|
||||||
# why sqlx?
|
|
||||||
*.db-shm
|
*.db-shm
|
||||||
*.db-wal
|
*.db-wal
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use log::LevelFilter;
|
|
||||||
use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, TerminalMode, WriteLogger};
|
|
||||||
|
|
||||||
pub fn init() -> anyhow::Result<()> {
|
|
||||||
// init better_panic
|
|
||||||
better_panic::install();
|
|
||||||
|
|
||||||
// init logger
|
|
||||||
CombinedLogger::init(vec![
|
|
||||||
TermLogger::new(
|
|
||||||
LevelFilter::Debug,
|
|
||||||
Config::default(),
|
|
||||||
TerminalMode::Mixed,
|
|
||||||
ColorChoice::Auto,
|
|
||||||
),
|
|
||||||
WriteLogger::new(
|
|
||||||
LevelFilter::Info,
|
|
||||||
Config::default(),
|
|
||||||
File::create("logs.log").expect("create logs file"),
|
|
||||||
),
|
|
||||||
])?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,12 +1,14 @@
|
||||||
mod init;
|
|
||||||
|
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_server::run_http_server;
|
use homedisk_server::serve_http;
|
||||||
use homedisk_types::config::types::Config;
|
use homedisk_types::config::Config;
|
||||||
|
|
||||||
|
/// Main function
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
init::init()?;
|
// init better_panic
|
||||||
|
better_panic::install();
|
||||||
|
// init logger
|
||||||
|
init_logger()?;
|
||||||
|
|
||||||
// parse config
|
// parse config
|
||||||
let config = Config::parse()?;
|
let config = Config::parse()?;
|
||||||
|
@ -22,6 +24,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.map(|e| e.parse().expect("parse CORS hosts"))
|
.map(|e| e.parse().expect("parse CORS hosts"))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// format host ip and port
|
||||||
let host = format!(
|
let host = format!(
|
||||||
"{host}:{port}",
|
"{host}:{port}",
|
||||||
host = config.http.host,
|
host = config.http.host,
|
||||||
|
@ -29,7 +32,31 @@ async fn main() -> anyhow::Result<()> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// start http server
|
// start http server
|
||||||
run_http_server(host, origins, db, config).await?;
|
serve_http(host, origins, db, config).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Init logger
|
||||||
|
fn init_logger() -> anyhow::Result<()> {
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
use log::LevelFilter;
|
||||||
|
use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, TerminalMode, WriteLogger};
|
||||||
|
|
||||||
|
CombinedLogger::init(vec![
|
||||||
|
TermLogger::new(
|
||||||
|
LevelFilter::Debug,
|
||||||
|
Config::default(),
|
||||||
|
TerminalMode::Mixed,
|
||||||
|
ColorChoice::Auto,
|
||||||
|
),
|
||||||
|
WriteLogger::new(
|
||||||
|
LevelFilter::Info,
|
||||||
|
Config::default(),
|
||||||
|
File::create("logs.log").expect("create logs file"),
|
||||||
|
),
|
||||||
|
])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod error;
|
|
||||||
mod sqlite;
|
mod sqlite;
|
||||||
|
|
||||||
pub use error::*;
|
/// Imported from `homedisk_types::database::User`.
|
||||||
pub use homedisk_types::database::User;
|
pub use homedisk_types::database::User;
|
||||||
|
/// Imported from `homedisk_types::errors::DatabaseError`.
|
||||||
|
pub use homedisk_types::errors::DatabaseError as Error;
|
||||||
pub use sqlite::*;
|
pub use sqlite::*;
|
||||||
|
|
|
@ -4,9 +4,10 @@ use sqlx::{sqlite::SqliteQueryResult, Executor, Row, SqlitePool};
|
||||||
|
|
||||||
use super::{Error, User};
|
use super::{Error, User};
|
||||||
|
|
||||||
|
/// SQL Database
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
/// Sqlite Connection Pool
|
/// SQLite Connection Pool
|
||||||
pub conn: SqlitePool,
|
pub conn: SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +16,11 @@ impl Database {
|
||||||
/// ```ignore,rust
|
/// ```ignore,rust
|
||||||
/// use homedisk_database::Database;
|
/// use homedisk_database::Database;
|
||||||
///
|
///
|
||||||
|
/// // open database in memory
|
||||||
/// Database::open("sqlite::memory:").await?;
|
/// Database::open("sqlite::memory:").await?;
|
||||||
|
///
|
||||||
|
/// // open database from file
|
||||||
|
/// Database::open("path/to/file.db").await?;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn open(path: &str) -> Result<Self, Error> {
|
pub async fn open(path: &str) -> Result<Self, Error> {
|
||||||
debug!("Opening SQLite database");
|
debug!("Opening SQLite database");
|
||||||
|
@ -29,7 +34,10 @@ impl Database {
|
||||||
/// ```ignore,rust
|
/// ```ignore,rust
|
||||||
/// use homedisk_database::{Database, User};
|
/// use homedisk_database::{Database, User};
|
||||||
///
|
///
|
||||||
|
/// // create `User` type
|
||||||
/// let user = User::new("username", "password");
|
/// let user = User::new("username", "password");
|
||||||
|
///
|
||||||
|
/// // create a user in database
|
||||||
/// db.create_user(&user).await?;
|
/// db.create_user(&user).await?;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn create_user(&self, user: &User) -> Result<SqliteQueryResult, Error> {
|
pub async fn create_user(&self, user: &User) -> Result<SqliteQueryResult, Error> {
|
||||||
|
@ -47,24 +55,32 @@ impl Database {
|
||||||
/// ```ignore,rust
|
/// ```ignore,rust
|
||||||
/// use homedisk_database::{Database, User};
|
/// use homedisk_database::{Database, User};
|
||||||
///
|
///
|
||||||
|
/// // create `User` type
|
||||||
/// let user = User::new("username", "password");
|
/// let user = User::new("username", "password");
|
||||||
///
|
///
|
||||||
|
/// // search for a user in database
|
||||||
/// db.find_user(&user.username, &user.password).await?;
|
/// db.find_user(&user.username, &user.password).await?;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn find_user(&self, username: &str, password: &str) -> Result<User, Error> {
|
pub async fn find_user(&self, username: &str, password: &str) -> Result<User, Error> {
|
||||||
debug!("Searching for a user - {}", username);
|
debug!("Searching for a user - {}", username);
|
||||||
|
|
||||||
|
// create query request to database
|
||||||
let query =
|
let query =
|
||||||
sqlx::query_as::<_, User>("SELECT * FROM user WHERE username = ? AND password = ?")
|
sqlx::query_as::<_, User>("SELECT * FROM user WHERE username = ? AND password = ?")
|
||||||
.bind(username)
|
.bind(username)
|
||||||
.bind(password);
|
.bind(password);
|
||||||
|
|
||||||
|
// fetch query
|
||||||
let mut stream = self.conn.fetch(query);
|
let mut stream = self.conn.fetch(query);
|
||||||
|
|
||||||
|
// get rows from query
|
||||||
let row = stream.try_next().await?.ok_or(Error::UserNotFound)?;
|
let row = stream.try_next().await?.ok_or(Error::UserNotFound)?;
|
||||||
|
|
||||||
|
// get `id` row
|
||||||
let id = row.try_get("id")?;
|
let id = row.try_get("id")?;
|
||||||
|
// get `username` row
|
||||||
let username = row.try_get("username")?;
|
let username = row.try_get("username")?;
|
||||||
|
// get `password` row
|
||||||
let password = row.try_get("password")?;
|
let password = row.try_get("password")?;
|
||||||
|
|
||||||
Ok(User {
|
Ok(User {
|
||||||
|
@ -78,21 +94,29 @@ impl Database {
|
||||||
/// ```ignore,rust
|
/// ```ignore,rust
|
||||||
/// use homedisk_database::{Database, User};
|
/// use homedisk_database::{Database, User};
|
||||||
///
|
///
|
||||||
|
/// // create `User` type
|
||||||
/// let user = User::new("username", "password");
|
/// let user = User::new("username", "password");
|
||||||
///
|
///
|
||||||
|
/// // search for a user by UUID in database
|
||||||
/// db.find_user_by_id(&user.id).await?;
|
/// db.find_user_by_id(&user.id).await?;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn find_user_by_id(&self, id: String) -> Result<User, Error> {
|
pub async fn find_user_by_id(&self, id: String) -> Result<User, Error> {
|
||||||
debug!("Searching for a user by UUID - {}", id);
|
debug!("Searching for a user by UUID - {}", id);
|
||||||
|
|
||||||
|
// create query request to database
|
||||||
let query = sqlx::query_as::<_, User>("SELECT * FROM user WHERE id = ?").bind(id);
|
let query = sqlx::query_as::<_, User>("SELECT * FROM user WHERE id = ?").bind(id);
|
||||||
|
|
||||||
|
// fetch query
|
||||||
let mut stream = self.conn.fetch(query);
|
let mut stream = self.conn.fetch(query);
|
||||||
|
|
||||||
|
// get rows from query
|
||||||
let row = stream.try_next().await?.ok_or(Error::UserNotFound)?;
|
let row = stream.try_next().await?.ok_or(Error::UserNotFound)?;
|
||||||
|
|
||||||
|
// get `id` row
|
||||||
let id = row.try_get("id")?;
|
let id = row.try_get("id")?;
|
||||||
|
// get `username` row
|
||||||
let username = row.try_get("username")?;
|
let username = row.try_get("username")?;
|
||||||
|
// get `password` row
|
||||||
let password = row.try_get("password")?;
|
let password = row.try_get("password")?;
|
||||||
|
|
||||||
Ok(User {
|
Ok(User {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use axum::{extract::rejection::JsonRejection, Extension, Json};
|
||||||
use homedisk_database::{Database, Error, User};
|
use homedisk_database::{Database, Error, User};
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
auth::login::{Request, Response},
|
auth::login::{Request, Response},
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{AuthError, ServerError},
|
errors::{AuthError, ServerError},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,13 @@ use axum::{extract::rejection::JsonRejection, Extension, Json};
|
||||||
use homedisk_database::{Database, User};
|
use homedisk_database::{Database, User};
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
auth::login::{Request, Response},
|
auth::login::{Request, Response},
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{AuthError, ServerError},
|
errors::{AuthError, ServerError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::middleware::{create_token, validate_json};
|
use crate::middleware::{create_token, validate_json};
|
||||||
|
|
||||||
|
/// Handle `/auth/register` requests
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
Extension(db): Extension<Database>,
|
Extension(db): Extension<Database>,
|
||||||
Extension(config): Extension<Config>,
|
Extension(config): Extension<Config>,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum_auth::AuthBearer;
|
||||||
use homedisk_database::{Database, Error};
|
use homedisk_database::{Database, Error};
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
auth::whoami::Response,
|
auth::whoami::Response,
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{AuthError, ServerError},
|
errors::{AuthError, ServerError},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ pub async fn handle(
|
||||||
// validate user token
|
// validate user token
|
||||||
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
|
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
|
||||||
|
|
||||||
|
// search for a user in database
|
||||||
let response = match db.find_user_by_id(token.claims.sub).await {
|
let response = match db.find_user_by_id(token.claims.sub).await {
|
||||||
Ok(res) => Response {
|
Ok(res) => Response {
|
||||||
username: res.username,
|
username: res.username,
|
||||||
|
|
|
@ -1,29 +1,35 @@
|
||||||
|
// HTTP Error
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
// axum::Error
|
||||||
#[error("axum error - {0}")]
|
#[error("axum error - {0}")]
|
||||||
Axum(axum::Error),
|
Axum(axum::Error),
|
||||||
|
// hyper::Error
|
||||||
#[error("hyper error - {0}")]
|
#[error("hyper error - {0}")]
|
||||||
Hyper(hyper::Error),
|
Hyper(hyper::Error),
|
||||||
|
// std::net::AddrParseError
|
||||||
#[error("std::net::AddrParseError - {0}")]
|
#[error("std::net::AddrParseError - {0}")]
|
||||||
AddrParseError(std::net::AddrParseError),
|
AddrParseError(std::net::AddrParseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Custom Result
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// axum::Error
|
||||||
impl From<axum::Error> for Error {
|
impl From<axum::Error> for Error {
|
||||||
fn from(err: axum::Error) -> Self {
|
fn from(err: axum::Error) -> Self {
|
||||||
Error::Axum(err)
|
Error::Axum(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// hyper::Error
|
||||||
impl From<hyper::Error> for Error {
|
impl From<hyper::Error> for Error {
|
||||||
fn from(err: hyper::Error) -> Self {
|
fn from(err: hyper::Error) -> Self {
|
||||||
Error::Hyper(err)
|
Error::Hyper(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// std::net::AddrParseError
|
||||||
impl From<std::net::AddrParseError> for Error {
|
impl From<std::net::AddrParseError> for Error {
|
||||||
fn from(err: std::net::AddrParseError) -> Self {
|
fn from(err: std::net::AddrParseError) -> Self {
|
||||||
Error::AddrParseError(err)
|
Error::AddrParseError(err)
|
||||||
|
|
|
@ -5,13 +5,14 @@ use axum_auth::AuthBearer;
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_types::fs::create_dir::{Request, Response};
|
use homedisk_types::fs::create_dir::{Request, Response};
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{FsError, ServerError},
|
errors::{FsError, ServerError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::fs::validate_path;
|
use crate::fs::validate_path;
|
||||||
use crate::middleware::{find_user, validate_json, validate_jwt};
|
use crate::middleware::{find_user, validate_json, validate_jwt};
|
||||||
|
|
||||||
|
/// Handle `/fs/createdir` requests
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
Extension(db): Extension<Database>,
|
Extension(db): Extension<Database>,
|
||||||
Extension(config): Extension<Config>,
|
Extension(config): Extension<Config>,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::Extension;
|
||||||
use axum_auth::AuthBearer;
|
use axum_auth::AuthBearer;
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{FsError, ServerError},
|
errors::{FsError, ServerError},
|
||||||
fs::delete::Request,
|
fs::delete::Request,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,10 +6,11 @@ use axum::Extension;
|
||||||
use axum_auth::AuthBearer;
|
use axum_auth::AuthBearer;
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_types::fs::upload::Pagination;
|
use homedisk_types::fs::upload::Pagination;
|
||||||
use homedisk_types::{config::types::Config, errors::ServerError};
|
use homedisk_types::{config::Config, errors::ServerError};
|
||||||
|
|
||||||
use crate::middleware::{find_user, validate_jwt};
|
use crate::middleware::{find_user, validate_jwt};
|
||||||
|
|
||||||
|
/// Handle `/fs/download` requests
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
Extension(db): Extension<Database>,
|
Extension(db): Extension<Database>,
|
||||||
Extension(config): Extension<Config>,
|
Extension(config): Extension<Config>,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use byte_unit::Byte;
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_types::fs::list::DirInfo;
|
use homedisk_types::fs::list::DirInfo;
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{FsError, ServerError},
|
errors::{FsError, ServerError},
|
||||||
fs::list::{FileInfo, Request, Response},
|
fs::list::{FileInfo, Request, Response},
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ use axum_auth::AuthBearer;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_types::{
|
use homedisk_types::{
|
||||||
config::types::Config,
|
config::Config,
|
||||||
errors::{FsError, ServerError},
|
errors::{FsError, ServerError},
|
||||||
fs::upload::{Pagination, Response},
|
fs::upload::{Pagination, Response},
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@ use homedisk_types::{
|
||||||
use crate::fs::validate_path;
|
use crate::fs::validate_path;
|
||||||
use crate::middleware::{find_user, validate_jwt};
|
use crate::middleware::{find_user, validate_jwt};
|
||||||
|
|
||||||
|
/// Handle `/fs/upload` requests
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
Extension(db): Extension<Database>,
|
Extension(db): Extension<Database>,
|
||||||
Extension(config): Extension<Config>,
|
Extension(config): Extension<Config>,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
pub mod auth;
|
mod auth;
|
||||||
pub mod fs;
|
|
||||||
pub mod middleware;
|
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
mod fs;
|
||||||
|
mod middleware;
|
||||||
|
|
||||||
use axum::{http::HeaderValue, routing::get, Extension, Router, Server};
|
use axum::{http::HeaderValue, routing::get, Extension, Router, Server};
|
||||||
use homedisk_database::Database;
|
use homedisk_database::Database;
|
||||||
use homedisk_types::config::types::Config;
|
use homedisk_types::config::Config;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use tower_http::cors::{AllowOrigin, CorsLayer};
|
use tower_http::cors::{AllowOrigin, CorsLayer};
|
||||||
|
|
||||||
|
@ -15,7 +14,8 @@ async fn health_check() -> &'static str {
|
||||||
"I'm alive!"
|
"I'm alive!"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_http_server(
|
/// Start HTTP server
|
||||||
|
pub async fn serve_http(
|
||||||
host: String,
|
host: String,
|
||||||
origins: Vec<HeaderValue>,
|
origins: Vec<HeaderValue>,
|
||||||
db: Database,
|
db: Database,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! `/auth/login` Request and Response types
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
//! HTTP `/auth/*` types for Request and Response
|
||||||
|
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod whoami;
|
pub mod whoami;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! `/auth/whoami` Response type
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
pub mod types;
|
//! Types for configuration file
|
||||||
|
|
||||||
#[cfg(feature = "config")]
|
#[cfg(feature = "config")]
|
||||||
pub mod toml;
|
mod toml;
|
||||||
|
mod types;
|
||||||
|
|
||||||
|
pub use types::*;
|
||||||
|
|
|
@ -8,6 +8,11 @@ use super::types::Config;
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Parse configuration file
|
/// Parse configuration file
|
||||||
|
/// ```
|
||||||
|
/// use homedisk_types::config::Config;
|
||||||
|
///
|
||||||
|
/// let config = Config::parse().unwrap();
|
||||||
|
/// ```
|
||||||
pub fn parse() -> Result<Config> {
|
pub fn parse() -> Result<Config> {
|
||||||
// config file path
|
// config file path
|
||||||
let config_dir = option_return!(dirs::config_dir(), "get config dir")?;
|
let config_dir = option_return!(dirs::config_dir(), "get config dir")?;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
//! Configuration file types
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Config type
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub http: ConfigHTTP,
|
pub http: ConfigHTTP,
|
||||||
|
@ -7,6 +10,7 @@ pub struct Config {
|
||||||
pub storage: ConfigStorage,
|
pub storage: ConfigStorage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HTTP config
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ConfigHTTP {
|
pub struct ConfigHTTP {
|
||||||
/// HTTP Host
|
/// HTTP Host
|
||||||
|
@ -17,6 +21,7 @@ pub struct ConfigHTTP {
|
||||||
pub cors: Vec<String>,
|
pub cors: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Json Web Token config
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ConfigJWT {
|
pub struct ConfigJWT {
|
||||||
/// JWT Secret string
|
/// JWT Secret string
|
||||||
|
@ -25,6 +30,7 @@ pub struct ConfigJWT {
|
||||||
pub expires: i64,
|
pub expires: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Storage config
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ConfigStorage {
|
pub struct ConfigStorage {
|
||||||
/// Directory where user files will be stored
|
/// Directory where user files will be stored
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Typed for a database
|
||||||
|
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
pub use user::*;
|
pub use user::*;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use rust_utilities::crypto::sha::{encode, Algorithm, CryptographicHash};
|
use rust_utilities::crypto::sha::{encode, Algorithm, CryptographicHash};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// SQL `user` Table
|
/// SQL user table
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
#[derive(Debug, sqlx::FromRow)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -53,12 +53,14 @@ impl User {
|
||||||
/// assert_eq!(dir, "/home/homedisk/medzik")
|
/// assert_eq!(dir, "/home/homedisk/medzik")
|
||||||
/// ```
|
/// ```
|
||||||
pub fn user_dir(&self, storage: &str) -> String {
|
pub fn user_dir(&self, storage: &str) -> String {
|
||||||
|
// get a user storage path
|
||||||
let path = format!(
|
let path = format!(
|
||||||
"{path}/{username}",
|
"{path}/{username}",
|
||||||
path = storage,
|
path = storage,
|
||||||
username = self.username,
|
username = self.username,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// return user storage path
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// `/auth/*` Error
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("user not found")]
|
#[error("user not found")]
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
|
/// Database Error
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("user not found")]
|
#[error("user not found")]
|
||||||
UserNotFound,
|
UserNotFound,
|
||||||
|
/// sqlx::Error
|
||||||
#[error("sqlx error - {0}")]
|
#[error("sqlx error - {0}")]
|
||||||
SQLx(sqlx::Error),
|
SQLx(sqlx::Error),
|
||||||
|
/// std::io::Error
|
||||||
#[error("std::io error - {0}")]
|
#[error("std::io error - {0}")]
|
||||||
Io(std::io::Error),
|
StdIo(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// sqlx::Error
|
/// sqlx::Error
|
||||||
|
@ -20,6 +21,6 @@ impl From<sqlx::Error> for Error {
|
||||||
/// std::io::Error
|
/// std::io::Error
|
||||||
impl From<std::io::Error> for Error {
|
impl From<std::io::Error> for Error {
|
||||||
fn from(err: std::io::Error) -> Self {
|
fn from(err: std::io::Error) -> Self {
|
||||||
Error::Io(err)
|
Error::StdIo(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// `/fs/*` Error
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("file already exists")]
|
#[error("file already exists")]
|
||||||
|
|
|
@ -1,79 +1,12 @@
|
||||||
|
//! Error types
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
|
#[cfg(feature = "database")]
|
||||||
|
mod database;
|
||||||
mod fs;
|
mod fs;
|
||||||
|
mod server;
|
||||||
|
|
||||||
pub use auth::Error as AuthError;
|
pub use auth::Error as AuthError;
|
||||||
|
pub use database::Error as DatabaseError;
|
||||||
pub use fs::Error as FsError;
|
pub use fs::Error as FsError;
|
||||||
|
pub use server::Error as ServerError;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
#[serde(tag = "error", content = "error_message", rename_all = "kebab-case")]
|
|
||||||
pub enum ServerError {
|
|
||||||
#[error("auth error: {0}")]
|
|
||||||
AuthError(#[from] AuthError),
|
|
||||||
|
|
||||||
#[error("fs error: {0}")]
|
|
||||||
FsError(#[from] FsError),
|
|
||||||
|
|
||||||
#[error("too may requests, please slow down")]
|
|
||||||
TooManyRequests,
|
|
||||||
|
|
||||||
#[error("missing json content type")]
|
|
||||||
MissingJsonContentType,
|
|
||||||
|
|
||||||
#[error("error deserialize json")]
|
|
||||||
JsonDataError,
|
|
||||||
|
|
||||||
#[error("json syntax error")]
|
|
||||||
JsonSyntaxError,
|
|
||||||
|
|
||||||
#[error("failed to extract the request body")]
|
|
||||||
BytesRejection,
|
|
||||||
|
|
||||||
#[error("unexpected error - {0}")]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "axum")]
|
|
||||||
impl axum::response::IntoResponse for ServerError {
|
|
||||||
fn into_response(self) -> axum::response::Response {
|
|
||||||
use axum::http::StatusCode;
|
|
||||||
|
|
||||||
let status = match self {
|
|
||||||
Self::AuthError(ref err) => match err {
|
|
||||||
AuthError::UserNotFound => StatusCode::BAD_REQUEST,
|
|
||||||
AuthError::UserAlreadyExists => StatusCode::NOT_ACCEPTABLE,
|
|
||||||
AuthError::UsernameTooShort => StatusCode::NOT_ACCEPTABLE,
|
|
||||||
AuthError::UsernameTooLong => StatusCode::NOT_ACCEPTABLE,
|
|
||||||
AuthError::PasswordTooShort => StatusCode::NOT_ACCEPTABLE,
|
|
||||||
AuthError::TokenGenerate => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
AuthError::InvalidToken => StatusCode::BAD_REQUEST,
|
|
||||||
AuthError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
},
|
|
||||||
Self::FsError(ref err) => match err {
|
|
||||||
FsError::FileAlreadyExists => StatusCode::BAD_REQUEST,
|
|
||||||
FsError::FileDoesNotExist => StatusCode::BAD_REQUEST,
|
|
||||||
FsError::MultipartError => StatusCode::BAD_REQUEST,
|
|
||||||
FsError::CreateFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
FsError::CreateDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
FsError::DeleteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
FsError::DeleteDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
FsError::WriteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
FsError::Base64(_) => StatusCode::BAD_REQUEST,
|
|
||||||
FsError::ReadDir(_) => StatusCode::BAD_REQUEST,
|
|
||||||
FsError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
},
|
|
||||||
Self::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
|
|
||||||
Self::MissingJsonContentType => StatusCode::BAD_REQUEST,
|
|
||||||
Self::JsonDataError => StatusCode::BAD_REQUEST,
|
|
||||||
Self::JsonSyntaxError => StatusCode::BAD_REQUEST,
|
|
||||||
Self::BytesRejection => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Self::Other(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut response = axum::Json(self).into_response();
|
|
||||||
*response.status_mut() = status;
|
|
||||||
|
|
||||||
response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{AuthError, FsError};
|
||||||
|
|
||||||
|
/// HTTP Server Error
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
||||||
|
#[serde(tag = "error", content = "error_message", rename_all = "kebab-case")]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("auth error: {0}")]
|
||||||
|
AuthError(#[from] AuthError),
|
||||||
|
|
||||||
|
#[error("fs error: {0}")]
|
||||||
|
FsError(#[from] FsError),
|
||||||
|
|
||||||
|
#[error("too may requests, please slow down")]
|
||||||
|
TooManyRequests,
|
||||||
|
|
||||||
|
#[error("missing json content type")]
|
||||||
|
MissingJsonContentType,
|
||||||
|
|
||||||
|
#[error("error deserialize json")]
|
||||||
|
JsonDataError,
|
||||||
|
|
||||||
|
#[error("json syntax error")]
|
||||||
|
JsonSyntaxError,
|
||||||
|
|
||||||
|
#[error("failed to extract the request body")]
|
||||||
|
BytesRejection,
|
||||||
|
|
||||||
|
#[error("unexpected error - {0}")]
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "axum")]
|
||||||
|
impl axum::response::IntoResponse for Error {
|
||||||
|
fn into_response(self) -> axum::response::Response {
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
|
||||||
|
let status = match self {
|
||||||
|
Self::AuthError(ref err) => match err {
|
||||||
|
AuthError::UserNotFound => StatusCode::BAD_REQUEST,
|
||||||
|
AuthError::UserAlreadyExists => StatusCode::NOT_ACCEPTABLE,
|
||||||
|
AuthError::UsernameTooShort => StatusCode::NOT_ACCEPTABLE,
|
||||||
|
AuthError::UsernameTooLong => StatusCode::NOT_ACCEPTABLE,
|
||||||
|
AuthError::PasswordTooShort => StatusCode::NOT_ACCEPTABLE,
|
||||||
|
AuthError::TokenGenerate => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
AuthError::InvalidToken => StatusCode::BAD_REQUEST,
|
||||||
|
AuthError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
},
|
||||||
|
Self::FsError(ref err) => match err {
|
||||||
|
FsError::FileAlreadyExists => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::FileDoesNotExist => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::MultipartError => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::CreateFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::CreateDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::DeleteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::DeleteDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::WriteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::Base64(_) => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::ReadDir(_) => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
},
|
||||||
|
Self::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
|
||||||
|
Self::MissingJsonContentType => StatusCode::BAD_REQUEST,
|
||||||
|
Self::JsonDataError => StatusCode::BAD_REQUEST,
|
||||||
|
Self::JsonSyntaxError => StatusCode::BAD_REQUEST,
|
||||||
|
Self::BytesRejection => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
Self::Other(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut response = axum::Json(self).into_response();
|
||||||
|
*response.status_mut() = status;
|
||||||
|
|
||||||
|
response
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! HTTP `/fs/*` types for Request and Response
|
||||||
|
|
||||||
pub mod create_dir;
|
pub mod create_dir;
|
||||||
pub mod delete;
|
pub mod delete;
|
||||||
pub mod download;
|
pub mod download;
|
||||||
|
|
|
@ -4,4 +4,5 @@ pub mod config;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod macros;
|
|
||||||
|
mod macros;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/// Return value or error (if None) from Some(T)
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! option_return {
|
macro_rules! option_return {
|
||||||
($variable:expr,$err_desc:expr) => {
|
($variable:expr,$err_desc:expr) => {
|
||||||
|
|
Loading…
Reference in New Issue