Skip to content

Commit 28e46b0

Browse files
authored
Merge pull request #5 from fiji-flo/cache
cache username lookups
2 parents c399ebf + 7554cf9 commit 28e46b0

7 files changed

Lines changed: 94 additions & 21 deletions

File tree

.travis.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
language: rust
2+
rust:
3+
- stable
4+
- nightly
5+
cache: cargo
6+
matrix:
7+
allow_failures:
8+
- rust: nightly
9+
fast_finish: true
10+
11+
before_script:
12+
- rustup component add rustfmt-preview
13+
- rustup component add clippy-preview
14+
15+
script:
16+
- cargo fmt --all -- --check
17+
- cargo clippy -- -D warnings
18+
- cargo build --all
19+
- cargo test --all

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ oauth2 = "2.0.0-beta.2"
1515
url = "1.7.2"
1616
base64 = "0.10.1"
1717
rand = "0.6.5"
18-
actix-web = { version = "1.0.0", features = ["ssl"] }
19-
actix-session = "0.1.0"
18+
actix-web = { version = "1.0", features = ["ssl"] }
19+
actix-cors = "0.1"
20+
actix-session = "0.1"
2021
failure = "0.1.5"
2122
config = "0.9.3"
2223
serde = "1.0.80"
@@ -26,3 +27,4 @@ futures = "0.1"
2627
chrono = "0.4.6"
2728
env_logger = "0.6.1"
2829
log = "0.4.6"
30+
ttl_cache = "0.5.1"

src/bugzilla/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ use crate::settings::BugZilla;
22
use crate::settings::WhoAmI;
33
use crate::update::update_bugzilla;
44
use crate::userid::UserId;
5+
use actix_cors::Cors;
56
use actix_session::CookieSession;
67
use actix_session::Session;
78
use actix_web::client::Client;
89
use actix_web::cookie::SameSite;
910
use actix_web::dev::HttpServiceFactory;
1011
use actix_web::http;
11-
use actix_web::middleware::cors::Cors;
1212
use actix_web::web;
1313
use actix_web::Error;
1414
use actix_web::HttpResponse;

src/github/app.rs

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@ use crate::settings::GitHub;
22
use crate::settings::WhoAmI;
33
use crate::update::update_github;
44
use crate::userid::UserId;
5+
use actix_cors::Cors;
56
use actix_session::CookieSession;
67
use actix_session::Session;
78
use actix_web::client::Client;
89
use actix_web::cookie::SameSite;
910
use actix_web::dev::HttpServiceFactory;
1011
use actix_web::http;
11-
use actix_web::middleware::cors::Cors;
1212
use actix_web::web;
1313
use actix_web::Error;
1414
use actix_web::HttpResponse;
1515
use actix_web::Responder;
1616
use cis_client::getby::GetBy;
1717
use cis_client::AsyncCisClientTrait;
1818
use cis_profile::schema::Profile;
19-
use future::IntoFuture;
2019
use futures::future;
20+
use futures::future::Either;
2121
use futures::Future;
22+
use futures::IntoFuture;
2223
use oauth2::basic::BasicClient;
2324
use oauth2::prelude::*;
2425
use oauth2::AuthUrl;
@@ -31,12 +32,17 @@ use oauth2::Scope;
3132
use oauth2::TokenResponse;
3233
use oauth2::TokenUrl;
3334
use std::sync::Arc;
35+
use std::sync::RwLock;
36+
use std::time::Duration;
37+
use ttl_cache::TtlCache;
3438
use url::Url;
3539

3640
const AUTH_URL: &str = "https://github.com/login/oauth/authorize";
3741
const TOKEN_URL: &str = "https://github.com/login/oauth/access_token";
3842
const USER_URL: &str = "https://api.github.com/user";
3943

44+
const CACHE_DURATION: Duration = Duration::from_secs(24 * 60 * 60);
45+
4046
#[derive(Deserialize)]
4147
pub struct Auth {
4248
code: String,
@@ -56,21 +62,40 @@ pub struct GitHubUser {
5662
node_id: String,
5763
}
5864

59-
fn id_to_username(id: web::Path<String>) -> impl Future<Item = HttpResponse, Error = Error> {
60-
Client::default()
61-
.get(format!("{}/{}", USER_URL, id))
62-
.header(http::header::USER_AGENT, "whoami")
63-
.send()
64-
.map_err(Into::into)
65-
.and_then(|mut res| {
66-
info!("status: {}", res.status());
67-
res.json::<GitHubUser>().map_err(Into::into)
68-
})
69-
.and_then(|user| {
70-
HttpResponse::Ok().json(GitHubUsername {
71-
username: user.login,
72-
})
73-
})
65+
fn id_to_username(
66+
id: web::Path<String>,
67+
cache: web::Data<Arc<RwLock<TtlCache<String, String>>>>,
68+
) -> impl Future<Item = HttpResponse, Error = Error> {
69+
if let Some(username) = cache.read().ok().and_then(|c| c.get(&*id).cloned()) {
70+
info!("serving {} → {} from cache", &*id, &username);
71+
Either::A(Ok(HttpResponse::Ok().json(GitHubUsername { username })).into_future())
72+
} else {
73+
let cache = Arc::clone(&*cache);
74+
let cache_id = (*id).clone();
75+
Either::B(
76+
Client::default()
77+
.get(format!("{}/{}", USER_URL, id))
78+
.header(http::header::USER_AGENT, "whoami")
79+
.send()
80+
.map_err(Into::into)
81+
.and_then(|mut res| {
82+
info!("status: {}", res.status());
83+
res.json::<GitHubUser>().map_err(Into::into)
84+
})
85+
.map(move |user| {
86+
if let Ok(mut c) = cache.write() {
87+
info!("caching {} → {}", &cache_id, &user.login);
88+
c.insert(cache_id, user.login.clone(), CACHE_DURATION);
89+
}
90+
user
91+
})
92+
.and_then(|user| {
93+
HttpResponse::Ok().json(GitHubUsername {
94+
username: user.login,
95+
})
96+
}),
97+
)
98+
}
7499
}
75100

76101
fn redirect(client: web::Data<Arc<BasicClient>>, session: Session) -> impl Responder {
@@ -172,6 +197,7 @@ pub fn github_app<T: AsyncCisClientTrait + 'static>(
172197
let github_client_secret = ClientSecret::new(github.client_secret.clone());
173198
let auth_url = AuthUrl::new(Url::parse(AUTH_URL).expect("Invalid authorization endpoint URL"));
174199
let token_url = TokenUrl::new(Url::parse(TOKEN_URL).expect("Invalid token endpoint URL"));
200+
let ttl_cache = Arc::new(RwLock::new(TtlCache::<String, String>::new(2000)));
175201

176202
let client = Arc::new(
177203
BasicClient::new(
@@ -207,6 +233,7 @@ pub fn github_app<T: AsyncCisClientTrait + 'static>(
207233
)
208234
.data(client)
209235
.data(cis_client)
236+
.data(ttl_cache)
210237
.service(web::resource("/add").route(web::get().to(redirect)))
211238
.service(web::resource("/auth").route(web::get().to_async(auth::<T>)))
212239
.service(web::resource("/username/{id}").route(web::get().to_async(id_to_username)))

src/healthz.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
use actix_cors::Cors;
12
use actix_web::dev::HttpServiceFactory;
23
use actix_web::http;
3-
use actix_web::middleware::cors::Cors;
44
use actix_web::web;
55
use actix_web::HttpRequest;
66
use actix_web::HttpResponse;

src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
extern crate log;
33
#[macro_use]
44
extern crate serde_derive;
5+
extern crate actix_cors;
56
extern crate actix_session;
67
extern crate actix_web;
78
extern crate base64;
@@ -12,6 +13,7 @@ extern crate env_logger;
1213
extern crate futures;
1314
extern crate rand;
1415
extern crate serde_json;
16+
extern crate ttl_cache;
1517
extern crate url;
1618

1719
mod bugzilla;

0 commit comments

Comments
 (0)