From 9c52da41c037aaa5ee0242fb20b73f87fe462e75 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Tue, 31 Dec 2024 09:12:33 +0000 Subject: [PATCH] fix: Import*Actor shutsdown properly on error closes kemitix/trello-to-deck#6 --- src/import/attachment.rs | 112 ++++++++++++++++++++------------------- src/import/card.rs | 16 ++++-- src/import/label.rs | 21 +++++--- src/import/stack.rs | 10 +++- 4 files changed, 92 insertions(+), 67 deletions(-) diff --git a/src/import/attachment.rs b/src/import/attachment.rs index 3a45183..30dd7e0 100644 --- a/src/import/attachment.rs +++ b/src/import/attachment.rs @@ -1,15 +1,17 @@ -use color_eyre::eyre::Context; // -use crate::import::rate_limit::{RateLimitActor, RequestToken}; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Context; +use kameo::{actor::ActorRef, mailbox::unbounded::UnboundedMailbox, Actor}; + use crate::{ - ask, e, f, - nextcloud::model::{NextcloudBoardId, NextcloudCardId, NextcloudStackId}, + ask, f, + import::rate_limit::{RateLimitActor, RequestToken}, + nextcloud::model::{Attachment, NextcloudBoardId, NextcloudCardId, NextcloudStackId}, on_actor_start, p, trello::model::{attachment::TrelloAttachment, card::TrelloCardId}, FullCtx, }; -use kameo::actor::ActorRef; -use kameo::{mailbox::unbounded::UnboundedMailbox, Actor}; pub(crate) struct ImportAttachmentActor { ctx: FullCtx, @@ -40,6 +42,39 @@ impl ImportAttachmentActor { rate_limit_actor, } } + + async fn import_attachment(&self, file_name: &Path) -> color_eyre::Result { + let temp_fs = kxio::fs::temp()?; + let file_path = temp_fs.base().join(file_name); + + // - - - download the attachment from trello + ask!(self.rate_limit_actor, RequestToken)?; + let attachment_path = self + .ctx + .trello_client() + .save_attachment( + &self.trello_card_id, + &self.trello_attachment.id, + Some(&file_path), + &temp_fs, + ) + .await + .with_context(|| f!("saving attachment {}", file_path.display()))?; + + // - - - upload the attachment to nextcloud card + tracing::info!("Nextcloud: upload attachment"); + self.ctx + .deck_client() + .add_attachment_to_card( + self.nextcloud_board_id, + self.nextcloud_stack_id, + self.nextcloud_card_id, + &temp_fs.file(&attachment_path), + ) + .await + .result + .with_context(|| f!("adding attachment to card {}", file_path.display())) + } } impl Actor for ImportAttachmentActor { type Mailbox = UnboundedMailbox; @@ -50,61 +85,28 @@ impl Actor for ImportAttachmentActor { ">> Adding attachment: {}", this.trello_attachment.name ); - // - - - download the attachment from trello let file_name = f!( "{}-{}", this.trello_attachment.id, this.trello_attachment.name ); - let file_path = this.ctx.temp_fs.base().join(&file_name); - ask!(this.rate_limit_actor, RequestToken)?; // FIXME: (#6) handle error - let attachment_path = this - .ctx - .trello_client() - .save_attachment( - &this.trello_card_id, - &this.trello_attachment.id, - Some(&file_path), - &this.ctx.temp_fs, - ) - .await - .with_context(|| f!("saving attachment {}", file_path.display()))?; // FIXME: (#6) handle error - let attachment_file = this.ctx.temp_fs.file(&attachment_path); - // - - - upload the attachment to nextcloud card - tracing::info!("Nextcloud: upload attachment"); - let attachment = this - .ctx - .deck_client() - .add_attachment_to_card( - this.nextcloud_board_id, - this.nextcloud_stack_id, - this.nextcloud_card_id, - &attachment_file, - ) - .await - .result - .inspect_err(|e| { - e!( - this.ctx.prt, - ">> Error adding attachment {} to card: {}", - file_path.display(), - e.to_string() - ); - }) - .with_context(|| f!("adding attachment to card {}", file_path.display()))?; // FIXME: (#6) handle error - p!( - this.ctx.prt, - ">> Attachment added: {}:{}", - attachment.id, - attachment.attachment_type, - // attachment.extended_data.mimetype - ); - // delete local copy of attachment - attachment_file - .remove() - .with_context(|| f!("deleting temp file {attachment_file}"))?; // FIXME: (#6) handle error - tracing::info!("ImportAttachmentActor finished"); + match this.import_attachment(&PathBuf::from(file_name)).await { + Ok(attachment) => { + p!( + this.ctx.prt, + ">> Attachment added: {}:{}", + attachment.id, + attachment.attachment_type, + // attachment.extended_data.mimetype + ); + tracing::info!("ImportAttachmentActor finished"); + } + Err(err) => { + tracing::error!(?err); + } + } + Ok(actor_ref.stop_gracefully().await?) }); } diff --git a/src/import/card.rs b/src/import/card.rs index 9b5dd4d..202dd40 100644 --- a/src/import/card.rs +++ b/src/import/card.rs @@ -73,8 +73,9 @@ impl Actor for ImportCardActor { 0 => None, _ => Some(NextcloudCardDescription::from(&this.trello_card.desc)), }; + tracing::info!("Nextcloud: Create card"); - let nextcloud_card = this + let nextcloud_card_id = match this .ctx .deck_client() .create_card( @@ -84,7 +85,14 @@ impl Actor for ImportCardActor { desc.as_ref(), ) .await - .result?; // FIXME: (#6) handle error + .result + { + Ok(card) => card.id, + Err(err) => { + tracing::error!(?err); + return Ok(actor_ref.stop_gracefully().await?); + } + }; let mut limit = RateLimit::new("labels & attachments", 10, 10.0, this.ctx.now()); @@ -101,7 +109,7 @@ impl Actor for ImportCardActor { this.ctx.clone(), this.nextcloud_board_id, this.nextcloud_stack_id, - nextcloud_card.id, + nextcloud_card_id, trello_label, this.labels_actor_ref.clone(), ) @@ -129,7 +137,7 @@ impl Actor for ImportCardActor { this.ctx.clone(), this.nextcloud_board_id, this.nextcloud_stack_id, - nextcloud_card.id, + nextcloud_card_id, this.trello_card.id.clone(), trello_attachment, this.rate_limit_actor.clone(), diff --git a/src/import/label.rs b/src/import/label.rs index dc51b3d..3e1e880 100644 --- a/src/import/label.rs +++ b/src/import/label.rs @@ -41,17 +41,24 @@ impl Actor for ImportLabelActor { type Mailbox = UnboundedMailbox; on_actor_start!(this, actor_ref, { - let label_id = ask!( + let label_id = match ask!( this.labels_actor_ref, labels::LookupNextcloudLabelId { trello_name: this.trello_label.name.clone(), trello_color: this.trello_label.color.clone() } - )?; // FIXME: (#6) handle error + ) { + Ok(label_id) => label_id, + Err(err) => { + tracing::error!(?err); + return Ok(actor_ref.stop_gracefully().await?); + } + }; // - - - add the label to the nextcloud card tracing::info!("Nextcloud: add label to card"); - this.ctx + match this + .ctx .deck_client() .add_label_to_card( this.nextcloud_board_id, @@ -60,9 +67,11 @@ impl Actor for ImportLabelActor { label_id, ) .await - .result?; // FIXME: (#6) handle error - - tracing::info!("ImportLabelActor finished"); + .result + { + Ok(_) => tracing::info!("ImportLabelActor finished"), + Err(err) => tracing::error!(?err), + } Ok(actor_ref.stop_gracefully().await?) }); } diff --git a/src/import/stack.rs b/src/import/stack.rs index 48ebf48..46baccd 100644 --- a/src/import/stack.rs +++ b/src/import/stack.rs @@ -62,7 +62,10 @@ impl Actor for ImportStackActor { crate::p!(this.ctx.prt, "Importing stack: {}", this.trello_stack.name); // - get the list of trello cards in the stack - ask!(this.rate_limit_actor, RequestToken)?; // FIXME: (#6) handle error + if let Err(err) = ask!(this.rate_limit_actor, RequestToken) { + tracing::error!(?err); + return Ok(actor_ref.stop_gracefully().await?); + } let mut trello_cards = trello_client .list_cards(&TrelloListId::new(this.trello_stack.id.as_ref())) .await @@ -75,7 +78,10 @@ impl Actor for ImportStackActor { // - for each card in the trello stack for trello_card in trello_cards.into_iter() { limit.block_until_token_available(this.ctx.now()).await; - ask!(this.rate_limit_actor, RequestToken)?; // FIXME: (#6) handle error + if let Err(err) = ask!(this.rate_limit_actor, RequestToken) { + tracing::error!(?err); + return Ok(actor_ref.stop_gracefully().await?); + } let trello_card_name = trello_card.name.clone(); let child: ActorRef = spawn_in_thread!( actor_ref.clone(),