Skip to content

Commit

Permalink
Format and fix clippy warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
JElgar committed Aug 26, 2024
1 parent c918590 commit 3b348fe
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 80 deletions.
19 changes: 11 additions & 8 deletions src/crawler/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::include_str;

use lazy_static::lazy_static;
use serde::Deserialize;
use regex::Regex;
use serde::Deserialize;

const RAW_CRAWLER_DATA: &str = include_str!("crawler-user-agents.json");

Expand All @@ -17,14 +17,17 @@ struct Crawler {
}

lazy_static! {
static ref CRAWLERS: Vec<Crawler> = serde_json::from_str::<Vec<CrawlerData>>(&RAW_CRAWLER_DATA).unwrap().into_iter().map(|crawler| Crawler {
pattern: Regex::new(&crawler.pattern).unwrap(),
}).collect();
static ref CRAWLERS: Vec<Crawler> = serde_json::from_str::<Vec<CrawlerData>>(RAW_CRAWLER_DATA)
.unwrap()
.into_iter()
.map(|crawler| Crawler {
pattern: Regex::new(&crawler.pattern).unwrap(),
})
.collect();
}

pub fn is_crawler(user_agent: &str) -> bool {
CRAWLERS.iter().any(|crawler| {
crawler.pattern.is_match(user_agent)
})
CRAWLERS
.iter()
.any(|crawler| crawler.pattern.is_match(user_agent))
}

26 changes: 13 additions & 13 deletions src/dao/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::iter;

use poem_openapi::Object;
use rand::Rng;
use sqlx::prelude::FromRow;

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -34,8 +31,7 @@ pub struct Link {
pub image_url: String,
}

const LINKS_SELECT_FIELDS: &str =
"id, link_path, title, description, image_url";
const LINKS_SELECT_FIELDS: &str = "id, link_path, title, description, image_url";

pub async fn create_link(
pool: &sqlx::Pool<sqlx::Postgres>,
Expand Down Expand Up @@ -101,10 +97,12 @@ pub async fn get_link(
) -> Result<Option<Link>, Error> {
tracing::info!("Getting link by id link_id={link_id}");

let result = sqlx::query_as::<_, Link>(&format!("SELECT {LINKS_SELECT_FIELDS} FROM links WHERE id = $1"))
.bind(link_id)
.fetch_optional(pool)
.await;
let result = sqlx::query_as::<_, Link>(&format!(
"SELECT {LINKS_SELECT_FIELDS} FROM links WHERE id = $1"
))
.bind(link_id)
.fetch_optional(pool)
.await;

result.map_err(|err| {
tracing::error!("Error whilst fetching link link_id={link_id} err={err}");
Expand All @@ -118,10 +116,12 @@ pub async fn get_link_by_link_path(
) -> Result<Option<Link>, Error> {
tracing::info!("Getting link by url path link_path={link_path}");

let result = sqlx::query_as::<_, Link>(&format!("SELECT {LINKS_SELECT_FIELDS} FROM links WHERE link_path = $1"))
.bind(link_path)
.fetch_optional(pool)
.await;
let result = sqlx::query_as::<_, Link>(&format!(
"SELECT {LINKS_SELECT_FIELDS} FROM links WHERE link_path = $1"
))
.bind(link_path)
.fetch_optional(pool)
.await;

result.map_err(|err| {
tracing::error!("Error whilst creating link err={err}");
Expand Down
71 changes: 32 additions & 39 deletions src/link_router/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::env;

use askama::Template;
use poem::{
get, handler, http::StatusCode, web::{Data, Html, Path, Redirect}, EndpointExt, FromRequest, IntoResponse, Request, RequestBody, Response, Result, Route
get, handler,
http::StatusCode,
web::{Data, Html, Path, Redirect},
FromRequest, IntoResponse, Request, RequestBody, Response, Result, Route,
};
use regex::Regex;
use askama::Template;
use url::Url;

use crate::{crawler::is_crawler, dao, AppContext, FallbackData};

Expand All @@ -20,7 +20,7 @@ enum Platform {
#[derive(Debug)]
enum RequestActor {
Crawler,
User(Platform)
User(Platform),
}

#[derive(Template)]
Expand Down Expand Up @@ -50,7 +50,7 @@ fn get_platform_from_user_agent(user_agent: &str) -> Platform {
{
return Platform::Web;
}
return Platform::Unknown;
Platform::Unknown
}

impl<'a> FromRequest<'a> for RequestActor {
Expand All @@ -60,13 +60,11 @@ impl<'a> FromRequest<'a> for RequestActor {
.get("User-Agent")
.and_then(|value| value.to_str().ok());

Ok(
match user_agent_header {
None => RequestActor::User(Platform::Unknown),
Some(header_value) if is_crawler(header_value) => RequestActor::Crawler,
Some(header_value) => RequestActor::User(get_platform_from_user_agent(header_value)),
}
)
Ok(match user_agent_header {
None => RequestActor::User(Platform::Unknown),
Some(header_value) if is_crawler(header_value) => RequestActor::Crawler,
Some(header_value) => RequestActor::User(get_platform_from_user_agent(header_value)),
})
}
}

Expand All @@ -80,38 +78,33 @@ async fn link_handler(
tracing::info!("Handling link link_path={link_path} request_actor={request_actor:?}");

match dao::get_link_by_link_path(&app_context.pool, &link_path).await {
Ok(Some(link)) => {
match request_actor {
RequestActor::Crawler => {
let response = CrawlerResponseTemplate {
og_title: link.title,
og_description: link.description,
og_url: link.link_path,
og_image_url: link.image_url,
og_type: "website".to_string(),
};
Html(response.render().unwrap()).into_response()
},
RequestActor::User(platform) => {
Redirect::temporary(match platform {
Platform::Android => &fallback_data.android_fallback,
Platform::Ios => &fallback_data.ios_fallback,
Platform::Web | Platform::Unknown => &fallback_data.web_fallback,
}).into_response()
}
Ok(Some(link)) => match request_actor {
RequestActor::Crawler => {
let response = CrawlerResponseTemplate {
og_title: link.title,
og_description: link.description,
og_url: link.link_path,
og_image_url: link.image_url,
og_type: "website".to_string(),
};
Html(response.render().unwrap()).into_response()
}

}
RequestActor::User(platform) => Redirect::temporary(match platform {
Platform::Android => &fallback_data.android_fallback,
Platform::Ios => &fallback_data.ios_fallback,
Platform::Web | Platform::Unknown => &fallback_data.web_fallback,
})
.into_response(),
},
Ok(None) => Response::builder()
.status(StatusCode::NOT_FOUND)
.body(format!("Link not found")),
.body("Link not found".to_string()),
Err(_) => Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("Unknown error")),
.body("Unknown error".to_string()),
}
}

pub fn create_link_router_service() -> Route {
Route::new()
.at("/*path", get(link_handler))
Route::new().at("/*path", get(link_handler))
}
11 changes: 7 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use tracing::info;
use url::Url;

use sqlx::Postgres;
use tracing_subscriber;

#[derive(Clone)]
struct AppContext {
Expand All @@ -29,8 +28,8 @@ struct FallbackData {
}

fn get_fallback_from_env(env_name: &str) -> Url {
let env_value = env::var(env_name).expect(&format!("{env_name} must be defined"));
Url::parse(&env_value).expect(&format!("{env_name} must be a valid url"))
let env_value = env::var(env_name).unwrap_or_else(|_| panic!("{env_name} must be defined"));
Url::parse(&env_value).unwrap_or_else(|_| panic!("{env_name} must be a valid url"))
}

#[tokio::main]
Expand All @@ -57,7 +56,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let app = Route::new()
.nest("/api", create_management_service(&base_url))
.nest("/", create_link_router_service())
.data(AppContext { pool, base_url, api_key })
.data(AppContext {
pool,
base_url,
api_key,
})
.data(FallbackData {
web_fallback: get_fallback_from_env("WEB_FALLBACK_URL"),
android_fallback: get_fallback_from_env("ANDROID_FALLBACK_URL"),
Expand Down
45 changes: 29 additions & 16 deletions src/management/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use poem_openapi::{
};
use url::Url;

use crate::{dao::{self, update_link, LinkData}, AppContext};
use crate::{
dao::{self, update_link, LinkData},
AppContext,
};

pub struct ManagementApi;

Expand All @@ -32,7 +35,7 @@ impl dao::Link {
}
}

fn to_json(self, base_url: &Url) -> Json<Link> {
fn into_json(self, base_url: &Url) -> Json<Link> {
Json(self.serialize(base_url))
}
}
Expand Down Expand Up @@ -76,15 +79,12 @@ enum UpdateLinkResponse {
)]
struct ApiKeyAuth(());

async fn api_key_checker(
request: &Request,
api_key: ApiKey,
) -> Option<()> {
async fn api_key_checker(request: &Request, api_key: ApiKey) -> Option<()> {
let app_context: &AppContext = request.data().unwrap();
if api_key.key == app_context.api_key {
return Some(());
}
return None;
None
}

impl From<dao::Error> for poem::Error {
Expand All @@ -103,7 +103,10 @@ impl ManagementApi {
_auth: ApiKeyAuth,
) -> Result<ListLinksResponse> {
let links = dao::list_links(&app_context.pool).await?;
let links: Vec<Link> = links.into_iter().map(|item| item.serialize(&app_context.base_url)).collect();
let links: Vec<Link> = links
.into_iter()
.map(|item| item.serialize(&app_context.base_url))
.collect();
Ok(ListLinksResponse::Ok(Json(links)))
}

Expand All @@ -116,7 +119,7 @@ impl ManagementApi {
_auth: ApiKeyAuth,
) -> Result<GetLinkResponse> {
Ok(match dao::get_link(&app_context.pool, &link_id).await? {
Some(link) => GetLinkResponse::Ok(link.to_json(&app_context.base_url)),
Some(link) => GetLinkResponse::Ok(link.into_json(&app_context.base_url)),
None => GetLinkResponse::NotFound,
})
}
Expand All @@ -131,7 +134,9 @@ impl ManagementApi {
) -> Result<CreateLinkResponse> {
let link = dao::create_link(&app_context.pool, input).await?;

Ok(CreateLinkResponse::Ok(link.to_json(&app_context.base_url)))
Ok(CreateLinkResponse::Ok(
link.into_json(&app_context.base_url),
))
}

/// Update an existing polylink
Expand All @@ -143,22 +148,30 @@ impl ManagementApi {
Data(app_context): Data<&AppContext>,
_auth: ApiKeyAuth,
) -> Result<UpdateLinkResponse> {
Ok(match update_link(&app_context.pool, &link_id, input).await? {
Some(link) => UpdateLinkResponse::Ok(link.to_json(&app_context.base_url)),
None => UpdateLinkResponse::NotFound,
})
Ok(
match update_link(&app_context.pool, &link_id, input).await? {
Some(link) => UpdateLinkResponse::Ok(link.into_json(&app_context.base_url)),
None => UpdateLinkResponse::NotFound,
},
)
}
}

pub fn create_management_service(base_url: &Url) -> Route {
let api_service = OpenApiService::new(ManagementApi, "PolyLink Management API", "0.0.1")
.server(base_url.join("/api").expect("Cannot join base url with api").to_string());
.server(
base_url
.join("/api")
.expect("Cannot join base url with api")
.to_string(),
);

let ui = api_service.swagger_ui();
let json_spec_endpoint = api_service.spec_endpoint();
let yaml_spec_endpoint = api_service.spec_endpoint_yaml();

Route::new().nest("/", api_service)
Route::new()
.nest("/", api_service)
.nest("/docs", ui)
.nest("/docs/spec.json", json_spec_endpoint)
.nest("/docs/spec.yaml", yaml_spec_endpoint)
Expand Down

0 comments on commit 3b348fe

Please sign in to comment.