use config::{Config, ConfigError, File}; use serde_derive::{Deserialize, Serialize}; use std::fs; use std::io::Write; pub fn data_file(s: &str) -> String { let file = "/.config/ai/token"; let mut f = shellexpand::tilde("~").to_string(); f.push_str(&file); match &*s { "toml" => f + &".toml", "json" => f + &".json", _ => 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(); } #[derive(Serialize, Deserialize)] pub struct Notify { pub notifications: Vec } #[derive(Serialize, Deserialize)] pub struct Status { pub handle: String, pub did: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct DidDocs { pub verificationMethod: Vec, pub service: Vec, pub id: String, pub alsoKnownAs: Vec, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct VerificationMethod { pub id: String, pub r#type: String, pub controller: String, pub publicKeyMultibase: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Service { pub id: String, pub r#type: String, pub serviceEndpoint: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct AlsoKnownAs { } #[derive(Serialize, Deserialize)] pub struct Timeline { pub feed: Vec } #[derive(Serialize, Deserialize)] pub struct Session { pub did: String, pub email: String, pub handle: String, } #[derive(Serialize, Deserialize)] pub struct Follow { pub follows: Vec, pub cursor: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Notifications { pub uri: String, pub cid: String, pub author: Author, pub reason: String, //pub reasonSubject: String, pub record: Record, pub isRead: bool, pub indexedAt: String, //pub labels: Labels, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Thread { pub r#type: String, pub post: String, pub root: String, pub author: Author, pub reason: String, //pub reasonSubject: String, pub record: Record, pub isRead: bool, pub indexedAt: String, //pub labels: Labels, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Author { pub did: String, //pub declaration: Declaration, pub description: Option, pub displayName: Option, pub handle: String, pub avatar: Option, pub viewer: Viewer, //pub labels: Labels, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Labels { pub src: Option, pub uri: Option, pub cid: Option, pub val: Option, pub cts: Option, pub neg: Option, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Declaration { pub actorType: String, pub cid: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Viewer { pub muted: bool, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] #[derive(Debug)] pub struct Record { pub text: Option, pub createdAt: String, pub reply: Option, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] #[derive(Debug)] pub struct Reply { pub parent: ReplyParent, pub root: ReplyRoot, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] #[derive(Debug)] pub struct ReplyRoot { pub cid: String, pub uri: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] #[derive(Debug)] pub struct ReplyParent { pub cid: String, pub uri: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Langs { } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Feed { pub post: Post, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Post { pub did: Option, pub uri: String, pub cid: String, pub collection: Option, pub record: Record, pub author: Author, pub reason: Option, pub indexedAt: String, pub replyCount: i32, pub postCount: Option, pub repostCount: i32, pub likeCount: i32, } #[derive(Serialize, Deserialize)] pub struct Cid { pub cid: String } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Img { pub blob: Blob } #[derive(Serialize, Deserialize)] pub struct Blob { pub r#ref: Ref, } #[derive(Serialize, Deserialize)] pub struct Ref { pub link: String, } #[derive(Serialize, Deserialize)] pub struct Handle { pub handle: String } //#[derive(Serialize, Deserialize)] //pub struct Did { // pub did: String //} //#[derive(Serialize, Deserialize)] //pub struct Labels { //} // //#[derive(Serialize, Deserialize)] //pub struct Viewer { // pub muted: bool, // pub blockedBy: bool, //} // #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct ProfileIdentityResolve { pub did: String, } #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Profile { pub did: String, pub handle: String, pub followsCount: Option, pub followersCount: Option, pub postsCount: i32, pub indexedAt: Option, pub avatar: Option, pub banner: Option, pub displayName: Option, pub description: Option, pub viewer: Viewer, pub labels: Labels, }