use axum::{
Json, Router,
extract::{Path, State},
http::StatusCode,
response::IntoResponse,
routing::{delete, get, post},
};
use kivis::{MemoryStorage, Repository};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
type SharedStorage = Arc<Mutex<MemoryStorage>>;
#[derive(Debug, Serialize, Deserialize)]
pub struct InsertRequest {
pub key: String,
pub value: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GetResponse {
pub value: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RemoveResponse {
pub value: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct KeysResponse {
pub keys: Vec<String>,
}
pub fn create_router(storage: MemoryStorage) -> Router {
let shared_storage = Arc::new(Mutex::new(storage));
Router::new()
.route("/insert", post(insert_handler))
.route("/get/:key", get(get_handler))
.route("/remove/:key", delete(remove_handler))
.route("/keys/:start/:end", get(keys_handler))
.with_state(shared_storage)
}
async fn insert_handler(
State(storage): State<SharedStorage>,
Json(request): Json<InsertRequest>,
) -> impl IntoResponse {
let key = match hex::decode(&request.key) {
Ok(k) => k,
Err(_) => return (StatusCode::BAD_REQUEST, "Invalid hex key"),
};
let value = match hex::decode(&request.value) {
Ok(v) => v,
Err(_) => return (StatusCode::BAD_REQUEST, "Invalid hex value"),
};
let mut storage = storage.lock().unwrap();
match Repository::insert_entry(&mut *storage, &key, &value) {
Ok(_) => (StatusCode::OK, "Inserted successfully"),
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Failed to insert"),
}
}
async fn get_handler(
State(storage): State<SharedStorage>,
Path(key_hex): Path<String>,
) -> impl IntoResponse {
let key = match hex::decode(&key_hex) {
Ok(k) => k,
Err(_) => return (StatusCode::BAD_REQUEST, Json(GetResponse { value: None })),
};
let storage = storage.lock().unwrap();
match Repository::get_entry(&*storage, &key) {
Ok(Some(value)) => {
let value_hex = hex::encode(&value);
(
StatusCode::OK,
Json(GetResponse {
value: Some(value_hex),
}),
)
}
Ok(None) => (StatusCode::NOT_FOUND, Json(GetResponse { value: None })),
Err(_) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(GetResponse { value: None }),
),
}
}
async fn remove_handler(
State(storage): State<SharedStorage>,
Path(key_hex): Path<String>,
) -> impl IntoResponse {
let key = match hex::decode(&key_hex) {
Ok(k) => k,
Err(_) => {
return (
StatusCode::BAD_REQUEST,
Json(RemoveResponse { value: None }),
);
}
};
let mut storage = storage.lock().unwrap();
match Repository::remove_entry(&mut *storage, &key) {
Ok(Some(value)) => {
let value_hex = hex::encode(&value);
(
StatusCode::OK,
Json(RemoveResponse {
value: Some(value_hex),
}),
)
}
Ok(None) => (StatusCode::NOT_FOUND, Json(RemoveResponse { value: None })),
Err(_) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(RemoveResponse { value: None }),
),
}
}
async fn keys_handler(
State(storage): State<SharedStorage>,
Path((start, end)): Path<(String, String)>,
) -> impl IntoResponse {
let start_key = match hex::decode(&start) {
Ok(k) => k,
Err(_) => return (StatusCode::BAD_REQUEST, Json(KeysResponse { keys: vec![] })),
};
let end_key = match hex::decode(&end) {
Ok(k) => k,
Err(_) => return (StatusCode::BAD_REQUEST, Json(KeysResponse { keys: vec![] })),
};
let storage = storage.lock().unwrap();
let keys_result: Result<Vec<String>, kivis::MemoryStorageError> = (|| {
let iter = Repository::scan_range(&*storage, start_key..end_key)?;
let keys: Vec<String> = iter
.filter_map(|result| result.ok())
.map(|key| hex::encode(&key))
.collect();
Ok(keys)
})();
match keys_result {
Ok(keys) => (StatusCode::OK, Json(KeysResponse { keys })),
Err(_) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(KeysResponse { keys: vec![] }),
),
}
}