diff options
Diffstat (limited to 'adenosine-cli/src/main.rs')
-rw-r--r-- | adenosine-cli/src/main.rs | 322 |
1 files changed, 287 insertions, 35 deletions
diff --git a/adenosine-cli/src/main.rs b/adenosine-cli/src/main.rs index 0246fd6..eea16bc 100644 --- a/adenosine-cli/src/main.rs +++ b/adenosine-cli/src/main.rs @@ -1,12 +1,11 @@ use adenosine_cli::*; use anyhow::anyhow; -use serde_json::Value; +use serde_json::{json, Value}; use std::collections::HashMap; use colored_json::to_colored_json_auto; -use log::{self, debug, info}; +use log::{self, debug}; use std::io::Write; -use std::path::PathBuf; use structopt::StructOpt; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; @@ -58,10 +57,57 @@ enum AccountCommand { password: String, }, Delete, - Login, + Login { + #[structopt(long, short)] + username: String, + + #[structopt(long, short)] + password: String, + }, Logout, Info, - CreateRevocationKey, + // TODO: CreateRevocationKey, +} + +#[derive(StructOpt)] +enum RepoCommand { + Root { + #[structopt(long)] + did: String, + }, + Export { + #[structopt(long)] + did: String, + #[structopt(long)] + from: Option<String>, + }, + Import { + // XXX: either path or stdin + #[structopt(long)] + did: String, + }, +} + +#[derive(StructOpt)] +enum BskyCommand { + Feed { name: Option<String> }, + Notifications, + Post { text: String }, + Repost { uri: String }, + Like { uri: String }, + // TODO: Repost { uri: String, }, + Follow { uri: String }, + // TODO: Unfollow { uri: String, }, + /* + Follows { + name: String, + }, + Followers { + name: String, + }, + */ + Profile { name: String }, + SearchUsers { query: String }, } #[derive(StructOpt)] @@ -70,6 +116,30 @@ enum Command { uri: String, }, + Ls { + uri: String, + }, + + Create { + collection: String, + body: String, + }, + Update { + uri: String, + params: String, + }, + Delete { + uri: String, + }, + + Describe { + name: String, + }, + + Resolve { + name: String, + }, + Xrpc { method: XrpcMethod, nsid: String, @@ -82,6 +152,16 @@ enum Command { cmd: AccountCommand, }, + Repo { + #[structopt(subcommand)] + cmd: RepoCommand, + }, + + Bsky { + #[structopt(subcommand)] + cmd: BskyCommand, + }, + /// Summarize connection and authentication with API Status, } @@ -136,40 +216,73 @@ fn main() -> Result<()> { Ok(()) } +fn print_result_json(result: Option<Value>) -> Result<()> { + if let Some(val) = result { + writeln!(&mut std::io::stdout(), "{}", to_colored_json_auto(&val)?)? + }; + Ok(()) +} + fn run(opt: Opt) -> Result<()> { - let xrpc_client = XrpcClient::new(opt.atp_host, opt.auth_token)?; + let xrpc_client = XrpcClient::new(opt.atp_host.clone(), opt.auth_token.clone())?; + let mut params: HashMap<String, String> = HashMap::new(); + let jwt_did: Option<String> = if let Some(ref token) = opt.auth_token { + Some(parse_did_from_jwt(token)?) + } else { + None + }; - match opt.cmd { + let result = match opt.cmd { + Command::Status => { + // XXX + println!("Configuration"); + println!(" ATP_HOST: {}", opt.atp_host); + if opt.auth_token.is_some() { + println!(" ATP_AUTH_TOKEN: <configured>"); + } else { + println!(" ATP_AUTH_TOKEN:"); + } + // TODO: parse JWT? + // TODO: connection, auth check + // TODO: account username, did, etc + None + } + Command::Describe { name } => { + params.insert("user".to_string(), name); + xrpc_client.get("com.atproto.repoDescribe", Some(params))? + } + Command::Resolve { name } => { + let mut params: HashMap<String, String> = HashMap::new(); + params.insert("name".to_string(), name); + xrpc_client.get("com.atproto.resolveName", Some(params))? + } + Command::Get { uri } => { + println!("GET: {}", uri); + None + } + Command::Ls { uri } => { + unimplemented!() + } + Command::Create { collection, body } => { + unimplemented!() + } + Command::Update { uri, params } => { + unimplemented!() + } + Command::Delete { uri } => { + unimplemented!() + } Command::Xrpc { method, nsid, params, } => { let body: Value = ().into(); - let res = match method { + match method { // XXX: parse params - XrpcMethod::Get => xrpc_client.get(nsid, None)?, - XrpcMethod::Post => xrpc_client.post(nsid, None, body)?, - }; - if let Some(val) = res { - writeln!(&mut std::io::stdout(), "{}", to_colored_json_auto(&val)?)? - }; - } - Command::Get { uri } => { - println!("GET: {}", uri); - /* - let result = specifier.get_from_api(&mut api_client, expand, hide)?; - if toml { - writeln!(&mut std::io::stdout(), "{}", result.to_toml_string()?)? - } else { - // "if json" - writeln!( - &mut std::io::stdout(), - "{}", - to_colored_json_auto(&result.to_json_value()?)? - )? + XrpcMethod::Get => xrpc_client.get(&nsid, None)?, + XrpcMethod::Post => xrpc_client.post(&nsid, None, body)?, } - */ } Command::Account { cmd: @@ -178,15 +291,154 @@ fn run(opt: Opt) -> Result<()> { username, password, }, + } => xrpc_client.post( + "com.atproto.createAccount", + None, + json!({ + "email": email, + "username": username, + "password": password, + }), + )?, + Command::Account { + cmd: AccountCommand::Login { username, password }, + } => xrpc_client.post( + "com.atproto.createSession", + None, + json!({ + "username": username, + "password": password, + }), + )?, + Command::Account { + cmd: AccountCommand::Logout, + } => xrpc_client.post("com.atproto.deleteSession", None, json!({}))?, + Command::Account { + cmd: AccountCommand::Delete, + } => xrpc_client.post("com.atproto.deleteAccount", None, json!({}))?, + Command::Account { + cmd: AccountCommand::Info, + } => xrpc_client.get("com.atproto.getAccount", None)?, + Command::Repo { + cmd: RepoCommand::Root { did }, + } => { + params.insert("did".to_string(), did); + xrpc_client.get("com.atproto.syncGetRoot", Some(params))? + } + Command::Repo { + cmd: RepoCommand::Export { did, from }, + } => { + params.insert("did".to_string(), did); + if let Some(from) = from { + params.insert("from".to_string(), from); + }; + xrpc_client.get_to_writer( + "com.atproto.syncGetRepo", + Some(params), + &mut std::io::stdout(), + )?; + None + } + Command::Repo { + cmd: RepoCommand::Import { did }, + } => { + params.insert("did".to_string(), did); + xrpc_client.post_cbor_from_reader( + "com.atproto.syncUpdateRepo", + Some(params), + &mut std::io::stdin(), + )? + } + Command::Bsky { + cmd: BskyCommand::Feed { name }, } => { - println!( - "REGISTER: email={} username={} password={}", - email, username, password + if let Some(name) = name { + params.insert("author".to_string(), name); + xrpc_client.get("app.bsky.getAuthorFeed", Some(params))? + } else { + xrpc_client.get("app.bsky.getHomeFeed", None)? + } + } + Command::Bsky { + cmd: BskyCommand::Notifications, + } => xrpc_client.get("app.bsky.getNotifications", None)?, + Command::Bsky { + cmd: BskyCommand::Post { text }, + } => { + params.insert( + "did".to_string(), + jwt_did.ok_or(anyhow!("need auth token"))?, ); + params.insert("collection".to_string(), "app.bsky.post".to_string()); + xrpc_client.post( + "com.atproto.repoCreateRecord", + Some(params), + json!({ + "text": text, + }), + )? } - _ => { - unimplemented!("some command"); + Command::Bsky { + cmd: BskyCommand::Repost { uri }, + } => { + params.insert( + "did".to_string(), + jwt_did.ok_or(anyhow!("need auth token"))?, + ); + params.insert("collection".to_string(), "app.bsky.repost".to_string()); + xrpc_client.post( + "com.atproto.repoCreateRecord", + Some(params), + json!({ + "subject": uri, + }), + )? } - } + Command::Bsky { + cmd: BskyCommand::Like { uri }, + } => { + params.insert( + "did".to_string(), + jwt_did.ok_or(anyhow!("need auth token"))?, + ); + params.insert("collection".to_string(), "app.bsky.like".to_string()); + xrpc_client.post( + "com.atproto.repoCreateRecord", + Some(params), + json!({ + "subject": uri, + }), + )? + } + Command::Bsky { + cmd: BskyCommand::Follow { uri }, + } => { + params.insert( + "did".to_string(), + jwt_did.ok_or(anyhow!("need auth token"))?, + ); + params.insert("collection".to_string(), "app.bsky.follow".to_string()); + xrpc_client.post( + "com.atproto.repoCreateRecord", + Some(params), + json!({ + "subject": uri, + }), + )? + } + Command::Bsky { + cmd: BskyCommand::Profile { name }, + } => { + params.insert("name".to_string(), name); + xrpc_client.get("app.bsky.getProfile", Some(params))? + } + Command::Bsky { + cmd: BskyCommand::SearchUsers { query }, + } => { + params.insert("term".to_string(), query); + xrpc_client.get("app.bsky.getUsersSearch", Some(params))? + } + }; + print_result_json(result)?; Ok(()) } |