use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
use enigmatick::models::activities::NewActivity;
use enigmatick::models::actors as actor_model_ops;
use enigmatick::runner::{get_inboxes, send_to_inboxes};
use jdt_activity_pub::{ApActivity, ApActor, ApDelete, ApUpdate};
#[derive(Parser)]
pub struct SendArgs {
#[command(subcommand)]
pub command: SendCommands,
}
#[derive(Subcommand)]
pub enum SendCommands {
Update(UpdateArgs),
Delete(DeleteArgs),
}
#[derive(Parser)]
pub struct UpdateArgs {
#[command(subcommand)]
pub command: UpdateCommands,
}
#[derive(Subcommand)]
pub enum UpdateCommands {
Actor { username: String },
}
#[derive(Parser)]
pub struct DeleteArgs {
#[command(subcommand)]
pub command: DeleteCommands,
}
#[derive(Subcommand)]
pub enum DeleteCommands {
Actor { username: String },
}
pub async fn handle_send_command(args: SendArgs) -> Result<()> {
match args.command {
SendCommands::Update(update_args) => handle_update_command(update_args).await,
SendCommands::Delete(delete_args) => handle_delete_command(delete_args).await,
}
}
async fn handle_update_command(args: UpdateArgs) -> Result<()> {
match args.command {
UpdateCommands::Actor { username } => {
println!("Attempting to send actor update for user: {username}...");
match execute_send_actor_update(username).await {
Ok(_) => println!("Successfully processed sending of actor update."),
Err(e) => eprintln!("Error sending actor update: {e:?}"),
};
}
}
Ok(())
}
async fn execute_send_actor_delete(username: String) -> Result<()> {
let conn = enigmatick::db::POOL.get().await?;
let actor_record = actor_model_ops::get_actor_by_username(&conn, username.clone()).await?;
let ap_actor_to_delete: ApActor = ApActor::from(actor_record.clone());
let mut delete_ap_object =
ApDelete::try_from(ap_actor_to_delete).map_err(anyhow::Error::msg)?;
let delete_activity = ApActivity::Delete(Box::new(delete_ap_object.clone()));
let new_activity_to_save =
NewActivity::try_from((delete_activity.clone(), Some(actor_record.clone().into())))?;
let save_activity_result =
enigmatick::models::activities::create_activity(&conn, new_activity_to_save).await?;
delete_ap_object.id = Some(
save_activity_result
.ap_id
.ok_or(anyhow!("CLI: Saved Activity does not have an ID."))?,
);
println!("CLI: Successfully saved Delete activity for '{username}' locally.");
let delivery_inboxes = get_inboxes(&conn, delete_activity.clone(), actor_record.clone()).await;
if delivery_inboxes.is_empty() {
println!("CLI: No active instance inboxes found to send the delete to.");
return Ok(());
}
println!(
"CLI: Preparing to send actor delete for '{}' to {} instance inboxes.",
username,
delivery_inboxes.len()
);
let delete_activity = ApActivity::Delete(Box::new(delete_ap_object.clone()));
match send_to_inboxes(
&conn,
delivery_inboxes,
actor_record.clone(),
delete_activity,
)
.await
{
Ok(_) => {
println!(
"CLI: Actor delete for '{username}' has been successfully queued for sending to instance inboxes."
);
if enigmatick::models::actors::tombstone_actor_by_as_id(&conn, actor_record.as_id)
.await
.is_ok()
{
println!(
"CLI: Actor delete for '{username}' has been successfully executed locally."
);
}
}
Err(e) => eprintln!("CLI: Error queueing actor delete for '{username}' for sending: {e:?}"),
}
Ok(())
}
async fn handle_delete_command(args: DeleteArgs) -> Result<()> {
match args.command {
DeleteCommands::Actor { username } => {
println!("Attempting to send actor delete for user: {username}...");
match execute_send_actor_delete(username).await {
Ok(_) => println!("Successfully processed sending of actor delete."),
Err(e) => eprintln!("Error sending actor delete: {e:?}"),
};
}
}
Ok(())
}
async fn execute_send_actor_update(username: String) -> Result<()> {
let conn = enigmatick::db::POOL.get().await?;
let actor_record = actor_model_ops::get_actor_by_username(&conn, username.clone()).await?;
let ap_actor_to_update: ApActor = ApActor::from(actor_record.clone());
let mut update_ap_object =
ApUpdate::try_from(ap_actor_to_update).map_err(anyhow::Error::msg)?;
let update_activity = ApActivity::Update(update_ap_object.clone());
let new_activity_to_save =
NewActivity::try_from((update_activity.clone(), Some(actor_record.clone().into())))?;
let save_activity_result =
enigmatick::models::activities::create_activity(&conn, new_activity_to_save).await;
match save_activity_result {
Ok(activity) => {
update_ap_object.id = Some(
activity
.ap_id
.ok_or(anyhow!("CLI: Saved Activity does not have an ID."))?,
);
println!("CLI: Successfully saved Update activity for '{username}' locally.")
}
Err(e) => eprintln!("CLI: Failed to save Update activity for '{username}' locally: {e:?}"),
}
let delivery_inboxes = get_inboxes(&conn, update_activity.clone(), actor_record.clone()).await;
if delivery_inboxes.is_empty() {
println!("CLI: No active instance inboxes found to send the update to.");
return Ok(());
}
println!(
"CLI: Preparing to send actor update for '{}' to {} instance inboxes.",
username,
delivery_inboxes.len()
);
let update_activity = ApActivity::Update(update_ap_object.clone());
match send_to_inboxes(&conn, delivery_inboxes, actor_record, update_activity).await {
Ok(_) => println!(
"CLI: Actor update for '{username}' has been successfully queued for sending to instance inboxes."
),
Err(e) => eprintln!(
"CLI: Error queueing actor update for '{username}' for sending: {e:?}"
),
}
Ok(())
}