Fixed long-running requests to be cancelled when users try to change tabs or contexts.
This commit is contained in:
+66
-51
@@ -2,13 +2,15 @@ use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::{debug, error};
|
||||
use log::{debug, error, warn};
|
||||
use regex::Regex;
|
||||
use reqwest::{Client, RequestBuilder};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use strum_macros::Display;
|
||||
use tokio::select;
|
||||
use tokio::sync::{Mutex, MutexGuard};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::network::radarr_network::RadarrEvent;
|
||||
@@ -27,18 +29,20 @@ pub enum NetworkEvent {
|
||||
|
||||
pub struct Network<'a, 'b> {
|
||||
client: Client,
|
||||
cancellation_token: CancellationToken,
|
||||
pub app: &'a Arc<Mutex<App<'b>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Network<'a, 'b> {
|
||||
pub fn new(app: &'a Arc<Mutex<App<'b>>>) -> Self {
|
||||
pub fn new(app: &'a Arc<Mutex<App<'b>>>, cancellation_token: CancellationToken) -> Self {
|
||||
Network {
|
||||
client: Client::new(),
|
||||
app,
|
||||
cancellation_token,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_network_event(&self, network_event: NetworkEvent) {
|
||||
pub async fn handle_network_event(&mut self, network_event: NetworkEvent) {
|
||||
match network_event {
|
||||
NetworkEvent::Radarr(radarr_event) => self.handle_radarr_event(radarr_event).await,
|
||||
}
|
||||
@@ -48,7 +52,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
}
|
||||
|
||||
pub async fn handle_request<B, R>(
|
||||
&self,
|
||||
&mut self,
|
||||
request_props: RequestProps<B>,
|
||||
mut app_update_fn: impl FnMut(R, MutexGuard<'_, App<'_>>),
|
||||
) where
|
||||
@@ -56,54 +60,65 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
R: DeserializeOwned,
|
||||
{
|
||||
let method = request_props.method;
|
||||
match self.call_api(request_props).await.send().await {
|
||||
Ok(response) => {
|
||||
if response.status().is_success() {
|
||||
match method {
|
||||
RequestMethod::Get | RequestMethod::Post => {
|
||||
match utils::parse_response::<R>(response).await {
|
||||
Ok(value) => {
|
||||
let app = self.app.lock().await;
|
||||
app_update_fn(value, app);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to parse response! {:?}", e);
|
||||
self
|
||||
.app
|
||||
.lock()
|
||||
.await
|
||||
.handle_error(anyhow!("Failed to parse response! {:?}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
RequestMethod::Delete | RequestMethod::Put => (),
|
||||
}
|
||||
} else {
|
||||
let status = response.status();
|
||||
let whitespace_regex = Regex::new(r"\s+").unwrap();
|
||||
let response_body = response.text().await.unwrap_or_default();
|
||||
let error_body = whitespace_regex
|
||||
.replace_all(&response_body.replace('\n', " "), " ")
|
||||
.to_string();
|
||||
|
||||
error!(
|
||||
"Request failed. Received {} response code with body: {}",
|
||||
status, response_body
|
||||
);
|
||||
self.app.lock().await.handle_error(anyhow!(
|
||||
"Request failed. Received {} response code with body: {}",
|
||||
status,
|
||||
error_body
|
||||
));
|
||||
}
|
||||
let request_uri = request_props.uri.clone();
|
||||
select! {
|
||||
_ = self.cancellation_token.cancelled() => {
|
||||
warn!("Received Cancel request. Cancelling request to: {}", request_uri);
|
||||
let mut app = self.app.lock().await;
|
||||
self.cancellation_token = app.reset_cancellation_token();
|
||||
app.is_loading = false;
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to send request. {:?}", e);
|
||||
self
|
||||
.app
|
||||
.lock()
|
||||
.await
|
||||
.handle_error(anyhow!("Failed to send request. {} ", e));
|
||||
resp = tokio::spawn(self.call_api(request_props).await.send()) => {
|
||||
match resp.unwrap() {
|
||||
Ok(response) => {
|
||||
if response.status().is_success() {
|
||||
match method {
|
||||
RequestMethod::Get | RequestMethod::Post => {
|
||||
match utils::parse_response::<R>(response).await {
|
||||
Ok(value) => {
|
||||
let app = self.app.lock().await;
|
||||
app_update_fn(value, app);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to parse response! {:?}", e);
|
||||
self
|
||||
.app
|
||||
.lock()
|
||||
.await
|
||||
.handle_error(anyhow!("Failed to parse response! {:?}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
RequestMethod::Delete | RequestMethod::Put => (),
|
||||
}
|
||||
} else {
|
||||
let status = response.status();
|
||||
let whitespace_regex = Regex::new(r"\s+").unwrap();
|
||||
let response_body = response.text().await.unwrap_or_default();
|
||||
let error_body = whitespace_regex
|
||||
.replace_all(&response_body.replace('\n', " "), " ")
|
||||
.to_string();
|
||||
|
||||
error!(
|
||||
"Request failed. Received {} response code with body: {}",
|
||||
status, response_body
|
||||
);
|
||||
self.app.lock().await.handle_error(anyhow!(
|
||||
"Request failed. Received {} response code with body: {}",
|
||||
status,
|
||||
error_body
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to send request. {:?}", e);
|
||||
self
|
||||
.app
|
||||
.lock()
|
||||
.await
|
||||
.handle_error(anyhow!("Failed to send request. {} ", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user