From 3ccf7daff6c5f4b6e548382b7f557fede4c1499f Mon Sep 17 00:00:00 2001 From: Baptiste Gelez Date: Wed, 6 Feb 2019 21:05:20 +0100 Subject: [PATCH] Use a thread pool --- Cargo.lock | 11 ++++++ Cargo.toml | 4 ++- src/api.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 15 ++++++++ src/ui/login_page.rs | 41 +++++++++++---------- src/ui/main_page.rs | 4 +-- 6 files changed, 135 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f5a897..98b7bc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -325,10 +325,12 @@ dependencies = [ "gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gtk 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "workerpool 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1468,6 +1470,14 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "workerpool" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1637,4 +1647,5 @@ dependencies = [ "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum workerpool 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f49756646617bde19ff95b370cfa5c0f7ead17a90c90d7cb62dc31dfaa8c625" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/Cargo.toml b/Cargo.toml index fa17ad3..12a076c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,6 @@ gtk = { version = "0.5", features = [ "v3_22" ] } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -reqwest = "0.9" \ No newline at end of file +reqwest = "0.9" +workerpool = "1.1.1" +lazy_static = "1.2" \ No newline at end of file diff --git a/src/api.rs b/src/api.rs index 0ca2bf6..42121fc 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,4 +1,88 @@ use serde_derive::*; +use lazy_static::*; +use workerpool::Worker; +use std::{ + cell::RefCell, + sync::{ + Arc, + mpsc::{channel, Receiver}, + Mutex, MutexGuard + }, +}; + +lazy_static! { + pub static ref API: Arc>> + = Arc::new(Mutex::new(None)); + + static ref JOBS: workerpool::Pool + = workerpool::Pool::new(5); +} + +pub fn execute(req: reqwest::RequestBuilder) -> Receiver { + let (tx, rx) = channel(); + JOBS.execute_to(tx, req); + rx +} + +pub struct RequestContext { + token: String, + instance: String, + client: reqwest::Client, +} + +impl RequestContext { + pub fn new(instance: String) -> Self { + RequestContext { + token: String::new(), + instance: instance.clone(), + client: reqwest::Client::new() + } + } + + pub fn auth(&mut self, token: String) { + self.token = token.clone(); + } + + pub fn get>(&self, url: S) -> reqwest::RequestBuilder { + self.client + .get(&format!("https://{}{}", self.instance, url.as_ref())) + .header(reqwest::header::AUTHORIZATION, format!("JWT {}", self.token)) + } + + /// Warning: no authentication, since it is only used for login + pub fn post>(&self, url: S) -> reqwest::RequestBuilder { + self.client + .post(&format!("https://{}{}", self.instance, url.as_ref())) + } +} + +#[derive(Default)] +pub struct Req; + +impl Worker for Req { + type Input = reqwest::RequestBuilder; + type Output = reqwest::Response; + + fn execute(&mut self, req: Self::Input) -> Self::Output { + req.send().expect("Error while sending request") + } +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum ApiResult { + Ok(T), + Err +} + +impl Into> for ApiResult { + fn into(self) -> Result { + match self { + ApiResult::Ok(t) => Ok(t), + ApiResult::Err => Err(()), + } + } +} #[derive(Deserialize, Serialize)] pub struct LoginData { diff --git a/src/main.rs b/src/main.rs index 64c7dc0..b5ba048 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,21 @@ macro_rules! clone { ); } +macro_rules! wait { + ($exp:expr => | $res:ident | $then:block) => { + let rx = $exp; + gtk::idle_add(move || { + match rx.try_recv() { + Err(_) => glib::Continue(true), + Ok(mut $res) => { + $then; + glib::Continue(false) + }, + } + }) + } +} + mod api; mod ui; diff --git a/src/ui/login_page.rs b/src/ui/login_page.rs index 110786d..414de42 100644 --- a/src/ui/login_page.rs +++ b/src/ui/login_page.rs @@ -2,9 +2,9 @@ use gtk::*; use std::{ rc::Rc, cell::RefCell, + ops::Deref }; -use crate::{State, api, ui::title}; - +use crate::{State, api::*, ui::title}; pub fn render(state: State) -> gtk::Box { let cont = gtk::Box::new(Orientation::Vertical, 24); @@ -27,27 +27,26 @@ pub fn render(state: State) -> gtk::Box { instance, username, password ))); login_bt.connect_clicked(clone!(state, widgets => move |_| { - state.borrow_mut().instance = widgets.borrow().0.get_text(); - state.borrow_mut().username = widgets.borrow().1.get_text(); - state.borrow_mut().password = widgets.borrow().2.get_text(); + let mut api_ctx = crate::api::API.lock().expect("1"); + *api_ctx = Some(RequestContext::new( + widgets.borrow().0.get_text().unwrap() + )); - let res: api::LoginInfo = reqwest::Client::new() - .post(&format!("https://{}/api/v1/token/", state.borrow().instance.clone().unwrap())) - .json(&api::LoginData { - username: state.borrow().username.clone().unwrap(), - password: state.borrow().password.clone().unwrap(), - }) - .send() - .unwrap() - .json() - .unwrap(); + let state = state.clone(); + wait!(execute(api_ctx.as_ref().unwrap().post("/api/v1/token/").json(&LoginData { + username: widgets.borrow().1.get_text().clone().unwrap(), + password: widgets.borrow().2.get_text().clone().unwrap(), + })) => |res| { + let res: Result<_, _> = res.json::>().unwrap().into(); - state.borrow_mut().token = Some(res.token); - let main_page = crate::ui::main_page::render(state.clone()); - main_page.show_all(); - state.borrow_mut().stack.add_named(&main_page, "main"); - state.borrow_mut().stack.set_visible_child(&main_page); - state.borrow_mut().stack.show_all(); + if let Some(ref mut api) = *crate::api::API.lock().expect("3") { + api.auth(res.unwrap().token.clone()); + } + + state.borrow_mut().stack.add_named(&crate::ui::main_page::render(state.clone()), "main"); + state.borrow_mut().stack.set_visible_child_name("main"); + state.borrow_mut().stack.show_all(); + }); })); cont.add(&title); diff --git a/src/ui/main_page.rs b/src/ui/main_page.rs index 00813ab..d54acbe 100644 --- a/src/ui/main_page.rs +++ b/src/ui/main_page.rs @@ -17,7 +17,7 @@ pub fn render(state: State) -> gtk::Box { cont.set_margin_end(96); let avatar_path = dirs::cache_dir().unwrap().join("funkload-avatar.png"); - let user: api::UserInfo = reqwest::Client::new() + /*let user: api::UserInfo = reqwest::Client::new() .get(&format!("https://{}/api/v1/users/users/me/", state.borrow().instance.clone().unwrap())) .header(reqwest::header::AUTHORIZATION, format!("JWT {}", state.borrow().token.clone().unwrap_or_default())) .send() @@ -75,7 +75,7 @@ pub fn render(state: State) -> gtk::Box { cont.add(&avatar); let lbl = Label::new(format!("Welcome {}.", user.username).as_ref()); lbl.get_style_context().map(|c| c.add_class("h1")); - cont.add(&lbl); + cont.add(&lbl);*/ let search = SearchEntry::new(); search.set_placeholder_text("Search");