Use a thread pool

This commit is contained in:
Baptiste Gelez 2019-02-06 21:05:20 +01:00
parent f4447a2648
commit 3ccf7daff6
6 changed files with 135 additions and 24 deletions

11
Cargo.lock generated
View File

@ -325,10 +325,12 @@ dependencies = [
"gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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 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_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)", "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]] [[package]]
@ -1468,6 +1470,14 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "ws2_32-sys" name = "ws2_32-sys"
version = "0.2.1" 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-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-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 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" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"

View File

@ -15,3 +15,5 @@ serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"
reqwest = "0.9" reqwest = "0.9"
workerpool = "1.1.1"
lazy_static = "1.2"

View File

@ -1,4 +1,88 @@
use serde_derive::*; 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<Mutex<Option<RequestContext>>>
= Arc::new(Mutex::new(None));
static ref JOBS: workerpool::Pool<Req>
= workerpool::Pool::new(5);
}
pub fn execute(req: reqwest::RequestBuilder) -> Receiver<reqwest::Response> {
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<S: AsRef<str>>(&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<S: AsRef<str>>(&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<T> {
Ok(T),
Err
}
impl<T> Into<Result<T, ()>> for ApiResult<T> {
fn into(self) -> Result<T, ()> {
match self {
ApiResult::Ok(t) => Ok(t),
ApiResult::Err => Err(()),
}
}
}
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct LoginData { pub struct LoginData {

View File

@ -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 api;
mod ui; mod ui;

View File

@ -2,9 +2,9 @@ use gtk::*;
use std::{ use std::{
rc::Rc, rc::Rc,
cell::RefCell, cell::RefCell,
ops::Deref
}; };
use crate::{State, api, ui::title}; use crate::{State, api::*, ui::title};
pub fn render(state: State) -> gtk::Box { pub fn render(state: State) -> gtk::Box {
let cont = gtk::Box::new(Orientation::Vertical, 24); let cont = gtk::Box::new(Orientation::Vertical, 24);
@ -27,27 +27,26 @@ pub fn render(state: State) -> gtk::Box {
instance, username, password instance, username, password
))); )));
login_bt.connect_clicked(clone!(state, widgets => move |_| { login_bt.connect_clicked(clone!(state, widgets => move |_| {
state.borrow_mut().instance = widgets.borrow().0.get_text(); let mut api_ctx = crate::api::API.lock().expect("1");
state.borrow_mut().username = widgets.borrow().1.get_text(); *api_ctx = Some(RequestContext::new(
state.borrow_mut().password = widgets.borrow().2.get_text(); widgets.borrow().0.get_text().unwrap()
));
let res: api::LoginInfo = reqwest::Client::new() let state = state.clone();
.post(&format!("https://{}/api/v1/token/", state.borrow().instance.clone().unwrap())) wait!(execute(api_ctx.as_ref().unwrap().post("/api/v1/token/").json(&LoginData {
.json(&api::LoginData { username: widgets.borrow().1.get_text().clone().unwrap(),
username: state.borrow().username.clone().unwrap(), password: widgets.borrow().2.get_text().clone().unwrap(),
password: state.borrow().password.clone().unwrap(), })) => |res| {
}) let res: Result<_, _> = res.json::<ApiResult<LoginInfo>>().unwrap().into();
.send()
.unwrap()
.json()
.unwrap();
state.borrow_mut().token = Some(res.token); if let Some(ref mut api) = *crate::api::API.lock().expect("3") {
let main_page = crate::ui::main_page::render(state.clone()); api.auth(res.unwrap().token.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.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(); state.borrow_mut().stack.show_all();
});
})); }));
cont.add(&title); cont.add(&title);

View File

@ -17,7 +17,7 @@ pub fn render(state: State) -> gtk::Box {
cont.set_margin_end(96); cont.set_margin_end(96);
let avatar_path = dirs::cache_dir().unwrap().join("funkload-avatar.png"); 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())) .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())) .header(reqwest::header::AUTHORIZATION, format!("JWT {}", state.borrow().token.clone().unwrap_or_default()))
.send() .send()
@ -75,7 +75,7 @@ pub fn render(state: State) -> gtk::Box {
cont.add(&avatar); cont.add(&avatar);
let lbl = Label::new(format!("Welcome {}.", user.username).as_ref()); let lbl = Label::new(format!("Welcome {}.", user.username).as_ref());
lbl.get_style_context().map(|c| c.add_class("h1")); lbl.get_style_context().map(|c| c.add_class("h1"));
cont.add(&lbl); cont.add(&lbl);*/
let search = SearchEntry::new(); let search = SearchEntry::new();
search.set_placeholder_text("Search"); search.set_placeholder_text("Search");