pub mod config;
pub mod conn;
pub mod contacts;
pub mod delete;
pub mod folders;
pub mod get;
pub mod hub;
pub mod list;
pub mod send;
pub mod spoke;
pub mod threads;
pub mod watch;
pub mod watch_hub;
use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::cli::{Cli, Command, ConfigCmd, SpokeCmd};
use crate::output;
use crate::progress::with_spinner;
pub(crate) async fn dispatch(cli: Cli) -> Result<()> {
let Cli { hub, device, config: config_path, command, .. } = cli;
let spoke = if hub {
Some(transport::iroh::bind_spoke().await.context("binding iroh spoke endpoint")?)
} else {
None
};
let result = run_command(command, spoke.as_ref(), device.as_deref(), config_path).await;
if let Some(ep) = &spoke {
ep.close().await;
}
(result?).map_or_else(|| Ok(()), |out| output::line(&out))
}
async fn run_command(
command: Command,
spoke: Option<&transport::iroh::Endpoint>,
device: Option<&str>,
config_path: Option<PathBuf>,
) -> Result<Option<String>> {
let out = match command {
Command::Config { cmd } => Some(match cmd {
ConfigCmd::Show => config::run_show(config_path)?,
ConfigCmd::SetDevice { address } => config::run_set_device(&address)?,
}),
Command::Hub => {
let cfg = load(config_path)?;
hub::run(&cfg).await?;
None
}
Command::Spoke { cmd } => Some(match cmd {
SpokeCmd::Add { key } => spoke::run_add(&key).await?,
}),
Command::List { folder, unread, long, from, since, limit, offset } => {
let cfg = load(config_path)?;
let filter = list::build_filter(unread, from, since, limit, offset);
Some(
with_spinner("listing", list::run(&cfg, spoke, device, folder, filter, long))
.await?,
)
}
Command::Folders => {
let cfg = load(config_path)?;
Some(with_spinner("folders", folders::run(&cfg, spoke, device)).await?)
}
Command::Get { handle, folder, mark_read } => {
let cfg = load(config_path)?;
Some(
with_spinner("fetching", get::run(&cfg, spoke, device, handle, folder, mark_read))
.await?,
)
}
Command::Delete { handle, folder, undelete } => {
let cfg = load(config_path)?;
Some(
with_spinner(
"deleting",
delete::run(&cfg, spoke, device, handle, folder, undelete),
)
.await?,
)
}
Command::Send { number, message } => {
let cfg = load(config_path)?;
Some(with_spinner("sending", send::run(&cfg, spoke, device, number, message)).await?)
}
Command::Contacts { list, get, lookup, path, raw, limit, page } => {
let cfg = load(config_path)?;
Some(
with_spinner(
"contacts",
contacts::run(
&cfg,
spoke,
device,
contacts::ContactsOpts { list, get, lookup, path, raw, limit, page },
),
)
.await?,
)
}
Command::Threads => {
let cfg = load(config_path)?;
Some(with_spinner("threads", threads::run(&cfg, spoke, device)).await?)
}
Command::Watch => {
let cfg = load(config_path)?;
watch::run(&cfg, spoke, device).await?;
None
}
};
Ok(out)
}
fn load(path: Option<PathBuf>) -> Result<::config::Config> {
::config::load(path)
.context("loading config (run `imsg config set-device <ADDR>` if device.address is unset)")
}