Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cargo fmt #2

Merged
merged 1 commit into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 47 additions & 30 deletions crates/api/src/handler/avatar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::hash::{DefaultHasher, Hash, Hasher};
use crate::libs::{
http::AppState,
redis::{get_value, set_value},
};
use actix_web::{get, web, Error, HttpResponse};
use crate::libs::{http::AppState, redis::{set_value, get_value}};
use gen_avatar_lib::{AvatarBuilder, AvatarResult};
use std::hash::{DefaultHasher, Hash, Hasher};

#[derive(Debug, serde::Deserialize)]
pub struct AvatarParams {
Expand All @@ -19,11 +22,7 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
s.finish()
}

fn avatar(
name: String,
font_color: String,
background_color: String,
) -> AvatarResult {
fn avatar(name: String, font_color: String, background_color: String) -> AvatarResult {
AvatarBuilder::new(&name)
.with_font_color(&font_color)?
.with_background_color(&background_color)?
Expand Down Expand Up @@ -52,10 +51,7 @@ fn hsl_to_rgb(h: f32, s: f32, l: f32) -> (f32, f32, f32) {
((r + m) * 255.0, (g + m) * 255.0, (b + m) * 255.0)
}

fn generate_color(
name_hash: u64,
theme: &str,
) -> String {
fn generate_color(name_hash: u64, theme: &str) -> String {
// Pick a random color for hue using the hash
let hue = name_hash as f32 % 360.0;

Expand All @@ -75,14 +71,17 @@ fn generate_color(

let background_color = hsl_to_rgb(hue, saturation, lightness);

format!("#{:02x}{:02x}{:02x}", background_color.0 as u8, background_color.1 as u8, background_color.2 as u8)
format!(
"#{:02x}{:02x}{:02x}",
background_color.0 as u8, background_color.1 as u8, background_color.2 as u8
)
}

#[get("/avatar/{name}")]
pub async fn generate_avatar(
path: web::Path<AvatarParams>,
query: web::Query<AvatarQuery>,
data: web::Data<AppState>
data: web::Data<AppState>,
) -> Result<HttpResponse, Error> {
let query = query.into_inner();
let param_input = path.into_inner();
Expand All @@ -94,46 +93,64 @@ pub async fn generate_avatar(

let hash = calculate_hash(&param_input.name);

let background_color = generate_color(
hash,
theme.as_str()
);
let background_color = generate_color(hash, theme.as_str());

let font_color = match theme.as_str() {
"dark" => "#ffffff",
_ => "#ffffff",
};

println!("Generated avatar for: {} with theme: {}, {}", param_input.name, font_color, background_color);
println!(
"Generated avatar for: {} with theme: {}, {}",
param_input.name, font_color, background_color
);

// Check if the avatar is in the cache
let cached_avatar = get_value(
&mut data.redis_client.get_multiplexed_async_connection().await.unwrap(),
format!("avatar:{}:{}", hash, theme).as_str()
).await;
&mut data
.redis_client
.get_multiplexed_async_connection()
.await
.unwrap(),
format!("avatar:{}:{}", hash, theme).as_str(),
)
.await;

if !cached_avatar.is_empty() {
return Ok(HttpResponse::Ok().content_type("image/png").body(cached_avatar));
return Ok(HttpResponse::Ok()
.content_type("image/png")
.body(cached_avatar));
}

let avatar_image = avatar(param_input.name.clone(), font_color.to_string(), background_color.to_string())
.unwrap();
let avatar_image = avatar(
param_input.name.clone(),
font_color.to_string(),
background_color.to_string(),
)
.unwrap();

let avatar_image = avatar_image.draw();

let mut buffer = std::io::Cursor::new(Vec::new());
avatar_image.write_to(&mut buffer, image::ImageFormat::Png).unwrap();
avatar_image
.write_to(&mut buffer, image::ImageFormat::Png)
.unwrap();
let buffer = buffer.into_inner();

let _ = set_value(
&mut data.redis_client.get_multiplexed_async_connection().await.unwrap(),
format!("avatar:{}:{}", hash, theme).as_str(),
&buffer
).await;
&mut data
.redis_client
.get_multiplexed_async_connection()
.await
.unwrap(),
format!("avatar:{}:{}", hash, theme).as_str(),
&buffer,
)
.await;

Ok(HttpResponse::Ok().content_type("image/png").body(buffer))
}

pub fn init_avatar_routes(config: &mut web::ServiceConfig) {
config.service(generate_avatar);
}
}
2 changes: 1 addition & 1 deletion crates/api/src/handler/health.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ pub async fn health() -> Result<HttpResponse, Error> {

pub fn init_health_routes(config: &mut web::ServiceConfig) {
config.service(health);
}
}
2 changes: 1 addition & 1 deletion crates/api/src/handler/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod avatar;
pub mod health;
pub mod health;
28 changes: 11 additions & 17 deletions crates/api/src/libs/http.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::handler::{avatar, health};

use listenfd::ListenFd;
use actix_web::{web, App, HttpServer};
use env_logger::Env;
use listenfd::ListenFd;
use tracing_actix_web::TracingLogger;

#[derive(Clone)]
Expand All @@ -11,45 +11,39 @@ pub struct AppState {
}

#[actix_web::main]
pub async fn start_web_server(
) -> std::io::Result<()> {
pub async fn start_web_server() -> std::io::Result<()> {
let env_config: crate::utils::config::AppConfig = crate::env_config();

let redis_client: redis::Client = crate::libs::redis::connection_to_redis(
&env_config.redis_url
).await;
let redis_client: redis::Client =
crate::libs::redis::connection_to_redis(&env_config.redis_url).await;

let app_state: AppState = AppState {
redis_client: redis_client.clone(),
};

env_logger::init_from_env(Env::default().default_filter_or(
env_config.log_level
));
env_logger::init_from_env(Env::default().default_filter_or(env_config.log_level));

let mut listenfd: ListenFd = ListenFd::from_env();

let mut server = HttpServer::new(
move || App::new()
let mut server = HttpServer::new(move || {
App::new()
.app_data(web::Data::new(app_state.clone()))
.wrap(TracingLogger::default())
.configure(avatar::init_avatar_routes)
.configure(health::init_health_routes)
);
});

server = match listenfd.take_tcp_listener(0)? {
Some(listener) => server.listen(listener)?,
None => {
let host: &str = "0.0.0.0";
let port: u16 = env_config.web_server_port;

println!("Web Server started at http://{}:{}", host, port);

server.bind(format!("{}:{}", host, port))?
}
};

server.workers(
env_config.num_workers
).run().await
}
server.workers(env_config.num_workers).run().await
}
2 changes: 1 addition & 1 deletion crates/api/src/libs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod http;
pub mod redis;
pub mod redis;
16 changes: 9 additions & 7 deletions crates/api/src/libs/redis.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
use redis::AsyncCommands;

pub async fn connection_to_redis(
redis_url: &str,
) -> redis::Client {
pub async fn connection_to_redis(redis_url: &str) -> redis::Client {
let client: redis::Client = redis::Client::open(redis_url).unwrap();
client
}

pub async fn get_value(connection: &mut redis::aio::MultiplexedConnection, key: &str) -> String {
let value = connection.get(key).await;

match value {
Ok(value) => value,
Err(_) => "".to_string(),
}
}

pub async fn set_value(connection: &mut redis::aio::MultiplexedConnection, key: &str, value: &Vec<u8>) -> String {
pub async fn set_value(
connection: &mut redis::aio::MultiplexedConnection,
key: &str,
value: &Vec<u8>,
) -> String {
let value = connection.set(key, value).await;

match value {
Ok(value) => value,
Err(_) => "".to_string(),
}
}
}
4 changes: 2 additions & 2 deletions crates/api/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod libs;
mod handler;
mod libs;
mod utils;

use confik::{Configuration as _, EnvSource};
Expand Down Expand Up @@ -27,4 +27,4 @@ async fn main() {
})
.await
.unwrap();
}
}
2 changes: 1 addition & 1 deletion crates/api/src/utils/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ pub struct AppConfig {
pub redis_url: String,
pub num_workers: usize,
pub log_level: String,
}
}
2 changes: 1 addition & 1 deletion crates/api/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pub mod config;
pub mod config;
4 changes: 1 addition & 3 deletions crates/gen-avatar/src/avatar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,11 @@ impl AvatarBuilder {
}
}



// apply gaussian blur to the image if specified
if let Some(b) = self.blur {
imageops::blur(&image, b)
} else {
image
}
}
}
}
11 changes: 4 additions & 7 deletions crates/gen-avatar/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
use std::num::ParseIntError;
use std::io;
use std::num::ParseIntError;

/// Custom Error type for Avatar
#[derive(Debug)]
pub enum Error {
/// Invalid hex string
InvalidHexFormat {
actual: String,
expected: String,
},
InvalidHexFormat { actual: String, expected: String },
/// Parse error
Parse(ParseIntError),
/// IO read/write error
IO(io::Error)
IO(io::Error),
}

impl From<ParseIntError> for Error {
Expand All @@ -25,4 +22,4 @@ impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error::IO(error)
}
}
}
2 changes: 1 addition & 1 deletion crates/gen-avatar/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ pub mod error;

pub use avatar::AvatarBuilder;
pub use avatar::AvatarResult;
pub use error::Error;
pub use error::Error;
Loading