If no ttl given, data could be made permanent
This commit is contained in:
parent
2bf4a6e54c
commit
613f951af7
44
src/main.rs
44
src/main.rs
@ -2,6 +2,7 @@ use async_std::fs::{create_dir_all, read_dir, read_to_string, remove_file, File}
|
|||||||
use sdk_common::sp_client::bitcoin::hex::{DisplayHex, FromHex};
|
use sdk_common::sp_client::bitcoin::hex::{DisplayHex, FromHex};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
use async_std::io::WriteExt;
|
use async_std::io::WriteExt;
|
||||||
use async_std::path::Path;
|
use async_std::path::Path;
|
||||||
@ -57,14 +58,13 @@ async fn cleanup_expired_files() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sleep for 1 minute before next cleanup
|
// Sleep for 1 minute before next cleanup
|
||||||
// task::sleep(Duration::from_secs(60)).await;
|
task::sleep(Duration::from_secs(60)).await;
|
||||||
task::sleep(Duration::from_secs(10)).await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
struct Metadata {
|
struct Metadata {
|
||||||
expires_at: u64,
|
expires_at: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a `SystemTime` to a UNIX timestamp (seconds since UNIX epoch).
|
/// Converts a `SystemTime` to a UNIX timestamp (seconds since UNIX epoch).
|
||||||
@ -106,7 +106,7 @@ async fn get_file_path(key: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Store data on the filesystem
|
/// Store data on the filesystem
|
||||||
async fn store_data(key: &str, value: &[u8], expires_at: SystemTime) -> Result<(), tide::Error> {
|
async fn store_data(key: &str, value: &[u8], expires_at: Option<SystemTime>) -> Result<(), tide::Error> {
|
||||||
let file_name = get_file_path(key).await;
|
let file_name = get_file_path(key).await;
|
||||||
let file_path = Path::new(&file_name);
|
let file_path = Path::new(&file_name);
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ async fn store_data(key: &str, value: &[u8], expires_at: SystemTime) -> Result<(
|
|||||||
.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?;
|
.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?;
|
||||||
|
|
||||||
let metadata = Metadata {
|
let metadata = Metadata {
|
||||||
expires_at: system_time_to_unix(expires_at),
|
expires_at: expires_at.map(|e| system_time_to_unix(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let metadata_json = serde_json::to_string(&metadata)
|
let metadata_json = serde_json::to_string(&metadata)
|
||||||
@ -165,7 +165,7 @@ async fn retrieve_data(key: &str) -> Result<Vec<u8>, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handler for the /store endpoint
|
/// Handler for the /store endpoint
|
||||||
async fn handle_store(mut req: Request<()>) -> tide::Result<Response> {
|
async fn handle_store(mut req: Request<()>, no_ttl_permanent: bool) -> tide::Result<Response> {
|
||||||
// Parse the JSON body
|
// Parse the JSON body
|
||||||
let data: StoreRequest = match req.body_json().await {
|
let data: StoreRequest = match req.body_json().await {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
@ -184,7 +184,7 @@ async fn handle_store(mut req: Request<()>) -> tide::Result<Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate the ttl
|
// Validate the ttl
|
||||||
let live_for = if let Some(ttl) = data.ttl {
|
let live_for: Option<Duration> = if let Some(ttl) = data.ttl {
|
||||||
if ttl < MIN_TTL {
|
if ttl < MIN_TTL {
|
||||||
return Ok(Response::builder(StatusCode::BadRequest)
|
return Ok(Response::builder(StatusCode::BadRequest)
|
||||||
.body(format!(
|
.body(format!(
|
||||||
@ -197,15 +197,22 @@ async fn handle_store(mut req: Request<()>) -> tide::Result<Response> {
|
|||||||
.body(format!("Invalid ttl: must be at most {} seconds.", MAX_TTL))
|
.body(format!("Invalid ttl: must be at most {} seconds.", MAX_TTL))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
Duration::from_secs(ttl)
|
Some(Duration::from_secs(ttl))
|
||||||
|
} else if no_ttl_permanent {
|
||||||
|
// When no_ttl_permanent is true, requests without TTL are permanent
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
Duration::from_secs(DEFAULT_TTL)
|
Some(Duration::from_secs(DEFAULT_TTL))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let expires_at: Option<SystemTime> = if let Some(live_for) = live_for {
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let expires_at = now
|
Some(now
|
||||||
.checked_add(live_for)
|
.checked_add(live_for)
|
||||||
.ok_or(tide::Error::from_str(StatusCode::BadRequest, "Invalid ttl"))?;
|
.ok_or(tide::Error::from_str(StatusCode::BadRequest, "Invalid ttl"))?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Decode the value from Base64
|
// Decode the value from Base64
|
||||||
let value_bytes = match Vec::from_hex(&data.value) {
|
let value_bytes = match Vec::from_hex(&data.value) {
|
||||||
@ -263,7 +270,7 @@ async fn handle_file_cleanup(now: u64, meta_path: &Path) -> Result<(), String> {
|
|||||||
let metadata: Metadata = serde_json::from_str(&meta_content)
|
let metadata: Metadata = serde_json::from_str(&meta_content)
|
||||||
.map_err(|e| format!("Failed to parse metadata: {}", e.to_string()))?;
|
.map_err(|e| format!("Failed to parse metadata: {}", e.to_string()))?;
|
||||||
|
|
||||||
if metadata.expires_at < now {
|
if metadata.expires_at.is_some() && metadata.expires_at.unwrap() < now {
|
||||||
let data_file_path = meta_path.with_extension("");
|
let data_file_path = meta_path.with_extension("");
|
||||||
remove_file(&data_file_path)
|
remove_file(&data_file_path)
|
||||||
.await
|
.await
|
||||||
@ -279,6 +286,17 @@ async fn handle_file_cleanup(now: u64, meta_path: &Path) -> Result<(), String> {
|
|||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
async fn main() -> tide::Result<()> {
|
async fn main() -> tide::Result<()> {
|
||||||
sdk_common::env_logger::init();
|
sdk_common::env_logger::init();
|
||||||
|
|
||||||
|
// Parse command line arguments
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
let no_ttl_permanent = args.iter().any(|arg| arg == "--no-ttl-permanent");
|
||||||
|
|
||||||
|
if no_ttl_permanent {
|
||||||
|
log::info!("No-TTL requests will be treated as permanent");
|
||||||
|
} else {
|
||||||
|
log::info!("No-TTL requests will use default TTL of {} seconds", DEFAULT_TTL);
|
||||||
|
}
|
||||||
|
|
||||||
create_dir_all(STORAGE_DIR)
|
create_dir_all(STORAGE_DIR)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create storage directory.");
|
.expect("Failed to create storage directory.");
|
||||||
@ -286,7 +304,7 @@ async fn main() -> tide::Result<()> {
|
|||||||
task::spawn(cleanup_expired_files());
|
task::spawn(cleanup_expired_files());
|
||||||
|
|
||||||
let mut app = tide::new();
|
let mut app = tide::new();
|
||||||
app.at("/store").post(handle_store);
|
app.at("/store").post(move |req| handle_store(req, no_ttl_permanent));
|
||||||
app.at("/retrieve/:key").get(handle_retrieve);
|
app.at("/retrieve/:key").get(handle_retrieve);
|
||||||
app.listen("0.0.0.0:8080").await?;
|
app.listen("0.0.0.0:8080").await?;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user