feat: added the redirect part

This commit is contained in:
meeg_leeto 2022-04-29 23:30:38 +01:00
parent a10c2a01f0
commit 927d6d32b9
1 changed files with 60 additions and 12 deletions

View File

@ -549,19 +549,18 @@ mod service {
} }
/// Request the URL associated to the provided slug, if it exists. /// Request the URL associated to the provided slug, if it exists.
pub async fn get_slug(&self, slug: Slug) -> Result<Option<HttpUrl>, ()> { ///
/// This is an asynchronous operation; as such, a
/// `oneshot::Receiver` is returned, rather than a result. One
/// should await on this receiver for the result of the operation.
/// (Note that, as a consequence of this, this function is *not*
/// asynchronous.)
pub fn get_slug(&self, slug: Slug) -> sync::oneshot::Receiver<GetResult> {
let (tx, rx) = sync::oneshot::channel(); let (tx, rx) = sync::oneshot::channel();
self.tx self.tx
.send(SlugDbMessage::Get(slug, tx)) .send(SlugDbMessage::Get(slug, tx))
.expect("The SlugDbMessage channel is unexpectedly closed."); .expect("The SlugDbMessage channel is unexpectedly closed.");
match rx rx
.await
.expect("The query channel was unexpectedly dropped.")
{
GetResult::Found(url) => Ok(Some(url)),
GetResult::NotFound => Ok(None),
GetResult::InternalError => Err(()),
}
} }
} }
} }
@ -719,7 +718,47 @@ async fn shorten(
ifdbg!(eprintln!("{}", e)); ifdbg!(eprintln!("{}", e));
Err(( Err((
warp::http::StatusCode::INTERNAL_SERVER_ERROR, warp::http::StatusCode::INTERNAL_SERVER_ERROR,
debuginfo!("Receiver error on response of slug insertion.").into(), debuginfo!("Response channel for insertion is unexpectedly closed").into(),
))
}
}
}
/// Redirect from a slug.
async fn redirect(
slug_str: &str,
slug_factory: &slug::SlugFactory,
db: &db::SlugDatabase,
) -> Result<HttpUrl, (StatusCode, String)> {
// Check that the slug is valid.
let slug = slug_factory.parse_str(slug_str).map_err(|e| match e {
slug::InvalidSlug::TooLong => (
warp::http::StatusCode::BAD_REQUEST,
debuginfo!("Given slug is too long.", "Invalid URL.").into(),
),
slug::InvalidSlug::BadChar => (
warp::http::StatusCode::BAD_REQUEST,
debuginfo!("Given slug has invalid characters.", "Invalid URL.").into(),
),
})?;
match db.get_slug(slug).await {
Ok(result) => match result {
db::GetResult::Found(url) => Ok(url),
db::GetResult::NotFound => Err((
warp::http::StatusCode::BAD_REQUEST,
debuginfo!("The slug does not exist in the database.", "Invalid URL.").into(),
)),
db::GetResult::InternalError => Err((
warp::http::StatusCode::BAD_REQUEST,
"Internal error.".into(),
)),
},
Err(e) => {
ifdbg!(eprintln!("{}", e));
Err((
warp::http::StatusCode::INTERNAL_SERVER_ERROR,
debuginfo!("Response channel for insertion is unexpectedly closed").into(),
)) ))
} }
} }
@ -810,13 +849,22 @@ async fn serve() {
// GET /l/:Slug // GET /l/:Slug
let link = warp::path("l") let link = warp::path("l")
.and(warp::path::param()) .and(warp::path::param())
.map(|slug: String| warp::reply()); .then(move |slug: String| async move {
match redirect(&slug, &slug_factory, &db).await {
Ok(url) => Response::builder()
.status(warp::http::StatusCode::FOUND)
.header("Location", url.to_string())
.body("".to_string())
.unwrap(),
Err((status, message)) => Response::builder().status(status).body(message).unwrap(),
}
});
let get_routes = warp::get().and(homepage.or(link)); let get_routes = warp::get().and(homepage.or(link));
let post_routes = warp::post().and(shorten); let post_routes = warp::post().and(shorten);
let routes = get_routes.or(post_routes); let routes = get_routes.or(post_routes);
println!( eprintln!(
"Now serving lonk at IP {}, port {}!", "Now serving lonk at IP {}, port {}!",
config.serve_rules.addr.ip, config.serve_rules.addr.port config.serve_rules.addr.ip, config.serve_rules.addr.port
); );