feat: better command handling

This commit is contained in:
Patrick 2024-09-11 21:40:37 +02:00
parent 2fb8f1dbbf
commit 4760406224
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F
3 changed files with 221 additions and 62 deletions

68
Cargo.lock generated
View file

@ -68,7 +68,7 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -78,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -304,6 +304,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "eyre" name = "eyre"
version = "0.6.12" version = "0.6.12"
@ -314,6 +324,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "fastrand"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -594,6 +610,12 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.12" version = "0.4.12"
@ -656,7 +678,7 @@ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
"wasi", "wasi",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -808,6 +830,19 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]]
name = "rustix"
version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.18" version = "1.0.18"
@ -889,6 +924,7 @@ dependencies = [
"jsonrpsee", "jsonrpsee",
"serde", "serde",
"serde_json", "serde_json",
"tempfile",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
@ -917,7 +953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -937,6 +973,19 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tempfile"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
dependencies = [
"cfg-if",
"fastrand",
"once_cell",
"rustix",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.63" version = "1.0.63"
@ -982,7 +1031,7 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -1202,6 +1251,15 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.52.6"

View file

@ -13,6 +13,7 @@ futures = "0.3.30"
jsonrpsee = { version = "0.24.3", features = ["macros", "async-client"] } jsonrpsee = { version = "0.24.3", features = ["macros", "async-client"] }
serde = { version = "1.0.209", features = ["derive"] } serde = { version = "1.0.209", features = ["derive"] }
serde_json = "1.0.127" serde_json = "1.0.127"
tempfile = "3.12.0"
thiserror = "1.0.63" thiserror = "1.0.63"
tokio = { version = "1.40.0", features = ["full"] } tokio = { version = "1.40.0", features = ["full"] }
tokio-stream = "0.1.15" tokio-stream = "0.1.15"

View file

@ -1,18 +1,21 @@
use std::fs::{create_dir_all, write, File, OpenOptions}; use std::fs::{create_dir_all, remove_file, rename, write, File, OpenOptions};
use std::io::{BufRead, BufReader, Write}; use std::io::{BufRead, BufReader, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Stdio; use std::process::Stdio;
use std::time::Duration;
use askama::Template; use askama::Template;
use base64::prelude::BASE64_STANDARD; use base64::prelude::BASE64_STANDARD;
use base64::Engine; use base64::Engine;
use chrono::{DateTime, Local, Timelike}; use chrono::{DateTime, Local};
use clap::{command, Parser}; use clap::{command, Parser};
use color_eyre::eyre::Result; use color_eyre::eyre::{eyre, Result};
use futures::future::join_all; use futures::future::join_all;
use jsonrpsee::async_client::{Client, ClientBuilder}; use jsonrpsee::async_client::{Client, ClientBuilder};
use serde_json::Value; use serde_json::Value;
use tempfile::tempdir;
use tokio::process::Command; use tokio::process::Command;
use tokio::task::yield_now;
use tokio_util::codec::{FramedRead, LinesCodec}; use tokio_util::codec::{FramedRead, LinesCodec};
use crate::jsonrpc::RpcClient; use crate::jsonrpc::RpcClient;
@ -37,9 +40,9 @@ struct Config {
#[arg(short, long)] #[arg(short, long)]
output_folder: String, output_folder: String,
///The time of day when generate the post ///The used as the journal
#[arg(short, long)] #[arg(short, long)]
time: String, url: String,
} }
#[derive(Debug, Default, Template)] #[derive(Debug, Default, Template)]
@ -57,14 +60,12 @@ struct Message {
time: String, time: String,
} }
async fn generate_post(config: &Config, client: &mut Client) -> Result<()> { async fn generate_post(config: &Config, client: &mut Client) -> Result<String> {
let day: DateTime<Local> = Local::now(); let day: DateTime<Local> = Local::now();
let _hour = day.hour(); let file = PathBuf::from(format!("{}/texts.json", config.data_folder));
let folder: PathBuf = [config.output_folder.clone(), day.to_rfc3339()] let tempdir = tempdir()?;
.iter() if !file.exists() {
.collect(); return Err(eyre!("No content to post"));
if !folder.exists() {
create_dir_all(&folder)?;
} }
let mut template = PostTemplate { let mut template = PostTemplate {
date: day.to_rfc3339(), date: day.to_rfc3339(),
@ -72,14 +73,15 @@ async fn generate_post(config: &Config, client: &mut Client) -> Result<()> {
..Default::default() ..Default::default()
}; };
let mut msgs = Vec::new(); let mut msgs = Vec::new();
let file = File::open(format!("{}/texts.json", config.data_folder))?; {
let reader = BufReader::new(file); let file = File::open(file.clone())?;
let reader = BufReader::new(file.try_clone()?);
for line in reader.lines() { for line in reader.lines() {
let v = serde_json::from_str(&line?)?; let v = serde_json::from_str(&line?)?;
let mut attachments = Vec::new(); let mut attachments = Vec::new();
if let Some(i) = get_msg_attachments(client, &v).await { if let Some(i) = get_msg_attachments(client, &v).await {
for (id, content) in i { for (id, content) in i {
let path = folder.join(id); let path = tempdir.path().join(id);
save_picture(&path, &content)?; save_picture(&path, &content)?;
attachments.push(id.to_string()); attachments.push(id.to_string());
} }
@ -91,10 +93,24 @@ async fn generate_post(config: &Config, client: &mut Client) -> Result<()> {
time: get_msg_time(&v).unwrap(), time: get_msg_time(&v).unwrap(),
}); });
} }
if msgs.is_empty() {
return Err(eyre!("No content to post"));
};
template.messages = msgs; template.messages = msgs;
println!("{}", template.render()?); println!("{}", template.render()?);
Ok(()) write(tempdir.path().join("index.md"), template.render()?)?;
}
let folder: PathBuf = [config.output_folder.clone(), day.to_rfc3339()]
.iter()
.collect();
if folder.exists() {
return Err(eyre!("Blog folder already exists"));
}
rename(tempdir, folder)?;
// Delete messages after we're finished with writing
remove_file(file)?;
Ok(day.to_rfc3339())
} }
#[tokio::main] #[tokio::main]
@ -120,17 +136,18 @@ async fn main() -> Result<()> {
let mut stream = client.subscribe_receive(None).await?; let mut stream = client.subscribe_receive(None).await?;
loop { loop {
let v = stream.next().await.unwrap()?; let v = stream.next().await.unwrap()?;
let sender = get_msg_sender(&v); // which message doesn't have a sender?
let sender = get_msg_sender(&v).expect("which message doesn't have a sender?");
let text = get_msg_text(&v); let text = get_msg_text(&v);
let at = get_msg_attachments(&mut client, &v).await; let at = get_msg_attachments(&mut client, &v).await;
if text.is_none() && at.is_none() { if text.is_none() && at.is_none() {
continue; continue;
} else if sender != Some(&config.allowed_sender) { } else if sender != &config.allowed_sender {
println!("{:?}", sender); println!("{:?}", sender);
if let Some(x) = sender { client
client.send( .send(
None, None,
vec![x.to_string()], vec![sender.to_string()],
Vec::new(), Vec::new(),
false, false,
false, false,
@ -153,33 +170,116 @@ async fn main() -> Result<()> {
None, None,
None, None,
None, None,
).await?; )
} .await?;
continue; continue;
}; };
println!("{v}"); println!("{v}");
println!("{:?}", text); println!("{:?}", text);
if text == Some("post") { if let Some(text) = text {
generate_post(&config, &mut client).await?; // ©ontrol character
if let Some(text) = text.strip_prefix("©").and_then(|x| Some(x.trim())) {
match text {
"post" => {
let res = generate_post(&config, &mut client).await;
if let Ok(res) = res {
client
.send(
None,
vec![sender.to_string()],
Vec::new(),
false,
false,
format!("Generated blog post at: {}/{}", config.url, res)
.to_string(),
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
} else { } else {
client
.send(
None,
vec![sender.to_string()],
Vec::new(),
false,
false,
format!("Error generating blog post:\n{:?}", res).to_string(),
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
}
}
_ => {
client
.send(
None,
vec![sender.to_string()],
Vec::new(),
false,
false,
format!("Unknown command: {}", text).to_string(),
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
}
}
continue;
}
}
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.append(true) .append(true)
.create(true) .create(true)
.open(format!("{}/texts.json", config.data_folder))?; .open(format!("{}/texts.json", config.data_folder))?;
writeln!(file, "{}", v.to_string())?; writeln!(file, "{}", v.to_string())?;
} }
//let at = get_msg_attachments(&mut client, &v).await;
//if let Some(i) = at {
// for (id, content) in i {
// let path = format!("{}/{}", &config.data_folder, id);
// save_picture(&path, &content)?;
// }
//}
}
//stream.unsubscribe().await?;
//Ok(())
} }
/// make sure the directory exists before trying to save into it /// make sure the directory exists before trying to save into it