feat: timezone implementation
This commit is contained in:
parent
41f9b6f3f5
commit
b2c44e9003
224
src/main.rs
224
src/main.rs
|
@ -1,13 +1,14 @@
|
||||||
use copy_dir::copy_dir;
|
use copy_dir::copy_dir;
|
||||||
use std::fs::{create_dir_all, remove_file, write, File, OpenOptions};
|
use std::fs::{create_dir_all, read_to_string, remove_file, write, File, OpenOptions};
|
||||||
use std::io::{BufRead, BufReader, Write};
|
use std::io::{BufRead, BufReader, Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
|
||||||
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, Days, Local};
|
use chrono::offset::FixedOffset;
|
||||||
|
use chrono::{DateTime, Days, Local, Utc};
|
||||||
use clap::{command, Parser};
|
use clap::{command, Parser};
|
||||||
use color_eyre::eyre::{eyre, OptionExt, Result};
|
use color_eyre::eyre::{eyre, OptionExt, Result};
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
|
@ -42,6 +43,10 @@ struct Config {
|
||||||
///The used as the journal
|
///The used as the journal
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
url: String,
|
url: String,
|
||||||
|
|
||||||
|
///The timezone used if none is given in the data folder
|
||||||
|
#[arg(short, long)]
|
||||||
|
timezone: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Template)]
|
#[derive(Debug, Default, Template)]
|
||||||
|
@ -89,11 +94,18 @@ async fn generate_post(config: &Config, client: &mut Client) -> Result<String> {
|
||||||
attachments.push(id.to_string());
|
attachments.push(id.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let time = get_msg_time(&v).ok_or_eyre("Message without time???")?;
|
||||||
|
let secs = config.timezone.parse::<i32>()?;
|
||||||
|
println!("{:?}", secs);
|
||||||
|
let tz = FixedOffset::east_opt(config.timezone.parse::<i32>()? * 3600)
|
||||||
|
.ok_or_eyre("timezone von nem anderen planete?")?;
|
||||||
|
let time = time.with_timezone(&tz);
|
||||||
|
println!("{:?}", time);
|
||||||
|
|
||||||
msgs.push(Message {
|
msgs.push(Message {
|
||||||
content: get_msg_text(&v).unwrap_or("").to_string(),
|
content: get_msg_text(&v).unwrap_or("").to_string(),
|
||||||
attachments,
|
attachments,
|
||||||
time: get_msg_time(&v).ok_or_eyre("Message without time???")?,
|
time: time.format("%H:%M").to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if msgs.is_empty() {
|
if msgs.is_empty() {
|
||||||
|
@ -117,10 +129,15 @@ async fn generate_post(config: &Config, client: &mut Client) -> Result<String> {
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let config = Config::parse();
|
let mut config = Config::parse();
|
||||||
if !Path::new(&config.data_folder).exists() {
|
if !Path::new(&config.data_folder).exists() {
|
||||||
create_dir_all(&config.data_folder)?
|
create_dir_all(&config.data_folder)?
|
||||||
}
|
}
|
||||||
|
let tz_data_path = format!("{}/tz.data", config.data_folder);
|
||||||
|
if Path::new(&tz_data_path).exists() {
|
||||||
|
config.timezone = read_to_string(&tz_data_path)?;
|
||||||
|
}
|
||||||
|
println!("{:?}", config.timezone);
|
||||||
|
|
||||||
let mut cmd = Command::new(COMMAND_PATH)
|
let mut cmd = Command::new(COMMAND_PATH)
|
||||||
.arg("jsonRpc")
|
.arg("jsonRpc")
|
||||||
|
@ -146,131 +163,69 @@ async fn main() -> Result<()> {
|
||||||
continue;
|
continue;
|
||||||
} else if sender != &config.allowed_sender {
|
} else if sender != &config.allowed_sender {
|
||||||
println!("{:?}", sender);
|
println!("{:?}", sender);
|
||||||
client
|
send(
|
||||||
.send(
|
&client,
|
||||||
None,
|
sender,
|
||||||
vec![sender.to_string()],
|
"This is the signal-to-blog bot, you are not in the list of allowed writers."
|
||||||
Vec::new(),
|
.to_string(),
|
||||||
false,
|
)
|
||||||
false,
|
.await?;
|
||||||
"This is the signal-to-blog bot, you are not in the list of allowed writers."
|
|
||||||
.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;
|
continue;
|
||||||
};
|
};
|
||||||
println!("{v}");
|
println!("{v}");
|
||||||
println!("{:?}", text);
|
println!("{:?}", text);
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
// ©ontrol character
|
// ©ontrol character
|
||||||
if let Some(text) = text.strip_prefix("©").and_then(|x| Some(x.trim())) {
|
let cmds: Vec<&str> = text.split_whitespace().collect();
|
||||||
match text {
|
if cmds.len() >= 2 && cmds[0] == "©" {
|
||||||
|
match cmds[1] {
|
||||||
|
"help" => {
|
||||||
|
let text = "
|
||||||
|
Available commands:
|
||||||
|
- post: Generate post for yesterday
|
||||||
|
- tz: change timezone
|
||||||
|
"
|
||||||
|
.to_string();
|
||||||
|
send(&client, sender, text).await?;
|
||||||
|
}
|
||||||
"post" => {
|
"post" => {
|
||||||
let res = generate_post(&config, &mut client).await;
|
let res = generate_post(&config, &mut client).await;
|
||||||
if let Ok(res) = res {
|
if let Ok(res) = res {
|
||||||
client
|
send(
|
||||||
.send(
|
&client,
|
||||||
None,
|
sender,
|
||||||
vec![sender.to_string()],
|
format!("Generated blog post at: {}/{}", config.url, res),
|
||||||
Vec::new(),
|
)
|
||||||
false,
|
.await?;
|
||||||
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(
|
||||||
.send(
|
&client,
|
||||||
None,
|
sender,
|
||||||
vec![sender.to_string()],
|
format!("Error generating blog post:\n{:?}", res),
|
||||||
Vec::new(),
|
)
|
||||||
false,
|
.await?;
|
||||||
false,
|
}
|
||||||
format!("Error generating blog post:\n{:?}", res).to_string(),
|
}
|
||||||
Vec::new(),
|
"tz" => {
|
||||||
Vec::new(),
|
if cmds.get(2).is_some_and(|x| {
|
||||||
Vec::new(),
|
x.parse::<i32>()
|
||||||
None,
|
.is_ok_and(|x| FixedOffset::east_opt(x * 3600).is_some())
|
||||||
None,
|
}) {
|
||||||
None,
|
println!("{}", tz_data_path);
|
||||||
Vec::new(),
|
let mut file = OpenOptions::new()
|
||||||
Vec::new(),
|
.create(true)
|
||||||
Vec::new(),
|
.write(true)
|
||||||
None,
|
.open(&tz_data_path)?;
|
||||||
None,
|
file.write_all(cmds[2].as_bytes())?;
|
||||||
None,
|
config.timezone = cmds[2].to_string();
|
||||||
None,
|
|
||||||
None,
|
send(&client, sender, format!("Updated tz data")).await?;
|
||||||
None,
|
} else {
|
||||||
None,
|
send(&client, sender, format!("Error parsing")).await?;
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
client
|
send(&client, sender, format!("Unknown command: {}", text)).await?;
|
||||||
.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;
|
continue;
|
||||||
|
@ -283,6 +238,36 @@ async fn main() -> Result<()> {
|
||||||
writeln!(file, "{}", v.to_string())?;
|
writeln!(file, "{}", v.to_string())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async fn send(client: &Client, sender: &str, msg: String) -> Result<()> {
|
||||||
|
client
|
||||||
|
.send(
|
||||||
|
None,
|
||||||
|
vec![sender.to_string()],
|
||||||
|
Vec::new(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
msg,
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// make sure the directory exists before trying to save into it
|
/// make sure the directory exists before trying to save into it
|
||||||
fn save_picture(file: &PathBuf, content: &str) -> Result<()> {
|
fn save_picture(file: &PathBuf, content: &str) -> Result<()> {
|
||||||
|
@ -325,12 +310,11 @@ fn get_msg_sender(val: &Value) -> Option<&str> {
|
||||||
val.pointer("/envelope/source").and_then(|x| x.as_str())
|
val.pointer("/envelope/source").and_then(|x| x.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_msg_time(val: &Value) -> Option<String> {
|
fn get_msg_time(val: &Value) -> Option<DateTime<Utc>> {
|
||||||
let time = val
|
let time = val
|
||||||
.pointer("/envelope/timestamp")
|
.pointer("/envelope/timestamp")
|
||||||
.and_then(|x| x.as_i64())?;
|
.and_then(|x| x.as_i64())?;
|
||||||
let time = DateTime::from_timestamp(time, 0)?;
|
DateTime::from_timestamp_millis(time)
|
||||||
Some(time.format("%H:%M").to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_msg_text(val: &Value) -> Option<&str> {
|
fn get_msg_text(val: &Value) -> Option<&str> {
|
||||||
|
|
Loading…
Reference in a new issue