From 613f951af7a1cf8679ef7fc01c6e26c658882f70 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Tue, 8 Jul 2025 16:44:04 +0200 Subject: [PATCH] If no ttl given, data could be made permanent --- src/main.rs | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7f4638c..f1e6cfc 100644 --- a/src/main.rs +++ b/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 serde::{Deserialize, Serialize}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::env; use async_std::io::WriteExt; use async_std::path::Path; @@ -57,14 +58,13 @@ async fn cleanup_expired_files() { } } // Sleep for 1 minute before next cleanup - // task::sleep(Duration::from_secs(60)).await; - task::sleep(Duration::from_secs(10)).await; + task::sleep(Duration::from_secs(60)).await; } } #[derive(Debug, Deserialize, Serialize)] struct Metadata { - expires_at: u64, + expires_at: Option, } /// 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 -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) -> Result<(), tide::Error> { let file_name = get_file_path(key).await; 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))?; 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) @@ -165,7 +165,7 @@ async fn retrieve_data(key: &str) -> Result, String> { } /// Handler for the /store endpoint -async fn handle_store(mut req: Request<()>) -> tide::Result { +async fn handle_store(mut req: Request<()>, no_ttl_permanent: bool) -> tide::Result { // Parse the JSON body let data: StoreRequest = match req.body_json().await { Ok(data) => data, @@ -184,7 +184,7 @@ async fn handle_store(mut req: Request<()>) -> tide::Result { } // Validate the ttl - let live_for = if let Some(ttl) = data.ttl { + let live_for: Option = if let Some(ttl) = data.ttl { if ttl < MIN_TTL { return Ok(Response::builder(StatusCode::BadRequest) .body(format!( @@ -197,15 +197,22 @@ async fn handle_store(mut req: Request<()>) -> tide::Result { .body(format!("Invalid ttl: must be at most {} seconds.", MAX_TTL)) .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 { - Duration::from_secs(DEFAULT_TTL) + Some(Duration::from_secs(DEFAULT_TTL)) }; - let now = SystemTime::now(); - let expires_at = now - .checked_add(live_for) - .ok_or(tide::Error::from_str(StatusCode::BadRequest, "Invalid ttl"))?; + let expires_at: Option = if let Some(live_for) = live_for { + let now = SystemTime::now(); + Some(now + .checked_add(live_for) + .ok_or(tide::Error::from_str(StatusCode::BadRequest, "Invalid ttl"))?) + } else { + None + }; // Decode the value from Base64 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) .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(""); remove_file(&data_file_path) .await @@ -279,6 +286,17 @@ async fn handle_file_cleanup(now: u64, meta_path: &Path) -> Result<(), String> { #[async_std::main] async fn main() -> tide::Result<()> { sdk_common::env_logger::init(); + + // Parse command line arguments + let args: Vec = 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) .await .expect("Failed to create storage directory."); @@ -286,7 +304,7 @@ async fn main() -> tide::Result<()> { task::spawn(cleanup_expired_files()); 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.listen("0.0.0.0:8080").await?;