diff --git a/src/main.rs b/src/main.rs index db36845..eedf733 100644 --- a/src/main.rs +++ b/src/main.rs @@ -93,24 +93,37 @@ struct RetrieveResponse { value: String, } -/// Store data on the filesystem -async fn store_data(key: &str, value: &[u8], expires_at: SystemTime) -> Result<(), String> { +async fn get_file_path(key: &str) -> String { let dir_name = format!("{}/{}", STORAGE_DIR, &key[..2]); let file_path = format!("{}/{}", dir_name, &key[2..]); - let metadata_path = format!("{}.meta", file_path); + + file_path +} - create_dir_all(&dir_name).await.map_err(|e| e.to_string())?; +/// Store data on the filesystem +async fn store_data(key: &str, value: &[u8], expires_at: SystemTime) -> Result<(), tide::Error> { + let file_name = get_file_path(key).await; + let file_path = Path::new(&file_name); - 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())?; + // Check if key exists + if file_path.exists().await { + return Err(tide::Error::from_str(StatusCode::Conflict, "Key already exists")); + } + + create_dir_all(file_path).await.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?; + + let metadata_path = format!("{}.meta", file_name); + + let mut file = File::create(&file_path).await.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?; + file.write_all(value).await.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?; let metadata = Metadata { expires_at: system_time_to_unix(expires_at) }; - let metadata_json = serde_json::to_string(&metadata).map_err(|e| e.to_string())?; - let mut meta_file = File::create(&metadata_path).await.map_err(|e| e.to_string())?; - meta_file.write_all(metadata_json.as_bytes()).await.map_err(|e| e.to_string())?; + let metadata_json = serde_json::to_string(&metadata).map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?; + let mut meta_file = File::create(&metadata_path).await.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?; + meta_file.write_all(metadata_json.as_bytes()).await.map_err(|e| tide::Error::new(StatusCode::InternalServerError, e))?; Ok(()) } @@ -127,9 +140,14 @@ async fn retrieve_data(key: &str) -> Result, String> { /// Handler for the /store endpoint async fn handle_store(mut req: Request<()>) -> tide::Result { // Parse the JSON body - let data: StoreRequest = req.body_json().await.map_err(|_| { - tide::Error::from_str(StatusCode::BadRequest, "Invalid JSON payload") - })?; + let data: StoreRequest = match req.body_json().await { + Ok(data) => data, + Err(e) => { + return Ok(Response::builder(StatusCode::BadRequest) + .body(format!("Invalid request: {}", e)) + .build()); + } + }; // Validate the key if data.key.len() != 64 || !data.key.chars().all(|c| c.is_ascii_hexdigit()) { @@ -139,25 +157,36 @@ async fn handle_store(mut req: Request<()>) -> tide::Result { } // Decode the value from Base64 - let value_bytes = base64::decode(&data.value).map_err(|_| { - tide::Error::from_str(StatusCode::BadRequest, "Invalid Base64 value") - })?; + let value_bytes = match base64::decode(&data.value) { + Ok(value) => value, + Err(e) => { + return Ok(Response::builder(StatusCode::BadRequest) + .body(format!("Invalid request: {}", e)) + .build()); + } + }; let now = SystemTime::now(); let live_for = if let Some(ttl) = data.ttl { Duration::from_secs(ttl) } else { Duration::from_secs(DEFAULT_TTL) }; let expires_at = now.checked_add(live_for).ok_or(tide::Error::from_str(StatusCode::BadRequest, "Invalid ttl"))?; // Store the data - store_data(&data.key, &value_bytes, expires_at).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()) + match store_data(&data.key, &value_bytes, expires_at).await { + Ok(()) => { + Ok(Response::builder(StatusCode::Ok) + .body(serde_json::to_value(&ApiResponse { + message: "Data stored successfully.".to_string(), + })?) + .build()) + } + Err(e) => { + Ok(Response::builder(e.status()) + .body(serde_json::to_value(&ApiResponse { + message: e.to_string(), + })?) + .build()) + } + } } async fn handle_retrieve(req: Request<()>) -> tide::Result {