netsky 0.2.0

netsky CLI: the viable system launcher and subcommand dispatcher
Documentation
use clap::Subcommand;

#[derive(Subcommand, Debug)]
#[command(subcommand_required = true, arg_required_else_help = true)]
pub enum ImessageCommand {
    Send {
        #[arg(long, conflicts_with = "owner")]
        chat: Option<String>,
        #[arg(long, conflicts_with = "chat")]
        owner: bool,
        text: String,
    },
    #[command(name = "ls", visible_alias = "list")]
    List {
        #[arg(long, default_value_t = 20)]
        limit: usize,
    },
    Read {
        #[arg(long)]
        chat: String,
    },
}

pub fn run(cmd: ImessageCommand) -> netsky_core::Result<()> {
    match cmd {
        ImessageCommand::Send { chat, owner, text } => send(chat.as_deref(), owner, &text),
        ImessageCommand::List { limit } => list(limit),
        ImessageCommand::Read { chat } => read(&chat),
    }
}

fn send(chat: Option<&str>, owner: bool, text: &str) -> netsky_core::Result<()> {
    let chat_id = match (chat, owner) {
        (Some(chat_id), false) => chat_id.to_string(),
        (None, true) => netsky_channels::imessage::access::load()
            .self_
            .chat_id
            .ok_or_else(|| netsky_core::Error::Message("self.chat_id is unset".to_string()))?,
        _ => {
            return Err(netsky_core::Error::Message(
                "pass exactly one of --chat or --owner".to_string(),
            ));
        }
    };
    netsky_channels::imessage::send::send_text(&chat_id, text)
        .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    println!("sent: {chat_id}");
    Ok(())
}

fn list(limit: usize) -> netsky_core::Result<()> {
    let conn = netsky_channels::imessage::db::open()
        .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    let access = netsky_channels::imessage::access::load();
    let mut self_handles = netsky_channels::imessage::db::self_handles(&conn)
        .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    for handle in &access.self_.handles {
        self_handles.insert(handle.to_lowercase());
    }
    let chats =
        netsky_channels::imessage::db::list_recent_chats(&conn, &access, &self_handles, limit)
            .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    println!(
        "{}",
        serde_json::to_string_pretty(&chats)
            .map_err(|e| netsky_core::Error::Message(e.to_string()))?
    );
    Ok(())
}

fn read(chat: &str) -> netsky_core::Result<()> {
    let conn = netsky_channels::imessage::db::open()
        .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    let access = netsky_channels::imessage::access::load();
    let mut self_handles = netsky_channels::imessage::db::self_handles(&conn)
        .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    for handle in &access.self_.handles {
        self_handles.insert(handle.to_lowercase());
    }
    let messages =
        netsky_channels::imessage::db::read_chat(&conn, &access, &self_handles, chat, 20)
            .map_err(|e| netsky_core::Error::Message(e.to_string()))?;
    println!(
        "{}",
        serde_json::to_string_pretty(&messages)
            .map_err(|e| netsky_core::Error::Message(e.to_string()))?
    );
    Ok(())
}