Skip to content

Commit

Permalink
Adds token refresh to the fetcher
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbrain-za committed Nov 11, 2023
1 parent e67ebf8 commit 0cd0ed3
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 111 deletions.
2 changes: 1 addition & 1 deletion src/apps/binary_upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl super::App for BinaryUpload {
match submission {
SubmissionResult::NotStarted => {}
SubmissionResult::NotAuthorized => {
self.token_refresh_promise = refresh::submit_refresh(&self.url);
self.token_refresh_promise = refresh::submit_refresh();
self.last_result = submission;
}
_ => {
Expand Down
2 changes: 1 addition & 1 deletion src/apps/code_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl super::App for CodeEditor {
match submission {
SubmissionResult::NotStarted => {}
SubmissionResult::NotAuthorized => {
self.token_refresh_promise = refresh::submit_refresh(&self.url);
self.token_refresh_promise = refresh::submit_refresh();
self.last_result = submission;
}
_ => {
Expand Down
4 changes: 2 additions & 2 deletions src/apps/login_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl Default for LoginApp {
.unwrap_or("http://localhost:3000/")
.to_string();
Self {
token_refresh_promise: refresh::submit_refresh(&url),
token_refresh_promise: refresh::submit_refresh(),
login_promise: Default::default(),
register_promise: Default::default(),
url,
Expand Down Expand Up @@ -261,7 +261,7 @@ impl LoginApp {
}
Ok(LoginState::Expired) => {
self.state = LoginState::Expired;
self.token_refresh_promise = refresh::submit_refresh(&self.url);
self.token_refresh_promise = refresh::submit_refresh();
}
Err(e) => {
self.toasts
Expand Down
139 changes: 56 additions & 83 deletions src/apps/scoreboard_app.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::helpers::{refresh, Challenges};
use gloo_net::http;
use poll_promise::Promise;
use crate::helpers::{
fetchers::{GetStatus, Getter},
Challenges,
};
use scoreboard_db::Builder as FilterBuilder;
use scoreboard_db::Filter as ScoreBoardFilter;
use scoreboard_db::{NiceTime, Score, ScoreBoard, SortColumn};
use std::str::FromStr;
use web_sys::RequestCredentials;
use std::{borrow::BorrowMut, str::FromStr};

#[derive(PartialEq, Clone, Copy, serde::Deserialize, serde::Serialize)]
enum FilterOption {
Expand All @@ -32,15 +32,11 @@ pub struct ScoreBoardApp {
active_sort_column: String,

scores: Option<Vec<Score>>,

#[serde(skip)]
promise: Option<Promise<FetchResponse>>,
#[serde(skip)]
token_refresh_promise: refresh::RefreshPromise,
#[serde(skip)]
url: String,

#[serde(skip)]
refresh: bool,
score_fetcher: Option<Getter>,
}

impl Default for ScoreBoardApp {
Expand All @@ -49,86 +45,62 @@ impl Default for ScoreBoardApp {
challenge: Challenges::default(),
filter: FilterOption::All,
sort_column: "time".to_string(),
promise: None,
token_refresh_promise: None,
url: option_env!("BACKEND_URL")
.unwrap_or("http://123.4.5.6:3000/")
.to_string(),
refresh: true,

active_challenge: Challenges::default(),
active_challenge: Challenges::None,
active_filter: FilterOption::All,
active_sort_column: "time".to_string(),
scores: None,
score_fetcher: None,
}
}
}

impl ScoreBoardApp {
fn fetch(&mut self, ctx: &egui::Context) {
if !self.refresh {
return;
}
self.refresh = false;
fn fetch(&mut self) {
self.scores = None;

let url = format!("{}api/game/scores/{}", self.url, self.challenge);
let ctx = ctx.clone();

let promise = poll_promise::Promise::spawn_local(async move {
let response = http::Request::get(&url).credentials(RequestCredentials::Include);
let response = response.send().await.unwrap();
let text = response.text().await;
let text = text.map(|text| text.to_owned());

let result = match response.status() {
200 => {
let scores: Vec<Score> = serde_json::from_str(text.as_ref().unwrap()).unwrap();
FetchResponse::Success(scores)
}
401 => {
let text = match text {
Ok(text) => text,
Err(e) => e.to_string(),
};
log::warn!("Auth Error: {:?}", text);
FetchResponse::FailAuth
}
_ => {
log::error!("Response: {:?}", text);
FetchResponse::Failure(text.unwrap())
}
};
ctx.request_repaint(); // wake up UI thread
result
});
self.promise = Some(promise);
log::debug!("Fetching challenge info");
let mut getter = Getter::new(&url, true);
getter.get();
self.score_fetcher = Some(getter);
}

fn check_for_reload(&mut self) {
fn check_for_reload(&mut self) -> bool {
if self.active_challenge != self.challenge
|| self.active_filter != self.filter
|| self.active_sort_column != self.sort_column
{
self.active_challenge = self.challenge;
self.active_filter = self.filter;
self.active_sort_column = self.sort_column.clone();
self.refresh = true;
return true;
}
false
}

fn check_fetch_promise(&mut self) -> Option<FetchResponse> {
if let Some(promise) = &self.promise {
if let Some(result) = promise.ready() {
if let FetchResponse::FailAuth = result {
self.token_refresh_promise = refresh::submit_refresh(&self.url);
fn check_fetch_promise(&mut self) -> GetStatus {
let getter = &mut self.score_fetcher;

if let Some(getter) = getter {
let result = &getter.check_promise();

match result {
GetStatus::Success(_) => {
self.score_fetcher = None;
}
GetStatus::Failed(_) => {
self.score_fetcher = None;
}
let result = Some(result.clone());
self.promise = None;
return result;
_ => {}
}
return result.clone();
}
None
GetStatus::NotStarted
}
}

Expand All @@ -138,8 +110,17 @@ impl super::App for ScoreBoardApp {
}

fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
self.check_for_reload();
self.fetch(ctx);
if self.check_for_reload() {
self.fetch();
}

if let Some(fetcher) = self.score_fetcher.borrow_mut() {
if fetcher.refresh_context() {
log::debug!("Refreshing context");
ctx.request_repaint();
}
}

egui::Window::new(self.name())
.open(open)
.default_width(400.0)
Expand Down Expand Up @@ -192,7 +173,7 @@ impl super::View for ScoreBoardApp {
);
ui.separator();
if ui.button("Refresh").clicked() {
self.refresh = true;
self.fetch();
}
});
});
Expand All @@ -210,29 +191,21 @@ impl ScoreBoardApp {
fn table_ui(&mut self, ui: &mut egui::Ui) {
use egui_extras::{Column, TableBuilder};

if let Some(result) = self.check_fetch_promise() {
match result {
FetchResponse::Success(s) => {
self.scores = Some(s);
}
FetchResponse::Failure(text) => {
ui.label(text);
}
FetchResponse::FailAuth => {
ui.label("Failed to authenticate, refreshing token");
}
match self.check_fetch_promise() {
GetStatus::Success(text) => {
self.score_fetcher = None;
self.scores = Some(serde_json::from_str(&text).unwrap());
}
}
match refresh::check_refresh_promise(&mut self.token_refresh_promise) {
refresh::RefreshStatus::NotStarted => {}
refresh::RefreshStatus::InProgress => {}
refresh::RefreshStatus::Success => {
self.refresh = true;
GetStatus::Failed(e) => {
self.score_fetcher = None;
let message = format!("Failed to fetch scores: {}", e);
log::error!("{}", message);
ui.label(message);
}
refresh::RefreshStatus::Failed(text) => {
log::error!("Failed to refresh token: {:?}", text);
ui.label(text);
GetStatus::InProgress => {
ui.label("Fetching scores...");
}
GetStatus::NotStarted => {}
}

let text_height = egui::TextStyle::Body.resolve(ui.style()).size;
Expand Down
2 changes: 1 addition & 1 deletion src/code_editor/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl CodeEditor {
match submission {
SubmissionResult::NotStarted => {}
SubmissionResult::NotAuthorized => {
self.token_refresh_promise = refresh::submit_refresh(&self.url);
self.token_refresh_promise = refresh::submit_refresh();
self.last_result = submission;
}
SubmissionResult::Success { score: _, message } => {
Expand Down
42 changes: 20 additions & 22 deletions src/helpers/fetchers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::helpers::refresh;
use gloo_net::http;
use poll_promise::Promise;
use web_sys::RequestCredentials;
Expand Down Expand Up @@ -33,6 +34,7 @@ pub struct Getter {
url: String,
retry_count: usize,
state_has_changed: bool,
token_refresh_promise: refresh::RefreshPromise,
}

impl Getter {
Expand All @@ -46,10 +48,25 @@ impl Getter {
false => 0,
},
state_has_changed: false,
token_refresh_promise: None,
}
}

pub fn check_promise(&mut self) -> GetStatus {
match refresh::check_refresh_promise(&mut self.token_refresh_promise) {
refresh::RefreshStatus::NotStarted => {}
refresh::RefreshStatus::InProgress => {}
refresh::RefreshStatus::Success => {
log::debug!("Retrying Request");
self.get();
return GetStatus::InProgress;
}
refresh::RefreshStatus::Failed(_) => {
self.state_has_changed = true;
return GetStatus::Failed("Failed to authenticate".to_string());
}
}

let mut res = GetStatus::NotStarted;
if let Some(promise) = &self.promise {
res = match promise.ready() {
Expand All @@ -58,8 +75,10 @@ impl Getter {
Ok(FetchResponse::Failure(e)) => GetStatus::Failed(e.to_string()),
Ok(FetchResponse::FailAuth) => {
if self.retry_count > 0 {
log::debug!("Retrying auth");
self.retry_count -= 1;
self.get();
self.promise = None;
self.token_refresh_promise = refresh::submit_refresh();
GetStatus::InProgress
} else {
GetStatus::Failed("Authentication failed".to_string())
Expand Down Expand Up @@ -115,24 +134,3 @@ impl Getter {
self.promise = Some(promise);
}
}

// impl<T: Clone + DeserializeOwned + Sync + Send> Getter<T> {
// pub fn _get_json(&mut self) {
// let url = self.url.clone();
// let ctx = self.context.clone();
// let with_credentials = self.with_credentials;
// let promise = Promise::spawn_local(async move {
// let request = http::Request::get(&url);
// let request = match with_credentials {
// true => request.credentials(RequestCredentials::Include),
// false => request,
// };
// let response = request.send().await.map_err(|e| e.to_string())?;
// if let Some(ctx) = ctx {
// ctx.request_repaint(); // wake up UI thread
// }
// response.json::<T>().await.map_err(|e| e.to_string())
// });
// self.promise = Some(promise);
// }
// }
5 changes: 4 additions & 1 deletion src/helpers/refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ pub enum RefreshStatus {

pub type RefreshPromise = Option<Promise<Result<RefreshResponse, String>>>;

pub fn submit_refresh(url: &str) -> RefreshPromise {
pub fn submit_refresh() -> RefreshPromise {
let url = option_env!("BACKEND_URL")
.unwrap_or("http://123.4.5.6:3000/")
.to_string();
let url = format!("{}api/auth/refresh", url);
log::debug!("Refreshing token");

Expand Down

0 comments on commit 0cd0ed3

Please sign in to comment.