Set up web routes
This commit is contained in:
parent
ac0f6292ed
commit
c194daa42c
7 changed files with 286 additions and 52 deletions
84
Cargo.lock
generated
84
Cargo.lock
generated
|
|
@ -54,6 +54,61 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum-core",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"itoa",
|
||||||
|
"matchit",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper 1.0.1",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-core"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"mime",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"sync_wrapper 0.1.2",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.71"
|
version = "0.3.71"
|
||||||
|
|
@ -404,6 +459,12 @@ version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
|
@ -417,6 +478,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
|
@ -525,6 +587,12 @@ version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchit"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.2"
|
version = "2.7.2"
|
||||||
|
|
@ -814,7 +882,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper",
|
"sync_wrapper 0.1.2",
|
||||||
"system-configuration",
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
|
|
@ -830,10 +898,12 @@ dependencies = [
|
||||||
name = "rust-twitch-avatar-cache"
|
name = "rust-twitch-avatar-cache"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"axum",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"redis 0.25.3",
|
"redis 0.25.3",
|
||||||
"redis-derive",
|
"redis-derive",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"twitch_api",
|
"twitch_api",
|
||||||
"twitch_oauth2",
|
"twitch_oauth2",
|
||||||
|
|
@ -875,6 +945,12 @@ version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
|
checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
|
@ -1034,6 +1110,12 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-configuration"
|
name = "system-configuration"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
axum = "0.7.5"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
redis = "0.25.3"
|
redis = "0.25.3"
|
||||||
redis-derive = "0.1.7"
|
redis-derive = "0.1.7"
|
||||||
|
|
@ -16,6 +17,7 @@ tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros"] }
|
||||||
twitch_api = { git = "https://github.com/twitch-rs/twitch_api/", features = ["client", "helix", "reqwest", "twitch_oauth2"] }
|
twitch_api = { git = "https://github.com/twitch-rs/twitch_api/", features = ["client", "helix", "reqwest", "twitch_oauth2"] }
|
||||||
twitch_oauth2 = { git = "https://github.com/twitch-rs/twitch_api/", features = ["reqwest", "client"] }
|
twitch_oauth2 = { git = "https://github.com/twitch-rs/twitch_api/", features = ["reqwest", "client"] }
|
||||||
twitch_types = { git = "https://github.com/twitch-rs/twitch_api/" }
|
twitch_types = { git = "https://github.com/twitch-rs/twitch_api/" }
|
||||||
|
serde = { version = "1.0.198", features = ["derive"] }
|
||||||
|
|
||||||
# workaround for https://github.com/twitch-rs/twitch_api/issues/256
|
# workaround for https://github.com/twitch-rs/twitch_api/issues/256
|
||||||
[patch.crates-io.twitch_types]
|
[patch.crates-io.twitch_types]
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,7 @@ pub struct AvatarCache {
|
||||||
|
|
||||||
impl AvatarCache {
|
impl AvatarCache {
|
||||||
pub fn new(redis: Client, timeout: i64) -> Self {
|
pub fn new(redis: Client, timeout: i64) -> Self {
|
||||||
AvatarCache {
|
AvatarCache { redis, timeout }
|
||||||
redis,
|
|
||||||
timeout,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(config: &RedisConfig) -> RedisResult<Self> {
|
pub fn connect(config: &RedisConfig) -> RedisResult<Self> {
|
||||||
|
|
@ -34,10 +31,16 @@ impl AvatarCache {
|
||||||
} else {
|
} else {
|
||||||
// Something else went wrong
|
// Something else went wrong
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.get_cache_by_id(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cache_by_id(&self, id: &str) -> RedisResult<Option<UserData>> {
|
||||||
|
let mut con = self.redis.get_connection()?;
|
||||||
|
|
||||||
match con.hgetall(UserData::redis_id_from_str(&id)) {
|
match con.hgetall(UserData::redis_id_from_str(&id)) {
|
||||||
Ok(v) => Ok(Some(v)),
|
Ok(v) => Ok(Some(v)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -48,7 +51,7 @@ impl AvatarCache {
|
||||||
// Something else went wrong
|
// Something else went wrong
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,7 @@ pub struct AvatarFetch {
|
||||||
|
|
||||||
impl AvatarFetch {
|
impl AvatarFetch {
|
||||||
pub fn new(client: TwitchClient<'static, reqwest::Client>, token: AppAccessToken) -> Self {
|
pub fn new(client: TwitchClient<'static, reqwest::Client>, token: AppAccessToken) -> Self {
|
||||||
AvatarFetch {
|
AvatarFetch { client, token }
|
||||||
client,
|
|
||||||
token,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn connect(config: &config::TwitchConfig) -> Result<Self, Box<dyn Error>> {
|
pub async fn connect(config: &config::TwitchConfig) -> Result<Self, Box<dyn Error>> {
|
||||||
|
|
@ -27,7 +24,8 @@ impl AvatarFetch {
|
||||||
config.client_id().into(),
|
config.client_id().into(),
|
||||||
config.client_secret().into(),
|
config.client_secret().into(),
|
||||||
vec![],
|
vec![],
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
Ok(Self::new(client, token))
|
Ok(Self::new(client, token))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,30 +33,29 @@ impl AvatarFetch {
|
||||||
let mut request = users::GetUsersRequest::new();
|
let mut request = users::GetUsersRequest::new();
|
||||||
let ids: &[&twitch_types::UserIdRef] = &[id.into()];
|
let ids: &[&twitch_types::UserIdRef] = &[id.into()];
|
||||||
request.id = ids.into();
|
request.id = ids.into();
|
||||||
let response: Vec<users::User> = self.client.helix.req_get(request, &self.token).await?.data;
|
let response: Vec<users::User> =
|
||||||
|
self.client.helix.req_get(request, &self.token).await?.data;
|
||||||
|
|
||||||
Ok(self.user_from_response(response))
|
Ok(self.user_from_response(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_from_response(&self, response: Vec<users::User>) -> Option<UserData> {
|
pub fn user_from_response(&self, response: Vec<users::User>) -> Option<UserData> {
|
||||||
if let Some(user) = response.first() {
|
response.first().map(|user| {
|
||||||
dbg!(user);
|
UserData::new(
|
||||||
Some(UserData::new(
|
|
||||||
user.login.to_string(),
|
user.login.to_string(),
|
||||||
user.display_name.to_string(),
|
user.display_name.to_string(),
|
||||||
user.id.to_string(),
|
user.id.to_string(),
|
||||||
user.profile_image_url.clone().unwrap_or("".to_string()),
|
user.profile_image_url.clone().unwrap_or("".to_string()),
|
||||||
))
|
)
|
||||||
} else {
|
})
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user_by_name(&self, name: &str) -> Result<Option<UserData>, Box<dyn Error>> {
|
pub async fn get_user_by_name(&self, name: &str) -> Result<Option<UserData>, Box<dyn Error>> {
|
||||||
let mut request = users::GetUsersRequest::new();
|
let mut request = users::GetUsersRequest::new();
|
||||||
let logins: &[&twitch_types::UserNameRef] = &[name.into()];
|
let logins: &[&twitch_types::UserNameRef] = &[name.into()];
|
||||||
request.login = logins.into();
|
request.login = logins.into();
|
||||||
let response: Vec<users::User> = self.client.helix.req_get(request, &self.token).await?.data;
|
let response: Vec<users::User> =
|
||||||
|
self.client.helix.req_get(request, &self.token).await?.data;
|
||||||
|
|
||||||
Ok(self.user_from_response(response))
|
Ok(self.user_from_response(response))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,23 @@ impl RedisConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AppConfig {
|
||||||
|
bind_port: i64,
|
||||||
|
bind_host: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppConfig {
|
||||||
|
pub fn bind_address(&self) -> String {
|
||||||
|
format!("{}:{}", self.bind_host, self.bind_port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
twitch: TwitchConfig,
|
twitch: TwitchConfig,
|
||||||
redis: RedisConfig,
|
redis: RedisConfig,
|
||||||
|
app: AppConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
|
@ -43,9 +56,15 @@ impl Config {
|
||||||
dotenvy::dotenv()?;
|
dotenvy::dotenv()?;
|
||||||
|
|
||||||
let redis_url = std::env::var("REDIS_URL").unwrap_or("redis://127.0.0.1/".to_string());
|
let redis_url = std::env::var("REDIS_URL").unwrap_or("redis://127.0.0.1/".to_string());
|
||||||
let redis_cache_time: i64 = std::env::var("REDIS_CACHE_TIME").unwrap_or("60".to_string()).parse()?;
|
let redis_cache_time: i64 = std::env::var("REDIS_CACHE_TIME")
|
||||||
|
.unwrap_or("60".to_string())
|
||||||
|
.parse()?;
|
||||||
let twitch_client_id = std::env::var("TWITCH_CLIENT_ID")?;
|
let twitch_client_id = std::env::var("TWITCH_CLIENT_ID")?;
|
||||||
let twitch_client_secret = std::env::var("TWITCH_CLIENT_SECRET")?;
|
let twitch_client_secret = std::env::var("TWITCH_CLIENT_SECRET")?;
|
||||||
|
let app_bind_port: i64 = std::env::var("APP_BIND_PORT")
|
||||||
|
.unwrap_or("3000".to_string())
|
||||||
|
.parse()?;
|
||||||
|
let app_bind_host = std::env::var("APP_BIND_HOST").unwrap_or("127.0.0.1".to_string());
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
twitch: TwitchConfig {
|
twitch: TwitchConfig {
|
||||||
|
|
@ -56,6 +75,10 @@ impl Config {
|
||||||
url: redis_url,
|
url: redis_url,
|
||||||
cache_time: redis_cache_time,
|
cache_time: redis_cache_time,
|
||||||
},
|
},
|
||||||
|
app: AppConfig {
|
||||||
|
bind_port: app_bind_port,
|
||||||
|
bind_host: app_bind_host,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,4 +89,8 @@ impl Config {
|
||||||
pub fn twitch(&self) -> &TwitchConfig {
|
pub fn twitch(&self) -> &TwitchConfig {
|
||||||
&self.twitch
|
&self.twitch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn app(&self) -> &AppConfig {
|
||||||
|
&self.app
|
||||||
|
}
|
||||||
}
|
}
|
||||||
143
src/main.rs
143
src/main.rs
|
|
@ -1,13 +1,19 @@
|
||||||
|
use axum::extract::{Query, State};
|
||||||
|
use axum::routing::get;
|
||||||
|
use axum::{serve, Json, Router};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use crate::avatar_cache::AvatarCache;
|
use crate::avatar_cache::AvatarCache;
|
||||||
use crate::avatar_fetch::AvatarFetch;
|
use crate::avatar_fetch::AvatarFetch;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
mod user_data;
|
|
||||||
mod avatar_cache;
|
mod avatar_cache;
|
||||||
mod config;
|
|
||||||
mod avatar_fetch;
|
mod avatar_fetch;
|
||||||
|
mod config;
|
||||||
|
mod user_data;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
@ -15,22 +21,127 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let cache = AvatarCache::connect(config.redis())?;
|
let cache = AvatarCache::connect(config.redis())?;
|
||||||
let fetch = AvatarFetch::connect(config.twitch()).await?;
|
let fetch = AvatarFetch::connect(config.twitch()).await?;
|
||||||
|
|
||||||
let target = "tbsliver";
|
let state = Arc::new(AppState::new(cache, fetch));
|
||||||
|
|
||||||
let data = cache.get_cache_by_name(target)?;
|
let router = Router::new()
|
||||||
|
.route("/", get(AppRoute::root))
|
||||||
|
.with_state(state);
|
||||||
|
|
||||||
match data {
|
let listener = TcpListener::bind(config.app().bind_address()).await?;
|
||||||
Some(d) => {
|
|
||||||
println!("Cache hit for {}", d.name());
|
println!("listening on {}", listener.local_addr()?);
|
||||||
cache.update_cache_expiry(&d)?;
|
|
||||||
}
|
serve(listener, router).await?;
|
||||||
None => {
|
|
||||||
println!("Cache miss for {}", target);
|
|
||||||
if let Some(u) = fetch.get_user_by_name(target).await? {
|
|
||||||
cache.set_cache_data(&u)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AppState {
|
||||||
|
cache: AvatarCache,
|
||||||
|
fetch: AvatarFetch,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
pub fn new(cache: AvatarCache, fetch: AvatarFetch) -> Self {
|
||||||
|
AppState { cache, fetch }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AppRoute {}
|
||||||
|
|
||||||
|
impl AppRoute {
|
||||||
|
async fn root(
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
Query(params): Query<AppQuery>,
|
||||||
|
) -> Json<AppResponse> {
|
||||||
|
let mut response = AppResponse {
|
||||||
|
success: false,
|
||||||
|
id: None,
|
||||||
|
name: None,
|
||||||
|
display_name: None,
|
||||||
|
profile_picture_url: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(id) = params.id {
|
||||||
|
let cache_val = state.cache.get_cache_by_id(&id).unwrap_or_else(|e| {
|
||||||
|
// Error fetching from cache
|
||||||
|
println!("Error Getting Cache by ID [{}] {}", id, e);
|
||||||
|
// Might still be able to just fetch, pretend empty
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if let Some(user) = cache_val {
|
||||||
|
println!("Cache Hit for ID [{}]", id);
|
||||||
|
response = user.to_app_response();
|
||||||
|
state.cache.update_cache_expiry(&user).unwrap_or_else(|e| {
|
||||||
|
// this is going well, isn't it?
|
||||||
|
println!("Error Updating Cache Expiry for ID [{}] {}", id, e);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
println!("Cache Miss for ID [{}]", id);
|
||||||
|
let fetch_val = state.fetch.get_user_by_id(&id).await.unwrap_or_else(|e| {
|
||||||
|
// Something went really wrong...
|
||||||
|
println!("Error Fetching by ID [{}] {}", id, e);
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if let Some(user) = fetch_val {
|
||||||
|
println!("Fetch Hit for ID [{}]", id);
|
||||||
|
response = user.to_app_response();
|
||||||
|
state.cache.set_cache_data(&user).unwrap_or_else(|e| {
|
||||||
|
println!("Error saving Cache Data for ID [{}] {}", id, e);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(name) = params.name {
|
||||||
|
let cache_val = state.cache.get_cache_by_name(&name).unwrap_or_else(|e| {
|
||||||
|
// Error fetching from cache
|
||||||
|
println!("Error Getting Cache by Name [{}] {}", name, e);
|
||||||
|
// Might still be able to just fetch, pretend empty
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if let Some(user) = cache_val {
|
||||||
|
println!("Cache Hit for Name [{}]", name);
|
||||||
|
response = user.to_app_response();
|
||||||
|
state.cache.update_cache_expiry(&user).unwrap_or_else(|e| {
|
||||||
|
// this is going well, isn't it?
|
||||||
|
println!("Error Updating Cache Expiry for Name [{}] {}", name, e);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
println!("Cache Miss for Name [{}]", name);
|
||||||
|
let fetch_val = state
|
||||||
|
.fetch
|
||||||
|
.get_user_by_name(&name)
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
// Something went really wrong...
|
||||||
|
println!("Error Fetching by Name [{}] {}", name, e);
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if let Some(user) = fetch_val {
|
||||||
|
println!("Fetch Hit for Name [{}]", name);
|
||||||
|
response = user.to_app_response();
|
||||||
|
state.cache.set_cache_data(&user).unwrap_or_else(|e| {
|
||||||
|
println!("Error saving Cache Data for Name [{}] {}", name, e);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Json(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct AppResponse {
|
||||||
|
success: bool,
|
||||||
|
id: Option<String>,
|
||||||
|
name: Option<String>,
|
||||||
|
display_name: Option<String>,
|
||||||
|
profile_picture_url: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct AppQuery {
|
||||||
|
id: Option<String>,
|
||||||
|
name: Option<String>,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::AppResponse;
|
||||||
use redis_derive::{FromRedisValue, ToRedisArgs};
|
use redis_derive::{FromRedisValue, ToRedisArgs};
|
||||||
|
|
||||||
#[derive(Debug, ToRedisArgs, FromRedisValue)]
|
#[derive(Debug, ToRedisArgs, FromRedisValue)]
|
||||||
|
|
@ -9,12 +10,17 @@ pub struct UserData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserData {
|
impl UserData {
|
||||||
pub fn new(name: String, display_name: String, id: String, profile_picture_url: String) -> Self {
|
pub fn new(
|
||||||
|
name: String,
|
||||||
|
display_name: String,
|
||||||
|
id: String,
|
||||||
|
profile_picture_url: String,
|
||||||
|
) -> Self {
|
||||||
UserData {
|
UserData {
|
||||||
name,
|
name,
|
||||||
display_name,
|
display_name,
|
||||||
id,
|
id,
|
||||||
profile_picture_url
|
profile_picture_url,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn redis_id_from_str(name: &str) -> String {
|
pub fn redis_id_from_str(name: &str) -> String {
|
||||||
|
|
@ -37,7 +43,13 @@ impl UserData {
|
||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn to_app_response(&self) -> AppResponse {
|
||||||
&self.name
|
AppResponse {
|
||||||
|
success: true,
|
||||||
|
id: Some(self.id.clone()),
|
||||||
|
name: Some(self.name.clone()),
|
||||||
|
display_name: Some(self.display_name.clone()),
|
||||||
|
profile_picture_url: Some(self.profile_picture_url.clone()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue