Initial commit.
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
1580
Cargo.lock
generated
Normal file
1580
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "gumbucket"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
axum = { version = "0.8.6", features = ["multipart"] }
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
color-eyre = "0.6"
|
||||
config = { version = "0.15", default-features = false, features = [ "yaml" ] }
|
||||
futures = "0.3"
|
||||
rocksdb = "0.24.0"
|
||||
tokio = { version = "1.47.1", features = ["fs", "macros", "rt-multi-thread"] }
|
||||
tokio-macros = "2.5"
|
||||
tower = { version = "0.5", features = ["buffer", "limit", "load-shed", "timeout"] }
|
||||
tower-http = { version = "0.6", features = ["compression-full", "limit", "trace", "util"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
|
||||
[profile.dev.package.backtrace]
|
||||
opt-level = 3
|
||||
1
index.html
Normal file
1
index.html
Normal file
@@ -0,0 +1 @@
|
||||
blah!
|
||||
96
src/main.rs
Normal file
96
src/main.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use axum::{
|
||||
BoxError, Router,
|
||||
error_handling::HandleErrorLayer,
|
||||
extract::{DefaultBodyLimit, Multipart},
|
||||
http::StatusCode,
|
||||
response::{Html, IntoResponse, Response},
|
||||
routing::{get, post},
|
||||
};
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::Result;
|
||||
use std::time::Duration;
|
||||
use tokio::fs;
|
||||
use tower::{ServiceBuilder, buffer::BufferLayer, limit::rate::RateLimitLayer};
|
||||
use tower_http::{compression::CompressionLayer, limit::RequestBodyLimitLayer, trace::TraceLayer};
|
||||
|
||||
mod store;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
struct Args {
|
||||
/// Configuration file locaation.
|
||||
#[arg(short, long)]
|
||||
config: String,
|
||||
}
|
||||
|
||||
async fn default_handler() -> Response {
|
||||
match fs::read_to_string("index.html").await {
|
||||
Ok(content) => Html(content).into_response(),
|
||||
Err(e) => (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Failed to read index.html: {}", e),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_error(err: BoxError) -> (StatusCode, String) {
|
||||
if err.is::<tower::timeout::error::Elapsed>() {
|
||||
(StatusCode::REQUEST_TIMEOUT, "Request timed out".to_string())
|
||||
} else if err.is::<tower::load_shed::error::Overloaded>() {
|
||||
(
|
||||
StatusCode::SERVICE_UNAVAILABLE,
|
||||
"Service overloaded, try again later".to_string(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Internal error: {}", err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn upload_handler(mut _multipart: Multipart) -> Response {
|
||||
// while let field = multipart.next_field().await {
|
||||
// match field {
|
||||
// Ok(field) => (StatusCode::OK, "Insert Link Here...".to_string()).into_response(),
|
||||
|
||||
// Err(err) => (
|
||||
// StatusCode::BAD_REQUEST,
|
||||
// format!("Error processing request: {}", err),
|
||||
// )
|
||||
// .into_response(),
|
||||
// }
|
||||
// }
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let _args = Args::parse();
|
||||
|
||||
let app = Router::new()
|
||||
.route("/", get(default_handler))
|
||||
.route("/", post(upload_handler))
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(HandleErrorLayer::new(handle_error))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
// Set to about the expected number of concurrent connections.
|
||||
.layer(BufferLayer::new(64))
|
||||
// Limit to 30 per minute
|
||||
.layer(RateLimitLayer::new(30, Duration::from_secs(60)))
|
||||
.layer(RequestBodyLimitLayer::new(1024 * 1024))
|
||||
.layer(DefaultBodyLimit::disable())
|
||||
.layer(CompressionLayer::new()),
|
||||
);
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
|
||||
.await
|
||||
.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
8
src/store/keyval/mod.rs
Normal file
8
src/store/keyval/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
// Default rocksdb storage.
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn init(_path: impl AsRef<str>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
1
src/store/mod.rs
Normal file
1
src/store/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub(crate) mod keyval;
|
||||
Reference in New Issue
Block a user