skytool 0.1.0-pre.2

an experimental API client for BlueSky / ATProto
Documentation
use crate::options::agent::AgentOptions;
use bsky_sdk::{
  agent::config::{Config, FileStore},
  BskyAgent,
};
use camino::Utf8PathBuf;
use iri_string::types::UriAbsoluteString;
use keyring::Entry;

pub(crate) mod api;
pub(crate) mod flow;

#[derive(Debug, thiserror::Error, miette::Diagnostic)]
#[error(transparent)]
pub(crate) enum Error {
  BlueSky(#[from] bsky_sdk::Error),
  Api(#[from] api::Error),
  Flow(#[from] flow::Error),
  #[error("missing authority")]
  MissingAuthority,
  #[error("missing password")]
  MissingPassword,
  Keyring(#[from] keyring::Error),
  Json(#[from] serde_json::Error),
  Yaml(#[from] serde_yml::Error),
  Io(#[from] std::io::Error),
}

#[derive(Debug, Clone, clap::Parser)]
#[command(arg_required_else_help = true, about = "online operations")]
pub(crate) struct Command {
  #[command(flatten)]
  agent: AgentOptions,
  #[command(subcommand)]
  subcommand: Option<Subcommand>,
}

#[derive(Debug, Clone, clap::Subcommand)]
pub(crate) enum Subcommand {
  #[command(subcommand)]
  Api(api::FlatCommand),
  #[command(subcommand)]
  Flow(flow::Command),
}

impl Command {
  pub(crate) async fn run(self) -> Result<Box<dyn crate::Output>, Error> {
    let Self { agent, subcommand } = self;

    let json = match subcommand {
      None => String::from("{}"),
      Some(command) => {
        let output = match command {
          Subcommand::Api(command) => {
            let loader = FileStore::from(agent.config.file);
            let config = Config::load(&loader).await?;
            let agent = BskyAgent::builder().config(config).build().await?;
            command.with(&agent).await?
          }
          Subcommand::Flow(command) => command.run(agent).await?,
        };
        serde_json::to_string_pretty(&output)?
      }
    };

    println!("{json}");

    Ok(Box::new(()))
  }
}