diff --git a/README.md b/README.md index 4673888..c590021 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ - name : ai bot - base : [rust](https://www.rust-lang.org) +- host : [yui.syui.ai](https://bsky.app/profile/yui.syui.ai), [ai.syu.is](https://web.syu.is/profile/ai.syu.is) ```sh $ ai @@ -45,9 +46,17 @@ $ ai r -s syu.is $ ai n ``` +``` +$ ai n | jq . +``` + ### bot ``` $ ai bot ``` +|command|type|body| +|---|---|---| +|@yui.syui.ai did|mention, reply| plc.directory/$did/log | + diff --git a/src/data.rs b/src/data.rs index d40b729..7a8614f 100644 --- a/src/data.rs +++ b/src/data.rs @@ -2,6 +2,9 @@ use config::{Config, ConfigError, File}; use serde_derive::{Deserialize, Serialize}; use std::fs; use std::io::Write; +use std::io::Read; +use std::fs::OpenOptions; +use std::path::Path; pub fn data_file(s: &str) -> String { let file = "/.config/ai/token"; @@ -14,6 +17,21 @@ pub fn data_file(s: &str) -> String { } } +pub fn log_file(s: &str) -> String { + let file = "/.config/ai/txt/"; + let mut f = shellexpand::tilde("~").to_string(); + f.push_str(&file); + let path = Path::new(&f); + if path.is_dir() == false { + let _ = fs::create_dir_all(f.clone()); + } + match &*s { + "n1" => f + &"notify_cid.txt", + "n2" => f + &"notify_cid_run.txt", + _ => f + &s, + } +} + impl Token { pub fn new() -> Result { let d = data_file("json"); @@ -167,24 +185,6 @@ pub fn data_toml(s: &str) -> String { } } -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 @@ -433,3 +433,67 @@ pub struct Profile { pub viewer: Viewer, pub labels: Labels, } + +pub fn c_char(i: String) -> String { + let l = 250; + let mut s = String::new(); + for ii in i.chars().enumerate() { + match ii.0 { + n if n > l.try_into().unwrap() => {break} + _ => {s.push(ii.1)} + } + } + return 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(); +} + +pub fn w_cid(cid :String, file: String, t: bool) -> bool { + let f = file; + let mut file = match OpenOptions::new() + .create(true) + .write(true) + .read(true) + .append(true) + .open(f.clone()) + { + Err(why) => panic!("Couldn't open {}: {}", f, why), + Ok(file) => file, + }; + let mut contents = String::new(); + + match file.read_to_string(&mut contents) { + Err(why) => panic!("Couldn't read {}: {}", f, why), + Ok(_) => (), + } + if contents.contains(&cid) == false { + if t { + let cid = cid + "\n"; + match file.write_all(cid.as_bytes()) { + Err(why) => panic!("Couldn't write \"{}\" to {}: {}", contents, f, why), + Ok(_) => println!("finished"), + } + } + let check = false; + return check + } else { + let check = true; + return check + } +} diff --git a/src/main.rs b/src/main.rs index c3d1718..6ad3526 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,11 @@ use std::env; use crate::ascii::c_ascii; use crate::data::data_toml; +use crate::data::log_file; use crate::data::url; use crate::data::w_cfg; +use crate::data::w_cid; +use crate::data::c_char; use data::Notify as Notify; pub mod data; @@ -33,7 +36,7 @@ fn main() { .command( Command::new("token") .alias("t") - .description("handle\n\t\t\t$ ai t syui.bsky.social -p password") + .description("handle\n\t\t\t$ ai t yui.syui.ai -p password\n\t\t\t$ ai t yui.syui.ai -p password -s bsky.social") .action(c_token) .flag( Flag::new("password", FlagType::String) @@ -49,6 +52,7 @@ fn main() { .command( Command::new("refresh") .alias("r") + .description("refresh\n\t\t\t$ ai r\n\t\t\t$ ai r -s bsky.social") .action(c_refresh) .flag( Flag::new("server", FlagType::String) @@ -59,12 +63,19 @@ fn main() { .command( Command::new("notify") .alias("n") + .description("notify\n\t\t\t$ ai n") .action(c_notify), ) .command( Command::new("bot") .alias("b") - .action(c_bot), + .description("bot\n\t\t\t$ ai b\n\t\t\t$ ai b -s bsky.social") + .action(c_bot) + .flag( + Flag::new("server", FlagType::String) + .description("server flag") + .alias("s"), + ) ) ; app.run(args); @@ -125,22 +136,23 @@ fn c_notify(_c: &Context) { notify(); } -pub fn char_c(i: String) -> String { - let l = 250; - let mut s = String::new(); - for ii in i.chars().enumerate() { - match ii.0 { - n if n > l.try_into().unwrap() => {break} - _ => {s.push(ii.1)} - } - } - return s -} - -fn bot(_c: &Context) { +fn bot(c: &Context) { + let h = async { - let notify = notify::get_request(100).await; + let server = "bsky.social"; + let mut notify = notify::get_request(100).await; + if notify == "err" { + if let Ok(s) = c.string_flag("server") { + let res = refresh::post_request().await; + w_cfg(&s, &res); + } else { + let res = refresh::post_request().await; + w_cfg(&server, &res); + } + notify = notify::get_request(100).await; + } let notify: Notify = serde_json::from_str(¬ify).unwrap(); + let n = notify.notifications; let length = &n.len(); let reason = &n[0].reason; @@ -149,12 +161,53 @@ fn bot(_c: &Context) { let read = n[0].isRead; let cid = &n[0].cid; let uri = &n[0].uri; + let time = &n[0].indexedAt; + let mut cid_root = cid; + let mut uri_root = uri; + let check_cid = w_cid(cid.to_string(), log_file(&"n1"), false); + let check_cid_run = w_cid(cid.to_string(), log_file(&"n2"), false); + // thread + if ! n[0].record.reply.is_none() { + cid_root = &n[0].record.reply.as_ref().unwrap().root.cid; + uri_root = &n[0].record.reply.as_ref().unwrap().root.uri; + } println!("{}", length); println!("{}", reason); println!("{}", handle); println!("{}", did); println!("{}", read); println!("{} {}", cid, uri); + let mut text = ""; + if ! n[0].record.text.is_none() { + text = &n[0].record.text.as_ref().unwrap(); + } + let vec: Vec<&str> = text.split_whitespace().collect(); + let rep_com = &vec[0..].join(" "); + + if check_cid == false && { reason == "mention" || reason == "reply" } || check_cid_run == false && { reason == "mention" || reason == "reply" } { + w_cid(cid.to_string(), log_file(&"n2"), true); + if rep_com.contains("did") == true || rep_com.contains("/did") == true { + let link = "https://plc.directory/".to_owned() + &did + &"/log"; + let s = 0; + let e = link.chars().count(); + println!("{}", link); + println!("{}", e); + + let d = "\n".to_owned() + &did.to_string(); + println!("{}", d); + let text_limit = c_char(d); + println!("{}", text_limit); + + if text_limit.len() > 3 { + let str_rep = reply_link::post_request(text_limit.to_string(), link.to_string(), s, e.try_into().unwrap(), cid.to_string(), uri.to_string(), cid_root.to_string(), uri_root.to_string()).await; + println!("{}", str_rep); + let str_notify = notify_read::post_request(time.to_string()).await; + println!("{}", str_notify); + + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } + } }; let res = tokio::runtime::Runtime::new().unwrap().block_on(h); return res diff --git a/src/reply.rs b/src/reply.rs index 478fbce..1e3fee6 100644 --- a/src/reply.rs +++ b/src/reply.rs @@ -4,7 +4,7 @@ use crate::url; use serde_json::json; use iso8601_timestamp::Timestamp; -pub async fn post_request(text: String, cid: String, uri: String, cid_p: String, uri_p: String) -> String { +pub async fn post_request(text: String, cid: String, uri: String, cid_root: String, uri_root: String) -> String { let token = data_toml(&"access"); let did = data_toml(&"did"); @@ -26,12 +26,12 @@ pub async fn post_request(text: String, cid: String, uri: String, cid_p: String, "createdAt": d.to_string(), "reply": { "root": { - "cid": cid.to_string(), - "uri": uri.to_string() + "cid": cid_root.to_string(), + "uri": uri_root.to_string() }, "parent": { - "cid": cid_p.to_string(), - "uri": uri_p.to_string() + "cid": cid.to_string(), + "uri": uri.to_string() } } }, diff --git a/src/reply_link.rs b/src/reply_link.rs index 1bae66b..1376e95 100644 --- a/src/reply_link.rs +++ b/src/reply_link.rs @@ -4,7 +4,7 @@ use crate::url; use serde_json::json; use iso8601_timestamp::Timestamp; -pub async fn post_request(text: String, link: String, s: i32, e: i32, cid: String, uri: String, cid_b: String, uri_b: String) -> String { +pub async fn post_request(text: String, link: String, s: i32, e: i32, cid: String, uri: String, cid_root: String, uri_root: String) -> String { let token = data_toml(&"access"); let did = data_toml(&"did"); @@ -25,12 +25,12 @@ pub async fn post_request(text: String, link: String, s: i32, e: i32, cid: Strin "createdAt": d.to_string(), "reply": { "root": { - "cid": cid.to_string(), - "uri": uri.to_string() + "cid": cid_root.to_string(), + "uri": uri_root.to_string() }, "parent": { - "cid": cid_b.to_string(), - "uri": uri_b.to_string() + "cid": cid.to_string(), + "uri": uri.to_string() } }, "facets": [