Fixed long-running requests to be cancelled when users try to change tabs or contexts.

This commit is contained in:
2023-08-08 10:50:07 -06:00
parent e253ca8359
commit a8f6a5398b
10 changed files with 299 additions and 193 deletions
+2 -1
View File
@@ -31,7 +31,8 @@ serde_json = "1.0.91"
serde = { version = "1.0", features = ["derive"] }
strum = {version = "0.25.0", features = ["derive"] }
strum_macros = "0.25.0"
tokio = { version = "1.24.1", features = ["full"] }
tokio = { version = "1.29.0", features = ["full"] }
tokio-util = "0.7.8"
tui = { version = "0.21.0", package = "ratatui", features = ["all-widgets"] }
urlencoding = "2.1.2"
+14
View File
@@ -16,6 +16,7 @@ mod tests {
assert_eq!(app.navigation_stack, vec![DEFAULT_ROUTE]);
assert!(app.network_tx.is_none());
assert!(!app.cancellation_token.is_cancelled());
assert_eq!(app.error, HorizontallyScrollableText::default());
assert!(app.response.is_empty());
assert_eq!(app.server_tabs.index, 0);
@@ -82,6 +83,19 @@ mod tests {
assert!(app.is_routing);
}
#[test]
fn test_reset_cancellation_token() {
let mut app = App::default();
app.cancellation_token.cancel();
assert!(app.cancellation_token.is_cancelled());
let new_token = app.reset_cancellation_token();
assert!(!app.cancellation_token.is_cancelled());
assert!(!new_token.is_cancelled());
}
#[test]
fn test_reset_tick_count() {
let mut app = App {
+15 -1
View File
@@ -3,6 +3,7 @@ use log::{debug, error};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::Sender;
use tokio::time::Instant;
use tokio_util::sync::CancellationToken;
use crate::app::radarr::{ActiveRadarrBlock, RadarrData};
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
@@ -19,6 +20,7 @@ const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies, None);
pub struct App<'a> {
navigation_stack: Vec<Route>,
network_tx: Option<Sender<NetworkEvent>>,
cancellation_token: CancellationToken,
pub server_tabs: TabState,
pub error: HorizontallyScrollableText,
pub response: String,
@@ -36,10 +38,15 @@ pub struct App<'a> {
}
impl<'a> App<'a> {
pub fn new(network_tx: Sender<NetworkEvent>, config: AppConfig) -> Self {
pub fn new(
network_tx: Sender<NetworkEvent>,
config: AppConfig,
cancellation_token: CancellationToken,
) -> Self {
App {
network_tx: Some(network_tx),
config,
cancellation_token,
..App::default()
}
}
@@ -102,6 +109,12 @@ impl<'a> App<'a> {
}
}
pub fn reset_cancellation_token(&mut self) -> CancellationToken {
self.cancellation_token = CancellationToken::new();
self.cancellation_token.clone()
}
pub fn pop_and_push_navigation_stack(&mut self, route: Route) {
self.pop_navigation_stack();
self.push_navigation_stack(route);
@@ -117,6 +130,7 @@ impl<'a> Default for App<'a> {
App {
navigation_stack: vec![DEFAULT_ROUTE],
network_tx: None,
cancellation_token: CancellationToken::new(),
error: HorizontallyScrollableText::default(),
response: String::default(),
server_tabs: TabState::new(vec![
+9 -1
View File
@@ -752,10 +752,18 @@ impl<'a> App<'a> {
self.dispatch_by_radarr_block(&active_radarr_block).await;
}
if self.is_routing || self.tick_count % self.tick_until_poll == 0 {
if self.is_routing {
if self.is_loading {
self.cancellation_token.cancel();
}
self.dispatch_by_radarr_block(&active_radarr_block).await;
self.refresh_metadata().await;
}
if self.tick_count % self.tick_until_poll == 0 {
self.refresh_metadata().await;
}
}
async fn refresh_metadata(&mut self) {
+35 -16
View File
@@ -1115,17 +1115,6 @@ mod tests {
assert!(!app.data.radarr_data.prompt_confirm);
}
#[tokio::test]
async fn test_radarr_on_tick_not_routing() {
let mut app = App::default();
app
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
.await;
assert!(!app.is_routing);
}
#[tokio::test]
async fn test_radarr_on_tick_routing() {
let (mut app, mut sync_network_rx) = construct_app_unit();
@@ -1159,6 +1148,41 @@ mod tests {
assert!(!app.data.radarr_data.prompt_confirm);
}
#[tokio::test]
async fn test_radarr_on_tick_routing_while_long_request_is_running_should_cancel_request() {
let (mut app, mut sync_network_rx) = construct_app_unit();
app.is_routing = true;
app.is_loading = true;
app
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
.await;
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetDownloads.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetTags.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetRootFolders.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetDownloads.into()
);
assert!(app.is_loading);
assert!(!app.data.radarr_data.prompt_confirm);
assert!(app.cancellation_token.is_cancelled());
}
#[tokio::test]
async fn test_radarr_on_tick_should_refresh() {
let (mut app, mut sync_network_rx) = construct_app_unit();
@@ -1187,10 +1211,6 @@ mod tests {
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
.await;
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetDownloads.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
@@ -1208,7 +1228,6 @@ mod tests {
RadarrEvent::GetDownloads.into()
);
assert!(app.is_loading);
assert!(!app.data.radarr_data.prompt_confirm);
}
#[tokio::test]
+14 -4
View File
@@ -12,6 +12,7 @@ use crossterm::terminal::{
};
use tokio::sync::mpsc::Receiver;
use tokio::sync::{mpsc, Mutex};
use tokio_util::sync::CancellationToken;
use tui::backend::CrosstermBackend;
use tui::Terminal;
@@ -44,12 +45,17 @@ async fn main() -> Result<()> {
let config = confy::load("managarr", "config")?;
let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
let cancellation_token = CancellationToken::new();
let app = Arc::new(Mutex::new(App::new(sync_network_tx, config)));
let app = Arc::new(Mutex::new(App::new(
sync_network_tx,
config,
cancellation_token.clone(),
)));
let app_nw = Arc::clone(&app);
std::thread::spawn(move || start_networking(sync_network_rx, &app_nw));
std::thread::spawn(move || start_networking(sync_network_rx, &app_nw, cancellation_token));
start_ui(&app).await?;
@@ -57,8 +63,12 @@ async fn main() -> Result<()> {
}
#[tokio::main]
async fn start_networking(mut network_rx: Receiver<NetworkEvent>, app: &Arc<Mutex<App<'_>>>) {
let network = Network::new(app);
async fn start_networking(
mut network_rx: Receiver<NetworkEvent>,
app: &Arc<Mutex<App<'_>>>,
cancellation_token: CancellationToken,
) {
let mut network = Network::new(app, cancellation_token);
while let Some(network_event) = network_rx.recv().await {
network.handle_network_event(network_event).await;
+66 -51
View File
@@ -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));
}
}
}
}
}
+43 -11
View File
@@ -8,12 +8,13 @@ mod tests {
use pretty_assertions::assert_str_eq;
use rstest::rstest;
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
use tokio::sync::{mpsc, Mutex};
use tokio_util::sync::CancellationToken;
use crate::app::{App, RadarrConfig};
use crate::app::{App, AppConfig, RadarrConfig};
use crate::models::HorizontallyScrollableText;
use crate::network::radarr_network::RadarrEvent;
use crate::network::{Network, RequestMethod, RequestProps};
use crate::network::{Network, NetworkEvent, RequestMethod, RequestProps};
#[tokio::test]
async fn test_handle_network_event_radarr_event() {
@@ -38,7 +39,7 @@ mod tests {
};
app.config.radarr = radarr_config;
let app_arc = Arc::new(Mutex::new(app));
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_network_event(RadarrEvent::HealthCheck.into())
@@ -62,7 +63,7 @@ mod tests {
.create_async()
.await;
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_request::<Test, ()>(
@@ -87,7 +88,7 @@ mod tests {
#[values(RequestMethod::Get, RequestMethod::Post)] request_method: RequestMethod,
) {
let (async_server, app_arc, server) = mock_api(request_method, 200, true).await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_request::<(), Test>(
@@ -105,6 +106,37 @@ mod tests {
assert_str_eq!(app_arc.lock().await.error.text, "Test");
}
#[tokio::test]
async fn test_handle_request_request_is_cancelled() {
let (async_server, _, server) = mock_api(RequestMethod::Get, 200, true).await;
let cancellation_token = CancellationToken::new();
let (tx, _) = mpsc::channel::<NetworkEvent>(500);
let app_arc = Arc::new(Mutex::new(App::new(
tx,
AppConfig::default(),
cancellation_token.clone(),
)));
app_arc.lock().await.is_loading = true;
let mut network = Network::new(&app_arc, cancellation_token);
network.cancellation_token.cancel();
network
.handle_request::<(), Test>(
RequestProps {
uri: format!("{}/test", server.url()),
method: RequestMethod::Get,
body: None,
api_token: "test1234".to_owned(),
},
|_, _| (),
)
.await;
assert!(!async_server.matched_async().await);
assert!(app_arc.lock().await.error.text.is_empty());
assert!(!network.cancellation_token.is_cancelled());
}
#[tokio::test]
async fn test_handle_request_get_invalid_body() {
let mut server = Server::new_async().await;
@@ -116,7 +148,7 @@ mod tests {
.create_async()
.await;
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_request::<(), Test>(
@@ -142,7 +174,7 @@ mod tests {
#[tokio::test]
async fn test_handle_request_failure_to_send_request() {
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_request::<(), Test>(
@@ -176,7 +208,7 @@ mod tests {
request_method: RequestMethod,
) {
let (async_server, app_arc, server) = mock_api(request_method, 404, true).await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_request::<(), Test>(
@@ -200,7 +232,7 @@ mod tests {
#[tokio::test]
async fn test_handle_request_non_success_code_empty_response_body() {
let (async_server, app_arc, server) = mock_api(RequestMethod::Post, 404, false).await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_request::<(), Test>(
@@ -252,7 +284,7 @@ mod tests {
async_server = async_server.create_async().await;
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc);
let network = Network::new(&app_arc, CancellationToken::new());
network
.call_api(RequestProps {
+51 -59
View File
@@ -107,7 +107,7 @@ impl From<RadarrEvent> for NetworkEvent {
}
impl<'a, 'b> Network<'a, 'b> {
pub async fn handle_radarr_event(&self, radarr_event: RadarrEvent) {
pub async fn handle_radarr_event(&mut self, radarr_event: RadarrEvent) {
match radarr_event {
RadarrEvent::AddMovie => self.add_movie().await,
RadarrEvent::AddRootFolder => self.add_root_folder().await,
@@ -148,7 +148,7 @@ impl<'a, 'b> Network<'a, 'b> {
}
}
async fn add_movie(&self) {
async fn add_movie(&mut self) {
info!("Adding new movie to Radarr");
let body = {
let quality_profile_id = self.extract_quality_profile_id().await;
@@ -226,7 +226,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn add_root_folder(&self) {
async fn add_root_folder(&mut self) {
info!("Adding new root folder to Radarr");
let body = AddRootFolderBody {
path: self.app.lock().await.data.radarr_data.edit_path.drain(),
@@ -247,7 +247,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn add_tag(&self, tag: String) {
async fn add_tag(&mut self, tag: String) {
info!("Adding a new Radarr tag");
let request_props = self
@@ -269,7 +269,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn delete_download(&self) {
async fn delete_download(&mut self) {
let download_id = self
.app
.lock()
@@ -300,7 +300,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn delete_indexer(&self) {
async fn delete_indexer(&mut self) {
let indexer_id = self
.app
.lock()
@@ -331,7 +331,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn delete_movie(&self) {
async fn delete_movie(&mut self) {
let movie_id = self.extract_movie_id().await;
let delete_files = self.app.lock().await.data.radarr_data.delete_movie_files;
let add_import_exclusion = self.app.lock().await.data.radarr_data.add_list_exclusion;
@@ -369,7 +369,7 @@ impl<'a, 'b> Network<'a, 'b> {
.reset_delete_movie_preferences();
}
async fn delete_root_folder(&self) {
async fn delete_root_folder(&mut self) {
let root_folder_id = self
.app
.lock()
@@ -405,7 +405,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn download_release(&self) {
async fn download_release(&mut self) {
let (guid, title, indexer_id) = {
let app = self.app.lock().await;
let Release {
@@ -435,7 +435,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn edit_collection(&self) {
async fn edit_collection(&mut self) {
info!("Editing Radarr collection");
info!("Fetching collection details");
@@ -511,7 +511,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn edit_movie(&self) {
async fn edit_movie(&mut self) {
info!("Editing Radarr movie");
info!("Fetching movie details");
@@ -573,7 +573,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_collections(&self) {
async fn get_collections(&mut self) {
info!("Fetching Radarr collections");
let request_props = self
@@ -591,18 +591,14 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_credits(&self) {
async fn get_credits(&mut self) {
info!("Fetching Radarr movie credits");
let request_uri = self
.append_movie_id_param(RadarrEvent::GetMovieCredits.resource())
.await;
let request_props = self
.radarr_request_props_from(
self
.append_movie_id_param(RadarrEvent::GetMovieCredits.resource())
.await
.as_str(),
RequestMethod::Get,
None::<()>,
)
.radarr_request_props_from(request_uri.as_str(), RequestMethod::Get, None::<()>)
.await;
self
@@ -624,7 +620,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_diskspace(&self) {
async fn get_diskspace(&mut self) {
info!("Fetching Radarr disk space");
let request_props = self
@@ -642,7 +638,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_downloads(&self) {
async fn get_downloads(&mut self) {
info!("Fetching Radarr downloads");
let request_props = self
@@ -664,7 +660,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn get_indexers(&self) {
async fn get_indexers(&mut self) {
info!("Fetching Radarr indexers");
let request_props = self
@@ -682,7 +678,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn get_indexer_settings(&self) {
async fn get_indexer_settings(&mut self) {
info!("Fetching Radarr indexer settings");
let request_props = self
@@ -700,7 +696,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_healthcheck(&self) {
async fn get_healthcheck(&mut self) {
info!("Performing Radarr health check");
let request_props = self
@@ -716,7 +712,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_logs(&self) {
async fn get_logs(&mut self) {
info!("Fetching Radarr logs");
let resource = format!(
@@ -762,7 +758,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_movie_details(&self) {
async fn get_movie_details(&mut self) {
info!("Fetching Radarr movie details");
let movie_id = self.extract_movie_id().await;
@@ -918,18 +914,14 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_movie_history(&self) {
async fn get_movie_history(&mut self) {
info!("Fetching Radarr movie history");
let request_uri = self
.append_movie_id_param(RadarrEvent::GetMovieHistory.resource())
.await;
let request_props = self
.radarr_request_props_from(
self
.append_movie_id_param(RadarrEvent::GetMovieHistory.resource())
.await
.as_str(),
RequestMethod::Get,
None::<()>,
)
.radarr_request_props_from(request_uri.as_str(), RequestMethod::Get, None::<()>)
.await;
self
@@ -945,7 +937,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_movies(&self) {
async fn get_movies(&mut self) {
info!("Fetching Radarr library");
let request_props = self
@@ -963,7 +955,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_quality_profiles(&self) {
async fn get_quality_profiles(&mut self) {
info!("Fetching Radarr quality profiles");
let request_props = self
@@ -984,7 +976,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_queued_events(&self) {
async fn get_queued_events(&mut self) {
info!("Fetching Radarr queued events");
let request_props = self
@@ -1006,7 +998,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_releases(&self) {
async fn get_releases(&mut self) {
let movie_id = self.extract_movie_id().await;
info!("Fetching releases for movie with id: {}", movie_id);
@@ -1030,7 +1022,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_root_folders(&self) {
async fn get_root_folders(&mut self) {
info!("Fetching Radarr root folders");
let request_props = self
@@ -1048,7 +1040,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_status(&self) {
async fn get_status(&mut self) {
info!("Fetching Radarr system status");
let request_props = self
@@ -1067,7 +1059,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_tags(&self) {
async fn get_tags(&mut self) {
info!("Fetching Radarr tags");
let request_props = self
@@ -1088,7 +1080,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_tasks(&self) {
async fn get_tasks(&mut self) {
info!("Fetching Radarr tasks");
let request_props = self
@@ -1106,7 +1098,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn get_updates(&self) {
async fn get_updates(&mut self) {
info!("Fetching Radarr updates");
let request_props = self
@@ -1197,7 +1189,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn search_movie(&self) {
async fn search_movie(&mut self) {
info!("Searching for specific Radarr movie");
let search_string = self.app.lock().await.data.radarr_data.search.text.clone();
@@ -1229,7 +1221,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn start_task(&self) {
async fn start_task(&mut self) {
let task_name = self
.app
.lock()
@@ -1258,7 +1250,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn trigger_automatic_search(&self) {
async fn trigger_automatic_search(&mut self) {
let movie_id = self.extract_movie_id().await;
info!("Searching indexers for movie with id: {}", movie_id);
let body = MovieCommandBody {
@@ -1279,7 +1271,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn update_all_movies(&self) {
async fn update_all_movies(&mut self) {
info!("Updating all movies");
let body = MovieCommandBody {
name: "RefreshMovie".to_owned(),
@@ -1299,7 +1291,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn update_and_scan(&self) {
async fn update_and_scan(&mut self) {
let movie_id = self.extract_movie_id().await;
info!("Updating and scanning movie with id: {}", movie_id);
let body = MovieCommandBody {
@@ -1320,7 +1312,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn update_collections(&self) {
async fn update_collections(&mut self) {
info!("Updating collections");
let body = CommandBody {
name: "RefreshCollections".to_owned(),
@@ -1339,7 +1331,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn update_downloads(&self) {
async fn update_downloads(&mut self) {
info!("Updating downloads");
let body = CommandBody {
name: "RefreshMonitoredDownloads".to_owned(),
@@ -1358,7 +1350,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
}
async fn update_indexer_settings(&self) {
async fn update_indexer_settings(&mut self) {
info!("Updating Radarr indexer settings");
let body = self
@@ -1416,7 +1408,7 @@ impl<'a, 'b> Network<'a, 'b> {
}
}
async fn extract_quality_profile_id(&self) -> u64 {
async fn extract_quality_profile_id(&mut self) -> u64 {
let app = self.app.lock().await;
let quality_profile = app
.data
@@ -1434,7 +1426,7 @@ impl<'a, 'b> Network<'a, 'b> {
.unwrap()
}
async fn extract_and_add_tag_ids_vec(&self) -> Vec<u64> {
async fn extract_and_add_tag_ids_vec(&mut self) -> Vec<u64> {
let tags_map = self.app.lock().await.data.radarr_data.tags_map.clone();
let edit_tags = self.app.lock().await.data.radarr_data.edit_tags.drain();
let tags = edit_tags.clone();
@@ -1462,7 +1454,7 @@ impl<'a, 'b> Network<'a, 'b> {
.collect()
}
async fn extract_movie_id(&self) -> u64 {
async fn extract_movie_id(&mut self) -> u64 {
if !self
.app
.lock()
@@ -1499,7 +1491,7 @@ impl<'a, 'b> Network<'a, 'b> {
}
}
async fn extract_collection_id(&self) -> u64 {
async fn extract_collection_id(&mut self) -> u64 {
if !self
.app
.lock()
@@ -1536,7 +1528,7 @@ impl<'a, 'b> Network<'a, 'b> {
}
}
async fn append_movie_id_param(&self, resource: &str) -> String {
async fn append_movie_id_param(&mut self, resource: &str) -> String {
let movie_id = self.extract_movie_id().await;
format!("{}?movieId={}", resource, movie_id)
}
+50 -49
View File
@@ -10,6 +10,7 @@ mod test {
use serde_json::{json, Value};
use strum::IntoEnumIterator;
use tokio::sync::Mutex;
use tokio_util::sync::CancellationToken;
use crate::app::radarr::ActiveRadarrBlock;
use crate::models::radarr_models::{
@@ -194,7 +195,7 @@ mod test {
RadarrEvent::HealthCheck.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::HealthCheck).await;
@@ -219,7 +220,7 @@ mod test {
RadarrEvent::GetOverview.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetOverview).await;
@@ -251,7 +252,7 @@ mod test {
RadarrEvent::GetStatus.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetStatus).await;
@@ -273,7 +274,7 @@ mod test {
RadarrEvent::GetMovies.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetMovies).await;
@@ -311,7 +312,7 @@ mod test {
.radarr_data
.movies
.set_items(vec![movie()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetReleases).await;
@@ -357,7 +358,7 @@ mod test {
)
.await;
app_arc.lock().await.data.radarr_data.search = "test term".to_owned().into();
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::SearchNewMovie)
@@ -397,7 +398,7 @@ mod test {
task_name: "TestTask".to_owned(),
..Task::default()
}]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::StartTask).await;
@@ -413,7 +414,7 @@ mod test {
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Get, None, Some(json!([])), &resource).await;
app_arc.lock().await.data.radarr_data.search = "test term".to_owned().into();
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::SearchNewMovie)
@@ -453,7 +454,7 @@ mod test {
.radarr_data
.movies
.set_items(vec![movie()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::TriggerAutomaticSearch)
@@ -481,7 +482,7 @@ mod test {
.radarr_data
.movies
.set_items(vec![movie()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::UpdateAndScan)
@@ -502,7 +503,7 @@ mod test {
RadarrEvent::UpdateAllMovies.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::UpdateAllMovies)
@@ -522,7 +523,7 @@ mod test {
RadarrEvent::UpdateDownloads.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::UpdateDownloads)
@@ -553,7 +554,7 @@ mod test {
.await;
app_arc.lock().await.data.radarr_data.indexer_settings = Some(indexer_settings());
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::UpdateIndexerSettings)
@@ -580,7 +581,7 @@ mod test {
RadarrEvent::UpdateCollections.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::UpdateCollections)
@@ -608,7 +609,7 @@ mod test {
.set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.quality_profile_map =
BiMap::from_iter([(2222, "HD - 1080p".to_owned())]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetMovieDetails)
@@ -715,7 +716,7 @@ mod test {
.set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.quality_profile_map =
BiMap::from_iter([(2222, "HD - 1080p".to_owned())]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetMovieDetails)
@@ -795,7 +796,7 @@ mod test {
.radarr_data
.movies
.set_items(vec![movie()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetMovieHistory)
@@ -846,7 +847,7 @@ mod test {
RadarrEvent::GetCollections.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetCollections)
@@ -881,7 +882,7 @@ mod test {
RadarrEvent::GetDownloads.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetDownloads).await;
@@ -946,7 +947,7 @@ mod test {
RadarrEvent::GetIndexers.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetIndexers).await;
@@ -977,7 +978,7 @@ mod test {
RadarrEvent::GetIndexerSettings.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetIndexerSettings)
@@ -1021,7 +1022,7 @@ mod test {
RadarrEvent::GetQueuedEvents.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetQueuedEvents)
@@ -1076,7 +1077,7 @@ mod test {
&resource,
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetLogs).await;
@@ -1109,7 +1110,7 @@ mod test {
RadarrEvent::GetQualityProfiles.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetQualityProfiles)
@@ -1135,7 +1136,7 @@ mod test {
RadarrEvent::GetTags.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetTags).await;
@@ -1190,7 +1191,7 @@ mod test {
RadarrEvent::GetTasks.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetTasks).await;
@@ -1279,7 +1280,7 @@ mod test {
RadarrEvent::GetUpdates.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::GetUpdates).await;
@@ -1301,7 +1302,7 @@ mod test {
.await;
app_arc.lock().await.data.radarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.add_tag("testing".to_owned()).await;
@@ -1331,7 +1332,7 @@ mod test {
RadarrEvent::GetRootFolders.resource(),
)
.await;
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetRootFolders)
@@ -1369,7 +1370,7 @@ mod test {
.radarr_data
.movies
.set_items(vec![movie()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::GetMovieCredits)
@@ -1400,7 +1401,7 @@ mod test {
app.data.radarr_data.delete_movie_files = true;
app.data.radarr_data.add_list_exclusion = true;
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::DeleteMovie).await;
@@ -1421,7 +1422,7 @@ mod test {
.radarr_data
.downloads
.set_items(vec![download_record()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::DeleteDownload)
@@ -1442,7 +1443,7 @@ mod test {
.radarr_data
.indexers
.set_items(vec![indexer()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::DeleteIndexer)
@@ -1463,7 +1464,7 @@ mod test {
.radarr_data
.root_folders
.set_items(vec![root_folder()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::DeleteRootFolder)
@@ -1548,7 +1549,7 @@ mod test {
.set_items(vec![add_movie_search_result()]);
}
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::AddMovie).await;
@@ -1568,7 +1569,7 @@ mod test {
.await;
app_arc.lock().await.data.radarr_data.edit_path = HorizontallyScrollableText::from("/nfs/test");
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::AddRootFolder)
@@ -1636,7 +1637,7 @@ mod test {
app.data.radarr_data.quality_profile_map =
BiMap::from_iter([(1111, "Any".to_owned()), (2222, "HD - 1080p".to_owned())]);
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network.handle_radarr_event(RadarrEvent::EditMovie).await;
@@ -1731,7 +1732,7 @@ mod test {
app.data.radarr_data.quality_profile_map =
BiMap::from_iter([(1111, "Any".to_owned()), (2222, "HD - 1080p".to_owned())]);
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::EditCollection)
@@ -1765,7 +1766,7 @@ mod test {
.radarr_data
.movie_releases
.set_items(vec![release()]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
network
.handle_radarr_event(RadarrEvent::DownloadRelease)
@@ -1787,7 +1788,7 @@ mod test {
app.data.radarr_data.quality_profile_map =
BiMap::from_iter([(1, "Any".to_owned()), (2, "HD - 1080p".to_owned())]);
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_eq!(network.extract_quality_profile_id().await, 1);
}
@@ -1804,7 +1805,7 @@ mod test {
(3, "hi".to_owned()),
]);
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_eq!(network.extract_and_add_tag_ids_vec().await, vec![2, 3, 1]);
}
@@ -1824,7 +1825,7 @@ mod test {
app.data.radarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]);
}
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
let tag_ids_vec = network.extract_and_add_tag_ids_vec().await;
@@ -1853,7 +1854,7 @@ mod test {
id: Number::from(1),
..Movie::default()
}]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_eq!(network.extract_movie_id().await, 1);
}
@@ -1871,7 +1872,7 @@ mod test {
id: Number::from(1),
..Movie::default()
}]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_eq!(network.extract_movie_id().await, 1);
}
@@ -1889,7 +1890,7 @@ mod test {
id: Number::from(1),
..Collection::default()
}]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_eq!(network.extract_collection_id().await, 1);
}
@@ -1907,7 +1908,7 @@ mod test {
id: Number::from(1),
..Collection::default()
}]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_eq!(network.extract_collection_id().await, 1);
}
@@ -1925,7 +1926,7 @@ mod test {
id: Number::from(1),
..Movie::default()
}]);
let network = Network::new(&app_arc);
let mut network = Network::new(&app_arc, CancellationToken::new());
assert_str_eq!(
network.append_movie_id_param("/test").await,
@@ -1936,7 +1937,7 @@ mod test {
#[tokio::test]
async fn test_radarr_request_props_from_default_radarr_config() {
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc);
let network = Network::new(&app_arc, CancellationToken::new());
let request_props = network
.radarr_request_props_from("/test", RequestMethod::Get, None::<()>)
@@ -1963,7 +1964,7 @@ mod test {
port: Some(8080),
api_token: api_token.clone(),
};
let network = Network::new(&app_arc);
let network = Network::new(&app_arc, CancellationToken::new());
let request_props = network
.radarr_request_props_from("/test", RequestMethod::Get, None::<()>)