diff --git a/Cargo.toml b/Cargo.toml index 2f638bd..0550884 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ai" -version = "0.1.0" +version = "0.0.1" edition = "2021" [dependencies] @@ -8,3 +8,10 @@ seahorse = "*" reqwest = { version = "*", features = ["blocking", "json"] } tokio = { version = "1", features = ["full"] } shellexpand = "*" +config = "*" +serde = "*" +serde_json = "*" +serde_derive = "*" +url = { version = "2.0", features = ["serde"] } +rustc-serialize = "*" +toml = "*" diff --git a/src/data.rs b/src/data.rs index a961fbe..c9bebeb 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,7 +1,9 @@ -//use config::{Config, ConfigError, File}; -//use serde_derive::{Deserialize, Serialize}; +use config::{Config, ConfigError, File}; +use serde_derive::{Deserialize, Serialize}; +use std::fs; +use std::io::Write; -pub fn token_file(s: &str) -> String { +pub fn data_file(s: &str) -> String { let file = "/.config/ai/token"; let mut f = shellexpand::tilde("~").to_string(); f.push_str(&file); @@ -11,3 +13,175 @@ pub fn token_file(s: &str) -> String { _ => f + &"." + &s, } } + +impl Token { + pub fn new() -> Result { + let d = data_file("json"); + let s = Config::builder() + .add_source(File::with_name(&d)) + .add_source(config::Environment::with_prefix("APP")) + .build()?; + s.try_deserialize() + } +} + +impl Data { + pub fn new() -> Result { + let d = data_file("toml"); + let s = Config::builder() + .add_source(File::with_name(&d)) + .add_source(config::Environment::with_prefix("APP")) + .build()?; + s.try_deserialize() + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(non_snake_case)] +pub struct Token { + pub did: String, + pub handle: String, + pub accessJwt: String, + pub refreshJwt: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(non_snake_case)] +pub struct Data { + pub host: String, + pub did: String, + pub handle: String, + pub access: String, + pub refresh: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct BaseUrl { + pub profile_get: String, + pub thread_get: String, + pub describe: String, + pub record_list: String, + pub record_create: String, + pub record_delete: String, + pub session_create: String, + pub session_refresh: String, + pub session_get: String, + pub timeline_get: String, + pub timeline_author: String, + pub upload_blob: String, + pub update_handle: String, + pub account_create: String, + pub notify_count: String, + pub notify_list: String, + pub notify_update: String, + pub repo_update: String, + pub like: String, + pub repost: String, + pub follow: String, + pub follows: String, + pub followers: String, +} + +pub fn url(s: &str) -> String { + let s = String::from(s); + let data = Data::new().unwrap(); + let data = Data { + host: data.host, + handle: data.handle, + did: data.did, + access: data.access, + refresh: data.refresh, + }; + let t = "https://".to_string() + &data.host.to_string() + &"/xrpc/".to_string(); + let baseurl = BaseUrl { + profile_get: "com.atproto.identity.resolveHandle".to_string(), + thread_get: "app.bsky.feed.getPostThread".to_string(), + record_create: "com.atproto.repo.createRecord".to_string(), + record_delete: "com.atproto.repo.deleteRecord".to_string(), + describe: "com.atproto.repo.describeRepo".to_string(), + record_list: "com.atproto.repo.listRecords".to_string(), + session_create: "com.atproto.server.createSession".to_string(), + session_refresh: "com.atproto.server.refreshSession".to_string(), + session_get: "com.atproto.server.getSession".to_string(), + timeline_get: "app.bsky.feed.getTimeline".to_string(), + timeline_author: "app.bsky.feed.getAuthorFeed".to_string(), + like: "app.bsky.feed.like".to_string(), + repost: "app.bsky.feed.repost".to_string(), + follow: "app.bsky.graph.follow".to_string(), + follows: "app.bsky.graph.getFollows".to_string(), + followers: "app.bsky.graph.getFollowers".to_string(), + upload_blob: "com.atproto.repo.uploadBlob".to_string(), + account_create: "com.atproto.server.createAccount".to_string(), + update_handle: "com.atproto.identity.updateHandle".to_string(), + notify_count: "app.bsky.notification.getUnreadCount".to_string(), + notify_list: "app.bsky.notification.listNotifications".to_string(), + notify_update: "app.bsky.notification.updateSeen".to_string(), + repo_update: "com.atproto.sync.updateRepo".to_string(), + }; + + match &*s { + "profile_get" => t.to_string() + &baseurl.profile_get, + "thread_get" => t.to_string() + &baseurl.thread_get, + "describe" => t.to_string() + &baseurl.describe, + "record_list" => t.to_string() + &baseurl.record_list, + "record_create" => t.to_string() + &baseurl.record_create, + "record_delete" => t.to_string() + &baseurl.record_delete, + "session_create" => t.to_string() + &baseurl.session_create, + "session_refresh" => t.to_string() + &baseurl.session_refresh, + "session_get" => t.to_string() + &baseurl.session_get, + "timeline_get" => t.to_string() + &baseurl.timeline_get, + "timeline_author" => t.to_string() + &baseurl.timeline_get, + "upload_blob" => t.to_string() + &baseurl.upload_blob, + "account_create" => t.to_string() + &baseurl.account_create, + "update_handle" => t.to_string() + &baseurl.update_handle, + "notify_list" => t.to_string() + &baseurl.notify_list, + "notify_count" => t.to_string() + &baseurl.notify_count, + "notify_update" => t.to_string() + &baseurl.notify_update, + "repo_update" => t.to_string() + &baseurl.repo_update, + "like" => t.to_string() + &baseurl.like, + "repost" => t.to_string() + &baseurl.repost, + "follow" => t.to_string() + &baseurl.follow, + "follows" => t.to_string() + &baseurl.follows, + "followers" => t.to_string() + &baseurl.followers, + _ => s, + } +} + +pub fn data_toml(s: &str) -> String { + let s = String::from(s); + let data = Data::new().unwrap(); + let data = Data { + host: data.host, + handle: data.handle, + did: data.did, + access: data.access, + refresh: data.refresh, + }; + match &*s { + "host" => data.handle, + "handle" => data.handle, + "did" => data.did, + "access" => data.access, + "refresh" => data.refresh, + _ => s, + } +} + +pub fn w_cfg(h: &str, res: &str) { + let f = data_file(&"json"); + let ff = data_file(&"toml"); + let mut f = fs::File::create(f.clone()).unwrap(); + let mut ff = fs::File::create(ff.clone()).unwrap(); + f.write_all(&res.as_bytes()).unwrap(); + let json: Token = serde_json::from_str(&res).unwrap(); + let datas = Data { + host: h.to_string(), + did: json.did.to_string(), + handle: json.handle.to_string(), + access: json.accessJwt.to_string(), + refresh: json.refreshJwt.to_string(), + }; + let toml = toml::to_string(&datas).unwrap(); + ff.write_all(&toml.as_bytes()).unwrap(); +} + diff --git a/src/main.rs b/src/main.rs index 7a22bc3..89742ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,16 @@ -pub mod refresh; -pub mod token; -pub mod ascii; -pub mod data; use seahorse::{App, Command, Context, Flag, FlagType}; use std::env; -use std::fs; -use std::io::Write; + use crate::ascii::c_ascii; -use crate::data::token_file; +use crate::data::data_toml; +use crate::data::url; +use crate::data::w_cfg; + +pub mod data; +pub mod refresh; +pub mod token; +pub mod ascii; fn main() { let args: Vec = env::args().collect(); @@ -47,31 +49,27 @@ fn c_ascii_art(c: &Context) { c_ascii(c.bool_flag("type")); } -fn refresh(c: &Context) { - let m = c.args[0].to_string(); +fn refresh() { let h = async { - let str = refresh::post_request(m.to_string()).await; - println!("{}",str); + let res = refresh::post_request().await; + println!("{}", res); + w_cfg("bsky.social", &res) }; let res = tokio::runtime::Runtime::new().unwrap().block_on(h); return res } -fn c_refresh(c: &Context) { - refresh(c); +fn c_refresh(_c: &Context) { + refresh(); } fn token(c: &Context) { let m = c.args[0].to_string(); - let f = token_file(&"json"); - let mut f = fs::File::create(f.clone()).unwrap(); - let h = async { if let Ok(p) = c.string_flag("password") { - let str = token::post_request(m.to_string(), p.to_string()).await; - println!("{}",str); - - f.write_all(&str.as_bytes()).unwrap(); + let res = token::post_request(m.to_string(), p.to_string()).await; + println!("{}", res); + w_cfg("bsky.social", &res) } }; let res = tokio::runtime::Runtime::new().unwrap().block_on(h); diff --git a/src/refresh.rs b/src/refresh.rs index fed8ec0..5f5f13e 100644 --- a/src/refresh.rs +++ b/src/refresh.rs @@ -1,8 +1,10 @@ extern crate reqwest; +use crate::data_toml; +use crate::url; -pub async fn post_request(refresh: String) -> String { - - let url = "https://bsky.social/xrpc/com.atproto.server.refreshSession"; +pub async fn post_request() -> String { + let refresh = data_toml(&"refresh"); + let url = url(&"session_refresh"); let client = reqwest::Client::new(); let res = client