fix: Import*Actor shutsdown properly on error
Some checks failed
Test / build (map[name:stable]) (push) Successful in 4m25s
Test / build (map[name:nightly]) (push) Successful in 4m34s
Release Please / Release-plz (push) Failing after 1m0s

closes kemitix/trello-to-deck#6
This commit is contained in:
Paul Campbell 2024-12-31 09:12:33 +00:00
parent 6e7244e1e4
commit 9c52da41c0
4 changed files with 92 additions and 67 deletions

View file

@ -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<Attachment> {
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<Self>;
@ -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?)
});
}

View file

@ -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(),

View file

@ -41,17 +41,24 @@ impl Actor for ImportLabelActor {
type Mailbox = UnboundedMailbox<Self>;
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?)
});
}

View file

@ -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<ImportCardActor> = spawn_in_thread!(
actor_ref.clone(),