feat (server): add http server (not finished yet)

This commit is contained in:
MedzikUser 2022-04-18 14:13:15 +02:00
parent c7a909fcb7
commit 65687fef74
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
20 changed files with 670 additions and 15 deletions

442
Cargo.lock generated
View File

@ -34,12 +34,68 @@ version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]]
name = "async-trait"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25"
dependencies = [
"async-trait",
"axum-core",
"bitflags",
"bytes",
"futures-util",
"http",
"http-body",
"hyper",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-http",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"mime",
]
[[package]]
name = "backtrace"
version = "0.3.64"
@ -191,6 +247,61 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "futures-channel"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]]
name = "futures-sink"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
[[package]]
name = "futures-task"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
[[package]]
name = "futures-util"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]]
name = "generic-array"
version = "0.14.5"
@ -218,6 +329,25 @@ version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
[[package]]
name = "h2"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
@ -256,12 +386,36 @@ name = "homedisk-core"
version = "0.0.0"
dependencies = [
"better-panic",
"homedisk-server",
"homedisk-utils",
"log",
"simplelog",
"tokio",
]
[[package]]
name = "homedisk-server"
version = "0.0.0"
dependencies = [
"axum",
"homedisk-types",
"homedisk-utils",
"hyper",
"log",
"serde",
"thiserror",
"tower-http",
]
[[package]]
name = "homedisk-types"
version = "0.0.0"
dependencies = [
"axum",
"serde",
"thiserror",
]
[[package]]
name = "homedisk-utils"
version = "0.0.0"
@ -278,6 +432,92 @@ dependencies = [
"uuid",
]
[[package]]
name = "http"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]]
name = "http-range-header"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
[[package]]
name = "httparse"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6330e8a36bd8c859f3fa6d9382911fbb7147ec39807f63b923933a247240b9ba"
[[package]]
name = "httpdate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "hyper"
version = "0.14.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.123"
@ -314,12 +554,30 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "matchit"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "mime"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "miniz_oxide"
version = "0.4.4"
@ -429,12 +687,44 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.25"
@ -500,6 +790,12 @@ version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -526,6 +822,29 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha-1"
version = "0.10.0"
@ -583,6 +902,12 @@ dependencies = [
"termcolor",
]
[[package]]
name = "slab"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]]
name = "smallvec"
version = "1.8.0"
@ -610,6 +935,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "sync_wrapper"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
[[package]]
name = "termcolor"
version = "1.1.3"
@ -690,6 +1021,20 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio-util"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
name = "toml"
version = "0.5.9"
@ -699,6 +1044,93 @@ dependencies = [
"serde",
]
[[package]]
name = "tower"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-http"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8"
dependencies = [
"bitflags",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-range-header",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62"
[[package]]
name = "tower-service"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
dependencies = [
"cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
dependencies = [
"lazy_static",
]
[[package]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typenum"
version = "1.15.0"
@ -733,6 +1165,16 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
dependencies = [
"log",
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"

View File

@ -1,6 +1,8 @@
[workspace]
members = [
"core",
"server",
"types",
"utils",
]
resolver = "2"

View File

@ -1,4 +1,6 @@
[http]
host = "localhost"
port = 8080
cors = "127.0.0.1:8080"
host = "0.0.0.0:8080"
cors = [
"127.0.0.1:8000",
"localhost:8000",
]

View File

@ -28,3 +28,6 @@ features = ["max_level_debug", "release_max_level_warn"]
[dependencies.homedisk-utils]
path = "../utils"
features = ["full"]
[dependencies.homedisk-server]
path = "../server"

View File

@ -1,21 +1,24 @@
mod init;
use homedisk_utils::{
config::Config,
database::{Database, User},
};
use homedisk_utils::{config::Config, database::Database};
#[tokio::main]
async fn main() {
init::init();
let _config = Config::parse().expect("parse configuration file");
let config = Config::parse().expect("parse configuration file");
let _db = Database::open("homedisk.db").expect("open SQLite database");
let db = Database::open("homedisk.db").expect("open SQLite database");
let user = User::new("medzik", "password").unwrap();
// change the type from Vec<String> to Vec<HeaderValue> so that the http server can correctly detect CORS hosts
let origins = config
.http
.cors
.iter()
.map(|e| e.parse().expect("parse CORS host"))
.collect();
println!("{:?}", user);
_db.create_user(user).unwrap();
homedisk_server::serve(config.http.host, origins, db)
.await
.expect("start http server");
}

29
server/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
name = "homedisk-server"
version = "0.0.0"
edition = "2021"
[dependencies]
axum = "0.5.1"
log = "0.4.16"
thiserror = "1.0.30"
[dependencies.tower-http]
version = "0.2.5"
features = ["cors"]
[dependencies.hyper]
version = "0.14.18"
features = ["full"]
[dependencies.serde]
version = "1.0.136"
features = ["derive"]
[dependencies.homedisk-utils]
path = "../utils"
features = ["full"]
[dependencies.homedisk-types]
path = "../types"
features = ["axum"]

9
server/src/auth/login.rs Normal file
View File

@ -0,0 +1,9 @@
use axum::Json;
use homedisk_types::{
auth::auth::login::{Request, Response},
errors::{AuthError, ServerError},
};
pub async fn handle(Json(_request): Json<Request>) -> Result<Json<Response>, ServerError> {
Err(ServerError::AuthError(AuthError::UserAlreadyExists))
}

7
server/src/auth/mod.rs Normal file
View File

@ -0,0 +1,7 @@
pub mod login;
pub fn app() -> axum::Router {
use axum::routing::post;
axum::Router::new().route("/login", post(login::handle))
}

10
server/src/auth/types.rs Normal file
View File

@ -0,0 +1,10 @@
#[derive(Debug, Clone)]
pub struct Request {
pub username: String,
pub password: String,
}
#[derive(Debug, Clone)]
pub enum ResponseLogin {
LoggedIn { access_token: String },
}

38
server/src/error.rs Normal file
View File

@ -0,0 +1,38 @@
use std::fmt;
#[derive(Debug)]
pub enum Error {
Axum(axum::Error),
Hyper(hyper::Error),
AddrParseError(std::net::AddrParseError),
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<axum::Error> for Error {
fn from(err: axum::Error) -> Self {
Error::Axum(err)
}
}
impl From<hyper::Error> for Error {
fn from(err: hyper::Error) -> Self {
Error::Hyper(err)
}
}
impl From<std::net::AddrParseError> for Error {
fn from(err: std::net::AddrParseError) -> Self {
Error::AddrParseError(err)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Axum(err) => write!(f, "axum error: {}", err),
Error::Hyper(err) => write!(f, "hyper error: {}", err),
Error::AddrParseError(err) => write!(f, "AddrParse error: {}", err),
}
}
}

31
server/src/lib.rs Normal file
View File

@ -0,0 +1,31 @@
pub mod auth;
mod error;
use std::sync::Arc;
use axum::{http::HeaderValue, routing::get, Router, Server};
use homedisk_utils::database::Database;
use log::{debug, info};
use tower_http::cors::{CorsLayer, Origin};
async fn health_check() -> &'static str {
"I'm alive!"
}
pub async fn serve(host: String, origins: Vec<HeaderValue>, db: Database) -> error::Result<()> {
debug!("starting http server");
info!("Website available at: http://{host}");
let _db = Arc::new(db);
let app = Router::new()
.route("/health-check", get(health_check))
.nest("/auth", auth::app())
.layer(CorsLayer::new().allow_origin(Origin::list(origins)));
Server::bind(&host.parse()?)
.serve(app.into_make_service())
.await?;
Ok(())
}

15
types/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "homedisk-types"
version = "0.0.0"
edition = "2021"
[dependencies]
thiserror = "1.0.30"
[dependencies.serde]
version = "1.0.136"
features = ["derive"]
[dependencies.axum]
version = "0.5.1"
optional = true

View File

@ -0,0 +1,15 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Request {
pub username: String,
pub password: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Response {
LoggedIn {
access_token: String,
refresh_token: String,
},
}

View File

@ -0,0 +1 @@
pub mod login;

1
types/src/auth/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod auth;

10
types/src/errors/auth.rs Normal file
View File

@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
pub enum Error {
#[error("user not found")]
UserNotFound,
#[error("user already exists")]
UserAlreadyExists,
}

35
types/src/errors/mod.rs Normal file
View File

@ -0,0 +1,35 @@
mod auth;
pub use auth::Error as AuthError;
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("too may requests, please slow down")]
TooManyRequests,
}
#[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::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
Self::AuthError(ref err) => match err {
AuthError::UserNotFound => StatusCode::BAD_REQUEST,
AuthError::UserAlreadyExists => StatusCode::NOT_ACCEPTABLE,
},
};
let mut response = axum::Json(self).into_response();
*response.status_mut() = status;
response
}
}

2
types/src/lib.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod auth;
pub mod errors;

View File

@ -12,8 +12,7 @@ pub struct Config {
#[derive(Debug, Serialize, Deserialize)]
pub struct ConfigHTTP {
pub host: String,
pub port: u32,
pub cors: String,
pub cors: Vec<String>,
}
impl Config {

View File

@ -3,6 +3,7 @@ use rusqlite::Connection;
use super::{user, Error};
#[derive(Debug)]
pub struct Database {
pub conn: Connection,
}