Basic store and retrieve data
This commit is contained in:
commit
2d530ec000
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/storage
|
2772
Cargo.lock
generated
Normal file
2772
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "sdk_storage"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
sdk_common = { git = "https://git.4nkweb.com/4nk/sdk_common.git", branch = "dev"}
|
||||
tide = "0.16.0"
|
||||
async-std = { version = "1.8.0", features = ["attributes"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
base64 = "0.13"
|
||||
|
117
src/main.rs
Normal file
117
src/main.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use async_std::fs::{create_dir_all, File};
|
||||
use async_std::io::WriteExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tide::{Request, Response, StatusCode};
|
||||
use base64;
|
||||
|
||||
const STORAGE_DIR: &str = "./storage";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct StoreRequest {
|
||||
key: String,
|
||||
value: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ApiResponse {
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RetrieveResponse {
|
||||
key: String,
|
||||
value: String,
|
||||
}
|
||||
|
||||
/// Store data on the filesystem
|
||||
async fn store_data(key: &str, value: &[u8]) -> Result<(), String> {
|
||||
// Create directory based on the first 2 characters of the key
|
||||
let dir_name = format!("{}/{}", STORAGE_DIR, &key[..2]);
|
||||
let file_path = format!("{}/{}", dir_name, &key[2..]);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
create_dir_all(&dir_name).await.map_err(|e| e.to_string())?;
|
||||
|
||||
// Write value to file
|
||||
let mut file = File::create(&file_path).await.map_err(|e| e.to_string())?;
|
||||
file.write_all(value).await.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn retrieve_data(key: &str) -> Result<Vec<u8>, String> {
|
||||
let file_path = format!("{}/{}/{}", STORAGE_DIR, &key[..2], &key[2..]);
|
||||
|
||||
let mut file = File::open(&file_path).await.map_err(|_| "Key not found.".to_string())?;
|
||||
let mut buffer = Vec::new();
|
||||
async_std::io::ReadExt::read_to_end(&mut file, &mut buffer).await.map_err(|e| e.to_string())?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
/// Handler for the /store endpoint
|
||||
async fn handle_store(mut req: Request<()>) -> tide::Result<Response> {
|
||||
// Parse the JSON body
|
||||
let data: StoreRequest = req.body_json().await.map_err(|_| {
|
||||
tide::Error::from_str(StatusCode::BadRequest, "Invalid JSON payload")
|
||||
})?;
|
||||
|
||||
// Validate the key
|
||||
if data.key.len() != 64 || !data.key.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
return Ok(Response::builder(StatusCode::BadRequest)
|
||||
.body("Invalid key: must be a 32 bytes hex string.".to_string())
|
||||
.build());
|
||||
}
|
||||
|
||||
// Decode the value from Base64
|
||||
let value_bytes = base64::decode(&data.value).map_err(|_| {
|
||||
tide::Error::from_str(StatusCode::BadRequest, "Invalid Base64 value")
|
||||
})?;
|
||||
|
||||
// Store the data
|
||||
store_data(&data.key, &value_bytes).await.map_err(|e| {
|
||||
tide::Error::from_str(StatusCode::InternalServerError, e)
|
||||
})?;
|
||||
|
||||
// Respond with success
|
||||
Ok(Response::builder(StatusCode::Ok)
|
||||
.body(serde_json::to_value(&ApiResponse {
|
||||
message: "Data stored successfully.".to_string(),
|
||||
})?)
|
||||
.build())
|
||||
}
|
||||
|
||||
async fn handle_retrieve(req: Request<()>) -> tide::Result<Response> {
|
||||
let key: String = req.param("key")?.to_string();
|
||||
|
||||
if key.len() != 64 || !key.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
return Ok(Response::builder(StatusCode::BadRequest)
|
||||
.body("Invalid key: must be a 32 bytes hex string.".to_string())
|
||||
.build());
|
||||
}
|
||||
|
||||
match retrieve_data(&key).await {
|
||||
Ok(value) => {
|
||||
let encoded_value = base64::encode(&value);
|
||||
Ok(Response::builder(StatusCode::Ok)
|
||||
.body(serde_json::to_value(&RetrieveResponse { key, value: encoded_value })?)
|
||||
.build())
|
||||
}
|
||||
Err(e) => Ok(Response::builder(StatusCode::NotFound)
|
||||
.body(e)
|
||||
.build()),
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() -> tide::Result<()> {
|
||||
create_dir_all(STORAGE_DIR).await.expect("Failed to create storage directory.");
|
||||
|
||||
let mut app = tide::new();
|
||||
app.at("/store").post(handle_store);
|
||||
app.at("/retrieve/:key").get(handle_retrieve);
|
||||
app.listen("0.0.0.0:8080").await?;
|
||||
|
||||
println!("Server running at http://0.0.0.0:8080");
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user