diff --git a/Dockerfile b/Dockerfile index 1f67891..397528e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,27 @@ FROM rust:1 as build +RUN cargo install cargo-build-deps -RUN mkdir /actix -WORKDIR /actix +RUN cargo new --bin simply-shorten +WORKDIR /simply-shorten -COPY ./actix/cargo.toml /actix/cargo.toml -COPY ./actix/cargo.lock /actix/cargo.lock +COPY ./actix/Cargo.toml . +COPY ./actix/Cargo.lock . -RUN cargo build --deps-only +RUN cargo build-deps --release -COPY ./actix /actix +COPY ./actix/src ./src +COPY ./actix/resources ./resources -RUN cargo install --path . +RUN cargo build --release FROM gcr.io/distroless/cc-debian10 EXPOSE 2000 -COPY --from=build /usr/local/cargo/bin/actix /usr/local/bin/actix +WORKDIR /opt -CMD ["actix"] +COPY --from=build /simply-shorten/target/release/simply-shorten /opt/simply-shorten +COPY --from=build /simply-shorten/resources /opt/resources +COPY ./urls.sqlite /opt/urls.sqlite + +CMD ["./simply-shorten"] diff --git a/actix/.directory b/actix/.directory new file mode 100644 index 0000000..e67a114 --- /dev/null +++ b/actix/.directory @@ -0,0 +1,3 @@ +[Dolphin] +Timestamp=2023,4,2,17,52,37.922 +Version=4 diff --git a/actix/Cargo.lock b/actix/Cargo.lock index ee2b422..d2b7191 100644 --- a/actix/Cargo.lock +++ b/actix/Cargo.lock @@ -2,14 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix" -version = "0.1.0" -dependencies = [ - "actix-files", - "actix-web", -] - [[package]] name = "actix-codec" version = "0.5.0" @@ -919,6 +911,17 @@ dependencies = [ "libc", ] +[[package]] +name = "simply-shorten" +version = "0.1.0" +dependencies = [ + "actix-files", + "actix-web", + "regex", + "sqlite", + "sqlite3-src", +] + [[package]] name = "slab" version = "0.4.8" @@ -944,6 +947,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "sqlite" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1908664131c21a38e5b531344d52a196ec338af5bf44f7fa2c83d539e9561d" +dependencies = [ + "libc", + "sqlite3-sys", +] + +[[package]] +name = "sqlite3-src" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1815a7a02c996eb8e5c64f61fcb6fd9b12e593ce265c512c5853b2513635691" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "sqlite3-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47c99824fc55360ba00caf28de0b8a0458369b832e016a64c13af0ad9fbb9ee" +dependencies = [ + "libc", + "sqlite3-src", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/actix/Cargo.toml b/actix/Cargo.toml index b8392a5..6166161 100644 --- a/actix/Cargo.toml +++ b/actix/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "actix" +name = "simply-shorten" version = "0.1.0" edition = "2021" @@ -7,4 +7,10 @@ edition = "2021" [dependencies] actix-web = "4" -actix-files = "0.6.2" \ No newline at end of file +actix-files = "0.6.2" +sqlite = "0.30.4" +regex = "1.7.3" + +[dependencies.sqlite3-src] +version="0.4.0" +features=["bundled"] \ No newline at end of file diff --git a/actix/src/database.rs b/actix/src/database.rs new file mode 100644 index 0000000..ddcf0b8 --- /dev/null +++ b/actix/src/database.rs @@ -0,0 +1,23 @@ +use sqlite::{open, Row}; + +pub fn find_url(shortlink: &str) -> String { + let db = open("./urls.sqlite").expect("Unable to open database!"); + + let query = "SELECT long_url FROM urls WHERE short_url = ?"; + + let statement: Vec = db + .prepare(query) + .unwrap() + .into_iter() + .bind((1, shortlink)) + .unwrap() + .map(|row| row.unwrap()) + .collect(); + + let mut longlink = ""; + if statement.len() == 1 { + longlink = statement[0].read::<&str, _>("long_url"); + } + + String::from(longlink) +} diff --git a/actix/src/main.rs b/actix/src/main.rs index 2400954..68c494e 100644 --- a/actix/src/main.rs +++ b/actix/src/main.rs @@ -1,19 +1,44 @@ -use actix_files::Files; -use actix_web::{get, web, App, HttpServer, Responder}; +use actix_files::{Files, NamedFile}; +use actix_web::{ + get, + web::{self, Redirect}, + App, HttpServer, Responder, +}; +mod database; +mod utils; -#[get("/hello/{name}")] -async fn greet(name: web::Path) -> impl Responder { - format!("Hello {name}!") +// Define the routes + +// Add new links + +// Return all active links + +// 404 error page +#[get("/err/404")] +async fn error404() -> impl Responder { + NamedFile::open_async("./resources/404.html").await } -#[actix_web::main] // or #[tokio::main] +// Handle a given shortlink +#[get("/{shortlink}")] +async fn link_handler(shortlink: web::Path) -> impl Responder { + let longlink = utils::get_longurl(shortlink); + if longlink == String::from("") { + Redirect::to("/err/404") + } else { + Redirect::to(longlink).permanent() + } +} + +#[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - .service(greet) + .service(link_handler) + .service(error404) .service(Files::new("/", "./resources/").index_file("index.html")) }) - .bind(("127.0.0.1", 2000))? + .bind(("0.0.0.0", 2000))? .run() .await } diff --git a/actix/src/utils.rs b/actix/src/utils.rs new file mode 100644 index 0000000..18182ba --- /dev/null +++ b/actix/src/utils.rs @@ -0,0 +1,16 @@ +use crate::database; +use actix_web::web; +use regex::Regex; + +pub fn get_longurl(shortlink: web::Path) -> String { + if validate_link(&shortlink) { + database::find_url(shortlink.as_str()) + } else { + String::from("") + } +} + +fn validate_link(link: &str) -> bool { + let re = Regex::new("[a-z0-9-_]+").unwrap(); + re.is_match(link) +}