From 62011b4b81caf2ad4c2a329101329071f3f910b0 Mon Sep 17 00:00:00 2001 From: VC Date: Mon, 7 Nov 2022 21:24:37 +0100 Subject: [PATCH] refactor: downloads/uploads every media from a tweet async way --- src/util.rs | 88 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/src/util.rs b/src/util.rs index 8aa34a8..af25269 100644 --- a/src/util.rs +++ b/src/util.rs @@ -15,45 +15,73 @@ pub async fn generate_media_ids( cache_path: &str, mastodon: &Mastodon, ) -> (String, Vec) { + let mut media_url = "".to_string(); let mut media_ids: Vec = vec![]; - let mut media_url: String = "".to_string(); if let Some(m) = &tweet.extended_entities { - for media in &m.media { - // attribute the media url + // create tasks list + let mut tasks = vec![]; + + // size of media_ids vector, should be equal to the media vector + media_ids.resize(m.media.len(), String::new()); + + for (i, media) in m.media.iter().enumerate() { + // attribute media url media_url = media.url.clone(); - let local_tweet_media_path = match get_tweet_media(media, cache_path).await { - Ok(m) => m, - Err(e) => { - error!("Cannot get tweet media for {}: {}", &media.url, e); - continue; - } - }; - let mastodon_media_ids = match mastodon - .media(Cow::from(local_tweet_media_path.to_owned())) - { - Ok(m) => { - remove_file(&local_tweet_media_path).await.unwrap_or_else(|e| - warn!("Attachment for {} has been uploaded, but I’m unable to remove the existing file: {}", &local_tweet_media_path, e)); - m.id - } - Err(e) => { - error!( - "Attachment {} cannot be uploaded to Mastodon Instance: {}", - &local_tweet_media_path, e - ); - // file is no longer useful, deleting - remove_file(&local_tweet_media_path).await.unwrap_or_else(|e| - warn!("Attachment for {} has been uploaded, but I’m unable to remove the existing file: {}", &local_tweet_media_path, e)); - continue; - } - }; + // clone everything we need + let cache_path = String::from(cache_path); + let media = media.clone(); + let mastodon = mastodon.clone(); - media_ids.push(mastodon_media_ids); + let task = tokio::task::spawn(async move { + // get the tweet embedded media + let local_tweet_media_path = match get_tweet_media(&media, &cache_path).await { + Ok(l) => l, + Err(e) => { + return Err(ScootalooError::new(&format!( + "Cannot get tweet media for {}: {}", + &media.url, e + ))) + } + }; + + // upload media to Mastodon + let mastodon_media = + match mastodon.media(Cow::from(local_tweet_media_path.to_owned())) { + Ok(l) => l, + Err(e) => { + return Err(ScootalooError::new(&format!( + "Attachment {} cannot be uploaded to Mastodon Instance: {}", + &local_tweet_media_path, e + ))) + } + }; + + // at this point, we can safely erase the original file + if let Err(e) = remove_file(&local_tweet_media_path).await { + ScootalooError::new(&format!("Attachment {} has been uploaded but I’m unable to remove the existing file: {}", &local_tweet_media_path, e)); + } + + Ok((i, mastodon_media.id)) + }); + + tasks.push(task); + } + + for task in tasks { + match task.await { + // insert the media at the right place + Ok(Ok((i, v))) => media_ids[i] = v, + Ok(Err(e)) => warn!("{}", e), + Err(e) => error!("Something went wrong when joining the main thread: {}", e), + } } } + // in case some media_ids slot remained empty due to errors, remove them + media_ids.retain(|x| !x.is_empty()); + (media_url, media_ids) }