diff --git a/Cargo.lock b/Cargo.lock index 82dbf6b..87e2830 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,6 +151,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base62" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f879ef8fc74665ed7f0e6127cb106315888fc2744f68e14b74f83edbb2a08992" + [[package]] name = "base64" version = "0.13.1" @@ -198,8 +204,10 @@ name = "briefly" version = "0.1.0" dependencies = [ "axum", + "base62", "chrono", "config", + "md5", "reqwest", "serde", "sqlx", @@ -970,6 +978,12 @@ dependencies = [ "digest", ] +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 9a38dbc..bab3a97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,8 @@ chrono = { version = "0.4.21", features = ["serde"] } tracing = "0.1.37" tracing-subscriber = "0.3.17" tower-http = { version = "0.4.3", features = ["trace"] } +md5 = "0.7.0" +base62 = "2.0.2" [dependencies.sqlx] version = "0.7.1" diff --git a/Tests/key_generator.rs b/Tests/key_generator.rs new file mode 100644 index 0000000..2ccf27a --- /dev/null +++ b/Tests/key_generator.rs @@ -0,0 +1,8 @@ +use briefly::key_generator::generate; + +#[test] +fn generate_seven_chars_key() { + let url = "https://www.rust-lang.org"; + let generated = generate(url); + assert_eq!(generated, "e2XSHcR".to_string()) +} diff --git a/src/key_generator.rs b/src/key_generator.rs new file mode 100644 index 0000000..6718081 --- /dev/null +++ b/src/key_generator.rs @@ -0,0 +1,9 @@ +use base62::encode; +use md5::compute; + +pub fn generate(value: &str) -> String { + let hash = compute(value); + let hash_bytes: [u8; 16] = hash.into(); + let hash_u128: u128 = u128::from_le_bytes(hash_bytes); + encode(hash_u128)[..7].to_string() +} diff --git a/src/lib.rs b/src/lib.rs index b6e12b2..24d561a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod configuration; +pub mod key_generator; pub mod model; pub mod request_tracing; pub mod routes; diff --git a/src/routes/full_url.rs b/src/routes/full_url.rs index 2c8342d..1ced939 100644 --- a/src/routes/full_url.rs +++ b/src/routes/full_url.rs @@ -1,6 +1,9 @@ -use crate::{model::UrlRequestModel, schema::CreateShortUrlSchema, AppState}; +use crate::{ + key_generator::generate, model::UrlRequestModel, schema::CreateShortUrlSchema, AppState, +}; use axum::{extract::State, Json}; use chrono::Utc; +use sqlx::Error; use std::sync::Arc; use uuid::Uuid; @@ -8,23 +11,42 @@ pub async fn full_url( State(data): State>, Json(payload): Json, ) { - let query_result = sqlx::query_as!( + let mut retry_count = 3; + + while retry_count > 0 { + let query_result = insert_in_db(&payload.url, State(data.clone())).await; + + match query_result { + Ok(note) => { + println!("okay received testing: {:?}", note); + break; + } + Err(e) => { + println!("failed with error: {:?}", e); + //TODO : - For now assume is failing because of error code 23505, that stands for + //duplicate key + retry_count += 1; + } + } + } +} + +async fn insert_in_db( + url: &str, + State(data): State>, +) -> Result { + let uuid = Uuid::new_v4(); + let modifier = uuid.to_string() + url; + let shortened = generate(&modifier); + + sqlx::query_as!( UrlRequestModel, "INSERT INTO briefly (id, url, extension, created_at) VALUES ($1, $2, $3, $4) RETURNING *", - Uuid::new_v4(), - payload.url.to_string(), - Uuid::new_v4().to_string(), // TODO: - handle extension to be shortened url extension + uuid, + url.to_string(), + shortened, Utc::now() ) .fetch_one(&data.db) - .await; - - match query_result { - Ok(note) => { - println!("okay received testing: {:?}", note); - } - Err(e) => { - println!("{:?}", e); - } - } + .await }