use anyhow::Result;
use clap::{CommandFactory, Parser, Subcommand};
use grr_core::prelude::*;
use grr_gmail::prelude::*;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
mod commands;
mod output;
use commands::{
auth, calendar, chat, contacts, drafts, drive, forms, history, import, labels, message_ops,
messages, profile, schema, send, send_as, thread_ops, transport, watch,
};
#[derive(Parser)]
#[command(
name = "grr",
version,
about = "Google tools from the terminal, at maximum performance"
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
#[command(subcommand, subcommand_required = true)]
Auth(auth::AuthCommands),
#[command(subcommand)]
Gmail(GmailCommands),
#[command(subcommand)]
Calendar(calendar::CalendarCommands),
#[command(subcommand)]
Drive(drive::DriveCommands),
#[command(subcommand)]
Contacts(contacts::ContactsCommands),
#[command(subcommand)]
Chat(chat::ChatCommands),
#[command(subcommand)]
Forms(forms::FormsCommands),
Transport(transport::TransportArgs),
Schema(schema::SchemaArgs),
}
#[derive(Subcommand)]
enum GmailCommands {
#[command(subcommand)]
Message(messages::MessageCommands),
#[command(subcommand)]
Label(labels::LabelCommands),
#[command(subcommand)]
Draft(drafts::DraftCommands),
#[command(subcommand)]
Send(send::SendCommands),
#[command(subcommand)]
Thread(thread_ops::ThreadCommands),
History(history::HistoryArgs),
#[command(subcommand)]
SendAs(send_as::SendAsCommands),
Profile(profile::ProfileArgs),
#[command(subcommand)]
Watch(watch::WatchCommands),
Import(import::ImportArgs),
#[command(subcommand)]
Msg(message_ops::MessageOpsCommands),
}
async fn build_auth(config: &GrrConfig) -> Result<GoogleAuth> {
Ok(AuthConfigBuilder::new()
.client_id(config.oauth.client_id.clone())
.client_secret(config.oauth.client_secret.clone())
.build()
.await?)
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::registry()
.with(tracing_subscriber::EnvFilter::new(
std::env::var("RUST_LOG").unwrap_or_else(|_| "info,quinn_udp=error".into()),
))
.with(tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
.init();
let cli = Cli::parse();
if let Commands::Schema(args) = &cli.command {
commands::schema::handle_schema_cmd(Cli::command(), args.clone())?;
return Ok(());
}
let config = ConfigLoader::load().await?;
let needs_gmail = matches!(
cli.command,
Commands::Auth(_) | Commands::Gmail(_) | Commands::Transport(_)
);
let gmail_client = if needs_gmail {
let auth = build_auth(&config).await?;
Some(GmailClientBuilder::new().auth(auth).build().await?)
} else {
None
};
match cli.command {
Commands::Schema(_) => unreachable!("schema handled before client construction"),
Commands::Auth(cmd) => {
let client = gmail_client.as_ref().expect("built for auth");
commands::auth::handle_auth_cmd(client, cmd).await?
}
Commands::Gmail(cmd) => {
let client = gmail_client.as_ref().expect("built for gmail");
match cmd {
GmailCommands::Message(cmd) => {
commands::messages::handle_message_cmd(client, cmd).await?
}
GmailCommands::Label(cmd) => {
commands::labels::handle_label_cmd(client, cmd).await?
}
GmailCommands::Draft(cmd) => {
commands::drafts::handle_draft_cmd(client, cmd).await?
}
GmailCommands::Send(cmd) => commands::send::handle_send_cmd(client, cmd).await?,
GmailCommands::Thread(cmd) => {
commands::thread_ops::handle_thread_cmd(client, cmd).await?
}
GmailCommands::History(args) => {
commands::history::handle_history_cmd(client, args).await?
}
GmailCommands::SendAs(cmd) => {
commands::send_as::handle_send_as_cmd(client, cmd).await?
}
GmailCommands::Profile(args) => {
commands::profile::handle_profile_cmd(client, args).await?
}
GmailCommands::Watch(cmd) => commands::watch::handle_watch_cmd(client, cmd).await?,
GmailCommands::Import(args) => {
commands::import::handle_import_cmd(client, args).await?
}
GmailCommands::Msg(cmd) => {
commands::message_ops::handle_message_ops_cmd(client, cmd).await?
}
}
}
Commands::Calendar(cmd) => {
let auth = build_auth(&config).await?;
let client = grr_calendar::CalendarClientBuilder::new()
.auth(auth)
.build()
.await?;
commands::calendar::handle_calendar_cmd(&client, cmd).await?
}
Commands::Drive(cmd) => {
let auth = build_auth(&config).await?;
let client = grr_drive::DriveClientBuilder::new()
.auth(auth)
.build()
.await?;
commands::drive::handle_drive_cmd(&client, cmd).await?
}
Commands::Contacts(cmd) => {
let auth = build_auth(&config).await?;
let client = grr_people::PeopleClientBuilder::new()
.auth(auth)
.build()
.await?;
commands::contacts::handle_contacts_cmd(&client, cmd).await?
}
Commands::Chat(cmd) => {
let auth = build_auth(&config).await?;
let client = grr_chat::ChatClientBuilder::new()
.auth(auth)
.build()
.await?;
commands::chat::handle_chat_cmd(&client, cmd).await?
}
Commands::Forms(cmd) => {
let auth = build_auth(&config).await?;
let client = grr_forms::FormsClientBuilder::new()
.auth(auth)
.build()
.await?;
commands::forms::handle_forms_cmd(&client, cmd).await?
}
Commands::Transport(args) => {
let client = gmail_client.as_ref().expect("built for transport");
commands::transport::handle_transport_cmd(client, args).await?
}
}
Ok(())
}